python使用元类实现代码复用

对象是由 __new__()__init__() 协作构造完成的

由 __new__() 创建

由 __init__() 定制  

所以 __init__() 返回的值只能是 None,否则会在运行时引发 TypeError

__new__() 是一个静态方法 (因为是特例所以你不需要显式地声明)

它会将所请求实例所属的类作为第一个参数其余的参数会被传递给对象构造器表达式 (对类的调用) __new__() 的返回值应为新对象实例 (通常是 cls 的实例)

注意 py2py3没有unbounded method in Python 3

py2 重写的 __new__ 需要 @staticmethod装饰器

Why staticmethod decorator not needed? docs.python.org/3/howto/descriptor.html still refers to “unbound methods”


python3-cookbook

通过元类实现单例模式

改变实例创建方式来实现单例缓存或其他类似的特性

通过重载new方法实现单例模式 (一个类的单例模式)


class Single(object):

    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance:
            return  cls._instance

        cls._instance = cv = super(Single, cls).__new__(cls, *args, **kwargs)
        return cv



a = Single()
b = Single()

print(a is b )

通过元类, 代码复用 (多个类的单例模式)



# 1 复写 __call__ 方法
class SingleMeta(type):


    def __init__(cls, *args, **kwargs):
        print("cls")
        cls._instance = None
        super(SingleMeta, cls).__init__(*args, **kwargs)


    def __call__(cls, *args, **kwargs):
        if cls._instance is None:
            return cls._instance
        cls._instance = super(SingleMeta, cls).__call__(*args, **kwargs)

        return cls._instance

# 1 class A(object, metaclass=SingleMeta) , 元类__init__, 创建 A类对象
# 2 A(),调用 元类的 __call__ 方法, __new__一个新对象


class A(object, metaclass=SingleMeta):
    ...


a = A()
b = A()

print(a is b)



# 2 重写 __new__ 方法  cls.__new__ = new_instance

class SingleMeta(type):
    def __init__(cls, *args):
        cls._instance = None
        origin_new = cls.__new__

        @staticmethod
        def new_instance(cls, *args, **kwargs):
            if cls._instance:
                return cls._instance
            cls._instance = cv = origin_new(cls)
            return cv

        cls.__new__ = new_instance


class A(metaclass=SingleMeta):
    ...

class B(metaclass=SingleMeta):
    ...

a = A()
a1 =A()
print(a is a1)




# 使用 类装饰器


def single_class(cls):

    cls._instance = None
    origin_new = cls.__new__

    def new_(cls, *args, **kwargs):
        if cls._instance:
            return cls._instance
        cls._instance = cv = origin_new(cls)
        return cv

    cls.__new__ = new_

    return cls


@single_class
class A():
    ...


a = A()
b = A()

print(a is b )  # True



# 或者


def single_class(cls):
    cls._instance = None
    
    def new_(cls, *args, **kw):
        if cls._instance:
            return cls._instance
        cls._instance = cv = object.__new__(cls)
        return cv

    cls.__new__ = new_
    return cls



@single_class
class A(object):
    ...


a = A()
b = A()

print(a is b )



类装饰器, 扩充类的功能

比如重写 特殊方法 __getattribute__

某种程度上来讲,类装饰器方案就显得更加直观,并且它不会引入新的继承体系。 它的运行速度也更快一些, 因为他并不依赖 super() 函数


def log_getattribute(cls):
    # Get the original implementation
    orig_getattribute = cls.__getattribute__

    # Make a new definition
    def __getattribute__(cls, name):
        print('getting:', name)
        return orig_getattribute(cls, name)

    cls.__getattribute__ = __getattribute__


    # def new_getattribute(cls, name):
    #     print('getting:', name)
    #     return orig_getattribute(cls, name)
    # 
    # cls.__getattribute__ = new_getattribute


    # Attach to the class and return
    return cls

# Example use
@log_getattribute
class A:
    def __init__(self,x):
        self.x = x
    def spam(self):
        pass


a = A(42)
print(a.x)


# 类装饰器实现单例模式

def single_class(cls):

    cls._instance = None
    origin_new = cls.__new__

    def new_(cls, *args, **kwargs):
        if cls._instance:
            return cls._instance
        cls._instance = cv = origin_new(cls)
        return cv

    cls.__new__ = new_

    return cls


@single_class
class A():
    ...


a = A()
b = A()

print(a is b )  # True


或者使用元类



class LoggedGetattribute(object):
    def __getattribute__(self, name):
        print('getting:', name)
        return super().__getattribute__(name)

# Example:
class A(LoggedGetattribute):
    def __init__(self,x):
        self.x = x
    def spam(self):
        pass


a = A(42)
print(a.x)




class LoggedGetattribute(type):
    def __init__(cls, name, bases, dict):
        origin_getattr = cls.__getattribute__

        def getattr(self, *args, **kwargs):
            print('__getattribute__:', args, kwargs)
            return origin_getattr(self, *args, **kwargs)

        cls.__getattribute__ = getattr


class A(object, metaclass=LoggedGetattribute):  # Python 3 是 class A(object,metaclass=TraceAttribute):
    a = 1
    b = 2


a = A()
print(a.a)
# output: __getattribute__:('a',){}




Buy me a 肥仔水!