3
votes

Instance de classe en tant que membre de classe de la même classe

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?


4 commentaires

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


@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.


3 Réponses :


2
votes

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:
    ...


1 commentaires

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é.



0
votes

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)


1 commentaires

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!



0
votes

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)


1 commentaires

Oui, j'y ai pensé aussi, mais l'instance membre n'est disponible qu'après la création d'une autre instance.