語言分類
- 面向機器:抽象成機器指令,機器容易理解。代表:匯編語言
- 面向過程:一件事情分步驟來完成,出現各種情況有解決辦法一一對應,問題規模小可以步驟化、按部就班的處理。代表:C語言
- 面向對象oop(object Oriented Programming):隨著計算機解決問題的規模擴大、情況更復雜,需要很多部分協作,面向過程編程就不合適了,演變出了面向對象編程。代表:java、python等
面向對象
面向對象是一種認識世界、分析世界的方法論。將所有事物抽象為類。
- 類class:類是抽象的概念,是所有事物的抽象,是一類事物的共同特征的集合。用計算機語言來描述類,就是屬性和方法的集合
- 對象instance、object:對象是類的具象,是一個實體(或者叫實例)。對于每個人這個個體,都是抽象概念人類的不同的實體。
- 屬性:它是對象狀態的抽象,用數據結構來描述。
- 操作:它是對象行為的抽象,用操作名和實現該操作的方法來描述。
- Python哲學:一切皆對象;對象是數據和操作的封裝;對象是獨立的,但是對象之間可以相互作用。目前oop是最接近人類認知的編程范式。
面向對象三要素
- 封裝
- 組裝:將數據和操作組裝到一起
- 隱藏數據:對外只暴露一些接口,通過接口訪問對象。
- 繼承
- 多復用:繼承來的就不用自己重新定義
- 多繼承少修改:開放封閉原則OCP(open-closed principle),使用繼承來改變、體現個性
- 多態
- 面向對象編程最靈活的地方,動態綁定
舉例:人類就是封裝;人類繼承自動物類,孩子繼承父母特征。分單一繼承、多繼承;多態,繼承自動物類的人類、貓類的操作‘吃’不同。
Python的類
- 定義
class ClassName: block
- 必須使用class關鍵字
- 類名必須使用大駝峰命名
- 類定義完成后,就產生了一個類對象,綁定到了ClassName上
- 類對象及類屬性
- 類對象:類的定義就會生成一個類對象
- 類的屬性:類定義中的變量和類中定義的方法都是類的屬性
- 類變量:x是類MyClass的變量 MyClass中,x、foo都是類的屬性,__doc__也是類的屬性
foo方法是類的屬性,如同吃是人類的方法,但是每一個具體的人才能吃東西,也就是說吃是人的實例才能調用的方法。
foo是method方法對象,不是普通的函數對象function了,他必須至少有一個參數,且第一個參數必須是self(self指代當前實例本身),這個參數位置就留給了self。
- 實例化
a = MyClass() #實例化
使用上面的語法,在類對象后面加上一個括號,就調用類的實例化方法,完成實例化。 實例化就是真正創建一個該類的對象。 實例化后獲得的實例,是不同的實例,即使是使用同樣的參數實例化,也得到不一樣的對象。Python類實例化后,會自動調用__init__方法。這個方法可以有多個參數,但是第一個參數必須留給self,其他沒有要求。 - __init__方法 MyClass()實際上調用的是__init__(self)方法,可以不定義,如果沒有定義會在實例化后飲食調用。作用:對實例進行初始化。 初始化函數可以多個參數,請注意第一個位置必須是self,例如init(self,name,age)
注意:__init__()方法不能有返回值,也就是只能是None
- 實例對象instance 類實例化后一定會獲得一個對象,就是實例對象 類實例化出一個實例對象,實例對象會綁定方法,調用方法時采用jerry.showage()的方式。 self.name就是jerry對象的name,name是保存在了jerry對象上,而不是Person類上。所以,稱為實例變量。
- self
self就是調用者,就是c對應的實例對象。 self這個名字是一個慣例,可以修改,但是為了代碼的可讀性,不要修改。
- 實例變量和類變量
實例變量是每一個實例自己的變量,是自己獨有的;類變量是類的變量,是類的所有實例共享的屬性和方法
特殊屬性 | 含義 |
---|---|
__name__ | 對象名 |
__class__ | 對象的類型 |
__dict__ | 對象的屬性的字典 |
__qualname__ | 類的限定名 |
舉例:
上面代碼中看到類屬性保存在類的\_\_dict\_\_中,實例屬性保存在實例的\_\_dict\_\_中,如果從實例訪問類的屬性,就需要解除\_\_class\_\_找到所屬的類。
- 總結 是類的屬性或方法也是這個類所有實例的;是實例的屬性或方法,就是這個實例自己的,通過類訪問不到 類變量是屬于類的變量,這個類的所有實例可以共享這個變量。 實例可以動態的給自己增加一個屬性。實例.__dict__[變量名]和實例.變量名都可以訪問到 實力的同名變量會隱藏這類變量,或者說是覆蓋了這個類變量。 實例屬性的查找順序:指的是實例使用.來訪問屬性,會先找自己的__dict__,如果沒有會通過屬性__class__找到自己的類,再去類的__dict__中找 一般來說,類變量使用全大寫來命名。
裝飾一個類
需求:為一個類通過裝飾,,增加一些類屬性
之所以能夠裝飾,本質上是為類對象動態的添加了一個屬性,而Person這個標識符指向這個類對象。
類方法和靜態方法
例子中定義的init等方法本身都是類的屬性,第一個參數必須是self,erself必須只想一個對象,也就是類必須實例化后由實例來調用這個方法。 普通函數
Person.normal_method()可以調用,因為這個方法只是被Person這個名詞空間管理的一個普通的方法,normal_method這是Person.normal的一個屬性而已。 由于normal_method再定義是再有指定self,所以不能完成實例對象的綁定,不能用Person().normal_method()調用。 ==注意:雖然語法對,但是禁止這么寫。
- 類方法
- 在類定義中使用@classmethod裝飾器修飾的方法
- 必須有至少一個參數,且第一個參數留給cls,cls指代調用者即類對象自身
- cls這個標識符可以是任意合法名稱,為了代碼可讀性,禁止修改
- 通過cls可以直接操作類屬性 類似于java、c++中的靜態方法
- 靜態方法
- 在類定義中使用@staticmethod裝飾器修飾的方法
- 調用時,不會隱式的傳入參數。靜態方法,只是表明這個方法屬于這個名詞空間。函數歸在一起,方便組織管理。
- 方法的調用
class Person: def normal_method(): print('normal') def method(self): print("{}'s method",format(self)) @classmethod def classmtd(cls): print('class = {0.__name__} ({0})'.format(cls)) cls.HEIGHT = 170 @staticmethod def static_methd(): print(Person.HEIGHT)
總結: 類除了普通方法都可以調用,普通方法需要對象的實例作為第一參數。 實例可以調用所有類中定義的方法(包括類方法、靜態方法),普通方法傳入實例自身,靜態方法和類方法需要找到實例的類。
訪問控制
- 私有(Private)屬性 私有屬性:使用雙下劃線開頭的屬性名,就是私有屬性 私有變量的本質:類定義的時候,如果聲明一個實例變量的時候,使用雙下劃線,Python解釋器會將其改名,轉換名稱**_類名__變量名**的名稱,所有原來的名字訪問不到了。但是如果知道了私有變量的新名稱,還是可以直接從外部訪問到并修改它。
- 保護變量 在變量名前使用一個下劃線,稱為保護變量。保護變量和普通的屬性一樣,解釋器不做任何特殊處理。這個只是開發者的約定,看到這種變量就知道這是保護變量,僅限于內部使用,不要直接使用。
- 私有方法 參照保護變量、私有變量,使用單下劃線、雙下劃線命名方法。
class Person:
def __init__(self,name,age=18):
self.name = name
self.__age = age
def _getname(self):
return self.name
def __getage(self):
return self._age
tom = Person('Tom')
print(tom._getname())
print(tom.__getage())
print(tom.__Dict__)
print(tom.__class__.__dict__)
print(tom._Person__getage())
私有方法的本質:單下劃線的方法只是開發者之間的約定,解釋器不做任何改變。雙下劃線的方法是私有方法,解釋器會幫助我們改名以達到隱藏該方法的目的,改名策略和私有變量相同,方法變量都在類的字典中可以找到。
- 私有成員總結 在Python中,使用單下劃線或者雙下劃線來標識一個成員被保護或者被私有化隱藏起來。但是,不管使用什么養的訪問控制,都不能真正的阻止修改類的成員。Python中沒有絕對的安全的保護成員或者私有成員。因此,簽到的下劃線只是一種警告和提醒,除非真有必要,否則不要修改或使用它們。
補丁
- 可以通過修改或者替換類的成員。使用者調用方式不變,但是類提供的功能可能已經改變了。
- 猴子補?。∕onkeyPatch):在運行時,對屬性進行動態替換。慎用
屬性裝飾器
一般的設計是:把實例的屬性保護起來,不讓外部直接訪問,外部使用getter讀取屬性和setter方法設置屬性。
- 通過age和set_age的方法操作屬性
class Person: def __init__(self,name,age=18): self.name = name self.__age = age def age(self): return self.__age def set_age(self,age): self.__age = age jerry = Person('jerry') print(jerry.age()) jerry.set_age(24) print(jerry.age())
- 使用屬性裝飾器的簡單方法
class Person: def __init__(self,name,age=18): self.name = name self.__age = age @property def age(self): return self.__age @age.setter def age(self,age): self.__age = age @age.deleter def age(self): del self.__age print('delete completed') jerry = Person('jerry') print(jerry.age) jerry.age = 24 print(jerry.age) del jerry.age
- Property裝飾能通過簡單的方式把對方法的操作變成對屬性的訪問,并起到了隱藏效果。特別注意:以下三個方法同名,但是property裝飾器必須在setter和deleter之前。
- property裝飾器,后面跟的函數名就是以后的屬性名。它就是getter,這個必須有,有了它至少是只讀屬性。
- setter裝飾器,于屬性名同名,且接收兩個參數,第一個shiself,第二個是將要賦值的值。有了它,屬性可寫。
- deleter裝飾器,可以控制是否刪除屬性。很少用
對象的銷毀
類中可以定義__del__方法,稱為析構函數(方法)。作用是銷毀類的實例,釋放占用的資源。由于Python實現了垃圾回收機制,這個方法不確定和實質性,有必要時請使用del語句刪除實例,來手動調用這個方法
class person:
def __init__(self,name,age=18):
self.name = name
self.age = age
def __del__(self):
print('{} is already deleted'.format(self.name))
tom = person('tom')
del tom
方法重載
在其他面向對象的高級語言中都有重載的概念。重載就是同一個方法名,但是參數數量、類型不一樣。但是Python中沒有重載,也不需要。因為Python中,方法定義中形參非常靈活,不需要指定類型,參數個數也不固定。一個函數的定義可以實現很多種不同形式是慘的調用。
封裝(Encapsulation) 面向對象三要素之一
封裝就是將數據和操作組織到類中;將數據隱藏起來,該使用者提供操作。使用這通過操作可以獲取或者修改數據;通過訪問內控制,保留適當的數據和操作給用戶,該隱藏的隱藏。
練習
- 隨機整數生成類,可以指定一批生成的個數,可以指定熟知的范圍,可以調整每批生成數字的個數
from collections import namedtuple
import random
class RandNum:
def __init__(self,pos=0,endpos=100,maxnum=20):
self.pos = pos
self.endpos = endpos
self.maxnum = maxnum
self.gen = self._gen()
def _gen(self):
while True:
yield [random.randint(self.pos,self.endpos) for _ in range(self.maxnum)]
def generate(self,count=None):
if count == None:
pass
else:
self.maxnum = count
return next(self.gen)
rg =RandNum()
print(rg)
- 使用上題中的類,隨機生成20個數字,兩兩配對形成二位坐標,把坐標組織起來輸出。
class CoordinatePoint:
def __init__(self,x,y):
self.x = x
self.y = y
def __repr__(self):
return 'Point({},{})'.format(self.x,self.y)
p=zip(rg.generate(),rg.generate())
print([CoordinatePoint(*item) for item in p])
- 記錄車的品牌、顏色、價格、速度等特征,并實線增加車輛信息,顯示全部車輛信息的功能
class CarInfo:
def __init__(self,mark,color,price,speed):
self.mark = mark
self.color = color
self.price = price
self.speed = speed
def add_info(self,name,info):
self.name = info
def __repr__(self):
return 'mark:{},color:{},${}w,{}Km/h'.format(self.mark,self.color,self.price,self.speed)
class Carset:
def __init__(self):
self.lst = []
def add_carinfo(self,car:CarInfo):
self.lst.append(car)
def getall(self):
print(self.lst)
lykan = CarInfo('Motor','blue',340,420)
carinfo = Carset()
carinfo.add_carinfo(lykan)
carinfo.getall()
- 實現溫度的處理,轉換
class Temperature: def __init__(self,t,unit = 'c'): self._c = None self._f = None self._k = None if unit == 'k': self._c = self.k2c(t) self._k = t elif unit == 'f': self._c = self.f2c(t) self._f = t else: self._c = t def __repr__(self): # return '攝氏度:{}℃,華氏度:{}℉,開氏度:{} K'.format(self._c,self._f,self._k) if self._c: return '攝氏度:{}℃'.format(self._c) elif self._f: return '華氏度:{}℉'.format(self._f) elif self._k: return '開氏度:{} K'.format(self._k) @property def k(self): if self._k is None: self._k = self.c2k(self._c) return '開氏度:{} K'.format(self._k) @property def c(self): if self._c is None: self._c = self.k2c(self._k) return '攝氏度:{}℃'.format(self._c) @property def f(self): if self._f is None: self._f = self.c2f(self._c) return '華氏度:{}℉'.format(self._f) @classmethod def c2f(cls,c): return c*9/5+32 @classmethod def c2k(cls,c): return c+273.15 @classmethod def f2c(cls,f): return (f-32)*5/9 @classmethod def k2c(cls,k): return k - 273.15 @classmethod def k2f(cls,k): return cls.c2f(cls.k2c(k)) @classmethod def f2k(cls,f): return cls.c2k(cls.f2c(f)) print(Temperature.c2f(40)) print(Temperature.f2c(333.15)) print(Temperature.c2k(40)) print(Temperature.f2k(333.15)) print(Temperature.k2f(190)) print(Temperature.k2c(190)) t= Temperature(120,'f') print(t) print(t.c,t.f,t.k)
- 模擬購物車功能
class merchandise: def __init__(self,name,price,count): self.name = name self.price = price self.count = count def __repr__(self): return 'name:{},${},count{}'.format(self.name,self.price,self.count) class ShopCar: def __init__(self): self.lst = [] def add_merchandise(self,thing:merchandise): self.lst.append(thing) def getall(self): return self.lst myshopcar = ShopCar() myphone = merchandise('glaxy',5398,10) mycar = merchandise('maserati Granti',248,1) myshopcar.add_merchandise(mycar) myshopcar.add_merchandise(myphone) myshopcar.getall()
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/88382