开发文章

Python面向对象编程进阶

  • 面向对象高级语法部分
    • 经典类vs新式类  
    • 静态方法、类方法、属性方法
    • 类的特殊方法
    • 反射
  • 异常处理
  • Socket开发基础
  • 作业:开发一个支持多用户在线的FTP程序

  

面向对象高级语法部分

 

经典类vs新式类

把下面代码用python2 和python3都执行一下

复制内容到剪贴板
  1. #_*_coding:utf-8_*_  
  2.    
  3.    
  4. class A:  
  5.     def __init__(self):  
  6.         self.n = 'A'  
  7.    
  8. class B(A):  
  9.     #  
  10.  def __init__(self):  
  11.     #      
  12.  self.n = 'B'  
  13.     pass  
  14.    
  15. class C(A):  
  16.     def __init__(self):  
  17.         self.n = 'C'  
  18.    
  19. class D(B,C):  
  20.     #  
  21.  def __init__(self):  
  22.     #      
  23.  self.n = 'D'  
  24.     pass  
  25.    
  26. obj = D()  
  27.    
  28. print(obj.n)  

classical vs new style:

  • 经典类:深度优先
  • 新式类:广度优先
  • super()用法

 

抽象接口

复制内容到剪贴板
  1. import abc  
  2.    
  3. class Alert(object):  
  4.     '''''报警基类'''  
  5.     __metaclass__ = abc.ABCMeta  
  6.   
  7.     @abc.abstractmethod  
  8.     def send(self):  
  9.         '''''报警消息发送接口'''  
  10.         pass  
  11.    
  12.    
  13.    
  14. class MailAlert(Alert):  
  15.     pass  
  16.    
  17.    
  18. m = MailAlert()  
  19. m.send()  

上面的代码仅在py2里有效,python3里怎么实现呢?

  

 

 

 

  

静态方法

通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

