Reputation: 7554
I have a setup like this:
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)
Which yields the following output:
('Meta', 'TestSub')
What I would have expected would be:
('Test', 'TestSub')
I know why that happens: test
is assigned on Test
before the metaclass Meta
is executed. But I have no idea about how to implement a clean way of changing this behavior. I know I could hack around in __init__
and __new__
of the Meta
class, but that seems dirty because I'd have to modify it for each new property. So is there a clean way (like writing a new decorator) to get this?
I also don't like the idea of creating an intermediate class just to work around this, but would accept it as a last resort.
Upvotes: 1
Views: 83
Reputation: 880547
If that's what you want, don't use a metaclass. Use inheritance:
class Base(object):
@property
def test(self):
return "Meta"
class Test(Base):
test = "Test"
class TestSub(object):
test = "TestSub"
print(Test.test, TestSub.test)
yields
('Test', 'TestSub')
Upvotes: 1
Reputation: 948
I'm not sure is it what you need?
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)
Upvotes: 0
Reputation: 251518
In fact, your Test
class's test
attribute is not overwritten. It's still there:
>>> Test.__dict__['test']
'Test'
However, doing Test.test
doesn't access it, because, according to the documentation:
If an instance’s dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence.
property
creates a data descriptor. So by using a property in the metaclass, you block access to the ordinary class variable on the class.
How best to solve this is not clear, because it's not clear what you're trying to accomplish with this structure. Given the code you posted, it's not clear why you're using a metaclass at all. If you just want override class attributes on subclasses, you can do it with simple inheritance as described in unutbu's answer.
Upvotes: 1