在python的类中__new__方法先于__init__方法执行
__new__可以理解为类的实例方法,属于类级别的方法
__init__可以理解为类的初始化方法,属于对象(实例)级别的方法
因此在python中使用类,是用__new__来创建对象,实例对象之后会立即调用__init__方法来对对象属性进行变量初始化,或动态添加对象属性并赋值。
需要注意的是,在重写 new 方法与 init 方法的参数应该保持一致
class Student(object):
cnt = 0 # 用于记录该类的实例创建了多少个
def __new__(cls, *args, **kwargs):
print '__new__'
cls.cnt += 1
return super(Student, cls).__new__(cls, *args, **kwargs)
def __init__(self):
print '__init__'
self.name = 'ELE' + str(self.cnt)
if __name__ == '__main__':
inst1 = Student()
print
inst2 = Student()
print inst2.name
print Student.cnt
输出结果
__new__
__init__
__new__
__init__
ELE2
2
关于 call 方法,不得不先提到一个概念,就是可调用对象(callable),我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable
如果在类中实现了 call 方法,那么实例对象也将成为一个可调用对象。
此处参考:https://www.jianshu.com/p/e1d95c4e1697
个人理解可以理解为调用对象的__call__方法,相当于是__call__重载了小括号运算符
python是垃圾自动回收的,不需要我们显式的销毁对象,当没有引用指向内存中的对象时,即引用计数为0时自动销毁。
当执行del obj时会调用对象的__del__方法, 这时对象的引用计数会减1,当对象的引用计数为0时,对象会被销毁,内存就会被回收。
代码解释如下:
import gc
class A(object):
def __init__(self):
self.large_list=[i for i in xrange(10000000)]
def __del__(self):
print "__del__"
@profile
def foo():
a=A()
b=a
del b
del a
gc.collect()
print
if __name__ == '__main__':
foo()
既然__new__是类级别的方法,则可以通过这个实例类的方法的重载实现python类的单例模式,如下(此处用name来验证是否是同一个实例对象,并动态创建类属性_instance)
class Singleton1(object):
name = ''
def __new__(cls, *args, **kwargs):
if not '_instance' in vars(cls):
print 'creating instance of Singleton1'
cls._instance = super(Singleton1, cls).__new__(cls)
if len(args) > 0:
cls.name = args[0]
elif 'name' in kwargs:
cls.name = kwargs['name']
return cls._instance
inst1 = Singleton1('a')
inst2 = Singleton1(name='b')
print inst1 is inst2
print inst1.name
print inst2.name
<creating instance of Singleton1
<True
<a
<a
或是以下不采用super的方法
class Singleton2(object):
_instance = None
def __new__(cls, *arg, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls, *arg, **kwarg)
return cls._instance
inst1 = Singleton2()
inst2 = Singleton2()
print inst1 is inst2
<True
首先简述两种创建类的方法:
1:
class X(object):
a = 1
2:
X = type('X', (object,), dict(a=1))
其中type(name, bases, dict)实际是构造函数,返回的为一个类对象,其实这里可以理解为一个类就是type的对象。
此处引入元类(metaclass)的解释X = type(‘X’, (object,), dict(a=1)),即类的类,而type就是一个元类,并且 它是python中所有类的元类。
既然知道type可以动态的创建类,则我们可以自定义的实现元类
参考: http://kissg.me/2016/04/25/python-metaclass/
我们为我们创建的新类中的类属性都手动的添加kissg_为前缀
# 我们已经知道type是一个元类,因此自定义元类应继承自type或其子类
# 有一个约定俗成的习惯,自定义元类一般以Metaclass作为后缀,以明确表示这是一个元类
class AddPrefixMetaclass(type):
# __new__方法在__init__方法之前被调用
# 因此,当我们想要控制类的创建行为时,一般使用__new__方法
# 定义普通类的方法时,我们用self作为第一个参数,来指向调用方法的类实例本身
# 此处addprefix_metaclass的意义与self类似,用于指向使用该元类创建的类本身
# 其他参数就是类的定义了,依次是类名,父类的元组,属性的字典
def __new__(addprefix_metaclass, class_name, class_bases, class_dict):
prefix = "kissg_"
addprefix_dict = {} # 我们用一个新的字典来储存加了前缀的属性
# 遍历类的属性,为所有非特殊属性与私有属性加上前缀
for name, val in class_dict.items():
if not name.startswith('_'):
addprefix_dict[prefix + name] = val
else:
addprefix_dict[name] = val
# 调用type函数来返回类,此时我们使用的是加了前缀的属性字典
return type(class_name, class_bases, addprefix_dict)
# 指定metaclass为自定义的元类,将在创建类时使用该自定义元类
class Myclass(object, metaclass=AddPrefixMetaclass):
name = "kissg"
kg = Myclass()
print(hasattr(Myclass, "name"))
# 输出: False
print(hasattr(Myclass, "kissg_name"))
# 输出: True
print(kg.kissg_name)
# 输出: kissg
依照oop写法,以上代码可写成:
class AddPrefixMetaclass(type):
# 此处__new__的参数也是约定俗成的写法,就像用**kw表示关键字参数一样
# cls - 使用自定义元类要创建的类,你可以就简单地记成self
# clsname - 类名
# bases - 父类的元组的(tuple)
# dct - 类属性的字典
def __new__(cls, clsname, bases, dict_):
prefix = "kissg_"
addprefix_dict = {}
for name, val in dict_.items():
if not name.startswith('_'):
addprefix_dict[prefix + name] = val
else:
addprefix_dict[name] = val
# 元类也是可以被继承的。
# 调用父类的__new__方法来创建类,简化继承
return super(AddPrefixMetaclass, cls).__new__(cls, clsname, bases, addprefix_dict)
最后原博客还强调,创建类的元类是可以被继承的,有点拗口,但请区别于元类是可以被继承的。这句话的意思是:定义子类时没有指定元类(即没有metaclass=XXXMetaclass),将自动使用其父类的元类来创建该子类。
python 2.x写法
class Singleton(type):
def __init__(cls, class_name, base_classes, attr_dict):
cls.__instance = None
# super(Singleton, cls).__init__(class_name, base_classes, attr_dict)
def __call__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super(Singleton, cls).__call__(*args, **kwargs)
return cls.__instance
else:
return cls.__instance
class Segger(object):
__metaclass__ = Singleton
def __init__(self, name):
self.name = name
if __name__ == '__main__':
inst1 = Segger('a')
inst2 = Segger('b')
print inst1 is inst2
print inst1.name
print inst2.name
<True
<a
<a # 由于单例只在第一次实例化时候调用call并实现赋值
# Singleton类中的new 和 init 在代码执行到__metaclass__ = Singleton时已经执行,而且只执行一次,不是在segger实例化时候执行的
class Fruit(object):
def __init__(self):
pass
def print_color(self):
pass
class Apple(Fruit):
def __init__(self):
pass
def print_color(self):
print("apple is in red")
class Orange(Fruit):
def __init__(self):
pass
def print_color(self):
print("orange is in orange")
class FruitFactory(object):
fruits = {"apple": Apple, "orange": Orange}
def __new__(cls, name):
if name in cls.fruits.keys():
return cls.fruits[name]()
else:
return Fruit()
fruit1 = FruitFactory("apple")
fruit2 = FruitFactory("orange")
fruit1.print_color()
fruit2.print_color()
输出
apple is in red
orange is in orange