对象
是由__new__()
和__init__()
协作构造完成的
由 __new__() 创建
由 __init__() 定制
所以 __init__() 返回的值只能是 None,否则会在运行时引发 TypeError
__new__()
是一个静态方法
(因为是特例所以你不需要显式地声明)
它会将所请求实例所属的类
作为第一个参数
。其余的参数
会被传递给对象构造器表达式
(对类的调用)
__new__() 的返回值
应为新对象实例 (通常是 cls 的实例
)
注意
py2
与py3
,没有unbounded method
inPython 3
py2 重写的 __new__ 需要 @staticmethod装饰器
Why staticmethod decorator not needed? docs.python.org/3/howto/descriptor.html still refers to “unbound methods”
通过元类
实现单例模式
改变实例创建方式
来实现单例
、缓存
或其他类似的特性
通过重载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',){}