Python学习之路(37)——元类metaclass
首先,再次强调一点,在Python的世界里,一切皆对象。无论是数值、字符串、序列(包括列表、元组等)、字典、函数、模块、类和实例,甚至文件等等。
元类(metaclass)是从Python 2.2版本开始引入的,它是用于定制类的创建行为。
我们看一下创建类和实例的例子:
class Foo:
def bar():
print('hello python!')
foo = Foo()
print(type(foo))
print(type(foo.bar))
print(type(Foo))
temp = Foo
Foo.var = 11
print(Foo)
######执行结果######
<class '__main__.Foo'>
<class 'method'>
<class 'type'>
<class '__main__.Foo'>
注意,例子中的type(Foo)说明Foo本身也是一个对象(即“类”也是对象),可以将其赋值给其他对象,对其添加属性,将其作为函数参数传递等等。
上面的例子中,Foo类的创建过程会执行class语句,此时需要确定元类(元类定制类的创建行为)。确定元类的过程如下:
1)确定Foo类是否有参数__metaclass__,如果有,Python会在内存中通过__metaclass_-创建一个名为Foo的类对象,如果没有则
2)确定Foo类的父类是否有参数__metaclass__,并尝试做和第1步同样的工作,如果没有则
3)再向上确定Foo类的父类的父类是否有参数__metaclass__,并尝试做和前面一样的工作,如果没有则
4)使用默认元类type
上例中前2项都不符合,则直接使用默认元类type,则上面的语句相当于:
def bar(self):
print('hello python!')
return
Foo = type("Foo", (object,), {"bar": bar})
foo = Foo()
foo.bar()
print(type(Foo))
print(type(foo))
print(type(foo.bar))
######执行结果######
hello python!
<class 'type'>
<class '__main__.Foo'>
<class 'method'>
此时可以看出,实际上Foo类是元类type的实例。
动态创建类
Python中的类可以动态创建(使用默认元类type),原型为:
type(object_or_name, bases, dict)
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
示例1:
def init(self, name):
self.name = name
return
def bar(self):
print("hello %s" % self.name)
return
Foo = type("Foo", (object,), {"__init__": init, "bar": bar, "cls_var": 10})
foo = Foo("nicolas")
print(foo.bar())
print(Foo.cls_var)
######执行结果######
hello nicolas
None
10
示例2:
#创建Foo类
Foo = type("Foo", (object,), {"bar": 10})
#继承Foo类
FooChild = type('FooChild', (Foo,), {})
print(FooChild)
print(FooChild.bar)
#给FooChild类添加方法
def hello(self):
print("hello python!")
FooChild = type("FooChild", (Foo,), {"hello": hello})
hasattr(Foo, "hello")
hasattr(FooChild, "hello")
my_foo = FooChild()
my_foo.hello()
######执行结果######
<class '__main__.FooChild'>
10
hello python!
自定义元类
>>> foo.__class__ # <class 'Foo'> >>> Foo.__class__ # <class 'type'> >>> type.__class__ # <class 'type'>
foo是Foo的实例,Foo是type的实例,type的类又是type。type是默认的元类,我们如何自定义元类?
举个例子,假设我们需要对一个模块追踪的所有函数添加作者属性。首先自定义一个元类,自定义时,需要继承默认的元类type,并重写其中的__new__方法:
class Author(type):
def __new__(mcs, name, bases, dict):
# 添加作者属性
dict["author"] = "nicolas"
return super(Author, mcs).__new__(mcs, name, bases, dict)
对模块中的所有函数的继承类参数中添加metaclass参数:
class Foo(object, metaclass=Author):
pass
foo = Foo()
print(foo.author)
######执行结果######
nicolas
注意:Python 3.x版本中不再有__metaclass__属性以及模块级别的__metaclass__属性。
浙公网安备 33010602011771号