面向?qū)ο?/h1>
- 類概念
- 類的定義
- 類的實例化
- 類和實例的屬性
- 類的私有變量
- 數(shù)據(jù)封裝
- 繼承
- 多態(tài)
- 多繼承
- 類的特殊方法
- 裝飾器
- 類的裝飾器
1.面向?qū)ο?Object Oriented,OO)概念
面向?qū)ο螅俏覀兙幊痰囊环N思維韭邓。
早期的計算機編程是基于面向過程的方法,例如實現(xiàn)算術(shù)運算1+1+2 = 4虽缕,通過設(shè)計一個算法就可以解決當(dāng)時的問題始藕。隨著計算機技術(shù)的不斷提高,計算機被用于解決越來越復(fù)雜的問題氮趋。通過面向?qū)ο蟮姆绞轿榕桑瑢F(xiàn)實世界的事物抽象成對象,現(xiàn)實世界中的關(guān)系抽象成類剩胁、繼承诉植。通過面向?qū)ο蟮姆椒ǎ谟萌死斫獾姆绞疥枪郏瑢?fù)雜系統(tǒng)進(jìn)行分析晾腔、設(shè)計與編程。同時也提高了系統(tǒng)的可維護(hù)性啊犬,可擴展性灼擂,可重用性。
(就是使編程的思維觉至,更接近與人的思維和認(rèn)知)
面向?qū)ο缶幊痰年P(guān)鍵剔应,就是類的定義。
類是對現(xiàn)實生活中一類具有共同特征的事物的抽象语御。
2.類的定義
基本形式:
class ClassName(object):
Statement
1.class定義類的關(guān)鍵字
2.ClassName類名峻贮,類名的每個單詞的首字母大寫(駝峰規(guī)則)。
3.object是父類名应闯,object是一切類的基類纤控。在python3中如果繼承類是基類可以省略不寫。
'''
class Animal(object):
pass
'''
'''
重點:學(xué)會定義類孽锥,了解屬性和方法嚼黔,類的初始化和實例化。
定義類時惜辑,這種方法可以使類對象實例按某種特定的模式生產(chǎn)出來唬涧。
'''
#類方法:
后面的參數(shù)中第一個參數(shù)我們約定俗成的為self參數(shù)名,
self代表的是在類實例化后這個實例對象本身盛撑。
'''
class Animal:
#構(gòu)造方法碎节,實例化對象,必須調(diào)用__init__
#在初始化的時候抵卫,默認(rèn)往構(gòu)造方法狮荔,傳入一個值
#self是實例化對象本身
def __init__(self):
print("正在實例化一個對象")
def test(self):#實例化對象調(diào)用方法胎撇,必須加上self
print("aaa")
def test1(self,b):#第一個參數(shù)默認(rèn)是self參數(shù),不需要傳值
print("方法;test1,self=%s"%(type(self)))
def test2():#未加self參數(shù)殖氏,只能通過 Animal.test2()直接調(diào)用晚树,實例化對象無法調(diào)用
print("方法;test2")
運行結(jié)果:
>>> Animal().test1(1111)
正在實例化一個對象
方法;test1,self=<class '__main__.Animal'>
'''
'''
class Animal: #當(dāng)我們沒有寫__init__(),默認(rèn)調(diào)用我們父類的__init__
def test(self):
print("aaa")
'''
初始化函數(shù)除了有self這個參數(shù)表示實例對象本身之外雅采,
其他的參數(shù)的定義也遵循函數(shù)的必備參數(shù)和默認(rèn)參數(shù)一樣的原則爵憎,
必備參數(shù)就是在實例化是一定要傳入的參數(shù),
默認(rèn)參數(shù)就是在定義時可以給這個參數(shù)一個初始值婚瓜。沒有函數(shù)名的函數(shù)
3.類的實例化
基本形式:實例對象名 = 類名(參數(shù))
在實例化的過程中宝鼓,self代表的就是這個實例對象自己。
實例化時會把類名后面接的參數(shù)傳進(jìn)去賦值給實例巴刻,
這樣傳進(jìn)去的參數(shù)就成為了這個實例對象的屬性愚铡。
實例化的過程遵循函數(shù)調(diào)用的原則。
在實例化時也必須個數(shù)和順序與定義時相同(使用關(guān)鍵字參數(shù)可以改變傳參的順序)胡陪。
當(dāng)初始化函數(shù)定義時使用了默認(rèn)參數(shù)時沥寥,在實例化時默認(rèn)參數(shù)可以不傳參這時
這個實例對象就會使用默認(rèn)的屬性,如果傳了參數(shù)進(jìn)去則會改變這參數(shù)值柠座,
使實例化對象的屬性就為你傳進(jìn)來的這個參數(shù)营曼。
isinstance(實例名,類名)
判斷一個實例是不是這個類的實例愚隧。
4.類和實例的屬性
類屬性
.類屬性是可以直接通過“類名.屬性名”來訪問和修改蒂阱。
.類屬性是這個類的所有實例對象所共有的屬性,
任意一個實例對象都可以訪問并修改這個屬性(私有隱藏除外)狂塘。
.對類屬性的修改录煤,遵循基本數(shù)據(jù)類型的特性:列表可以直接修改,字符串不可以荞胡,
所以當(dāng)類屬性是一個列表時妈踊,通過任意一個實例對象對其進(jìn)行修改。
但字符串類型的類屬性不能通過實例對象對其進(jìn)行修改泪漂。
當(dāng)實例對不可變對象進(jìn)行修改之后廊营,會查找實例的類屬性,不會查找類的屬性萝勤,同時類的屬性不會邊
實例屬性
.在屬性前面加了self標(biāo)識的屬性為實例的屬性露筒。
.在定義的時候用的self加屬性名字的形式,在查看實例的屬性時
就是通過實例的名稱+‘.’+屬性名來訪問實例屬性敌卓。
'''
class Aniaml:
eye=2 #共有的屬性
def __init__(self,name,food):
print("正在實例化")
self.name=name #實例化屬性
self.food=food
def getName(self):
print(self.name)
運行:
>>> dog=Aniaml("大黃","骨頭")
實例化屬性調(diào)用:
>>> dog.name #調(diào)用實例屬性
'大黃'
類屬性調(diào)用:
>>>Aniaml.eye
>>> dog.eye
'''
一些說明:
.一般慎式,方法第一個參數(shù)被命名為self,,這僅僅是一個約定,
self沒有特殊含義瘪吏,程序員遵循這個約定癣防。
.查看類中的屬性和實例屬性可以調(diào)用__dict__方法返回屬性組成的字典。
.Python中屬性的獲取是按照從下到上的順序來查找屬性
.Python中的類和實例是兩個完全獨立的對象
.Python中的屬性設(shè)置是針對對象本身進(jìn)行的
5.類的私有屬性和方法
在Python中掌眠,通過單下劃線”_”來實現(xiàn)模塊級別的私有化蕾盯,
一般約定以單下劃線”_”開頭的變量、函數(shù)為模塊私有的蓝丙,
也就是說”from moduleName import *”將不會引入以單下劃線”_”開頭的變量刑枝、函數(shù)
'''
import random #顯示所有的方法,屬性
from random import * #只顯示
'''
對于Python中的類屬性迅腔,可以通過雙下劃線”__”來實現(xiàn)一定程度的私有化。
_”和” __”的使用 更多的是一種規(guī)范/約定靠娱,并沒有真正達(dá)到限制的目的:
“_”:以單下劃線開頭只能允許其本身與子類進(jìn)行訪問沧烈,(起到一個保護(hù)的作用)
“__”:雙下劃線的表示的是私有類型的變量。這類屬性在運行時屬性名會加上單下劃線和類名像云。
“__foo__”:以雙下劃線開頭和結(jié)尾的(__foo__)代表python里特殊方法專用的標(biāo)識锌雀,如 __init__()
'''
class Aniaml:
eye=2
_age=3
__leg=4
def __init__(self,name,food):
self.name=name
self.food=food
def getName(self):
print(self.name)
>>> dog._age #單_會隱藏屬性名稱
>>> dog._Aniaml__leg #雙_會隱藏屬性名稱,雙_會修改屬性的名稱
'''
6.數(shù)據(jù)封裝
在類里面數(shù)據(jù)屬性和行為函數(shù)的形式封裝起來迅诬,
訪問時直接調(diào)用腋逆,不需知道類里面具體的實現(xiàn)方法。 比如侈贷,list.append
封裝:
def test2():
print("方法;test2")
7.繼承
用法:
.在定義類時惩歉,可以從已有的類繼承,
被繼承的類稱為基類(父類)俏蛮,新定義的類稱為派生類(子類)撑蚌。
.在類中找不到調(diào)用的屬性時就搜索基類,
如果基類是從別的類派生而來搏屑,這個規(guī)則會遞歸的應(yīng)用上去争涌。
反過來不行。
.如果派生類中的屬性與基類屬性重名辣恋,那么派生類的屬性會覆蓋掉基類的屬性亮垫。
包括初始化函數(shù)。
.派生類在初始化函數(shù)中需要繼承和修改初始化過程伟骨,
使用’類名+__init__(arg)’來實現(xiàn)繼承和私有特性,也可以使用super()函數(shù)饮潦。
issubclass(類名1,類名2)
判斷類1是否繼承了類2
作用:
面向?qū)ο蟮木幊處淼闹饕锰幹皇谴a的重用携狭,實現(xiàn)這種重用的方法之一是通過繼承機制害晦。
繼承完全可以理解成類之間的類型和子類型關(guān)系。
子類在重寫父類方法之后,如果要繼承父類方法中的功能壹瘟,要先調(diào)用父類的方法 class.fun(self)
'''
class Aniaml:
eye=2
_age=3
__leg=4
def __init__(self,name,food):
self.name=name
self.food=food
def getName(self):
print(self.name)
class People(Aniaml):#繼承
__leg=2
def __init__(self,name,food,sex):
self.name=name
self.food=food
self.sex=sex
def getSex(self):
print(self.sex)
'''
8.多態(tài)
當(dāng)派生類重寫了基類的方法時就實現(xiàn)了多態(tài)性鲫剿。(子類重寫父類方法)
class Aniaml:
eye=2
_age=3
__leg=4
def __init__(self,name,food):
self.name=name
self.food=food
def getName(self):
print(self.name)
class People(Aniaml):
__leg=2
def __init__(self,name,food,sex):
self.name=name
self.food=food
self.sex=sex
def getSex(self):
print(self.sex)
def speak(self):
print("adsfsfd")
class Chinese(People):#中國人
def speak(self):#中國文說你好
print("你好"
class America(People):#美國人
def speak(self):#美國人說Hello
print("Hello")
class Thai(People):#泰國人
def speak(self):#泰國人說薩瓦迪卡
print("薩瓦迪卡")
xiaomi=Chinese("小明","米飯","男")
jack=America("jack","面包","男")
lala=Thai("lala","香蕉","未知")
9.多繼承
#當(dāng)繼承的類有同種方法的時候,只會繼承前面一個的方法稻轨。調(diào)用父類方法super()
class Base:
def play(self):
print("This is base")
class A(Base):
def play(self):
print(type(self))
print("This is a")
class B(Base):
def play(self):
print("This is b")
class C(A,B):
def play(self):
#A.play(self) #第一種調(diào)用父類的方法
super().play()#第二種調(diào)用父類的方法灵莲,同super(C,self).play()
#super(C,self).play()
print("This is c")
運行效果:
<class '__main__.C'>
This is a
This is c
#對象的擴展使用
#C().__class__.mro() 查看對象的排序
#C(B,A) C->B->A->Base->object 針對C繼承對象排序
#C(A,B) C->A->B->Base->object 針對C繼承對象排序
class C(B,A):
def play(self):
#super(A,self).play() #調(diào)用base
super(B,self).play() #調(diào)用a
>>> C().__class__.mro() #C->B->A->Base->object 針對C繼承對象排序
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.Base'>, <class 'object'>]
10.類的特殊方法
千萬不要把自己往死胡同里面逼,否則你會走火入魔
'''
class Rectangle:
'''測試'''
aaa=1
def __init__(self,length,width):
if isinstance(length,(int,float)) and isinstance(width,(int,float)):
self.length=length
self.width=width
else:
print("請輸入int or float")
def area(self):
return self.length*self.width
def __str__(self):
return "這個長方形的面積%s"%self.area()
def __repr__(self):
return "長:%s 寬:%s"%(self.length,self.width)
def __call__(self):
print("這是一個Rectangle類殴俱,你要干嘛")
def __add__(self,other):
return self.area()+other.area()
def __sub__(self,other):
return self.area()-other.area()
r=Rectangle(2,3)
r1=Rectangle(2,3)
r2=Rectangle(2,3)
'''
#類屬性:
__dict__ # 類的屬性(包含一個字典政冻,由類的數(shù)據(jù)屬性組成)
>>> r.__dict__
{'length': 2, 'width': 3}
>>> r.aaa=33
>>> r.__dict__
#注意,共有屬性线欲,當(dāng)不修改時明场,默認(rèn)引用Rectangle
#修改之后,才會出現(xiàn)再實例里面
{'length': 2, 'width': 3, 'aaa': 33}
__doc__ # 類的文檔字符串
>>> r.__doc__
'測試'
#類方法:(魔法方法) ,方法也是對象
__init__ # 初始化
__repr__ # 直接返回這個對象 repr() 函數(shù)就是調(diào)用對象的這個方法
>>> r
長:2 寬:3
__str__ # print(obj) 如果類里面定義了__repr__李丰,沒有定義__str__ print(obj)也會返回__repr__的內(nèi)容苦锨,或者說__repr__的優(yōu)先級更高
>>> print(r) #重寫print方法了
這個長方形的面積6
"%s"%"ssss" 對應(yīng) __str__
"%r"%"rrrr" 對應(yīng) __repr__
__call__ # Obj() 使實例可被調(diào)用
>>> r()
這是一個Rectangle類,你要干嘛
#運算符方法
__add__(self,other) #x+y
>>> r1+r2
12
__sub__(self,other) #x-y
__mul__(self,other) #x*y
__mod__(self,other) #x%y
__iadd__(self,other) #x+=y
__isub__(self,other) #x-=y
__radd__(self,other) #y+x
__rsub__(self,other) #y-x
__imul__(self,other) #x*=y
__imod__(self,other) #x%=y
#和類有關(guān)的幾個函數(shù)
delattr() # 刪除對象屬性
getattr() # 得到某個屬性值
setattr() # 給對象添加某個屬性值
hasattr() # 判斷對象object是否包含名為name的特性
isinstance() # 檢查對象是否是類的對象趴泌,返回True或False
issubclass() # 檢查一個類是否是另一個類的子類舟舒。返回True或False
11.裝飾器
裝飾器(deco):
裝飾函數(shù)的參數(shù)是被裝飾的函數(shù)對象,返回原函數(shù)對象裝飾器本質(zhì)上是一個Python函數(shù)嗜憔,它可以讓其他函數(shù)在不需要做任何代碼變動的前提下增加額外功能秃励,裝飾器的返回值也是一個函數(shù)對象
概括的講,裝飾器的作用就是為已經(jīng)存在的對象添加額外的功能吉捶。
def f1(func):
print("f1 running")
def f2(y):
print("f2 running")
return func(y)+1
return f2
@f1
def gun2(m):
print("gun running")
return m*m
#運行結(jié)果
f1 running
>>> gun2(5)
f2 running
gun running
26
運行流程
1.@f1->f1(gun2)->f2
2.f2夺鲜,等待調(diào)用
3.gun2(2)->當(dāng)參數(shù)5傳入->f2(5)
4.f2(5),開始運行->print("f2 running")->fun(y):func=gun2 y=5
5.gun2(5) 開始運行->print("gun running")->25
6.25+1=26
#測試時間的裝飾器
import time #不要糾結(jié)
def run_time(func):
def new_fun():
t0 = time.time()
print('star time: %s'%(time.strftime('%x',time.localtime())) )
func()
print('end time: %s'%(time.strftime('%x',time.localtime())) )
print('run time: %s'%(time.time() - t0))
return new_fun
@run_time
def test():
for i in range(1,10):
for j in range(1,i+1):
print('%dx%d=%2s'%(j,i,i*j),end = ' ')
print ()
12.類裝飾器
'''
class Rectangle:
'''測試'''
aaa=1
def __init__(self,length,width):
if isinstance(length,(int,float)) and isinstance(width,(int,float)):
self.length=length
self.width=width
else:
print("請輸入int or float")
@property #可以把方法當(dāng)屬性使用
def area(self):
return self.length*self.width
@staticmethod #把方法變成靜態(tài)方法
def func():
print("可以調(diào)用")
@classmethod #把實例化對象轉(zhuǎn)換成類
def show(self):
print(self)
print("show fun")
>>> Rectangle(2,3).area
6
'''
@property
裝飾過的函數(shù)返回的不再是一個函數(shù)呐舔,而是一個property對象
裝飾過后的方法不再是可調(diào)用的對象谣旁,可以看做數(shù)據(jù)屬性直接訪問。
@staticmethod #(靜態(tài)方法)
把沒有參數(shù)的函數(shù)裝飾過后變成可被實例調(diào)用的函數(shù)滋早,
函數(shù)定義時是沒有參數(shù)的榄审,可以不接收參數(shù)
@classmethod (類方法)
把裝飾過的方法變成一個classmethod類對象,既能能被類調(diào)用又能被實例調(diào)用杆麸。
注意參數(shù)是cls代表這個類本身搁进。而是用實例的方法只能被實例調(diào)用。
一般來說昔头,要使用某個類的方法饼问,需要先實例化一個對象再調(diào)用方法。
而使用@staticmethod或@classmethod揭斧,就可以不需要實例化莱革,直接類名.方法名()來調(diào)用峻堰。
這有利于組織代碼,把某些應(yīng)該屬于某個類的函數(shù)給放到那個類里去盅视,同時有利于命名空間的整潔
'''
#類裝飾器
'''
class Test_Class():
def __init__(self,func):
self.func=func
def __call__(self):
print("類")
return self.func
@Test_Class
def fun_test():
print("這只是一個測試")
運行:
>>> fun_test()
類
<function fun_test at 0x033081E0>
>>> fun_test()()
類
這只是一個測試
#python自帶的3個捐名,類的內(nèi)置裝飾器
面向?qū)ο螅俏覀兙幊痰囊环N思維韭邓。
早期的計算機編程是基于面向過程的方法,例如實現(xiàn)算術(shù)運算1+1+2 = 4虽缕,通過設(shè)計一個算法就可以解決當(dāng)時的問題始藕。隨著計算機技術(shù)的不斷提高,計算機被用于解決越來越復(fù)雜的問題氮趋。通過面向?qū)ο蟮姆绞轿榕桑瑢F(xiàn)實世界的事物抽象成對象,現(xiàn)實世界中的關(guān)系抽象成類剩胁、繼承诉植。通過面向?qū)ο蟮姆椒ǎ谟萌死斫獾姆绞疥枪郏瑢?fù)雜系統(tǒng)進(jìn)行分析晾腔、設(shè)計與編程。同時也提高了系統(tǒng)的可維護(hù)性啊犬,可擴展性灼擂,可重用性。
(就是使編程的思維觉至,更接近與人的思維和認(rèn)知)
面向?qū)ο缶幊痰年P(guān)鍵剔应,就是類的定義。
類是對現(xiàn)實生活中一類具有共同特征的事物的抽象语御。
基本形式:
class ClassName(object):
Statement
1.class定義類的關(guān)鍵字
2.ClassName類名峻贮,類名的每個單詞的首字母大寫(駝峰規(guī)則)。
3.object是父類名应闯,object是一切類的基類纤控。在python3中如果繼承類是基類可以省略不寫。
'''
class Animal(object):
pass
'''
'''
重點:學(xué)會定義類孽锥,了解屬性和方法嚼黔,類的初始化和實例化。
定義類時惜辑,這種方法可以使類對象實例按某種特定的模式生產(chǎn)出來唬涧。
'''
#類方法:
后面的參數(shù)中第一個參數(shù)我們約定俗成的為self參數(shù)名,
self代表的是在類實例化后這個實例對象本身盛撑。
'''
class Animal:
#構(gòu)造方法碎节,實例化對象,必須調(diào)用__init__
#在初始化的時候抵卫,默認(rèn)往構(gòu)造方法狮荔,傳入一個值
#self是實例化對象本身
def __init__(self):
print("正在實例化一個對象")
def test(self):#實例化對象調(diào)用方法胎撇,必須加上self
print("aaa")
def test1(self,b):#第一個參數(shù)默認(rèn)是self參數(shù),不需要傳值
print("方法;test1,self=%s"%(type(self)))
def test2():#未加self參數(shù)殖氏,只能通過 Animal.test2()直接調(diào)用晚树,實例化對象無法調(diào)用
print("方法;test2")
運行結(jié)果:
>>> Animal().test1(1111)
正在實例化一個對象
方法;test1,self=<class '__main__.Animal'>
'''
'''
class Animal: #當(dāng)我們沒有寫__init__(),默認(rèn)調(diào)用我們父類的__init__
def test(self):
print("aaa")
'''
初始化函數(shù)除了有self這個參數(shù)表示實例對象本身之外雅采,
其他的參數(shù)的定義也遵循函數(shù)的必備參數(shù)和默認(rèn)參數(shù)一樣的原則爵憎,
必備參數(shù)就是在實例化是一定要傳入的參數(shù),
默認(rèn)參數(shù)就是在定義時可以給這個參數(shù)一個初始值婚瓜。沒有函數(shù)名的函數(shù)
基本形式:實例對象名 = 類名(參數(shù))
在實例化的過程中宝鼓,self代表的就是這個實例對象自己。
實例化時會把類名后面接的參數(shù)傳進(jìn)去賦值給實例巴刻,
這樣傳進(jìn)去的參數(shù)就成為了這個實例對象的屬性愚铡。
實例化的過程遵循函數(shù)調(diào)用的原則。
在實例化時也必須個數(shù)和順序與定義時相同(使用關(guān)鍵字參數(shù)可以改變傳參的順序)胡陪。
當(dāng)初始化函數(shù)定義時使用了默認(rèn)參數(shù)時沥寥,在實例化時默認(rèn)參數(shù)可以不傳參這時
這個實例對象就會使用默認(rèn)的屬性,如果傳了參數(shù)進(jìn)去則會改變這參數(shù)值柠座,
使實例化對象的屬性就為你傳進(jìn)來的這個參數(shù)营曼。
isinstance(實例名,類名)
判斷一個實例是不是這個類的實例愚隧。
類屬性
.類屬性是可以直接通過“類名.屬性名”來訪問和修改蒂阱。
.類屬性是這個類的所有實例對象所共有的屬性,
任意一個實例對象都可以訪問并修改這個屬性(私有隱藏除外)狂塘。
.對類屬性的修改录煤,遵循基本數(shù)據(jù)類型的特性:列表可以直接修改,字符串不可以荞胡,
所以當(dāng)類屬性是一個列表時妈踊,通過任意一個實例對象對其進(jìn)行修改。
但字符串類型的類屬性不能通過實例對象對其進(jìn)行修改泪漂。
當(dāng)實例對不可變對象進(jìn)行修改之后廊营,會查找實例的類屬性,不會查找類的屬性萝勤,同時類的屬性不會邊
實例屬性
.在屬性前面加了self標(biāo)識的屬性為實例的屬性露筒。
.在定義的時候用的self加屬性名字的形式,在查看實例的屬性時
就是通過實例的名稱+‘.’+屬性名來訪問實例屬性敌卓。
'''
class Aniaml:
eye=2 #共有的屬性
def __init__(self,name,food):
print("正在實例化")
self.name=name #實例化屬性
self.food=food
def getName(self):
print(self.name)
運行:
>>> dog=Aniaml("大黃","骨頭")
實例化屬性調(diào)用:
>>> dog.name #調(diào)用實例屬性
'大黃'
類屬性調(diào)用:
>>>Aniaml.eye
>>> dog.eye
'''
一些說明:
.一般慎式,方法第一個參數(shù)被命名為self,,這僅僅是一個約定,
self沒有特殊含義瘪吏,程序員遵循這個約定癣防。
.查看類中的屬性和實例屬性可以調(diào)用__dict__方法返回屬性組成的字典。
.Python中屬性的獲取是按照從下到上的順序來查找屬性
.Python中的類和實例是兩個完全獨立的對象
.Python中的屬性設(shè)置是針對對象本身進(jìn)行的
在Python中掌眠,通過單下劃線”_”來實現(xiàn)模塊級別的私有化蕾盯,
一般約定以單下劃線”_”開頭的變量、函數(shù)為模塊私有的蓝丙,
也就是說”from moduleName import *”將不會引入以單下劃線”_”開頭的變量刑枝、函數(shù)
'''
import random #顯示所有的方法,屬性
from random import * #只顯示
'''
對于Python中的類屬性迅腔,可以通過雙下劃線”__”來實現(xiàn)一定程度的私有化。
_”和” __”的使用 更多的是一種規(guī)范/約定靠娱,并沒有真正達(dá)到限制的目的:
“_”:以單下劃線開頭只能允許其本身與子類進(jìn)行訪問沧烈,(起到一個保護(hù)的作用)
“__”:雙下劃線的表示的是私有類型的變量。這類屬性在運行時屬性名會加上單下劃線和類名像云。
“__foo__”:以雙下劃線開頭和結(jié)尾的(__foo__)代表python里特殊方法專用的標(biāo)識锌雀,如 __init__()
'''
class Aniaml:
eye=2
_age=3
__leg=4
def __init__(self,name,food):
self.name=name
self.food=food
def getName(self):
print(self.name)
>>> dog._age #單_會隱藏屬性名稱
>>> dog._Aniaml__leg #雙_會隱藏屬性名稱,雙_會修改屬性的名稱
'''
在類里面數(shù)據(jù)屬性和行為函數(shù)的形式封裝起來迅诬,
訪問時直接調(diào)用腋逆,不需知道類里面具體的實現(xiàn)方法。 比如侈贷,list.append
封裝:
def test2():
print("方法;test2")
用法:
.在定義類時惩歉,可以從已有的類繼承,
被繼承的類稱為基類(父類)俏蛮,新定義的類稱為派生類(子類)撑蚌。
.在類中找不到調(diào)用的屬性時就搜索基類,
如果基類是從別的類派生而來搏屑,這個規(guī)則會遞歸的應(yīng)用上去争涌。
反過來不行。
.如果派生類中的屬性與基類屬性重名辣恋,那么派生類的屬性會覆蓋掉基類的屬性亮垫。
包括初始化函數(shù)。
.派生類在初始化函數(shù)中需要繼承和修改初始化過程伟骨,
使用’類名+__init__(arg)’來實現(xiàn)繼承和私有特性,也可以使用super()函數(shù)饮潦。
issubclass(類名1,類名2)
判斷類1是否繼承了類2
作用:
面向?qū)ο蟮木幊處淼闹饕锰幹皇谴a的重用携狭,實現(xiàn)這種重用的方法之一是通過繼承機制害晦。
繼承完全可以理解成類之間的類型和子類型關(guān)系。
子類在重寫父類方法之后,如果要繼承父類方法中的功能壹瘟,要先調(diào)用父類的方法 class.fun(self)
'''
class Aniaml:
eye=2
_age=3
__leg=4
def __init__(self,name,food):
self.name=name
self.food=food
def getName(self):
print(self.name)
class People(Aniaml):#繼承
__leg=2
def __init__(self,name,food,sex):
self.name=name
self.food=food
self.sex=sex
def getSex(self):
print(self.sex)
'''
當(dāng)派生類重寫了基類的方法時就實現(xiàn)了多態(tài)性鲫剿。(子類重寫父類方法)
class Aniaml:
eye=2
_age=3
__leg=4
def __init__(self,name,food):
self.name=name
self.food=food
def getName(self):
print(self.name)
class People(Aniaml):
__leg=2
def __init__(self,name,food,sex):
self.name=name
self.food=food
self.sex=sex
def getSex(self):
print(self.sex)
def speak(self):
print("adsfsfd")
class Chinese(People):#中國人
def speak(self):#中國文說你好
print("你好"
class America(People):#美國人
def speak(self):#美國人說Hello
print("Hello")
class Thai(People):#泰國人
def speak(self):#泰國人說薩瓦迪卡
print("薩瓦迪卡")
xiaomi=Chinese("小明","米飯","男")
jack=America("jack","面包","男")
lala=Thai("lala","香蕉","未知")
#當(dāng)繼承的類有同種方法的時候,只會繼承前面一個的方法稻轨。調(diào)用父類方法super()
class Base:
def play(self):
print("This is base")
class A(Base):
def play(self):
print(type(self))
print("This is a")
class B(Base):
def play(self):
print("This is b")
class C(A,B):
def play(self):
#A.play(self) #第一種調(diào)用父類的方法
super().play()#第二種調(diào)用父類的方法灵莲,同super(C,self).play()
#super(C,self).play()
print("This is c")
運行效果:
<class '__main__.C'>
This is a
This is c
#對象的擴展使用
#C().__class__.mro() 查看對象的排序
#C(B,A) C->B->A->Base->object 針對C繼承對象排序
#C(A,B) C->A->B->Base->object 針對C繼承對象排序
class C(B,A):
def play(self):
#super(A,self).play() #調(diào)用base
super(B,self).play() #調(diào)用a
>>> C().__class__.mro() #C->B->A->Base->object 針對C繼承對象排序
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.Base'>, <class 'object'>]
千萬不要把自己往死胡同里面逼,否則你會走火入魔
'''
class Rectangle:
'''測試'''
aaa=1
def __init__(self,length,width):
if isinstance(length,(int,float)) and isinstance(width,(int,float)):
self.length=length
self.width=width
else:
print("請輸入int or float")
def area(self):
return self.length*self.width
def __str__(self):
return "這個長方形的面積%s"%self.area()
def __repr__(self):
return "長:%s 寬:%s"%(self.length,self.width)
def __call__(self):
print("這是一個Rectangle類殴俱,你要干嘛")
def __add__(self,other):
return self.area()+other.area()
def __sub__(self,other):
return self.area()-other.area()
r=Rectangle(2,3)
r1=Rectangle(2,3)
r2=Rectangle(2,3)
'''
#類屬性:
__dict__ # 類的屬性(包含一個字典政冻,由類的數(shù)據(jù)屬性組成)
>>> r.__dict__
{'length': 2, 'width': 3}
>>> r.aaa=33
>>> r.__dict__
#注意,共有屬性线欲,當(dāng)不修改時明场,默認(rèn)引用Rectangle
#修改之后,才會出現(xiàn)再實例里面
{'length': 2, 'width': 3, 'aaa': 33}
__doc__ # 類的文檔字符串
>>> r.__doc__
'測試'
#類方法:(魔法方法) ,方法也是對象
__init__ # 初始化
__repr__ # 直接返回這個對象 repr() 函數(shù)就是調(diào)用對象的這個方法
>>> r
長:2 寬:3
__str__ # print(obj) 如果類里面定義了__repr__李丰,沒有定義__str__ print(obj)也會返回__repr__的內(nèi)容苦锨,或者說__repr__的優(yōu)先級更高
>>> print(r) #重寫print方法了
這個長方形的面積6
"%s"%"ssss" 對應(yīng) __str__
"%r"%"rrrr" 對應(yīng) __repr__
__call__ # Obj() 使實例可被調(diào)用
>>> r()
這是一個Rectangle類,你要干嘛
#運算符方法
__add__(self,other) #x+y
>>> r1+r2
12
__sub__(self,other) #x-y
__mul__(self,other) #x*y
__mod__(self,other) #x%y
__iadd__(self,other) #x+=y
__isub__(self,other) #x-=y
__radd__(self,other) #y+x
__rsub__(self,other) #y-x
__imul__(self,other) #x*=y
__imod__(self,other) #x%=y
#和類有關(guān)的幾個函數(shù)
delattr() # 刪除對象屬性
getattr() # 得到某個屬性值
setattr() # 給對象添加某個屬性值
hasattr() # 判斷對象object是否包含名為name的特性
isinstance() # 檢查對象是否是類的對象趴泌,返回True或False
issubclass() # 檢查一個類是否是另一個類的子類舟舒。返回True或False
裝飾器(deco):
裝飾函數(shù)的參數(shù)是被裝飾的函數(shù)對象,返回原函數(shù)對象裝飾器本質(zhì)上是一個Python函數(shù)嗜憔,它可以讓其他函數(shù)在不需要做任何代碼變動的前提下增加額外功能秃励,裝飾器的返回值也是一個函數(shù)對象
概括的講,裝飾器的作用就是為已經(jīng)存在的對象添加額外的功能吉捶。
def f1(func):
print("f1 running")
def f2(y):
print("f2 running")
return func(y)+1
return f2
@f1
def gun2(m):
print("gun running")
return m*m
#運行結(jié)果
f1 running
>>> gun2(5)
f2 running
gun running
26
運行流程
1.@f1->f1(gun2)->f2
2.f2夺鲜,等待調(diào)用
3.gun2(2)->當(dāng)參數(shù)5傳入->f2(5)
4.f2(5),開始運行->print("f2 running")->fun(y):func=gun2 y=5
5.gun2(5) 開始運行->print("gun running")->25
6.25+1=26
#測試時間的裝飾器
import time #不要糾結(jié)
def run_time(func):
def new_fun():
t0 = time.time()
print('star time: %s'%(time.strftime('%x',time.localtime())) )
func()
print('end time: %s'%(time.strftime('%x',time.localtime())) )
print('run time: %s'%(time.time() - t0))
return new_fun
@run_time
def test():
for i in range(1,10):
for j in range(1,i+1):
print('%dx%d=%2s'%(j,i,i*j),end = ' ')
print ()
'''
class Rectangle:
'''測試'''
aaa=1
def __init__(self,length,width):
if isinstance(length,(int,float)) and isinstance(width,(int,float)):
self.length=length
self.width=width
else:
print("請輸入int or float")
@property #可以把方法當(dāng)屬性使用
def area(self):
return self.length*self.width
@staticmethod #把方法變成靜態(tài)方法
def func():
print("可以調(diào)用")
@classmethod #把實例化對象轉(zhuǎn)換成類
def show(self):
print(self)
print("show fun")
>>> Rectangle(2,3).area
6
'''
@property
裝飾過的函數(shù)返回的不再是一個函數(shù)呐舔,而是一個property對象
裝飾過后的方法不再是可調(diào)用的對象谣旁,可以看做數(shù)據(jù)屬性直接訪問。
@staticmethod #(靜態(tài)方法)
把沒有參數(shù)的函數(shù)裝飾過后變成可被實例調(diào)用的函數(shù)滋早,
函數(shù)定義時是沒有參數(shù)的榄审,可以不接收參數(shù)
@classmethod (類方法)
把裝飾過的方法變成一個classmethod類對象,既能能被類調(diào)用又能被實例調(diào)用杆麸。
注意參數(shù)是cls代表這個類本身搁进。而是用實例的方法只能被實例調(diào)用。
一般來說昔头,要使用某個類的方法饼问,需要先實例化一個對象再調(diào)用方法。
而使用@staticmethod或@classmethod揭斧,就可以不需要實例化莱革,直接類名.方法名()來調(diào)用峻堰。
這有利于組織代碼,把某些應(yīng)該屬于某個類的函數(shù)給放到那個類里去盅视,同時有利于命名空間的整潔
'''
#類裝飾器
'''
class Test_Class():
def __init__(self,func):
self.func=func
def __call__(self):
print("類")
return self.func
@Test_Class
def fun_test():
print("這只是一個測試")
運行:
>>> fun_test()
類
<function fun_test at 0x033081E0>
>>> fun_test()()
類
這只是一個測試
#python自帶的3個捐名,類的內(nèi)置裝飾器