单例模式,类特殊方法笔记

元类,特殊类方法

元类

中断类的默认创建、修改类、最后返回修改后的类.

  • python中一切都是对象,类也是对象,类本身可以算是元类的实例
  • type(class_name, (father_class_name), {key:value})
  • 使用class能判断当前对象对应的类
1
2
3
4
5
In [6]: "11".__class__
Out[6]: str

In [7]: "11".__class__.__class__
Out[7]: type

在定义一个类的时候,对metaclass进行定义,那么该类就会按照metaclass来设计类

寻找元类的机制

1
2
class Foo(bar):
pass
  1. Foo中有metaclass这个属性吗?
  2. 如果有,python会在内存中通过metaclass创建一个名字为Foo的类对象。
  3. 如果python没有在Foo中找到metaclass,它会继续在Bar(父类)中寻找metaclass,并尝试做和前面同样的操作。
  4. 如果python由下往上遍历父类也都没有找不到metaclass,它就会在模块(module)中去寻找metaclass,并尝试做同样的操作。
  5. 如果还是没有找不到metaclass, python才会用内置的type(这也是一个metaclass)来创建这个类对象。
1
2
3
4
5
6
7
8
9
10
11
12
class UpperAttrMetaclass(type):

def __new__(cls, clsname, bases, attrs):
uppercase_attr = {}
for name, val in attrs.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, attrs)
# 等价1 return type.__new__(upperattr_metaclass,future_class_name,future_class_parents, uppercase_attr)
# 等价2 return type(UpperAttrMetaclass, future_class_parents, uppercase_attr)

super

在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现

  • 一个类的 MRO 列表就是合并所有父类的 MRO 列表,并遵循以下三条原则:
  1. 子类永远在父类前面
  2. 如果有多个父类,会根据它们在列表中的顺序被检查
  3. 如果对下一个类存在两个合法的选择,选择第一个父类
1
2
3
def super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]

其中,cls 代表类,inst 代表实例,上面的代码做了两件事:

  • 获取 inst 的 MRO 列表
  • 查找 cls 在当前 MRO 列表中的 index, 并返回它的下一个类,即 mro[index + 1]
  • 当你使用 super(cls, inst) 时,Python 会在 inst 的 MRO 列表上搜索 cls 的下一个类。

newcall

  1. new(cls, […])在创造实例前,定义完类就保存该类对象到内存中
  2. call(self, […])在调用实例的时候,一般用来改变实例的某些属性

单例模式

该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

  • 使用模块,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码
  • 使用 new

    1
    2
    3
    4
    5
    6
    7
    8
        class 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
    13
    from functools import wraps
    def singleton(cls):
    instances = {}
    @wraps(cls)
    def getinstance(*args, **kw):
    if cls not in instances:
    instances[cls] = cls(*args, **kw)
    return instances[cls]
    return getinstance

    @singleton
    class MyClass(object):
    a = 1
  • 使用元类(metaclass)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class 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

详细阅读1
详细阅读2
详细阅读3