Should I use a metaclass, class decorator, or override the __new__ method?
Here is my problem. I want the following class to have a bunch of property attributes. I could either write them all out like foo
and bar
, or based on some other examples I've seen, it looks like I could use a class decorator, a metaclass, or override the __new__
method to set the properties automagically. I'm just not sure what the "right" way to do it would be.
class Test(object):
def calculate_attr(self, attr):
# do calculaty stuff
return attr开发者_JS百科
@property
def foo(self):
return self.calculate_attr('foo')
@property
def bar(self):
return self.calculate_attr('bar')
Magic is bad. It makes your code harder to understand and maintain. You virtually never need metaclasses or __new__
.
It looks like your use case could be implemented with pretty straightforward code (with only a small hint of magic):
class Test(object):
def calculate_attr(self, attr):
return something
def __getattr__(self, name):
return self.calculate_attr(name)
A metaclass's __new__
does not become the __new__
for the class you make—it's used to make the class itself. The actual class object is returned by the metaclass. A new instance of a class is returned by __new__
.
Consider the following (insane) code:
def MyMetaClass(name, bases, dict):
print "name", name
print "bases", bases
print "dict", dict
return 7
class C('hello', 'world'):
__metaclass__ = MyMetaClass
foo = "bar"
def baz(self, qux):
pass
print "C", C
(I used a function instead of a class as the metaclass. Any callable can be used as a metaclass, but many people choose to right theirs as classes that inherit from type
with new overrided. The differences between that an a function are subtle.)
It outputs
name C
bases ('hello', 'world')
dict {'baz': <function baz at 0x4034c844>, '__module__': '__main__', 'foo': 'bar', '__metaclass__': <function MyMetaClass at 0x40345c34>}
C 7
Does that help you better make sense of what metaclasses are?
You will very seldom need to define a metaclass of your own.
Metaclass is used when new class - not instance - is created. This way you can for example register classes (django does it and uses it for example to create tables in the database). Since class
is an instruction you can think about as a decorator for a class.
精彩评论