Python面向对象编程(下 高级篇)
面向对象设计中最基础的3个概念:数据封装、继承和多态。
在Python中,面向对象还有很多高级特性,允许我们写出非常强大的功能。
特殊属性__slots__
__slots__类属性知识点汇总 - limalove - 博客园 (cnblogs.com)
***********************************************************************
@property
1,装饰器(decorator):可以给函数动态加上功能;对于类的方法,装饰器一样起作用。
2,Python内置的@property 装饰器就是负责把一个方法变成属性调用的。
3,在类的方法中,如何使用@property?
问题背景:直接给实例绑定属性值,没办法检查参数是否有问题,如果在类中定义方法,使用时又比较麻烦,有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?
>>> 把一个getter方法变成属性,只需要加上@property就可以了,此时,@property 本身又创建了另一个装饰器 @score.setter,负责把一个setter方法变成属性赋值。
只读属性:只定义getter方法,不定义setter方法的属性
可读写属性:既定义getter方法,又定义setter方法的属性
***********************************************************************
多重继承 MixIn
通过多重继承,一个子类就可以同时获得多个父类的所有功能。
参考:https://kevinguo.me/2018/01/19/python-topological-sorting/
MixIn的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个MixIn的功能,而不是设计多层次的复杂的继承关系。
(1)MixIn的目的就是给一个类增加多个功能。 解决对同一对象用不同标准来分类的问题。
举例:从性别划分,你是男人;从国家划分,你是中国人;从职业划分,你是程序员; mixin可以轻松定义具备跟你一样特征的人:中国男程序员(天朝屌丝逗比程序员)
(2)定义
在设计类的继承关系时,通常,主线都是单一继承下来的,但是,如果需要“混入”额外的功能,通过多重继承就可以实现,这种设计通常称之为MixIn.
(3)小结
只允许单一继承的语言(如JAVA),不能使用MixIn设计。
***********************************************************************
定制类
官网地址:https://docs.python.org/3/reference/datamodel.html#special-method-names
__str__
作用:规范化输出格式,输出用户能看懂的格式。
__str__( ),而是__repr__( ),两者的区别:
__str__( ):输出实例时,调用该方法,返回用户看到的字符串
__repr__( ):把实例赋给变量,输出变量时,调用该方法,返回程序开发者看到的字符串,__repr__( )是为调试服务的。
>>> 通常情况下,__repr__( )和 __str__( )的代码相同,所以偷懒时可以写成这种形式:__repr__=__str__ ,类似赋值,把__str__ 里的代码赋给__repr__.
………………………………………………………………………………………………………………………………
__iter__
1,如果一个类想被用于for ……in 循环,类似list、tuple那样,就必须使用一个__iter__( )方法, 该方法返回一个迭代对象。(说明,list tuple的定义中是有__iter__方法的)
2,然后,Python的for循环就会不断调用该迭代对象的__next__( )方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
注:好好理解上面2句话,反映了一些背后的逻辑,本质是什么。跟之前对实例调用len( )函数效果一样,当调用len( )函数时,就会调用该实例的特殊方法__len__.
举例:以斐波那契数列为例,写一个Fib类,可以作用于for循环:
class fib(object): def __init__(self): self.a,self.b=0,1 def __iter__(self): return self #实例本身就是迭代对象,所以返回自己 def __next__(self): #for循环的本质 self.a,self.b=self.b,self.a+self.b if self.a>500: raise StopIteration() return self.a for n in fib(): print(n)
………………………………………………………………………………………………………………………………
__getitem__
索引、 切片的实现逻辑
………………………………………………………………………………………………………………………………
__getattr__
正常情况下,当调用的类的方法或属性不存在时,就会报错。要避免这个错误,Python有一个机制,就是写一个__getattr__( )方法,动态返回一个属性。
只有在没有找到属性的情况下,才调用__getattr__,已有的属性,不会在__getattr__中查找。
任意调用如s.abc都会返回None,这是因为我们定义的__getattr__默认返回就是None。
………………………………………………………………………………………………………………………………
__call__
1,调用实例方法时,常用 实例.方法( ) instance.method( )
2,如果想直接对实例调用:任何类,只需要定义一个__call__( )方法,就可以直接对实例进行调用。
3,如何判断一个对象是否能被调用?
》》》通过callable( )函数可以判断一个对象是否是“ 可调用 ”对象。
***********************************************************************
枚举类
value属性则是自动赋给实例的int常量,默认从1开始计数。
@unique装饰器可以帮助我们检查保证没有重复值。
from enum import Enum, unique
Python提供了Enum类实现枚举。
创建Month类型的枚举类,可以直接使用Month.Jan引用一个常量,或者枚举它的所有成员。
from enum import Enum, unique #创建一个类Month,然后继承自枚举类Enum Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')) for i,j in Month.__members__.items(): print("%s 月份对应的值是 %s"%(i,j.value)) #这里的value是自动赋值,从1开始 #上面的这段代码实现功能和下面相同,只是写法不同 class Month(Enum): #创建一个类Month,然后继承自枚举类Enum,Jan Feb等则是实例名称 Jan=1 Feb=2 Mar=3 Apr=4 Fri=5 Jun=6 for i, j in Month.__members__.items(): print("%s 月份对应的值是 %s" % (i, j.value)) #这里的value返回的是我们创建类时指定的值
可见,既可以用成员名称引用枚举常量,又可以直接根据value的值获得枚举常量。
from enum import Enum, unique @unique #这个装饰器能够确保下面变量的值没有重复值 class Weekday(Enum): sun=0 mon=1 tue=2 wed=3 thu=4 fri=5 sat=6 #使用成员名称 或 值引用枚举常量 print(Weekday.mon) print(Weekday["mon"]) print(Weekday(1)) #这个1并不是索引位置,而是值value print(Weekday["tue"].value)
***********************************************************************
元类
type( ):创建类
动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。
作用:(1)可以查看一个对象的类型或变量的类型
(2)创建出新的类。
创建一个class对象时,type( )函数传入3个参数:
a. 类名
b. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,记住元组tuple的单元素写法,要加上逗号。例如:( object , )
c. 类的方法名和函数绑定。(这里要提前先定义好函数)
本质:创建类class的本质就是通过type( )函数创建的。通过type( )函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type( )函数创建出class。
区别:正常情况下,我们都用class Xxxx……来定义类,但是type( )函数也允许我们动态创建出类来,也就是说,动态语言本身支持运行期动态创建类,这和静态语言有非常大的不同,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现,本质上都是动态编译,会非常复杂。
……………………………………………………………………………………………………………………
metaclass 元类
根据metaclass创建出类,即是:先定义metaclass,然后创建类。
连接起来就是:先定义metaclass,就可以创建类,最后创建实例。
metaclass允许创建类或者修改类。
小结
metaclass是Python中非常具有魔术性的对象,它可以改变类创建时的行为。
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号