2017-02-22 1 views
3

Dans une méthode d'instance d'une classe python, je sais que nous pouvons obtenir le nom de la classe via self.__class__.__name__Enregistrer le nom de la classe dans la variable de la classe sans taper le nom de la classe?

Cependant, je voudrais enregistrer le nom d'une classe dans une variable de classe, sans coder le nom du classe.

Je sais que je peux le faire pour obtenir un nom de classe en une variable de classe:

class MyClass(object): 
    pass 
MyClass._myname = MyClass.__name__ 

Cependant, je dois coder la chaîne MyClass deux fois en dehors de la définition de la classe, tout simplement pour obtenir le nom de la classe dans une variable de classe. Dans ce cas, ce serait "MyClass", que je pourrais simplement le code comme suit:

class MyClass(object): 
    _myname = "MyClass" 

Mais même cela est redondant, étant donné que je dois coder en dur "MyClass" dans la classe MyClass.

Ce que je voudrais est d'obtenir en quelque sorte le nom d'une classe dans une variable de classe sans codage nom de la classe, comme suit:

class MyClass(object): 
    _myname = ???? # where ???? is a statement which returns the class 
       # name, in which the string "MyClass" does not appear 

Est-ce même possible?

Répondre

5

Vous pouvez utiliser un décorateur

>>> def autoname(cls): 
... cls._MyName=cls.__name__ 
... return cls 
... 
>>> @autoname 
... class check: 
... pass 
... 
>>> check._MyName 
'check' 
>>> 

ou si vous ne voulez pas coder en dur le nom de l'attribut:

>>> def autoname2(name): 
...  def autoname(cls): 
...   setattr(cls, name, cls.__name__) 
...   return cls 
...  return autoname 
... 
>>> @autoname2('_StoreHere') 
... class check2: 
...  pass 
... 
>>> check2._StoreHere 
'check2' 
>>> 

Bien sûr, la deuxième forme peut prendre plusieurs paramètres, par exemple:

>>> def autoname3(name, f=lambda x: x): 
...  def autoname(cls): 
...   setattr(cls, name, f(cls.__name__)) 
...   return cls 
...  return autoname 
... 
>>> @autoname3('_MyNameIs', lambda x: x.upper() + '_The_Bold') 
... class check3: 
...  pass 
... 
>>> check3._MyNameIs 
'CHECK3_The_Bold' 
>>> 

Une note sur le décorateur vs métaclasse: Metaclasses sont vraiment cool, nonetheles s, si l'on n'a pas strictement besoin d'eux, ils sont mieux évités en raison de l'infâme metaclass conflicts.

3

Vous pouvez faire cela avec un métaclasse:

class NameMeta(type): 
    def __new__(meta, name, bases, dct): 
     dct['_name'] = name 
     return super().__new__(meta, name, bases, dct) 

class Foo(metaclass=NameMeta): 
    pass 

print(Foo._name)  # prints "Foo" 

Notez que la définition du nom comme un nouvel attribut de la classe est un peu bête, puisque __name__ existe déjà. Probablement vous devriez changer n'importe quel code que vous écrivez qui regarde l'attribut _name et le fait rechercher __name__ à la place.

+0

Eh bien, en fait, j'ai trop simplifié le problème. Ce que je veux vraiment, c'est que la variable de classe contienne des données qui dépendent du nom de la classe ... en d'autres termes, ce serait le résultat d'une fonction du nom de la classe. – HippoMan

+0

PS: Une question peut-elle avoir deux réponses marquées? La réponse de Bickkngt et la réponse de Paul Panzer me donnent toutes les informations que je recherche. Je voudrais signaler vos deux réponses, si possible. – HippoMan

+0

@HippoMan Vous pouvez changer les deux. Mais accepte, je suis sûr que tu ne peux en avoir qu'un seul. –