元类,特殊类方法
元类
中断类的默认创建、修改类、最后返回修改后的类.
- python中一切都是对象,类也是对象,类本身可以算是元类的实例
- type(class_name, (father_class_name), {key:value})
- 使用class能判断当前对象对应的类
1 | In [6]: "11".__class__ |
在定义一个类的时候,对metaclass进行定义,那么该类就会按照metaclass来设计类
寻找元类的机制
1 | class Foo(bar): |
- Foo中有metaclass这个属性吗?
- 如果有,python会在内存中通过metaclass创建一个名字为Foo的类对象。
- 如果python没有在Foo中找到metaclass,它会继续在Bar(父类)中寻找metaclass,并尝试做和前面同样的操作。
- 如果python由下往上遍历父类也都没有找不到metaclass,它就会在模块(module)中去寻找metaclass,并尝试做同样的操作。
- 如果还是没有找不到metaclass, python才会用内置的type(这也是一个metaclass)来创建这个类对象。
1 | class UpperAttrMetaclass(type): |
super
在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现
- 一个类的 MRO 列表就是合并所有父类的 MRO 列表,并遵循以下三条原则:
- 子类永远在父类前面
- 如果有多个父类,会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
1 | def super(cls, inst): |
其中,cls 代表类,inst 代表实例,上面的代码做了两件事:
- 获取 inst 的 MRO 列表
- 查找 cls 在当前 MRO 列表中的 index, 并返回它的下一个类,即 mro[index + 1]
- 当你使用 super(cls, inst) 时,Python 会在 inst 的 MRO 列表上搜索 cls 的下一个类。
new和call
- new(cls, […])在创造实例前,定义完类就保存该类对象到内存中
- call(self, […])在调用实例的时候,一般用来改变实例的某些属性
单例模式
该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
- 使用模块,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码
使用 new
1
2
3
4
5
6
7
8class Singleton(object):
_instance = None
def __new__(cls, *args, **kw):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
return cls._instance
class MyClass(Singleton):
a = 1使用装饰器(decorator)
1
2
3
4
5
6
7
8
9
10
11
12
13from functools import wraps
def singleton(cls):
instances = {}
def getinstance(*args, **kw):
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return getinstance
class MyClass(object):
a = 1使用元类(metaclass)
1
2
3
4
5
6
7
8
9
10
11
12class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
# Python2
class MyClass(object):
__metaclass__ = Singleton
# Python3
# class MyClass(metaclass=Singleton):
# pass