- 類相關(guān)知識
- 對象相關(guān)知識
- 類屬性增刪改查
- 實(shí)例屬性增刪改查
- 對象與實(shí)例屬性
- 靜態(tài)屬性
- 類方法
- 靜態(tài)方法
- 組合
- 繼承
- 接口設(shè)計(jì)與歸一化設(shè)計(jì)
- 繼承順序之mro線性順序列表
- Python2中的繼承順序
- 子類調(diào)用父類的方法
- super調(diào)用父類的方法
- 多態(tài)
- 封裝
- 反射
- 動態(tài)導(dǎo)入模塊
- 類的內(nèi)置屬性attr
- 繼承方式完成包裝
- 組合方式完成授權(quán)
- getattribute
- item
- str與repr
- 自定制format
- slots屬性
- doc屬性
- module和class
- 析構(gòu)方法
- call方法
- 迭代器協(xié)議
- 描述符理論
- 描述符優(yōu)先級
- 類的裝飾器
- 自定制property
- 元類
- 自定義元類
類相關(guān)知識
對象相關(guān)知識
類屬性增刪改查
實(shí)例屬性增刪改查
對象與實(shí)例屬性
靜態(tài)屬性
類方法
靜態(tài)方法
組合
繼承
接口設(shè)計(jì)與歸一化設(shè)計(jì)
聚成順序之mro線性順序列表
Python2中的繼承順序
子類調(diào)用父類的方法
super調(diào)用父類的方法
多態(tài)
封裝
反射
動態(tài)導(dǎo)入模塊
類的內(nèi)置屬性attr
繼承方式完成包裝
組合方式完成授權(quán)
getattribute
item
str與repr
自定制format
slots屬性
doc屬性
module和class
析構(gòu)方法
call方法
迭代器協(xié)議
描述符理論
描述符優(yōu)先級
類的裝飾器
自定制property
元類
自定義元類
一. 面向?qū)ο缶幊痰囊恍┨匦?/h1>
相比于面向過程的編程方式,采用面向?qū)ο蟮木幊谭绞娇梢蕴岣叽a的復(fù)用性和靈活性
1. 復(fù)用性
設(shè)計(jì)一個類,就是為了將這個類作為一個模塊來使用,一個類多次被使用就提高了這個類的復(fù)用性,最終達(dá)到減少代碼量以及修改一處處處更新的目的。提高代碼復(fù)用性的方法有兩個:組合,派生
組合
組合就是將B類加入到A類中,兩個類的關(guān)系就是A has B,通過這種方式來增強(qiáng)B類的功能和A類的代碼重用性。
class Course(object):
def __init__(self, name, period):
self.name = name
self.period = period
class Teacher:
def __init__(self, name, gender, course):
self.name = name
self.gender = gender
self.course = course
c1 = Course('python', 7)
t1 = Teacher('Hax', 'male', c1)
print(t1.course.period)
>>7
Course類被組合進(jìn)Teacher類,Teacher就擁有了Course類的所有屬性和方法。
派生
子類繼承了父類的屬性,然后衍生出自己新的屬性,如果子類衍生出的新的屬性與父類的某個屬性的名字相同,那么再調(diào)用子類的這個屬性,就以子類的這個屬性為準(zhǔn)了。
類特征可以在子孫類或子類中進(jìn)行繼承。這些子類從基類繼承他們的核心屬性,并且不影響父類的的特性。
class Human(object):
def __init__(self, name, gender, birthday):
self.name = name
self.gender = gender
self.birthday = birthday
def prt(self):
print('from Human', self.name, self.gender, self.birthday)
def flag(self):
print('this is Human class')
class Teacher(Human):
def __init__(self, name, gender, birthday):
Human.__init__(self, name, gender, birthday)
def flag(self):
print('this is Teacher class')
h1 = Human('Ken', 'female', '2016/1/2')
t1 = Teacher('Joe', 'male', '2017/1/1')
h1.prt()
t1.prt()
h1.flag()
t1.flag()
>>
from Human Ken female 2016/1/2
from Human Joe male 2017/1/1
this is Human class
this is Teacher class
flag方法在子類中實(shí)現(xiàn)了,調(diào)用時(shí)只調(diào)用子類的flag方法,而不影響父類的flag方法。prt方法在父類中定義,而在子類中沒有定義,那么調(diào)用時(shí)父類子類都調(diào)用父類的prt方法。
2.靈活性
靈活性通過多態(tài)和多態(tài)性實(shí)現(xiàn)
多態(tài)是從類的定義的維度來定義的,以動物類為例,雞、鴨、魚、狗都是動物,但是是不同的動物,又都有動物的特性,即一類事物的不同形態(tài)。
**多態(tài)性是從類方法的應(yīng)用維度定義的。還是以動物類為例。所有的動物都有移動這個特性,移動這個特性包括:爬,游,走。為了方便應(yīng)用可以定義一個函數(shù)接受不同的動物作為參數(shù),執(zhí)行相同的方法--移動,但執(zhí)行的結(jié)果不同--爬,游,走,這就是多態(tài)性。
class Animal(object):
def __init__(self, sex, age):
self.sex = sex
self.age = age
def move(self):
pass
class Fish(Animal):
def __init__(self, sex, age):
Animal.__init__(self, sex, age)
def move(self):
print('Fish is swimming')
class Bird(Animal):
def __init__(self, sex, age):
Animal.__init__(self, sex, age)
def move(self):
print('Bird is flying')
f = Fish('female', 2)
b = Bird('male', 3)
def func(obj):
obj.move()
func(f)
func(b)
代碼中定義的魚和鳥就是動物類的多態(tài)表現(xiàn),通過func 方法傳入不同的動物的實(shí)例執(zhí)行實(shí)例對應(yīng)的方法就是多態(tài)性的體現(xiàn)
3. 封裝
封裝數(shù)據(jù):保護(hù)隱私
封裝方法:隔離復(fù)雜度
封裝需要提供訪問被封裝內(nèi)容的接口,接口調(diào)用者只能通過接口訪問內(nèi)部數(shù)據(jù),并且不能訪問被隱藏內(nèi)容的細(xì)節(jié)。此外,可以在接口中設(shè)計(jì)邏輯,限制調(diào)用者的訪問方式。
封裝分為兩個層次
第一個層次就是建立類,當(dāng)類建立之后,調(diào)用者只能通過點(diǎn)的方式訪問類內(nèi)的數(shù)據(jù)。第二層次是通過
第二個層次是將類內(nèi)的方法或?qū)傩远x為私有的,只能在類內(nèi)部調(diào)用,類外部是調(diào)用不到的,或者在有需求時(shí)通過設(shè)計(jì)接口的方式供類外部使用。
使用雙下劃線設(shè)置私有變量
class Teacher(object):
def __init__(self, name, salary):
self.name = name
self.__salary = salary # 變形為_Teacher__salary
def __set_salary(self, s): # 變形為_Teacher__set_salary
self.__salary = s
def get_salary(self):
return self.__salary
類中所有__ x都會變?yōu)?code>_類名 __ x ,self.__x引用的是變形后的屬性;這種變形的目的是在類的外部是無法通過類. __x或對象.__x來訪問到雙下滑先開頭定義的屬性或方法的。</br>
在子類定義的__x不會覆蓋在父類定義的__x,因?yàn)?strong>子類中變形成了:_子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時(shí),子類是無法覆蓋的。</br>
這種機(jī)制也并沒有真正意義上限制我們從外部直接訪問屬性,知道了類名和屬性名就可以拼出名字:_類名__屬性,然后就可以訪問了。</br>
變形的過程只在類的定義是發(fā)生一次,在定義后的賦值操作,不會變形</br>
在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有的
# 不使用雙下滑線定義方法,子類方法覆蓋了父類方法
class Human(object):
def language(self):
print('speak sth')
def speak(self):
self.language()
class China(Human):
def language(self):
print('speak chinese')
p = China()
p.speak()
>>speak chinese
# 使用雙下滑線定義方法,子類方法沒有覆蓋父類方法
class Human(object):
def __language(self):
print('speak sth')
def speak(self):
self.__language()
class China(Human):
def __language(self):
print('speak chinese')
p = China()
p.speak()
>>speak sth
python并不會真的阻止你訪問私有的屬性,模塊也遵循這種約定,如果模塊名以單下劃線開頭,那么from module import *時(shí)不能被導(dǎo)入,但是通過from module import _private_module依然是可以導(dǎo)入的
property
property是一種特殊的特性,使用該特性后對象調(diào)用方法時(shí)會使用像對象訪問屬性一樣的方式
import math
class Circle:
def __init__(self,radius):
self.radius=radius
@property
def area(self):
return math.pi * self.radius**2
@property
def perimeter(self):
return 2*math.pi*self.radius
c=Circle(10)
print(c.radius)
print(c.area) # 像訪問數(shù)據(jù)屬性訪問area,實(shí)際執(zhí)行函數(shù)功能,計(jì)算面積
print(c.perimeter) # 像訪問數(shù)據(jù)屬性訪問perimeter,實(shí)際執(zhí)行函數(shù)功能,計(jì)算周長
在C++里一般會將所有的所有的數(shù)據(jù)都設(shè)置為私有的,然后提供set和get方法(接口)去設(shè)置和獲取,在python中通過property方法可以實(shí)現(xiàn)
class Foo:
def __init__(self, val):
self.__NAME = val #將所有的數(shù)據(jù)屬性都隱藏起來
@property
def name(self):
pass
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError('%s must be str' % value)
self.__NAME = value
@name.getter
def name(self):
return self.__NAME
@name.deleter
def name(self):
raise TypeError('Can not delete')
f = Foo('Jack')
print(f.name)
>>Jack
上述例子通過@name.setter裝飾的方法將私有屬性在檢查過類型后賦值給了self.__NAME,然后通過@name.getter裝飾的方法方法獲取到了私有屬性。
二. 類相關(guān)的知識點(diǎn)
1. 類屬性及方法的增刪改查
2. super
super用于繼承中,用來替換父類,簡化代碼,下面舉例說明
python2
在介紹super前先引入一個概念:新式類,經(jīng)典類
在Python2中類有新式類和經(jīng)典類兩種類,新式類是有父類的類,如果沒有實(shí)際的父類就使用object作為父類;經(jīng)典類是沒有父類的類。
python2中super方法只對新式類有效
下面的例子就是新式類中super方法的使用范例
class People(object):
def __init__(self, name, gender, age):
self.name = name
self.gender = gender
self.age = age
def walk(self):
print '%s is walking' % self.name
class China(People):
country = 'china'
def __init__(self, name, gender, age, language='chinese'):
super(China, self).__init__(name, gender, age)
self.language = language
super代替People并在其后加上當(dāng)前類的類名China和self作為參數(shù)
python3
在``python3`中對語法進(jìn)行了進(jìn)一步的精簡
class People(object):
def __init__(self, name, gender, age):
self.name = name
self.gender = gender
self.age = age
def walk(self):
print('%s is walking' % self.name)
class China(People):
country = 'china'
def __init__(self, name, gender, age, language='chinese'):
super().__init__(name, gender, age)
self.language = language
可以看出將super后面的參數(shù)省去了
3. 接口與歸一化設(shè)計(jì)
在Python中沒有接口的概念,為了實(shí)現(xiàn)接口設(shè)計(jì),可以使用繼承實(shí)現(xiàn);為了實(shí)現(xiàn)強(qiáng)制子類實(shí)現(xiàn)接口功能,可以使用abc模塊
import abc
class File(metaclass=abc.ABCMeta):
@abc.abstractmethod
def file_write(self):
pass
@abc.abstractmethod
def file_read(self):
pass
class Text(File):
def file_write(self):
print('text file execute write operation')
def file_read(self):
print('text file execute read operation')
class Process(File):
def file_write(self):
print('process file execute write operation')
def file_read(self):
print('process file execute read operation')
class Disk(File):
def file_write(self):
print('disk file execute write operation')
def file_read(self):
print('disk file execute read operation')
4. 在類內(nèi)部定義的函數(shù)無的三種用途
綁定到對象的方法
只要是在類內(nèi)部定義的,并且沒有被任何裝飾器修飾過的方法,都是綁定到對象的
class Foo:
def test(self): #綁定到對象的方法
pass
def test1(): #也是綁定到對象的方法,只是對象.test1(),會把對象本身自動傳給test1,因test1沒有參數(shù)所以會拋出異常
pass
綁定到對象,指的是:由對象調(diào)用
使用方式:對象.對象的綁定方法(),不用為self傳值
特性:調(diào)用時(shí)會把對象本身當(dāng)做第一個參數(shù)傳給對象的綁定方法
綁定到類的方法:classmethod
在類內(nèi)部定義的,并且被裝飾器@classmethod修飾過的方法,都是綁定到類的
class Foo:
def test(self): #綁定到對象的方法
pass
def test1(): #也是綁定到對象的方法,只是對象.test1(),會把對象本身自動傳給test1,因test1沒有參數(shù)所以會拋出異常
pass
f = Foo()
f.test1()
>>TypeError: test1() takes 0 positional arguments but 1 was given
綁定到對象,指的是:就給對象去用,
使用方式:對象.對象的綁定方法()
特性:調(diào)用時(shí)會把對象本身當(dāng)做第一個參數(shù)傳給對象的綁定方法
解除綁定的方法:staticmethod
既不與類綁定,也不與對象綁定,不與任何事物綁定
綁定的特性:自動傳值(綁定到類的就是自動傳類,綁定到對象的就自動傳對象)
解除綁定的特性:不管是類還是對象來調(diào)用,都沒有自動傳值這么一說了
所以說staticmethod就是相當(dāng)于一個普通的工具包
class Foo:
def test1(self):
pass
def test2():
pass
@classmethod
def test3(cls):
pass
@classmethod
def test4():
pass
@staticmethod
def test5():
pass
test1與test2都是綁定到對象方法:調(diào)用時(shí)就是操作對象本身
<function Foo.test1 at 0x0000000000D8E488>
<function Foo.test2 at 0x0000000000D8E510>
test3與test4都是綁定到類的方法:調(diào)用時(shí)就是操作類本身
<bound method Foo.test3 of <class 'main.Foo'>>
<bound method Foo.test4 of <class 'main.Foo'>>
test5是不與任何事物綁定的:就是一個工具包,誰來都可以用,沒說專門操作誰這么一說
<function Foo.test5 at 0x0000000000D8E6A8>