深入 python 类和对象

python struggling 911次浏览 0个评论
文章目录

一,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方法。


DevOps-田飞雨 》》转载请注明源地址
喜欢 (0)or分享 (0)
发表我的评论
取消评论
*

表情 贴图 加粗 链接 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址