一 引言--类也是对象
先看一个例子:
class Foo(object):
pass
f = Foo()
print(f) # <__main__.Foo object at 0x000001D1E43CD8D0> f是通过Foo类实例化的对象
上述代码中,f是通过 Foo 类实例化的对象。其实,不仅f是一个对象,当使用关键字class的时候,python解释器在加载class的时候就会在内存创建一个名字为Foo对象,所以,Foo类本身也是一个对象。因为在Python中一切事物都是对象
如果按照一切事物都是对象的理论:f对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的构造方法创建
print(type(f)) # <class '__main__.Foo'> 表示f对象由Foo类创建
print(type(Foo)) # <class 'type'> 表示Foo对象由type类创建
既然类也是对象,那我们可以将其作为一个对象去使用,可以:
- 把类赋值给一个变量
- 把类作为函数参数进行传递
- 把类作为函数的返回值
- 在运行时动态地创建类
class Foo(object):
pass
a = Foo # 将类赋值给一个变量
print(a) # <class '__main__.Foo'>
def func(obj):
print(obj)
func(Foo) # 将类作为参数传给函数,输出结果:<class '__main__.Foo'>
def func2():
return Foo # 将类作为函数的返回值
res = func2()
print(res) # <class '__main__.Foo'>
示例
二 如何创建类
2.1 常规方式
class Foo(object):
def __init__(self):
pass
def func1(self):
pass
2.2 通过type创建
def __init__(self):
pass
def func1(self):
pass
Foo = type('Foo', (object,), {'xxx':'xxx','__init__':__init__,'func1': func1})
# type第一个参数:类名
# type第二个参数:当前类的基类,可以为空
# type第三个参数:类的成员,字典格式
print(Foo) # <class '__main__.Foo'>
print(Foo.xxx) # xxx
print(Foo.func1) # <function func1 at 0x000001BF23651268>
# 构造出来的类等同于:
class Foo(object):
xxx = 'xxx'
def __init__(self):
pass
def func1(self):
pass
通过type()
函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()
函数创建出class
正常情况下,我们都用class Xxx...
来定义类,但是,type()
函数也允许我们动态创建出类来,也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。
三 元类
3.1 何为元类
通过上面的描述,我们知道了Python中的类也是对象。元类就是用来创建这些类(对象)的,我们可以理解为:元类是类的类,是类的模板。元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为
元类的实例化的结果为我们用class定义的类,正如上面的例子:f1对象是Foo类的一个实例,Foo类(对象)是 type 类的一个实例
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
补充:我们可以通过type()函数或者__class__属性获取对象的的类,该点仅适用于Python3。因为在经典类中,类(class)和类型(type)并不完全相同,经典类的实例总是继承自一个名为instance的内置类型。如果obj是一个经典类的实例,那么obj.__class__就表示该类,但type(obj)始终是instance类型。
a = 111
str1 = 'joe1991'
list1 = [1,2,3]
def func():
pass
class Foo(object):
pass
f = Foo()
print(type(a)) # <class 'int'>
print(a.__class__) # <class 'int'>
print(type(str1)) # <class 'str'>
print(str1.__class__) # <class 'str'>
print(type(list1)) # <class 'list'>
print(list1.__class__) # <class 'list'>
print(type(func)) # <class 'function'>
print(func.__class__) # <class 'function'>
print(type(f)) # <class '__main__.Foo'>
print(f.__class__) # <class '__main__.Foo'>
print(type(Foo)) # <class 'type'>
print(Foo.__class__) # <class 'type'>
# 对于任何一个__class__的__class__属性又是什么
print(a.__class__.__class__) # <class 'type'>
print(str1.__class__.__class__) # <class 'type'>
print(list1.__class__.__class__) # <class 'type'>
print(func.__class__.__class__) # <class 'type'>
print(f.__class__.__class__) # <class 'type'>
print(Foo.__class__.__class__) # <class 'type'>
# 可以看到,最终都是type
View Code
3.2 metaclass
一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,我们也可以通过继承type来自定义元类,这时我们就需要用到metaclass来指定我们自定义的元类
我们可以这样来理解metaclass:
当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例
但是如果我们想创建出类呢?那就必须根据metaclass(这里的metaclass可以是自定义的,或者type)创建出类,所以:先定义metaclass,然后创建类
连接起来就是:先定义metaclass,就可以创建类,最后创建实例
所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”
class Foo(object): # py2
__metaclass__ = xxx
class Foo(metaclass = xxx): # py3
pass
补充说明:在类被定义的时候,并没有在内存中生成,直到它被调用。然后Python会在当前类中寻找metaclass属性,如果存在,Python会在内存中通过metaclass创建一个类对象,如果没有则会一直向上寻找,如果一直找不到,python就会用内置的type来创建这个类对象
3.3 类的创建过程
class Foo(object): # 不指定metaclass时,默认由type创建
def __init__(self, xxx):
self.xxx = xxx
def __call__(self, *args, **kwargs):
print(self, args, kwargs)
f = Foo('ooo') # Foo实例化,不会楚发__call__
f(1,2,3) # 对象f加括号执行才会触发__call__
# 总结:如果说类Foo是元类type的实例,那么在元类type内肯定也有一个__call__,会在调用Foo('ooo')时触发执行,然后返回一个初始化好了的对象obj
接下来我们自定义元类来完成这一过程
class MyMetaclass(type):
def __init__(self, *args, **kwargs):
super(MyMetaclass,self).__init__(*args, **kwargs)
def __call__(cls, *args, **kwargs):
obj = cls.__new__(cls, *args, **kwargs) # 若当前生成类无__new__方法,会一直向上寻找至object
cls.__init__(obj, *args, **kwargs)
return obj # 一定要返回obj,因为实例化对象时就是获取__call__的返回值
class Foo(object, metaclass=MyMetaclass):
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
return object.__new__(cls,)
# 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建obj对象
obj = Foo('joe')
print(obj.__dict__)
源码
总结:
1. 类由元类(包括type或者自定义元类)创建,创建时自动元类中的__init__方法,所以我们可以元类的__init__方法中控制类的创建行为
2. 类()执行元类的__call__方法(类的__new__方法以及__init__方法),然后返回类的实例对象
注意:
在python3的__new__方法中,若返回object.__new__(cls, *args, **kwargs)会报错:TypeError: object() takes no parameters,修改为:object.__new__(cls )即可,python2中无异常
3.4 自定义元类简单应用
class MyMetaclass(type):
def __init__(self, class_name, class_bases, class_dic): # 这里接收的参数实则为传入type()中参数:类名、基类元组、属性字典
if '__doc__' not in class_dic or not class_dic.get('__doc__').strip():
raise TypeError('必须为类指定文档注释')
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
super(MyMetaclass,self).__init__(class_name, class_bases, class_dic)
def __call__(cls, *args, **kwargs):
obj = object.__new__(cls) # 若当前生成类无__new__方法,会一直向上寻找至object
cls.__init__(obj, *args, **kwargs)
return obj
class Foo(object, metaclass=MyMetaclass):
"""
自定义元类玩玩
"""
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
return object.__new__(cls,)
# 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建obj对象
obj = Foo('joe')
print(obj.__dict__)
View Code
3.5 基于元类实现单例模式
class MySingleton(type):
def __init__(self, *args, **kwargs):
self.__instance = None # 初始化self.__instance = None
super(MySingleton,self).__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super(MySingleton,self).__call__(*args, **kwargs)
return self.__instance
class Foo(object, metaclass=MySingleton): # 执行元类中的__new__方法和__init__方法,且仅会执行一次
def __init__(self):
pass
f1 = Foo()
f2 = Foo()
print(f1 is f2) # True