我有这样的设置:
class Meta(type):
@property
def test(self):
return "Meta"
class Test(object):
__metaclass__ = Meta
test = "Test"
class TestSub(object):
test = "TestSub"
print(Test.test, TestSub.test)
产生以下输出:
('Meta', 'TestSub')
我期望的是:
('Test', 'TestSub')
我知道为什么会发生这种情况:在执行元类test
之前,Test
上会分配Meta
。但我不知道如何实现一种改变这种行为的简洁方法。我知道我可以在__init__
类的__new__
和Meta
中进行攻击,但这看起来很脏,因为我必须为每个新属性修改它。那么有一个干净的方式(比如写一个新的装饰器)来获得这个吗?
我也不喜欢创建一个中间类只是为了解决这个问题,但是会接受它作为最后的手段。
答案 0 :(得分:1)
如果这是您想要的,请不要使用元类。使用继承:
class Base(object):
@property
def test(self):
return "Meta"
class Test(Base):
test = "Test"
class TestSub(object):
test = "TestSub"
print(Test.test, TestSub.test)
产量
('Test', 'TestSub')
答案 1 :(得分:1)
事实上,您的Test
班级test
属性不会被覆盖。它还在那里:
>>> Test.__dict__['test']
'Test'
但是,Test.test
无法访问它,因为根据the documentation:
如果实例的字典具有与数据描述符同名的条目,则数据描述符优先。
property
创建数据描述符。因此,通过在元类中使用属性,可以阻止访问类上的普通类变量。
如何最好地解决这个问题尚不清楚,因为我们不清楚你用这种结构试图完成什么。鉴于您发布的代码,您不清楚为什么要使用元类。如果您只想在子类上覆盖类属性,则可以使用简单继承来完成它,如unutbu的答案中所述。
答案 2 :(得分:0)
我不确定你需要什么?
class Meta(type):
@property
def test(self):
return 'Meta'
def __new__(cls, name, bases, dct):
if 'test' not in dct:
dct['test'] = Meta.test
return super(Meta, cls).__new__(cls, name, bases, dct)
class Test(object):
__metaclass__ = Meta
test = "Test"
class TestSub(object):
test = "TestSub"
class TestWithoutTest(object):
__metaclass__ = Meta
print(Test.test, TestSub.test, TestWithoutTest.test)