复制内容到剪贴板
  1. class Dog(object):  
  2.    
  3.     def __init__(self,name):  
  4.         self.name = name  
  5.   
  6.     @staticmethod #把eat方法变为静态方法  
  7.     def eat(self):  
  8.         print("%s  
  9.  is eating" % self.name)  
  10.    
  11.    
  12.    
  13. d = Dog("ChenRonghua")  
  14. d.eat()  

上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。

复制内容到剪贴板
  1. Traceback  
  2.  (most recent call last):  
  3.   File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/静态方法.py",  
  4.  line 17in <module>  
  5.     d.eat()  
  6. TypeError:  
  7.  eat() missing 1 required  
  8.  positional argument: 'self'  
  9. </module>  

想让上面的代码可以正常工作有两种办法

1. 调用时主动传递实例本身给eat方法,即d.eat(d) 

2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了

复制内容到剪贴板
  1.  1 class Dog(object):  
  2.  2   
  3.  3     def __init__(self,name):  
  4.  4         self.name = name  
  5.  5   
  6.  6     @staticmethod  
  7.  7     def eat():  
  8.  8         print(" is eating")  
  9.  9   
  10. 10   
  11. 11   
  12. 12 d = Dog("ChenRonghua")  
  13. 13 d.eat()  

 

类方法  

类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量

复制内容到剪贴板
  1. class Dog(object):  
  2.     def __init__(self,name):  
  3.         self.name = name  
  4.   
  5.     @classmethod  
  6.     def eat(self):  
  7.         print("%s  
  8.  is eating" % self.name)  
  9.    
  10.    
  11.    
  12. d = Dog("ChenRonghua")  
  13. d.eat()  

执行报错如下,说Dog没有name属性,因为name是个实例变量,类方法是不能访问实例变量的

复制内容到剪贴板
  1. Traceback  
  2.  (most recent call last):  
  3.   File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py",  
  4.  line 16in <module>  
  5.     d.eat()  
  6.   File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py",  
  7.  line 11in eat  
  8.     print("%s  
  9.  is eating" % self.name)  
  10. AttributeError: type object 'Dog' has  
  11.  no attribute 'name'  

此时可以定义一个类变量,也叫name,看下执行效果

复制内容到剪贴板
  1. class Dog(object):  
  2.     name = "我是类变量"  
  3.     def __init__(self,name):  
  4.         self.name = name  
  5.   
  6.     @classmethod  
  7.     def eat(self):  
  8.         print("%s  
  9.  is eating" % self.name)  
  10.    
  11.    
  12.    
  13. d = Dog("ChenRonghua")  
  14. d.eat()  
  15.    
  16.    
  17. #执行结果  
  18.    
  19. 我是类变量 is eating  

属性方法  

属性方法的作用就是通过@property把一个方法变成一个静态属性

复制内容到剪贴板
  1. class Dog(object):  
  2.    
  3.     def __init__(self,name):  
  4.         self.name = name  
  5.   
  6.     @property  
  7.     def eat(self):  
  8.         print("  
  9.  %s is eating" %self.name)  
  10.    
  11.    
  12. d = Dog("ChenRonghua")  
  13. d.eat()  

调用会出以下错误, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了

复制内容到剪贴板
  1. Traceback  
  2.  (most recent call last):  
  3.  ChenRonghua is eating  
  4.   File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py",  
  5.  line 16in <module>  
  6.     d.eat()  
  7. TypeError: 'NoneType' object is not callable  

正常调用如下

复制内容到剪贴板
  1. d = Dog("ChenRonghua")  
  2. d.eat  
  3.    
  4. 输出  
  5.  ChenRonghua is eating  

好吧,把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:

1. 连接航空公司API查询

2. 对查询结果进行解析 

3. 返回结果给你的用户

因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以,明白 了么?

复制内容到剪贴板
  1. class Flight(object):  
  2.     def __init__(self,name):  
  3.         self.flight_name = name  
  4.   
  5.   
  6.     def checking_status(self):  
  7.         print("checking flight %s status " % self.flight_name)  
  8.         return  1  
  9.  
  10.     @property  
  11.     def flight_status(self):  
  12.         status = self.checking_status()  
  13.         if status == 0 :  
  14.             print("flight got canceled...")  
  15.         elif status == 1 :  
  16.             print("flight is arrived...")  
  17.         elif status == 2:  
  18.             print("flight has departured already...")  
  19.         else:  
  20.             print("cannot confirm the flight status...,please check later")  
  21.   
  22.   
  23. f = Flight("CA980")  
  24. f.flight_status  

cool , 那现在我只能查询航班状态, 既然这个flight_status已经是个属性了, 那我能否给它赋值呢?试试吧

复制内容到剪贴板
  1. f = Flight("CA980")  
  2. f.flight_status  
  3. f.flight_status =  2  

输出, 说不能更改这个属性,我擦。。。。,怎么办怎么办。。。

复制内容到剪贴板
  1. checking  
  2.  flight CA980 status  
  3. flight is arrived...  
  4. Traceback  
  5.  (most recent call last):  
  6.   File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py",  
  7.  line 58in <module>  
  8.     f.flight_status =  2  
  9. AttributeError:  
  10.  can't set attribute  

当然可以改, 不过需要通过@proerty.setter装饰器再装饰一下,此时 你需要写一个新方法, 对这个flight_status进行更改。

复制内容到剪贴板
  1. class Flight(object):  
  2.     def __init__(self,name):  
  3.         self.flight_name = name  
  4.   
  5.   
  6.     def checking_status(self):  
  7.         print("checking flight %s status " % self.flight_name)  
  8.         return  1  
  9.  
  10.  
  11.     @property  
  12.     def flight_status(self):  
  13.         status = self.checking_status()  
  14.         if status == 0 :  
  15.             print("flight got canceled...")  
  16.         elif status == 1 :  
  17.             print("flight is arrived...")  
  18.         elif status == 2:  
  19.             print("flight has departured already...")  
  20.         else:  
  21.             print("cannot confirm the flight status...,please check later")  
  22.      
  23.     @flight_status.setter #修改  
  24.     def flight_status(self,status):  
  25.         status_dic = {  
  26.             0 : "canceled",  
  27.             1 :"arrived",  
  28.             2 : "departured"  
  29.         }  
  30.         print("\033[31;1mHas changed the flight status to \033[0m",status_dic.get(status) )  
  31.  
  32.     @flight_status.deleter  #删除  
  33.     def flight_status(self):  
  34.         print("status got removed...")  
  35.   
  36. f = Flight("CA980")  
  37. f.flight_status  
  38. f.flight_status =  2 #触发@flight_status.setter   
  39. del f.flight_status #触发@flight_status.deleter   

注意以上代码里还写了一个@flight_status.deleter, 是允许可以将这个属性删除 

 

类的特殊成员方法

1. __doc__  表示类的描述信息

复制内容到剪贴板
  1. class Foo:  
  2.     """ 
  3.  描述类信息,这是用于看片的神奇 """  
  4.    
  5.     def func(self):  
  6.         pass  
  7.    
  8. print Foo.__doc__  
  9. #输出:类的描述信息  

 

2. __module__ 和  __class__ 

  __module__ 表示当前操作的对象在那个模块

  __class__     表示当前操作的对象的类是什么

class C:      def __init__(self):         self.name = 'wupeiqi'
from lib.aa import C  obj = C() print obj.__module__  # 输出 lib.aa,即:输出模块
print obj.__class__      # 输出 lib.aa.C,即:输出类

3. __init__ 构造方法,通过类创建对象时,自动触发执行。

4.__del__

 析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的

  

 5. __call__ 对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

复制内容到剪贴板
  1. class Foo:  
  2.    
  3.     def __init__(self):  
  4.         pass  
  5.        
  6.     def __call__(self, *args, **kwargs):  
  7.    
  8.         print '__call__'  
  9.    
  10.    
  11. obj = Foo() #  
  12.  执行 __init__  
  13. obj()       #  
  14.  执行 __call__  

6. __dict__ 查看类或对象中的所有成员   

复制内容到剪贴板
  1. class Province:  
  2.    
  3.     country = 'China'  
  4.    
  5.     def __init__(self,  
  6.  name, count):  
  7.         self.name = name  
  8.         self.count = count  
  9.    
  10.     def func(self, *args, **kwargs):  
  11.         print 'func'  
  12.    
  13. #  
  14.  获取类的成员,即:静态字段、方法、  
  15. print Province.__dict__  
  16. #  
  17.  输出:{'country''China''__module__''__main__''func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__'None}  
  18.    
  19. obj1 = Province('HeBei',10000)  
  20. print obj1.__dict__  
  21. #  
  22.  获取 对象obj1 的成员  
  23. #  
  24.  输出:{'count'10000'name''HeBei'}  
  25.    
  26. obj2 = Province('HeNan'3888)  
  27. print obj2.__dict__  
  28. #  
  29.  获取 对象obj1 的成员  
  30. #  
  31.  输出:{'count'3888'name''HeNan'}  

7.__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

复制内容到剪贴板
  1. class Foo:  
  2.    
  3.     def __str__(self):  
  4.         return 'alex  
  5.  li'  
  6.    
  7.    
  8. obj = Foo()  
  9. print obj  
  10. #  
  11.  输出:alex li  

8.__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

复制内容到剪贴板
  1. class Foo(object):  
  2.    
  3.     def __getitem__(self,  
  4.  key):  
  5.         print('__getitem__',key)  
  6.    
  7.     def __setitem__(self,  
  8.  key, value):  
  9.         print('__setitem__',key,value)  
  10.    
  11.     def __delitem__(self,  
  12.  key):  
  13.         print('__delitem__',key)  
  14.    
  15.    
  16. obj = Foo()  
  17.    
  18. result = obj['k1']      #  
  19.  自动触发执行 __getitem__  
  20. obj['k2'] = 'alex'   #  
  21.  自动触发执行 __setitem__  
  22. del obj['k1']     

9. __new__ \ __metaclass__

复制内容到剪贴板
  1. class Foo(object):  
  2.    
  3.    
  4.     def __init__(self,name):  
  5.         self.name = name  
  6.    
  7.    
  8. f = Foo("alex")  

上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象

如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

复制内容到剪贴板
  1. print type(f) #  
  2.  输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建  
  3. print type(Foo) #  
  4.  输出:<type 'type'>              表示,Foo类对象由 type 类创建  

所以,f对象是Foo类的一个实例Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

那么,创建类就可以有两种方式:

a). 普通方式

复制内容到剪贴板
  1. class Foo(object):  
  2.     
  3.     def func(self):  
  4.         print 'hello  
  5.  alex'  

b). 特殊方式

复制内容到剪贴板
  1. def func(self):  
  2.     print 'hello  
  3.  wupeiqi'  
  4.     
  5. Foo = type('Foo',(object,),  
  6.  {'func':  
  7.  func})  
  8. #type第一个参数:类名  
  9. #type第二个参数:当前类的基类  
  10. #type第三个参数:类的成员  

So ,孩子记住,类 是由 type 类实例化产生

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

创建的过程.png

复制内容到剪贴板
  1. #_*_coding:utf-8_*_  
  2.   
  3. class MyType(type):  
  4.     def __init__(self, child_cls, bases=None, dict=None):  
  5.         print("--MyType init---", child_cls,bases,dict)  
  6.         #super(MyType, self).__init__(child_cls, bases, dict)  
  7.       
  8.     # def __new__(cls, *args, **kwargs):  
  9.     #     print("in mytype new:",cls,args,kwargs)  
  10.     #     type.__new__(cls)  
  11.     def __call__(self, *args, **kwargs):  
  12.         print("in mytype call:"self,args,kwargs)  
  13.         obj = self.__new__(self,args,kwargs)  
  14.   
  15.         self.__init__(obj,*args,**kwargs)  
  16.   
  17. class Foo(object,metaclass=MyType): #in python3  
  18.     #__metaclass__ = MyType #in python2  
  19.   
  20.     def __init__(self, name):  
  21.         self.name = name  
  22.         print("Foo ---init__")  
  23.   
  24.     def __new__(cls, *args, **kwargs):  
  25.         print("Foo --new--")  
  26.         return object.__new__(cls)  
  27.   
  28.     def __call__(self, *args, **kwargs):  
  29.         print("Foo --call--",args,kwargs)  
  30. # 第一阶段:解释器从上到下执行代码创建Foo类  
  31. # 第二阶段:通过Foo类创建obj对象  
  32. obj = Foo("Alex")  
  33. #print(obj.name)  

 类的生成 调用 顺序依次是 __new__ --> __call__ --> __init__

 metaclass 详解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那个答案写的非常好

 

反射

通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方法

复制内容到剪贴板
  1. def getattr(object, name, default=None): # known special case of getattr  
  2.     """ 
  3.     getattr(object, name[, default]) -> value 
  4.      
  5.     Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. 
  6.     When a default argument is given, it is returned when the attribute doesn't 
  7.     exist; without it, an exception is raised in that case. 
  8.     """  
  9.     pass  

 

判断object中有没有一个name字符串对应的方法或属性

复制内容到剪贴板
  1. def setattr(x, y, v): # real signature unknown; restored from __doc__  
  2.     """  
  3.     Sets the named attribute on the given object to the specified value.  
  4.       
  5.     setattr(x, 'y', v) is equivalent to ``x.y = v''  
复制内容到剪贴板
  1. def delattr(x, y): # real signature unknown; restored from __doc__  
  2.     """ 
  3.     Deletes the named attribute from the given object. 
  4.      
  5.     delattr(x, 'y') is equivalent to ``del x.y'' 
  6.     """  
复制内容到剪贴板
  1. class Foo(object):  
  2.    
  3.     def __init__(self):  
  4.         self.name = 'wupeiqi'  
  5.    
  6.     def func(self):  
  7.         return 'func'  
  8.    
  9. obj = Foo()  
  10.    
  11. # #### 检查是否含有成员 ####  
  12. hasattr(obj, 'name')  
  13. hasattr(obj, 'func')  
  14.    
  15. # #### 获取成员 ####  
  16. getattr(obj, 'name')  
  17. getattr(obj, 'func')  
  18.    
  19. # #### 设置成员 ####  
  20. setattr(obj, 'age'18)  
  21. setattr(obj, 'show'lambda num: num + 1)  
  22.    
  23. # #### 删除成员 ####  
  24. delattr(obj, 'name')  
  25. delattr(obj, 'func')  

动态导入模块

动态导入模块.png

复制内容到剪贴板
  1. import importlib  
  2.    
  3. __import__('import_lib.metaclass'#这是解释器自己内部用的  
  4. #importlib.import_module('import_lib.metaclass')  
  5.  #与上面这句效果一样,官方建议用这个  

异常处理 

参考 http://www.cnblogs.com/wupeiqi/articles/5017742.html  

感谢 淡淡茶香 支持 磐实编程网 原文地址:
blog.csdn.net/shudaqi2010/article/details/53966020

上一篇:C++智能指针

下一篇:java的引用传递

文章信息

发布时间:2017-01-01

作者:淡淡茶香

发布者:aquwcw

浏览次数: