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中非常具有魔术性的对象,它可以改变类创建时的行为。

posted @ 2019-03-03 19:16  limalove  阅读(264)  评论(0)    收藏  举报