Python类名作为类变量

use*_*245 2 python class-variables python-3.x

我正在使用类和子类作为应用程序.对于每个类,super和sub,都有一个名为的变量类label.我希望label超类的变量默认为类名.例如:

class Super():
    label = 'Super'

class Sub(Super):
    label = 'Sub'
Run Code Online (Sandbox Code Playgroud)

而不是手动为每个类输出变量,是否可以从超类中的类名派生变量并自动为子类填充?

class Super():
    label = # Code to get class name

class Sub(Super)
    pass
    # When inherited Sub.label == 'Sub'.
Run Code Online (Sandbox Code Playgroud)

原因是这将是默认行为.我也希望如果我能获得默认行为,我可以稍后通过指定备用行为来覆盖它label.

class SecondSub(Super):
    label = 'Pie'  # Override the default of SecondSub.label == 'SecondSub'
Run Code Online (Sandbox Code Playgroud)

我尝试过使用__name__,但这不起作用,只是给了我'__main__'.

我想label在@classmethod方法中使用类变量.所以我希望能够在不必实际创建Super()或Sub()对象的情况下引用该值,如下所示:

class Super():
    label = # Magic

    @classmethod
    def do_something_with_label(cls):
        print(cls.label)
Run Code Online (Sandbox Code Playgroud)

Jor*_*ley 8

您可以self.__class__.__name__在标签中作为财产返回

class Super:
    @property
    def label(self):
        return self.__class__.__name__

class Sub(Super):
   pass

print Sub().label
Run Code Online (Sandbox Code Playgroud)

或者你可以在__init__方法中设置它

def __init__(self):
    self.label = self.__class__.__name__
Run Code Online (Sandbox Code Playgroud)

这显然只适用于实例化的类

要访问类方法中的类名,您只需要调用__name__它cls

class XYZ:
    @classmethod
    def my_label(cls):
        return cls.__name__

print XYZ.my_label()
Run Code Online (Sandbox Code Playgroud)

这个解决方案也可能起作用(来自/sf/answers/953740091/)

class classproperty(object):
    def __init__(self, fget):
        self.fget = fget
    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)

class Super(object): 
    @classproperty
    def label(cls):
        return cls.__name__

class Sub(Super):
   pass

print Sub.label  #works on class
print Sub().label #also works on an instance

class Sub2(Sub):
   @classmethod
   def some_classmethod(cls):
       print cls.label

Sub2.some_classmethod()
Run Code Online (Sandbox Code Playgroud)


use*_*ica 6

您可以使用描述符:

class ClassNameDescriptor(object):
    def __get__(self, obj, type_):
        return type_.__name__

class Super(object):
    label = ClassNameDescriptor()

class Sub(Super):
    pass

class SecondSub(Super):
    label = 'Foo'
Run Code Online (Sandbox Code Playgroud)

演示:

>>> Super.label
'Super'
>>> Sub.label
'Sub'
>>> SecondSub.label
'Foo'
>>> Sub().label
'Sub'
>>> SecondSub().label
'Foo'
Run Code Online (Sandbox Code Playgroud)

如果class ThirdSub(SecondSub)应该有ThirdSub.label == 'ThirdSub'而不是ThirdSub.label == 'Foo',你可以做更多的工作。label在类级别分配将被继承,除非您使用元类(这比它的价值要麻烦得多),但我们可以让label描述符查找_label属性:

class ClassNameDescriptor(object):
    def __get__(self, obj, type_):
        try:
            return type_.__dict__['_label']
        except KeyError:
            return type_.__name__
Run Code Online (Sandbox Code Playgroud)

演示:

>>> class SecondSub(Super):
...     _label = 'Foo'
...
>>> class ThirdSub(SecondSub):
...     pass
...
>>> SecondSub.label
'Foo'
>>> ThirdSub.label
'ThirdSub'
Run Code Online (Sandbox Code Playgroud)


che*_*ner 6

元类在这里可能很有用。

class Labeller(type):
    def __new__(meta, name, bases, dct):
        dct.setdefault('label', name)
        return super(Labeller, meta).__new__(meta, name, bases, dct)

# Python 2
# class Super(object):
#    __metaclass__ = Labeller

class Super(metaclass=Labeller):
    pass

class Sub(Super):
    pass

class SecondSub(Super):
    label = 'Pie'

class ThirdSub(SecondSub):
    pass
Run Code Online (Sandbox Code Playgroud)

免责声明:为您的类提供自定义元类时,您需要确保它与任何类在其祖先中使用的任何元类兼容。通常,这意味着确保您的元类继承自所有其他元类,但这样做并非易事。在实践中,元类并不常用,所以通常只是子类化的问题type,但这是需要注意的。