Quelle est la manière la plus "pythonique" de créer un membre de classe qui est une instance de cette classe? C'est à dire. quelque chose comme ceci:
class MyClass:
...
MyClass.instance_as_member = MyClass()
On peut résoudre ceci en ajoutant un membre après la définition de la classe:
class MyClass:
# error! (and this is to be expected as MyClass is not yet fully defined)
instance_as_member = MyClass()
def __init__(self):
print("MyClass instance created!")
mais cela semble un peu faux; naturellement, les membres de la classe doivent être définis dans cette classe.
Y a-t-il une meilleure façon de faire cela?
3 Réponses :
Ce n'est pas "Un peu faux" - c'est la manière simple et évidente de le faire. Une ligne de code, lisible par tout le monde et "ce que c'est" évident.
Pourtant, il ne "se sent" pas élégant. Donc, si vous ne voulez pas faire cela uniquement pour l'apparence, et peut-être, s'il y a beaucoup de classes comme celle-ci, sans répéter le code, cela pourrait être fait avec un décorateur de classe:
def instance_as_member(attr_name='instance_as_member', *init_args, **init_kwargs):
def decorator(cls):
instance = cls(*init_args, **init_kwargs)
setattr(cls, attr_name, instance)
return cls
return decorator
@instance_as_member()
class MyClass:
...
Bonne idée en utilisant le décorateur, mais je pense que votre premier commentaire est exact: il est probablement préférable de simplement faire le devoir après la définition de la classe pour des raisons de lisibilité.
Il semble que vous souhaitiez un type de fonctionnalité setUp . Voici une manière "légèrement sale" de le faire à partir de la classe: définissez un indicateur de variable de classe pour indiquer la première utilisation de la classe. Vérifiez l'indicateur lors de l'instanciation; s'il s'agit du premier accès, effacez l'indicateur et exécutez la méthode de configuration.
class MyClass:
first_touch = True
def __init__(self, id=0):
if MyClass.first_touch:
MyClass.setUp(id)
print("MyClass instance created!", id)
@classmethod
def setUp(self, id):
MyClass.first_touch = False
MyClass.instance_as_member = MyClass(-999)
print("Start")
local_obj = MyClass(1)
local_obj = MyClass(2)
local_obj = MyClass(3)
Même problème avec la réponse de match: cela ne fonctionnerait que si l'instance membre n'est accessible qu'après la création d'une autre instance. Merci pour la suggestion!
Bien que la classe ne soit pas définie dans le corps, elle est définie à l'intérieur de __init__
Cependant, il y a un problème qui instancie la classe à l'intérieur de __init__ est récursif, vous devez donc savoir si instance_as_member a déjà été créé.
Quelque chose comme ce qui suit fonctionne:
class Foo:
member_added = False
instance_as_member = None
def __init__(self):
if not Foo.member_added:
Foo.member_added = True
Foo.instance_as_member = Foo()
print(Foo.instance_as_member)
Foo()
print(Foo.instance_as_member)
Oui, j'y ai pensé aussi, mais l'instance membre n'est disponible qu'après la création d'une autre instance.
Eh bien, puisque la classe n'existe pas encore à l'intérieur du corps de la classe, vous devez trouver un point après que le corps de la classe est terminé.
Logique. La solution proposée est donc la seule façon de le faire, je suppose.
Related a >
@RobertR: il y a autre hooks disponible , mais il est parfois plus simple de simplement l'ajouter après la création de la classe.