我正在使用类和子类作为应用程序。对于每个类,super和sub,都有一个名为label
的类变量。我希望超类的label
变量默认为类名。例如:
class Super():
label = 'Super'
class Sub(Super):
label = 'Sub'
不是手动为每个类输出变量,是否可以从超类中的类名派生变量并自动为子类填充?
class Super():
label = # Code to get class name
class Sub(Super)
pass
# When inherited Sub.label == 'Sub'.
原因是这将是默认行为。我也希望如果我能获得默认行为,我可以稍后通过指定备用label
来覆盖它。
class SecondSub(Super):
label = 'Pie' # Override the default of SecondSub.label == 'SecondSub'
我已尝试使用__name__
,但这不起作用,只是给了我'__main__'
。
我想在label
方法中使用类变量@classmethod
。所以我希望能够引用该值而无需实际创建Super()或Sub()对象,如下所示:
class Super():
label = # Magic
@classmethod
def do_something_with_label(cls):
print(cls.label)
答案 0 :(得分:8)
您可以在标签中将self.__class__.__name__
作为属性
class Super:
@property
def label(self):
return self.__class__.__name__
class Sub(Super):
pass
print Sub().label
或者您可以在__init__
方法
def __init__(self):
self.label = self.__class__.__name__
这显然只适用于实例化的类
要访问类方法中的类名,只需在__name__
cls
即可
class XYZ:
@classmethod
def my_label(cls):
return cls.__name__
print XYZ.my_label()
这个解决方案也可能有用(从https://stackoverflow.com/a/13624858/541038获取)
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()
答案 1 :(得分:4)
您可以使用descriptor:
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'
演示:
>>> Super.label
'Super'
>>> Sub.label
'Sub'
>>> SecondSub.label
'Foo'
>>> Sub().label
'Sub'
>>> SecondSub().label
'Foo'
如果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__
演示:
>>> class SecondSub(Super):
... _label = 'Foo'
...
>>> class ThirdSub(SecondSub):
... pass
...
>>> SecondSub.label
'Foo'
>>> ThirdSub.label
'ThirdSub'
答案 2 :(得分:4)
元类在这里可能很有用。
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
免责声明:为您的班级提供自定义元类时,您需要确保它与其祖先中任何类使用的任何元类都兼容。通常,这意味着确保您的元类继承自所有其他元类,但这样做可能非常重要。实际上,元类并不常用,因此通常只需要对type
进行子类化,但这是需要注意的事项。
答案 3 :(得分:0)
从 Python 3.6 开始,最简洁的方法是使用 PEP 487 中引入的 __init_subclass__
钩子。它比使用元类简单得多(并且更容易管理继承)。
class Base:
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
if 'label' not in cls.__dict__: # Check if label has been set in the class itself, i.e. not inherited from any of its superclasses
cls.label = cls.__name__ # If not, default to class's __name__
class Sub1(Base):
pass
class Sub2(Base):
label = 'Custom'
class SubSub(Sub2):
pass
print(Sub1.label) # Sub1
print(Sub2.label) # Custom
print(SubSub.label) # SubSub