一,python 新式类和经典类的区别
python 的新式类是2.2版本引进来的,通常将之前的类叫做经典类或者旧类。
官方对新式类的解释是:
为了统一类(class)和类型(type),在 2.2 版本之前,类和类型是不同的,如下所示 a 是 class A的一个实例,那么a.class返回 ‘__main__.A‘
,type(a)返回总是<type 'instance'>
。而引入新类后,比如 class B是个新类,b是class B 的实例,b.class和type(b)都是返回‘<class '__main__.B'>'
,这样就统一了。
引入新类后,还有其他的好处,比如更多的内置属性将会引入,描述符的引入,属性可以来计算等等。
为了向前兼容,默认情况下用户定义的类为经典类,新类需要继承自所有类的基类 object 或者继承自object的新类。
#!/usr/bin/env python # coding=utf-8 class A: def __init__(self): pass class B(object): def __init__(self): pass a = A() b = B() print a.__class__,type(a) print b.__class__,type(b) [root@localhost py]# python test3.py __main__.A <type 'instance'> <class '__main__.B'> <class '__main__.B'>
二,动态添加字段和方法
#!/usr/bin/env python # coding=utf-8 class demo(object): def __init__(self): self.name = 'feiyu' def func(self): print 'func' @staticmethod def func1(self): print 'func1' def test(arg): print 'test:',arg def test1(arg): print '----test-1:',arg demo.func2 = test #添加的是动态方法,只有对象才可以调用 a = demo() a.func2() a.func3 = test1('aasdsad') demo.age = 18 print "demo.age:",demo.age a.gender = 'male' print 'a.gender:',a.gender
当给类添加方法时,添加的是动态方法,只有实例化后才能调用;给对象添加的字段是动态字段,对类添加的字段是静态字段。
三,__slots__ 的使用
在新式类中可以使用 slots 对类添加动态字段做一定的控制。
class demo(object): __slots__ = ('name','age') def __init__(self): self.name = 'feiyu' a = demo() a.name = 'feiyu' a.age = 20 a.gender = 'male' #__slots__ 中没有此方法
运行会报错:
a.gender = 'male' AttributeError: 'demo' object has no attribute 'gender'
但是对类添加静态字段没有限制:
#!/usr/bin/env python # coding=utf-8 class demo(object): __slots__ = ('name','age') def __init__(self): self.name = 'feiyu' a = demo() #a.name = 'feiyu' #a.age = 20 #a.gender = 'male' demo.age = 20 demo.name = 'feiyu' demo.gender = 'male' print demo.age,demo.name,demo.gender
四,父类的初始化
python实例化子类时,只执行自己的构造函数,其他语言像java,会先执行父类的构造函数,然后执行子类的构造函数,python 中需要手动执行父类的构造函数。
class Fa: def __init__(self): print 'fa.__init__' class So(Fa): def __init__(self): Fa.__init__(self) #--手动调用父类的构造函数 print 'so.__init__' s = So()
也可以使用 super 执行父类的构造函数,但 super 是新式类引进的,要使用 super 则需要继承 object 。
class Fa(object): def __init__(self): print 'fa.__init__' class So(Fa): def __init__(self): #Fa.__init__(self) super(So,self).__init__() print 'so.__init__' s = So() [root@sta test]# python test3.py fa.__init__ so.__init__
结论:
要主动执行父类的构造函数时,对于经典类:
使用 Fa.__init__(self) 执行父类的构造函数
对于新式类:
使用 super(So,self).__init__()
五,查看父类: __bases__ 只显示一层继承的所有父类
class A: pass class B: pass class C(A,B): pass print C.__bases__ [root@sta test]# python test.py (<class __main__.A at 0x7f6cfb21e590>, <class __main__.B at 0x7f6cfb21e5f0>)
改为以下进行多级继承:
class A: pass class B(A): pass class C(B): pass print C.__bases__ [root@sta test]# python test.py (<class __main__.B at 0x7f1ccd08c590>,)
六,__call__方法,对象实例化
call 是 python 中一个有趣的语法,只要定义类型的时候,实现call函数,这个类型就成为可调用的。即我们就可以把这个类的对象当作函数来使用,相当于重载了括号运算符。
class demo: def __init__(self): self.name = 'feiyu' def func(self): print 'func' a = demo() a() #对象实例化?? [root@sta test]# python test5.py Traceback (most recent call last): File "test5.py", line 13, in <module> a() AttributeError: demo instance has no __call__ method
然后添加call方法:
class demo: def __init__(self): self.name = 'feiyu' def func(self): print 'func' def __call__(self): print 'call' a = demo() a() [root@sta test]# python test5.py call
七,创建类的另一种方法 type
In [1]: type?? Docstring: type(object) -> the object's type type(name, bases, dict) -> a new type Type: type
type有两个功能,一个是查看对象的类型,它也能动态的创建类。type可以接受一个类的描述作为参数,然后返回一个类。
class Foo: def __init__(self): pass #f = Foo() #通过调用foo构造函数创建 f 对象 #foo = type(f) #通过调用type构造函数创建 foo 对象,foo 是type 的对象,type 也是一个类 bar = type('bar',(object,),{'name':'feiyu'}) print bar print bar.name print dir(bar) [root@sta test]# python test6.py <class '__main__.bar'> feiyu ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。type就是创建类对象的类,可以通过查看class属性来看到这一点。Python中所有的东西,包括整数、字符串、函数以及类都是对象。它们都是对象,而且它们都是从一个类创建而来。
In [1]: a = 1 In [2]: a.__class__ Out[2]: int In [3]: a.__class__.__class__ Out[3]: type In [4]: s = 'str' In [5]: s.__class__ Out[5]: str In [6]: s.__class__.__class__ Out[6]: type
八 ,__metaclass__ 属性
在目标类里面定义一个 metaclass 就可以使用指定的类去创建它。自定义元类的主要目的就是为了当创建类时能够自动地改变类。
class MyType(type): def __init__(self,names,bases,dict): print 'created a class' def __call__(self, *args, **kwargs): #type的call方法创建实例并且调用demo的__init__方法,重写call则不会创建类 print 'mytype.__call__' class demo: __metaclass__ = MyType def __init__(self): self.name = 'feiyu' def func(self): print self.name def __call__(self): print 'call' f = demo() print f [root@localhost py]# python test1.py created a class mytype.__call__ None
Python会在类的定义中寻找metaclass属性,如果找到了,Python就会用它来创建类 demo,如果没有找到,就会用内建的type来创建这个类。metaclass 内部代码比较复杂,目前还没有完全掌握,有待研究。
九,__new__ :根据类型生成对象
class MyType(type): def __init__(self,names,bases,dict): print 'created a class' def __call__(self, *args, **kwargs): # self 是个类型 print 'mytype.__call__' print self, args, kwargs # __new__ re = self.__new__(self, *args, **kwargs) #根据类名创建一个对象然后将对象传到 self.__init__(re) print re #__init__ (需要一个对象) self.__init__(re) class demo: __metaclass__ = MyType #由于定义了 metaclass ,所以这个类是由 MyType 的 __init__ 方法创建的 def __init__(self): self.name = 'feiyu' def func(self): print self.name def __call__(self): print 'call' f = demo() #而 f 这个对象是由 MyType 的 call 方法创建的 print f
type的call方法创建实例并且调用init方法。