Python面向?qū)ο缶幊蹋ǘ?/h1>
更新時間:2022年05月30日 09:03:37 作者:springsnow
本文詳細(xì)講解了Python的面向?qū)ο缶幊蹋闹型ㄟ^示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
一、對象的繼承
Python中支持一個類同時繼承多個父類
class Parent1:
pass
class Parent2:
pass
class Sub1(Parent1, Parent2):
pass
使用__bases__方法可以獲取對象繼承的類
print(Sub1.__bases__)
# (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
在Python3中如果一個類沒有繼承任何類,則默認(rèn)繼承object類。
print(Parent1.__bases__)
#('object'>,)
1、類的構(gòu)造函數(shù)繼承__init__():
- 子類需要自動調(diào)用父類的方法:子類不重寫__init__()方法,實(shí)例化子類后,會自動調(diào)用父類的__init__()的方法。
- 子類不需要自動調(diào)用父類的方法:子類重寫__init__()方法,實(shí)例化子類后,將不會自動調(diào)用父類的__init__()的方法。
- 子類重寫__init__()方法又需要調(diào)用父類的方法:需要使用super關(guān)鍵詞。
2、繼承關(guān)系中,對象查找屬性的順序
對象自己——>對象的類——>父類——>父類。。。
class OldboyPeople:
"""由于學(xué)生和老師都是人,因此人都有姓名、年齡、性別"""
school = 'oldboy'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class OldboyStudent(OldboyPeople):
def choose_course(self):
print('%s is choosing course' % self.name)
class OldboyTeacher(OldboyPeople):
def score(self, stu_obj, num):
print('%s is scoring' % self.name)
stu_obj.score = num
stu1 = OldboyStudent('tank', 18, 'male')
tea1 = OldboyTeacher('nick', 18, 'male')
print(stu1.school)
# oldboy
print(tea1.school)
# oldboy
print(stu1.__dict__)
# {'name': 'tank', 'age': 18, 'gender': 'male'}
tea1.score(stu1, 99)
# nick is scoring
print(stu1.__dict__)
# {'name': 'tank', 'age': 18, 'gender': 'male', 'score': 99}
二、類的派生
子類中新定義的屬性的這個過程叫做派生,子類在使用派生的屬性時始終以自己的為準(zhǔn)。
1、派生方法一(類調(diào)用)
指名道姓訪問某一個類的函數(shù):該方式與繼承無關(guān)
class OldboyPeople:
"""由于學(xué)生和老師都是人,因此人都有姓名、年齡、性別"""
school = 'oldboy'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class OldboyStudent(OldboyPeople):
"""由于學(xué)生類沒有獨(dú)自的__init__()方法,因此不需要聲明繼承父類的__init__()方法,會自動繼承"""
def choose_course(self):
print('%s is choosing course' % self.name)
class OldboyTeacher(OldboyPeople):
"""由于老師類有獨(dú)自的__init__()方法,因此需要聲明繼承父類的__init__()"""
def __init__(self, name, age, gender, level):
OldboyPeople.__init__(self, name, age, gender)
self.level = level # 派生
def score(self, stu_obj, num):
print('%s is scoring' % self.name)
stu_obj.score = num
stu1 = OldboyStudent('tank', 18, 'male')
tea1 = OldboyTeacher('nick', 18, 'male', 10)
print(stu1.__dict__)
# {'name': 'tank', 'age': 18, 'gender': 'male'}
print(tea1.__dict__)
# {'name': 'nick', 'age': 18, 'gender': 'male', 'level': 10}
2、派生方法二(super)
- 嚴(yán)格以繼承屬性查找關(guān)系
- super()會得到一個特殊的對象,該對象就是專門用來訪問父類中的屬性的(按照繼承的關(guān)系)
- super().__init__(不用為self傳值)
- super的完整用法是super(自己的類名,self),在python2中需要寫完整,而python3中可以簡寫為super()。
class OldboyPeople:
school = 'oldboy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def choose_course(self):
print('%s is choosing course' % self.name)
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex, stu_id):
# OldboyPeople.__init__(self,name,age,sex)
# super(OldboyStudent, self).__init__(name, age, sex)
super().__init__(name, age, sex)
self.stu_id = stu_id
def choose_course(self):
print('%s is choosing course' % self.name)
stu1 = OldboyStudent('tank', 19, 'male', 1)
super(OldboyStudent,stu1).choose_course() #用子類對象調(diào)用父類已被覆蓋的方法
print(stu1.__dict__)
# {'name': 'tank', 'age': 19, 'sex': 'male', 'stu_id': 1}
三、類的組合
類對象可以引用/當(dāng)做參數(shù)傳入/當(dāng)做返回值/當(dāng)做容器元素,類似于函數(shù)對象。
- 組合是用來解決類與類之間代碼冗余的問題
組合可以理解成多個人去造一個機(jī)器人,有的人造頭、有的人造腳、有的人造手、有的人造軀干,大家都完工后,造軀干的人把頭、腳、手拼接到自己的軀干上,因此一個機(jī)器人便造出來了
class Course:
def __init__(self, name, period, price):
self.name = name
self.period = period
self.price = price
class OldboyPeople:
school = 'oldboy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex, stu_id):
OldboyPeople.__init__(self, name, age, sex)
self.stu_id = stu_id
def choose_course(self):
print('%s is choosing course' % self.name)
class OldboyTeacher(OldboyPeople):
def __init__(self, name, age, sex, level):
OldboyPeople.__init__(self, name, age, sex)
self.level = level
def score(self, stu, num):
stu.score = num
print('老師[%s]為學(xué)生[%s]打分[%s]' % (self.name, stu.name, num))
# 創(chuàng)造課程
python = Course('python全棧開發(fā)', '5mons', 3000)
linux = Course('linux運(yùn)維', '5mons', 800)
# 創(chuàng)造學(xué)生與老師
stu1 = OldboyStudent('tank', 19, 'male', 1)
tea1 = OldboyTeacher('nick', 18, 'male', 10)
# 組合
# 將學(xué)生、老師與課程對象關(guān)聯(lián)/組合
stu1.course = python
tea1.course = linux
四、多父類繼承問題
Python同樣有限的支持多繼承形式。多繼承的類定義形如下例:
class DerivedClassName(Base1, Base2, Base3):
.
.
.
需要注意圓括號中父類的順序,若是父類中有相同的方法名,而在子類使用時未指定,python從左至右搜索 。即方法在子類中未找到時,從左到右查找父類中是否包含方法。
1、新式類(MRO)列表
- 繼承了object的類以及該類的子類,都是新式類
- Python3中所有的類都是新式類
- 廣度優(yōu)先, 老祖宗最后找。
class G(object):
# def test(self):
# print('from G')
pass
class E(G):
# def test(self):
# print('from E')
pass
class B(E):
# def test(self):
# print('from B')
pass
class F(G):
# def test(self):
# print('from F')
pass
class C(F):
# def test(self):
# print('from C')
pass
class D(G):
# def test(self):
# print('from D')
pass
class A(B, C, D):
def test(self):
print('from A')
obj = A()
obj.test() # A->B->E-C-F-D->G-object
# from A
python計(jì)算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表,來實(shí)現(xiàn)繼承的。
為了實(shí)現(xiàn)繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。而這個MRO列表的構(gòu)造是通過一個C3線性化算法來實(shí)現(xiàn)的。
print(A.mro()) # A.__mro__
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
for i in A.mro():
print(i)
# <class '__main__.A'>
# <class '__main__.B'>
# <class '__main__.E'>
# <class '__main__.C'>
# <class '__main__.F'>
# <class '__main__.D'>
# <class '__main__.G'>
# <class 'object'>
2、super()方法詳解
super() 函數(shù)是用于調(diào)用父類(超類)的一個方法。
super 是用來解決多重繼承問題的,直接用類名調(diào)用父類方法在使用單繼承的時候沒問題,但是如果使用多繼承,會涉及到查找順序(MRO)、重復(fù)調(diào)用(鉆石繼承)等種種問題。
下面的例子可以看到:
- 每個類開始調(diào)用是根據(jù)MRO順序進(jìn)行開始,然后逐個進(jìn)行結(jié)束的。
- 由于因?yàn)樾枰^承不同的父類,參數(shù)不一定,所有的父類都應(yīng)該加上不定參數(shù)*args , **kwargs ,不然參數(shù)不對應(yīng)是會報(bào)錯的。
# 胖子老板的父類
class FatFather(object):
def __init__(self, name, *args, **kwargs):
print()
print("=============== 開始調(diào)用 FatFather ========================")
print('FatFather的init開始被調(diào)用')
self.name = name
print('調(diào)用FatFather類的name是%s' % self.name)
print('FatFather的init調(diào)用結(jié)束')
print()
print("=============== 結(jié)束調(diào)用 FatFather ========================")
# 胖子老板類 繼承 FatFather 類
class FatBoss(FatFather):
def __init__(self, name, hobby, *args, **kwargs):
print()
print("=============== 開始調(diào)用 FatBoss ========================")
print('胖子老板的類被調(diào)用啦!')
# super().__init__(name)
# 因?yàn)槎嗬^承傳遞的參數(shù)不一致,所以使用不定參數(shù)
super().__init__(name, *args, **kwargs)
print("%s 的愛好是 %s" % (name, hobby))
print()
print("=============== 結(jié)束調(diào)用 FatBoss ========================")
# 胖子老板的老婆類 繼承 FatFather類
class FatBossWife(FatFather):
def __init__(self, name, housework, *args, **kwargs):
print()
print("=============== 開始調(diào)用 FatBossWife ========================")
print('胖子老板的老婆類被調(diào)用啦!要學(xué)會干家務(wù)')
# super().__init__(name)
# 因?yàn)槎嗬^承傳遞的參數(shù)不一致,所以使用不定參數(shù)
super().__init__(name, *args, **kwargs)
print("%s 需要干的家務(wù)是 %s" % (name, housework))
print()
print("=============== 結(jié)束調(diào)用 FatBossWife ========================")
# 胖子老板的女兒類 繼承 FatBoss FatBossWife類
class FatBossGril(FatBoss, FatBossWife):
def __init__(self, name, a, b):
print('胖子老板的女兒類被調(diào)用啦!要學(xué)會干家務(wù),還要會幫胖子老板斗地主')
super().__init__(name, a, b)
def main():
print("打印FatBossGril類的MRO")
print(FatBossGril.__mro__)
# (<class '__main__.FatBossGril'>, <class '__main__.FatBoss'>, <class '__main__.FatBossWife'>, <class '__main__.FatFather'>, <class 'object'>)
print("=========== 下面按照 MRO 順序執(zhí)行super方法 =============")
gril = FatBossGril("胖子老板", "打斗地主", "拖地")
if __name__ == "__main__":
main()
# =========== 下面按照 MRO 順序執(zhí)行super方法 =============
# 胖子老板的女兒類被調(diào)用啦!要學(xué)會干家務(wù),還要會幫胖子老板斗地主
#
# =============== 開始調(diào)用 FatBoss ========================
# 胖子老板的類被調(diào)用啦!
#
# =============== 開始調(diào)用 FatBossWife ========================
# 胖子老板的老婆類被調(diào)用啦!要學(xué)會干家務(wù)
#
# =============== 開始調(diào)用 FatFather ========================
# FatFather的init開始被調(diào)用
# 調(diào)用FatFather類的name是胖子老板
# FatFather的init調(diào)用結(jié)束
#
# =============== 結(jié)束調(diào)用 FatFather ========================
# 胖子老板 需要干的家務(wù)是 拖地
#
# =============== 結(jié)束調(diào)用 FatBossWife ========================
# 胖子老板 的愛好是 打斗地主
#
# =============== 結(jié)束調(diào)用 FatBoss ========================
五、抽象類
多態(tài)指的是一類事物有多種形態(tài),(一個抽象類有多個子類,因而多態(tài)的概念依賴于繼承)
import abc
class Animal(metaclass=abc.ABCMeta): # 同一類事物:動物
@abc.abstractmethod # 上述代碼子類是約定俗稱的實(shí)現(xiàn)這個方法,加上@abc.abstractmethod裝飾器后嚴(yán)格控制子類必須實(shí)現(xiàn)這個方法
def talk(self):
raise AttributeError('子類必須實(shí)現(xiàn)這個方法')
class People(Animal): # 動物的形態(tài)之一:人
def talk(self):
print('say hello')
class Dog(Animal): # 動物的形態(tài)之二:狗
def talk(self):
print('say wangwang')
class Pig(Animal): # 動物的形態(tài)之三:豬
def talk(self):
print('say aoao')
peo2 = People()
pig2 = Pig()
d2 = Dog()
peo2.talk()
pig2.talk()
d2.talk()
# say hello
# say aoao
# say wangwang
六、類的封裝
類中把某些屬性和方法隱藏起來(或者說定義成私有的),只在類的內(nèi)部使用、外部無法訪問,或者留下少量接口(函數(shù))供外部訪問。
1、私有屬性:雙下劃線的方式__x
在python中用雙下劃線的方式__x實(shí)現(xiàn)隱藏屬性(設(shè)置成私有的),我們需要在類中定義一個函數(shù)(接口函數(shù))在它內(nèi)部訪問被隱藏的屬性,然后外部就可以使用了。
class Site:
def __init__(self, name, url):
self.name = name # public
self.__url = url # private
def who(self):
print('name : ', self.name)
print('url : ', self.__url)
def __foo(self): # 私有方法
print('這是私有方法')
def foo(self): # 公共方法
print('這是公共方法')
self.__foo()
x = Site('菜鳥教程', 'www.runoob.com')
x.who() # 正常輸出
x.foo() # 正常輸出
x.__foo() # 報(bào)錯
2、外部使用變形訪問:_類名__x
類中所有雙下劃線開頭的名稱如__x都會自動變形成: _類名__x的形式:
這種自動變形的特點(diǎn):
- 類中定義的__x只能在內(nèi)部使用,如self.__x,引用的就是變形的結(jié)果。
- 這種變形其實(shí)正是針對內(nèi)部的變形,在外部是無法通過__x這個名字訪問到的。
- 在子類定義的__x不會覆蓋在父類定義的__x,因?yàn)樽宇愔凶冃纬闪耍篲子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。
這種機(jī)制也并沒有真正意義上限制我們從外部直接訪問屬性,知道了類名和屬性名就可以拼出名字:_類名__屬性,然后就可以訪問了,如a._A__N。
class A:
__N = 0 # 把類的數(shù)據(jù)屬性設(shè)置成私有的如__N,會變形為_A__N
def __init__(self):
self.__X = 10 # 變形為self._A__X
def __foo(self): # 變形為_A__foo
print('from A')
def bar(self):
self.__foo() # 只有在類內(nèi)部才可以通過__foo的形式訪問到.
# 對象測試
a = A()
print(a._A__N) # 0
print(a._A__X) # 10
# 類測試
print(A._A__N) # 0
print(A._A__X) # 對象私有的屬性# type object 'A' has no attribute '_A__X'
注意:變形的過程只在類的定義時發(fā)生一次,在定義后的賦值操作,不會變形。
a = A()
print(a.__dict__) # {'_A__X': 10}
a.__Y = 1
print(a.__dict__) # {'_A__X': 10, '__Y': 1}
3、在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有的
# 正常情況
class A:
def fa(self):
print('from A')
def test(self):
self.fa()
class B(A):
def fa(self):
print('from B')
b = B()
b.test() # from B
# 把fa定義成私有的,即__fa
class A:
def __fa(self): # 在定義時就變形為_A__fa
print('from A')
def test(self):
self.__fa() # 只會與自己所在的類為準(zhǔn),即調(diào)用_A__fa
class B(A):
def __fa(self): #子類無法覆蓋
print('from B')
b = B()
b.test() # from A
python模塊也遵循這種約定,如果模塊中的變量名_amodule以單下劃線開頭,那么from module import *時不能被導(dǎo)入該變量,但是你from module import_amodule依然是可以導(dǎo)入該變量的。
如果遇到下劃線開頭的(socket._socket,sys._home,sys._clear_type_cache),這些都是私有的,原則上是供內(nèi)部調(diào)用的,作為外部也是可以用的。嚴(yán)格控制屬性的訪問權(quán)限,只能借助內(nèi)置方法如__getattr__。
七、類的屬性(property)
1、裝飾器方式 (推薦使用)
property裝飾器用于將被裝飾的方法偽裝成一個數(shù)據(jù)屬性,在使用時可以不用加括號而直接使用。
- 1. 定義時,在實(shí)例方法的基礎(chǔ)上添加 @property 裝飾器,并且僅有一個self參數(shù)
- 2. 調(diào)用時,無需括號
property屬性的功能是:property屬性內(nèi)部進(jìn)行一系列的邏輯計(jì)算,最終將計(jì)算結(jié)果返回。
分頁的功能包括:
- 根據(jù)用戶請求的當(dāng)前頁和總數(shù)據(jù)條數(shù)計(jì)算出 m 和 n
- 根據(jù)m 和 n 去數(shù)據(jù)庫中請求數(shù)據(jù)
class Pager:
def __init__(self, current_page):
# 用戶當(dāng)前請求的頁碼(第一頁、第二頁...)
self.current_page = current_page
# 每頁默認(rèn)顯示10條數(shù)據(jù)
self.per_items = 10
@property
def start(self):
val = (self.current_page - 1) * self.per_items
return val
@property
def end(self):
val = self.current_page * self.per_items
return val
# ############### 調(diào)用 ###############
p = Pager(2)
print(p.start) # 就是起始值,即:m
# 10
print(p.end) # 就是結(jié)束值,即:n
# 20
2、經(jīng)典類和新式類的屬性方式:
經(jīng)典類中的屬性只有一種訪問方式,其對應(yīng)被 @property 修飾的方法。
新式類(如果類繼object,那么該類是新式類 )中的屬性有三種訪問方式,并分別對應(yīng)了三個被 @property、@方法名.setter、@方法名.deleter 修飾的方法,對同一個屬性:獲取、修改、刪除
class Goods(object):
def __init__(self):
# 原價
self.original_price = 100
# 折扣
self.discount = 0.8
@property
def price(self):
# 實(shí)際價格 = 原價 * 折扣
new_price = self.original_price * self.discount
return new_price
@price.setter
def price(self, value):
self.original_price = value
@price.deleter
def price(self):
print('del')
del self.original_price
obj = Goods()
print(obj.price) # 獲取商品價格
# 80.0
obj.price = 200 # 修改商品原價
print(obj.price)
# 160.0
del obj.price # 刪除商品原價
# del
3、類屬性方式
注意:當(dāng)使用類屬性的方式創(chuàng)建property屬性時,經(jīng)典類和新式類無區(qū)別。
property方法中有個四個參數(shù)
- 第一個參數(shù)是調(diào)用 對象.屬性 時自動觸發(fā)執(zhí)行方法
- 第二個參數(shù)是調(diào)用 對象.屬性 = XXX 時自動觸發(fā)執(zhí)行方法
- 第三個參數(shù)是調(diào)用 del 對象.屬性 時自動觸發(fā)執(zhí)行方法
- 第四個參數(shù)是字符串,調(diào)用 對象.屬性.__doc__ ,此參數(shù)是該屬性的描述信息
class Goods(object):
def __init__(self):
# 原價
self.original_price = 100
# 折扣
self.discount = 0.8
def get_price(self):
# 實(shí)際價格 = 原價 * 折扣
new_price = self.original_price * self.discount
return new_price
def set_price(self, value):
self.original_price = value
def del_price(self):
del self.original_price
PRICE = property(get_price, set_price, del_price, '價格屬性描述...')
obj = Goods()
print(obj.PRICE) # 獲取商品價格
# 80.0
obj.PRICE = 200 # 修改商品原價
print(obj.PRICE)
# 160.0
del obj.PRICE # 刪除商品原價
3、實(shí)例
實(shí)現(xiàn)一個屬性的設(shè)置和讀取方法,可做邊界判定
class Money(object):
def __init__(self):
self.__money = 0
# 使用裝飾器對money進(jìn)行裝飾,那么會自動添加一個叫money的屬性,當(dāng)調(diào)用獲取money的值時,調(diào)用裝飾的方法
@property
def money(self):
return self.__money
# 使用裝飾器對money進(jìn)行裝飾,當(dāng)對money設(shè)置值時,調(diào)用裝飾的方法
@money.setter
def money(self, value):
if isinstance(value, int):
self.__money = value
else:
print("error:不是整型數(shù)字")
a = Money()
a.money = 100
print(a.money)# 100
八、實(shí)例方法及非綁定實(shí)例方法
1、實(shí)例方法
在類中沒有被任何裝飾器修飾的方法就是綁定到對象的實(shí)例方法,這類方法專門為對象定制。
class Person:
country = "China"
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self):
print(self.name + ', ' + str(self.age))
p = Person('Kitty', 18)
print(p.__dict__)
# {'name': 'Kitty', 'age': 18}
print(Person.__dict__['speak'])
#
speak即為綁定到對象的方法,這個方法不在對象的名稱空間中,而是在類的名稱空間中。
綁定到對象的方法:
- 通過對象調(diào)用,會有一個自動傳值的過程,即自動將當(dāng)前對象傳遞給方法的第一個參數(shù)(self,一般都叫self,也可以寫成別的名稱);
- 使用類調(diào)用,則第一個參數(shù)需要手動傳值。
p = Person('Kitty', 18)
p.speak() # 通過對象調(diào)用
# Kitty, 18
Person.speak(p) # 通過類調(diào)用
# Kitty, 18
2、類方法(@classmethod )
類中使用 @classmethod 修飾的方法就是綁定到類的方法。這類方法專門為類定制。
- 通過類名調(diào)用綁定到類的方法時,會將類本身當(dāng)做參數(shù)傳給類方法的第一個參數(shù)。類方法默認(rèn)有個 cls 參數(shù)。
- 通過對象也可以調(diào)用,只是默認(rèn)傳遞的第一個參數(shù)還是這個對象對應(yīng)的類。
class Operate_database():
host = '192.168.0.5'
port = '3306'
user = 'abc'
password = '123456'
@classmethod
def connect(cls): # 約定俗成第一個參數(shù)名為cls,也可以定義為其他參數(shù)名
print(cls)
print(cls.host + ':' + cls.port + ' ' + cls.user + '/' + cls.password)
Operate_database.connect()
# <class '__main__.Operate_database'>
# 192.168.0.5:3306 abc/123456
Operate_database().connect() # 輸出結(jié)果一致
# <class '__main__.Operate_database'>
# 192.168.0.5:3306 abc/123456
3、靜態(tài)方法(@staticmethod )
在類內(nèi)部使用 @staticmethod 修飾的方法即為非綁定的靜態(tài)方法,這類方法和普通定義的函數(shù)沒有區(qū)別,不與類或?qū)ο蠼壎?,誰都可以調(diào)用,且沒有自動傳值的效果。
import hashlib
class Operate_database():
def __init__(self, host, port, user, password):
self.host = host
self.port = port
self.user = user
self.password = password
@staticmethod
def get_passwrod(salt, password):
m = hashlib.md5(salt.encode('utf-8')) # 加鹽處理
m.update(password.encode('utf-8'))
return m.hexdigest()
hash_password = Operate_database.get_passwrod('lala', '123456') # 通過類來調(diào)用
print(hash_password)
# f7a1cc409ed6f51058c2b4a94a7e1956
p = Operate_database('192.168.0.5', '3306', 'abc', '123456')
hash_password = p.get_passwrod(p.user, p.password) # 也可以通過對象調(diào)用
print(hash_password)
# 0659c7992e268962384eb17fafe88364
九、類的專有方法:
- __init__ : 構(gòu)造函數(shù),在生成對象時調(diào)用
- __del__ : 析構(gòu)函數(shù),釋放對象時使用
- __repr__ : 打印,轉(zhuǎn)換
- __setitem__ : 按照索引賦值
- __getitem__: 按照索引獲取值
- __len__: 獲得長度
- __cmp__: 比較運(yùn)算
- __call__: 函數(shù)調(diào)用
- __name__:模塊名稱,一段程序作為主線運(yùn)行程序時其內(nèi)置名稱就是 __main__
運(yùn)算符重載
- __add__: 加運(yùn)算
- __sub__: 減運(yùn)算
- __mul__: 乘運(yùn)算
- __truediv__: 除運(yùn)算
- __mod__: 求余運(yùn)算
- __pow__: 乘方
對類的專有方法進(jìn)行重載實(shí)例如下:
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
#Vector(7,8)
到此這篇關(guān)于Python面向?qū)ο缶幊痰奈恼戮徒榻B到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
-
Python實(shí)現(xiàn)解析yaml配置文件的示例詳解
在開發(fā)過程中,配置文件是少不了的,而且配置文件是有專門的格式的,比如:ini,yaml,toml等等。本文帶大家來看看Python如何解析yaml文件,它的表達(dá)能力相比?ini?更加的強(qiáng)大,需要的可以參考一下 2022-09-09
-
Python 中對 XML 文件的編碼轉(zhuǎn)換問題
這篇文章主要介紹了Python 中對 XML 文件的編碼轉(zhuǎn)換問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下 2023-03-03
-
詳解Python編程中基本的數(shù)學(xué)計(jì)算使用
這篇文章主要介紹了Python編程中基本的數(shù)學(xué)計(jì)算使用,其中重點(diǎn)講了除法運(yùn)算及相關(guān)division模塊的使用,需要的朋友可以參考下 2016-02-02
-
基于asyncio 異步協(xié)程框架實(shí)現(xiàn)收集B站直播彈幕
本文給大家分享的是基于asyncio 異步協(xié)程框架實(shí)現(xiàn)收集B站直播彈幕收集系統(tǒng)的簡單設(shè)計(jì),并附上源碼,有需要的小伙伴可以參考下 2016-09-09
-
Windows下的Jupyter Notebook 安裝與自定義啟動(圖文詳解)
這篇文章主要介紹了Windows下的Jupyter Notebook 安裝與自定義啟動(圖文詳解),需要的朋友可以參考下 2018-02-02
-
詳解python的幾種標(biāo)準(zhǔn)輸出重定向方式
這篇文章是基于Python2.7版本,介紹常見的幾種標(biāo)準(zhǔn)輸出(stdout)重定向方式。顯然,這些方式也適用于標(biāo)準(zhǔn)錯誤重定向。學(xué)習(xí)python的小伙伴們可以參考借鑒。 2016-08-08
最新評論
一、對象的繼承
Python中支持一個類同時繼承多個父類
class Parent1: pass class Parent2: pass class Sub1(Parent1, Parent2): pass
使用__bases__方法可以獲取對象繼承的類
print(Sub1.__bases__) # (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
在Python3中如果一個類沒有繼承任何類,則默認(rèn)繼承object類。
print(Parent1.__bases__) #('object'>,)
1、類的構(gòu)造函數(shù)繼承__init__():
- 子類需要自動調(diào)用父類的方法:子類不重寫__init__()方法,實(shí)例化子類后,會自動調(diào)用父類的__init__()的方法。
- 子類不需要自動調(diào)用父類的方法:子類重寫__init__()方法,實(shí)例化子類后,將不會自動調(diào)用父類的__init__()的方法。
- 子類重寫__init__()方法又需要調(diào)用父類的方法:需要使用super關(guān)鍵詞。
2、繼承關(guān)系中,對象查找屬性的順序
對象自己——>對象的類——>父類——>父類。。。
class OldboyPeople: """由于學(xué)生和老師都是人,因此人都有姓名、年齡、性別""" school = 'oldboy' def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class OldboyStudent(OldboyPeople): def choose_course(self): print('%s is choosing course' % self.name) class OldboyTeacher(OldboyPeople): def score(self, stu_obj, num): print('%s is scoring' % self.name) stu_obj.score = num stu1 = OldboyStudent('tank', 18, 'male') tea1 = OldboyTeacher('nick', 18, 'male') print(stu1.school) # oldboy print(tea1.school) # oldboy print(stu1.__dict__) # {'name': 'tank', 'age': 18, 'gender': 'male'} tea1.score(stu1, 99) # nick is scoring print(stu1.__dict__) # {'name': 'tank', 'age': 18, 'gender': 'male', 'score': 99}
二、類的派生
子類中新定義的屬性的這個過程叫做派生,子類在使用派生的屬性時始終以自己的為準(zhǔn)。
1、派生方法一(類調(diào)用)
指名道姓訪問某一個類的函數(shù):該方式與繼承無關(guān)
class OldboyPeople: """由于學(xué)生和老師都是人,因此人都有姓名、年齡、性別""" school = 'oldboy' def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class OldboyStudent(OldboyPeople): """由于學(xué)生類沒有獨(dú)自的__init__()方法,因此不需要聲明繼承父類的__init__()方法,會自動繼承""" def choose_course(self): print('%s is choosing course' % self.name) class OldboyTeacher(OldboyPeople): """由于老師類有獨(dú)自的__init__()方法,因此需要聲明繼承父類的__init__()""" def __init__(self, name, age, gender, level): OldboyPeople.__init__(self, name, age, gender) self.level = level # 派生 def score(self, stu_obj, num): print('%s is scoring' % self.name) stu_obj.score = num stu1 = OldboyStudent('tank', 18, 'male') tea1 = OldboyTeacher('nick', 18, 'male', 10) print(stu1.__dict__) # {'name': 'tank', 'age': 18, 'gender': 'male'} print(tea1.__dict__) # {'name': 'nick', 'age': 18, 'gender': 'male', 'level': 10}
2、派生方法二(super)
- 嚴(yán)格以繼承屬性查找關(guān)系
- super()會得到一個特殊的對象,該對象就是專門用來訪問父類中的屬性的(按照繼承的關(guān)系)
- super().__init__(不用為self傳值)
- super的完整用法是super(自己的類名,self),在python2中需要寫完整,而python3中可以簡寫為super()。
class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def choose_course(self): print('%s is choosing course' % self.name) class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, stu_id): # OldboyPeople.__init__(self,name,age,sex) # super(OldboyStudent, self).__init__(name, age, sex) super().__init__(name, age, sex) self.stu_id = stu_id def choose_course(self): print('%s is choosing course' % self.name) stu1 = OldboyStudent('tank', 19, 'male', 1) super(OldboyStudent,stu1).choose_course() #用子類對象調(diào)用父類已被覆蓋的方法 print(stu1.__dict__) # {'name': 'tank', 'age': 19, 'sex': 'male', 'stu_id': 1}
三、類的組合
類對象可以引用/當(dāng)做參數(shù)傳入/當(dāng)做返回值/當(dāng)做容器元素,類似于函數(shù)對象。
- 組合是用來解決類與類之間代碼冗余的問題
組合可以理解成多個人去造一個機(jī)器人,有的人造頭、有的人造腳、有的人造手、有的人造軀干,大家都完工后,造軀干的人把頭、腳、手拼接到自己的軀干上,因此一個機(jī)器人便造出來了
class Course: def __init__(self, name, period, price): self.name = name self.period = period self.price = price class OldboyPeople: school = 'oldboy' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, stu_id): OldboyPeople.__init__(self, name, age, sex) self.stu_id = stu_id def choose_course(self): print('%s is choosing course' % self.name) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level): OldboyPeople.__init__(self, name, age, sex) self.level = level def score(self, stu, num): stu.score = num print('老師[%s]為學(xué)生[%s]打分[%s]' % (self.name, stu.name, num)) # 創(chuàng)造課程 python = Course('python全棧開發(fā)', '5mons', 3000) linux = Course('linux運(yùn)維', '5mons', 800) # 創(chuàng)造學(xué)生與老師 stu1 = OldboyStudent('tank', 19, 'male', 1) tea1 = OldboyTeacher('nick', 18, 'male', 10) # 組合 # 將學(xué)生、老師與課程對象關(guān)聯(lián)/組合 stu1.course = python tea1.course = linux
四、多父類繼承問題
Python同樣有限的支持多繼承形式。多繼承的類定義形如下例:
class DerivedClassName(Base1, Base2, Base3): . . .
需要注意圓括號中父類的順序,若是父類中有相同的方法名,而在子類使用時未指定,python從左至右搜索 。即方法在子類中未找到時,從左到右查找父類中是否包含方法。
1、新式類(MRO)列表
- 繼承了object的類以及該類的子類,都是新式類
- Python3中所有的類都是新式類
- 廣度優(yōu)先, 老祖宗最后找。
class G(object): # def test(self): # print('from G') pass class E(G): # def test(self): # print('from E') pass class B(E): # def test(self): # print('from B') pass class F(G): # def test(self): # print('from F') pass class C(F): # def test(self): # print('from C') pass class D(G): # def test(self): # print('from D') pass class A(B, C, D): def test(self): print('from A') obj = A() obj.test() # A->B->E-C-F-D->G-object # from A
python計(jì)算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表,來實(shí)現(xiàn)繼承的。
為了實(shí)現(xiàn)繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。而這個MRO列表的構(gòu)造是通過一個C3線性化算法來實(shí)現(xiàn)的。
print(A.mro()) # A.__mro__ # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>] for i in A.mro(): print(i) # <class '__main__.A'> # <class '__main__.B'> # <class '__main__.E'> # <class '__main__.C'> # <class '__main__.F'> # <class '__main__.D'> # <class '__main__.G'> # <class 'object'>
2、super()方法詳解
super() 函數(shù)是用于調(diào)用父類(超類)的一個方法。
super 是用來解決多重繼承問題的,直接用類名調(diào)用父類方法在使用單繼承的時候沒問題,但是如果使用多繼承,會涉及到查找順序(MRO)、重復(fù)調(diào)用(鉆石繼承)等種種問題。
下面的例子可以看到:
- 每個類開始調(diào)用是根據(jù)MRO順序進(jìn)行開始,然后逐個進(jìn)行結(jié)束的。
- 由于因?yàn)樾枰^承不同的父類,參數(shù)不一定,所有的父類都應(yīng)該加上不定參數(shù)*args , **kwargs ,不然參數(shù)不對應(yīng)是會報(bào)錯的。
# 胖子老板的父類 class FatFather(object): def __init__(self, name, *args, **kwargs): print() print("=============== 開始調(diào)用 FatFather ========================") print('FatFather的init開始被調(diào)用') self.name = name print('調(diào)用FatFather類的name是%s' % self.name) print('FatFather的init調(diào)用結(jié)束') print() print("=============== 結(jié)束調(diào)用 FatFather ========================") # 胖子老板類 繼承 FatFather 類 class FatBoss(FatFather): def __init__(self, name, hobby, *args, **kwargs): print() print("=============== 開始調(diào)用 FatBoss ========================") print('胖子老板的類被調(diào)用啦!') # super().__init__(name) # 因?yàn)槎嗬^承傳遞的參數(shù)不一致,所以使用不定參數(shù) super().__init__(name, *args, **kwargs) print("%s 的愛好是 %s" % (name, hobby)) print() print("=============== 結(jié)束調(diào)用 FatBoss ========================") # 胖子老板的老婆類 繼承 FatFather類 class FatBossWife(FatFather): def __init__(self, name, housework, *args, **kwargs): print() print("=============== 開始調(diào)用 FatBossWife ========================") print('胖子老板的老婆類被調(diào)用啦!要學(xué)會干家務(wù)') # super().__init__(name) # 因?yàn)槎嗬^承傳遞的參數(shù)不一致,所以使用不定參數(shù) super().__init__(name, *args, **kwargs) print("%s 需要干的家務(wù)是 %s" % (name, housework)) print() print("=============== 結(jié)束調(diào)用 FatBossWife ========================") # 胖子老板的女兒類 繼承 FatBoss FatBossWife類 class FatBossGril(FatBoss, FatBossWife): def __init__(self, name, a, b): print('胖子老板的女兒類被調(diào)用啦!要學(xué)會干家務(wù),還要會幫胖子老板斗地主') super().__init__(name, a, b) def main(): print("打印FatBossGril類的MRO") print(FatBossGril.__mro__) # (<class '__main__.FatBossGril'>, <class '__main__.FatBoss'>, <class '__main__.FatBossWife'>, <class '__main__.FatFather'>, <class 'object'>) print("=========== 下面按照 MRO 順序執(zhí)行super方法 =============") gril = FatBossGril("胖子老板", "打斗地主", "拖地") if __name__ == "__main__": main() # =========== 下面按照 MRO 順序執(zhí)行super方法 ============= # 胖子老板的女兒類被調(diào)用啦!要學(xué)會干家務(wù),還要會幫胖子老板斗地主 # # =============== 開始調(diào)用 FatBoss ======================== # 胖子老板的類被調(diào)用啦! # # =============== 開始調(diào)用 FatBossWife ======================== # 胖子老板的老婆類被調(diào)用啦!要學(xué)會干家務(wù) # # =============== 開始調(diào)用 FatFather ======================== # FatFather的init開始被調(diào)用 # 調(diào)用FatFather類的name是胖子老板 # FatFather的init調(diào)用結(jié)束 # # =============== 結(jié)束調(diào)用 FatFather ======================== # 胖子老板 需要干的家務(wù)是 拖地 # # =============== 結(jié)束調(diào)用 FatBossWife ======================== # 胖子老板 的愛好是 打斗地主 # # =============== 結(jié)束調(diào)用 FatBoss ========================
五、抽象類
多態(tài)指的是一類事物有多種形態(tài),(一個抽象類有多個子類,因而多態(tài)的概念依賴于繼承)
import abc class Animal(metaclass=abc.ABCMeta): # 同一類事物:動物 @abc.abstractmethod # 上述代碼子類是約定俗稱的實(shí)現(xiàn)這個方法,加上@abc.abstractmethod裝飾器后嚴(yán)格控制子類必須實(shí)現(xiàn)這個方法 def talk(self): raise AttributeError('子類必須實(shí)現(xiàn)這個方法') class People(Animal): # 動物的形態(tài)之一:人 def talk(self): print('say hello') class Dog(Animal): # 動物的形態(tài)之二:狗 def talk(self): print('say wangwang') class Pig(Animal): # 動物的形態(tài)之三:豬 def talk(self): print('say aoao') peo2 = People() pig2 = Pig() d2 = Dog() peo2.talk() pig2.talk() d2.talk() # say hello # say aoao # say wangwang
六、類的封裝
類中把某些屬性和方法隱藏起來(或者說定義成私有的),只在類的內(nèi)部使用、外部無法訪問,或者留下少量接口(函數(shù))供外部訪問。
1、私有屬性:雙下劃線的方式__x
在python中用雙下劃線的方式__x實(shí)現(xiàn)隱藏屬性(設(shè)置成私有的),我們需要在類中定義一個函數(shù)(接口函數(shù))在它內(nèi)部訪問被隱藏的屬性,然后外部就可以使用了。
class Site: def __init__(self, name, url): self.name = name # public self.__url = url # private def who(self): print('name : ', self.name) print('url : ', self.__url) def __foo(self): # 私有方法 print('這是私有方法') def foo(self): # 公共方法 print('這是公共方法') self.__foo() x = Site('菜鳥教程', 'www.runoob.com') x.who() # 正常輸出 x.foo() # 正常輸出 x.__foo() # 報(bào)錯
2、外部使用變形訪問:_類名__x
類中所有雙下劃線開頭的名稱如__x都會自動變形成: _類名__x的形式:
這種自動變形的特點(diǎn):
- 類中定義的__x只能在內(nèi)部使用,如self.__x,引用的就是變形的結(jié)果。
- 這種變形其實(shí)正是針對內(nèi)部的變形,在外部是無法通過__x這個名字訪問到的。
- 在子類定義的__x不會覆蓋在父類定義的__x,因?yàn)樽宇愔凶冃纬闪耍篲子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。
這種機(jī)制也并沒有真正意義上限制我們從外部直接訪問屬性,知道了類名和屬性名就可以拼出名字:_類名__屬性,然后就可以訪問了,如a._A__N。
class A: __N = 0 # 把類的數(shù)據(jù)屬性設(shè)置成私有的如__N,會變形為_A__N def __init__(self): self.__X = 10 # 變形為self._A__X def __foo(self): # 變形為_A__foo print('from A') def bar(self): self.__foo() # 只有在類內(nèi)部才可以通過__foo的形式訪問到. # 對象測試 a = A() print(a._A__N) # 0 print(a._A__X) # 10 # 類測試 print(A._A__N) # 0 print(A._A__X) # 對象私有的屬性# type object 'A' has no attribute '_A__X'
注意:變形的過程只在類的定義時發(fā)生一次,在定義后的賦值操作,不會變形。
a = A() print(a.__dict__) # {'_A__X': 10} a.__Y = 1 print(a.__dict__) # {'_A__X': 10, '__Y': 1}
3、在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有的
# 正常情況 class A: def fa(self): print('from A') def test(self): self.fa() class B(A): def fa(self): print('from B') b = B() b.test() # from B # 把fa定義成私有的,即__fa class A: def __fa(self): # 在定義時就變形為_A__fa print('from A') def test(self): self.__fa() # 只會與自己所在的類為準(zhǔn),即調(diào)用_A__fa class B(A): def __fa(self): #子類無法覆蓋 print('from B') b = B() b.test() # from A
python模塊也遵循這種約定,如果模塊中的變量名_amodule以單下劃線開頭,那么from module import *時不能被導(dǎo)入該變量,但是你from module import_amodule依然是可以導(dǎo)入該變量的。
如果遇到下劃線開頭的(socket._socket,sys._home,sys._clear_type_cache),這些都是私有的,原則上是供內(nèi)部調(diào)用的,作為外部也是可以用的。嚴(yán)格控制屬性的訪問權(quán)限,只能借助內(nèi)置方法如__getattr__。
七、類的屬性(property)
1、裝飾器方式 (推薦使用)
property裝飾器用于將被裝飾的方法偽裝成一個數(shù)據(jù)屬性,在使用時可以不用加括號而直接使用。
- 1. 定義時,在實(shí)例方法的基礎(chǔ)上添加 @property 裝飾器,并且僅有一個self參數(shù)
- 2. 調(diào)用時,無需括號
property屬性的功能是:property屬性內(nèi)部進(jìn)行一系列的邏輯計(jì)算,最終將計(jì)算結(jié)果返回。
分頁的功能包括:
- 根據(jù)用戶請求的當(dāng)前頁和總數(shù)據(jù)條數(shù)計(jì)算出 m 和 n
- 根據(jù)m 和 n 去數(shù)據(jù)庫中請求數(shù)據(jù)
class Pager: def __init__(self, current_page): # 用戶當(dāng)前請求的頁碼(第一頁、第二頁...) self.current_page = current_page # 每頁默認(rèn)顯示10條數(shù)據(jù) self.per_items = 10 @property def start(self): val = (self.current_page - 1) * self.per_items return val @property def end(self): val = self.current_page * self.per_items return val # ############### 調(diào)用 ############### p = Pager(2) print(p.start) # 就是起始值,即:m # 10 print(p.end) # 就是結(jié)束值,即:n # 20
2、經(jīng)典類和新式類的屬性方式:
經(jīng)典類中的屬性只有一種訪問方式,其對應(yīng)被 @property 修飾的方法。
新式類(如果類繼object,那么該類是新式類 )中的屬性有三種訪問方式,并分別對應(yīng)了三個被 @property、@方法名.setter、@方法名.deleter 修飾的方法,對同一個屬性:獲取、修改、刪除
class Goods(object): def __init__(self): # 原價 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 實(shí)際價格 = 原價 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): print('del') del self.original_price obj = Goods() print(obj.price) # 獲取商品價格 # 80.0 obj.price = 200 # 修改商品原價 print(obj.price) # 160.0 del obj.price # 刪除商品原價 # del
3、類屬性方式
注意:當(dāng)使用類屬性的方式創(chuàng)建property屬性時,經(jīng)典類和新式類無區(qū)別。
property方法中有個四個參數(shù)
- 第一個參數(shù)是調(diào)用 對象.屬性 時自動觸發(fā)執(zhí)行方法
- 第二個參數(shù)是調(diào)用 對象.屬性 = XXX 時自動觸發(fā)執(zhí)行方法
- 第三個參數(shù)是調(diào)用 del 對象.屬性 時自動觸發(fā)執(zhí)行方法
- 第四個參數(shù)是字符串,調(diào)用 對象.屬性.__doc__ ,此參數(shù)是該屬性的描述信息
class Goods(object): def __init__(self): # 原價 self.original_price = 100 # 折扣 self.discount = 0.8 def get_price(self): # 實(shí)際價格 = 原價 * 折扣 new_price = self.original_price * self.discount return new_price def set_price(self, value): self.original_price = value def del_price(self): del self.original_price PRICE = property(get_price, set_price, del_price, '價格屬性描述...') obj = Goods() print(obj.PRICE) # 獲取商品價格 # 80.0 obj.PRICE = 200 # 修改商品原價 print(obj.PRICE) # 160.0 del obj.PRICE # 刪除商品原價
3、實(shí)例
實(shí)現(xiàn)一個屬性的設(shè)置和讀取方法,可做邊界判定
class Money(object): def __init__(self): self.__money = 0 # 使用裝飾器對money進(jìn)行裝飾,那么會自動添加一個叫money的屬性,當(dāng)調(diào)用獲取money的值時,調(diào)用裝飾的方法 @property def money(self): return self.__money # 使用裝飾器對money進(jìn)行裝飾,當(dāng)對money設(shè)置值時,調(diào)用裝飾的方法 @money.setter def money(self, value): if isinstance(value, int): self.__money = value else: print("error:不是整型數(shù)字") a = Money() a.money = 100 print(a.money)# 100
八、實(shí)例方法及非綁定實(shí)例方法
1、實(shí)例方法
在類中沒有被任何裝飾器修飾的方法就是綁定到對象的實(shí)例方法,這類方法專門為對象定制。
class Person: country = "China" def __init__(self, name, age): self.name = name self.age = age def speak(self): print(self.name + ', ' + str(self.age)) p = Person('Kitty', 18) print(p.__dict__) # {'name': 'Kitty', 'age': 18} print(Person.__dict__['speak']) #
speak即為綁定到對象的方法,這個方法不在對象的名稱空間中,而是在類的名稱空間中。
綁定到對象的方法:
- 通過對象調(diào)用,會有一個自動傳值的過程,即自動將當(dāng)前對象傳遞給方法的第一個參數(shù)(self,一般都叫self,也可以寫成別的名稱);
- 使用類調(diào)用,則第一個參數(shù)需要手動傳值。
p = Person('Kitty', 18) p.speak() # 通過對象調(diào)用 # Kitty, 18 Person.speak(p) # 通過類調(diào)用 # Kitty, 18
2、類方法(@classmethod )
類中使用 @classmethod 修飾的方法就是綁定到類的方法。這類方法專門為類定制。
- 通過類名調(diào)用綁定到類的方法時,會將類本身當(dāng)做參數(shù)傳給類方法的第一個參數(shù)。類方法默認(rèn)有個 cls 參數(shù)。
- 通過對象也可以調(diào)用,只是默認(rèn)傳遞的第一個參數(shù)還是這個對象對應(yīng)的類。
class Operate_database(): host = '192.168.0.5' port = '3306' user = 'abc' password = '123456' @classmethod def connect(cls): # 約定俗成第一個參數(shù)名為cls,也可以定義為其他參數(shù)名 print(cls) print(cls.host + ':' + cls.port + ' ' + cls.user + '/' + cls.password) Operate_database.connect() # <class '__main__.Operate_database'> # 192.168.0.5:3306 abc/123456 Operate_database().connect() # 輸出結(jié)果一致 # <class '__main__.Operate_database'> # 192.168.0.5:3306 abc/123456
3、靜態(tài)方法(@staticmethod )
在類內(nèi)部使用 @staticmethod 修飾的方法即為非綁定的靜態(tài)方法,這類方法和普通定義的函數(shù)沒有區(qū)別,不與類或?qū)ο蠼壎?,誰都可以調(diào)用,且沒有自動傳值的效果。
import hashlib class Operate_database(): def __init__(self, host, port, user, password): self.host = host self.port = port self.user = user self.password = password @staticmethod def get_passwrod(salt, password): m = hashlib.md5(salt.encode('utf-8')) # 加鹽處理 m.update(password.encode('utf-8')) return m.hexdigest() hash_password = Operate_database.get_passwrod('lala', '123456') # 通過類來調(diào)用 print(hash_password) # f7a1cc409ed6f51058c2b4a94a7e1956 p = Operate_database('192.168.0.5', '3306', 'abc', '123456') hash_password = p.get_passwrod(p.user, p.password) # 也可以通過對象調(diào)用 print(hash_password) # 0659c7992e268962384eb17fafe88364
九、類的專有方法:
- __init__ : 構(gòu)造函數(shù),在生成對象時調(diào)用
- __del__ : 析構(gòu)函數(shù),釋放對象時使用
- __repr__ : 打印,轉(zhuǎn)換
- __setitem__ : 按照索引賦值
- __getitem__: 按照索引獲取值
- __len__: 獲得長度
- __cmp__: 比較運(yùn)算
- __call__: 函數(shù)調(diào)用
- __name__:模塊名稱,一段程序作為主線運(yùn)行程序時其內(nèi)置名稱就是 __main__
運(yùn)算符重載
- __add__: 加運(yùn)算
- __sub__: 減運(yùn)算
- __mul__: 乘運(yùn)算
- __truediv__: 除運(yùn)算
- __mod__: 求余運(yùn)算
- __pow__: 乘方
對類的專有方法進(jìn)行重載實(shí)例如下:
class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2,10) v2 = Vector(5,-2) print (v1 + v2) #Vector(7,8)
到此這篇關(guān)于Python面向?qū)ο缶幊痰奈恼戮徒榻B到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python實(shí)現(xiàn)解析yaml配置文件的示例詳解
在開發(fā)過程中,配置文件是少不了的,而且配置文件是有專門的格式的,比如:ini,yaml,toml等等。本文帶大家來看看Python如何解析yaml文件,它的表達(dá)能力相比?ini?更加的強(qiáng)大,需要的可以參考一下2022-09-09Python 中對 XML 文件的編碼轉(zhuǎn)換問題
這篇文章主要介紹了Python 中對 XML 文件的編碼轉(zhuǎn)換問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03詳解Python編程中基本的數(shù)學(xué)計(jì)算使用
這篇文章主要介紹了Python編程中基本的數(shù)學(xué)計(jì)算使用,其中重點(diǎn)講了除法運(yùn)算及相關(guān)division模塊的使用,需要的朋友可以參考下2016-02-02基于asyncio 異步協(xié)程框架實(shí)現(xiàn)收集B站直播彈幕
本文給大家分享的是基于asyncio 異步協(xié)程框架實(shí)現(xiàn)收集B站直播彈幕收集系統(tǒng)的簡單設(shè)計(jì),并附上源碼,有需要的小伙伴可以參考下2016-09-09Windows下的Jupyter Notebook 安裝與自定義啟動(圖文詳解)
這篇文章主要介紹了Windows下的Jupyter Notebook 安裝與自定義啟動(圖文詳解),需要的朋友可以參考下2018-02-02詳解python的幾種標(biāo)準(zhǔn)輸出重定向方式
這篇文章是基于Python2.7版本,介紹常見的幾種標(biāo)準(zhǔn)輸出(stdout)重定向方式。顯然,這些方式也適用于標(biāo)準(zhǔn)錯誤重定向。學(xué)習(xí)python的小伙伴們可以參考借鑒。2016-08-08