在不输入类名的情况下将类名存储在类变量中?

时间:2017-02-22 02:44:43

标签: python class classname

在python类的实例方法中,我知道我们可以通过self.__class__.__name__获取类名

但是,我想在类变量中存储类的名称,而不编写类的名称。

我知道我可以这样做,将类的名称变成类变量:

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

但是,我必须在类定义之外两次编写字符串MyClass,只是为了将类名称转换为类变量。在这种情况下,那将是"MyClass",我可以简单地编码如下:

class MyClass(object):
  _myname = "MyClass"

但即使这是多余的,因为我必须在"MyClass"类中对MyClass进行硬编码。

我喜欢的是以某种方式将类的名称变成类变量而不编写类的名称,如下所示:

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

这甚至可能吗?

2 个答案:

答案 0 :(得分:5)

您可以使用装饰器

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

或者,如果您不想对属性的名称进行硬编码:

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

当然,第二种形式可以采用更多参数,例如:

>>> 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'
>>>

关于装饰者与元类的说明:元类非常酷,但是,如果不严格需要它们,最好避免因为臭名昭着的metaclass conflicts

答案 1 :(得分:3)

你可以用元类来做到这一点:

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"

请注意,将名称设置为类的新属性有点愚蠢,因为__name__已经存在。您可能应该更改正在编写的查看_name属性的任何代码,并使其查找__name__