【发布时间】:2018-09-05 17:46:04
【问题描述】:
我正在尝试创建一个返回类名和属性的类。这需要同时使用实例属性和类属性
class TestClass:
obj1 = 'hi'
即我想要以下(注意:有和没有类实例化)
>>> TestClass.obj1
('TestClass', 'hi')
>>> TestClass().obj1
('TestClass', 'hi')
在python中使用Enum包也可以得到类似的效果,但是如果我从Enum继承,就无法创建__init__函数,我也想做
如果我使用 Enum,我会得到:
from enum import Enum
class TestClass2(Enum):
obj1 = 'hi'
>>> TestClass2.obj1
<TestClass2.obj1: 'hi'>
我已经尝试过在元类中重写 __getattribute__ 魔术方法,如下所示:How can I override class attribute access in python。但是,这破坏了__dir__ 魔术方法,该方法不会返回任何内容,而且它似乎返回元类的名称,而不是子类的名称。示例如下:
class BooType(type):
def __getattribute__(self, attr):
if attr == '__class__':
return super().__getattribute__(attr)
else:
return self.__class__.__name__, attr
class Boo(metaclass=BooType):
asd = 'hi'
print(Boo.asd)
print(dir(Boo))
我也尝试过覆盖 __setattr__ 魔术方法,但这似乎只影响实例属性,而不影响类属性。
我应该声明我正在寻找一个通用的解决方案。不是我需要为每个属性编写 @property 或 @classmethod 函数或类似的东西
【问题讨论】:
-
您可以简单地使用一些新方法,例如.view() 返回您想要的输出。似乎没有必要重载 gettrib,使用 Enum 也是如此。
-
问题是你要实现的行为是由每个属性本身提供的,而不是
TestClass。您可以使用元类__prepare__方法来“预处理”您的类属性(例如,使它们成为某个自定义描述符的所有实例)。可以使用__setattr__而不是__prepare__类似地处理实例属性。 -
对,所以我需要通过一个元类来定义这个行为。使用
__prepare__意味着不是返回值,而是返回带有该值的字典?我想这可能会起作用,即使它不会像我的示例中所示将元组归还给我。通过__prepare__是最简单的,还是使用__new__也可以?