Python面向對象之成員相關知識總結
一、成員
1.1 變量
- 實例變量,屬于對象,每個對象中各自維護自己的數(shù)據(jù)。
- 類變量,屬于類,可以被所有對象共享,一般用于給對象提供公共數(shù)據(jù)(類似于全局變量)。
class Person(object): country = "中國" def __init__(self, name, age): self.name = name self.age = age def show(self): # message = "{}-{}-{}".format(Person.country, self.name, self.age) message = "{}-{}-{}".format(self.country, self.name, self.age) print(message) print(Person.country) # 中國 p1 = Person("華青水上",20) print(p1.name) print(p1.age) print(p1.country) # 中國 p1.show() # 中國-華青水上-20
提示:當把每個對象中都存在的相同的示例變量時,可以選擇把它放在類變量中,這樣就可以避免對象中維護多個相同數(shù)據(jù)。
易錯點
- 注意讀和寫的區(qū)別。
class Person(object): country = "中國" def __init__(self, name, age): self.name = name self.age = age def show(self): message = "{}-{}-{}".format(self.country, self.name, self.age) print(message) print(Person.country) # 中國 p1 = Person("華青水上",20) print(p1.name) # 華青水上 print(p1.age) # 20 print(p1.country) # 中國 p1.show() # 中國-華青水上-20 p1.name = "root" # 在對象p1中講name重置為root p1.num = 19 # 在對象p1中新增實例變量 num=19 p1.country = "china" # 在對象p1中新增實例變量 country="china" print(p1.country) # china print(Person.country) # 中國
class Person(object): country = "中國" def __init__(self, name, age): self.name = name self.age = age def show(self): message = "{}-{}-{}".format(self.country, self.name, self.age) print(message) print(Person.country) # 中國 Person.country = "美國" p1 = Person("華青水上",20) print(p1.name) # 華青水上 print(p1.age) # 20 print(p1.country) # 美國
- 繼承關系中的讀寫
class Base(object): country = "中國" class Person(Base): def __init__(self, name, age): self.name = name self.age = age def show(self): message = "{}-{}-{}".format(Person.country, self.name, self.age) # message = "{}-{}-{}".format(self.country, self.name, self.age) print(message) # 讀 print(Base.country) # 中國 print(Person.country) # 中國 obj = Person("華青水上",19) print(obj.country) # 中國 # 寫 Base.country = "china" Person.country = "泰國" obj.country = "日本"
1.2 方法
- 綁定方法,默認有一個self參數(shù),由對象進行調(diào)用(此時self就等于調(diào)用方法的這個對象)【對象&類均可調(diào)用】
- 類方法,默認有一個cls參數(shù),用類或對象都可以調(diào)用(此時cls就等于調(diào)用方法的這個類)【對象&類均可調(diào)用】
- 靜態(tài)方法,無默認參數(shù),用類和對象都可以調(diào)用。【對象&類均可調(diào)用】
class Foo(object): def __init__(self, name,age): self.name = name self.age = age def f1(self): print("綁定方法", self.name) @classmethod def f2(cls): print("類方法", cls) @staticmethod def f3(): print("靜態(tài)方法") # 綁定方法(對象) obj = Foo("武沛齊",20) obj.f1() # Foo.f1(obj) # 類方法 Foo.f2() # cls就是當前調(diào)用這個方法的類。(類) obj.f2() # cls就是當前調(diào)用這個方法的對象的類。 # 靜態(tài)方法 Foo.f3() # 類執(zhí)行執(zhí)行方法(類) obj.f3() # 對象執(zhí)行執(zhí)行方法
在Python中比較靈活,方法都可以通過對象和類進行調(diào)用;而在java、c#等語言中,綁定方法只能由對象調(diào)用;類方法或靜態(tài)方法只能由類調(diào)用。
import os import requests class Download(object): def __init__(self, folder_path): self.folder_path = folder_path @staticmethod def download_dou_yin(): # 下載抖音 res = requests.get('.....') with open("xxx.mp4", mode='wb') as f: f.write(res.content) def download_dou_yin_2(self): # 下載抖音 res = requests.get('.....') path = os.path.join(self.folder_path, 'xxx.mp4') with open(path, mode='wb') as f: f.write(res.content) obj = Download("video") obj.download_dou_yin()
1.3 屬性
屬性其實是由綁定方法 + 特殊裝飾器 組合創(chuàng)造出來的,讓我們以后在調(diào)用方法時可以不加括號。
class Foo(object): def __init__(self, name): self.name = name def f1(self): return 123 @property def f2(self): return 123 obj = Foo("華青水上") v1 = obj.f1() print(v1) v2 = obj.f2 print(v2)
class Pagination: def __init__(self, current_page, per_page_num=10): self.per_page_num = per_page_num if not current_page.isdecimal(): self.current_page = 1 return current_page = int(current_page) if current_page < 1: self.current_page = 1 return self.current_page = current_page def start(self): return (self.current_page - 1) * self.per_page_num def end(self): return self.current_page * self.per_page_num user_list = ["用戶-{}".format(i) for i in range(1, 3000)] # 分頁顯示,每頁顯示10條 while True: page = input("請輸入頁碼:") # page,當前訪問的頁碼 # 10,每頁顯示10條數(shù)據(jù) # 內(nèi)部執(zhí)行Pagination類的init方法。 pg_object = Pagination(page, 20) page_data_list = user_list[ pg_object.start() : pg_object.end() ] for item in page_data_list: print(item)
class Pagination: def __init__(self, current_page, per_page_num=10): self.per_page_num = per_page_num if not current_page.isdecimal(): self.current_page = 1 return current_page = int(current_page) if current_page < 1: self.current_page = 1 return self.current_page = current_page @property def start(self): return (self.current_page - 1) * self.per_page_num @property def end(self): return self.current_page * self.per_page_num user_list = ["用戶-{}".format(i) for i in range(1, 3000)] # 分頁顯示,每頁顯示10條 while True: page = input("請輸入頁碼:") pg_object = Pagination(page, 20) page_data_list = user_list[ pg_object.start : pg_object.end ] for item in page_data_list: print(item)
關于屬性的編寫有兩種方式:
- 方式一,基于裝飾器
class C(object): @property def x(self): pass @x.setter def x(self, value): pass @x.deleter def x(self): pass obj = C() obj.x obj.x = 123 del obj.x
- 方式二,基于定義變量
class C(object): def getx(self): pass def setx(self, value): pass def delx(self): pass x = property(getx, setx, delx, "I'm the 'x' property.") obj = C() obj.x obj.x = 123 del obj.x
注意:由于屬性和實例變量的調(diào)用方式相同,所以在編寫時需要注意:屬性名稱 不要 實例變量 重名。
class Foo(object): def __init__(self, name, age): self.name = name self.age = age @property def func(self): return 123 obj = Foo("華青水上", 123) print(obj.name)
一旦重名,可能就會有報錯。
class Foo(object): def __init__(self, name, age): self.name = name # 報錯,錯認為你想要調(diào)用 @name.setter 裝飾的方法。 self.age = age @property def name(self): return "{}-{}".format(self.name, self.age) obj = Foo("華青水上", 123)
class Foo(object): def __init__(self, name, age): self.name = name self.age = age @property def name(self): return "{}-{}".format(self.name, self.age) # 報錯,循環(huán)調(diào)用自己(直到層級太深報錯) @name.setter def name(self, value): print(value) obj = Foo("華青水上", 123) print(obj.name)
如果真的想要在名稱上創(chuàng)建一些關系,可以讓實例變量加上一個下劃線。
class Foo(object): def __init__(self, name, age): self._name = name self.age = age @property def name(self): return "{}-{}".format(self._name, self.age) obj = Foo("華青水上", 123) print(obj._name) print(obj.name)
二、成員修飾符
Python中成員的修飾符就是指的是:公有、私有。
- 公有,在任何地方都可以調(diào)用這個成員。
- 私有,只有在類的內(nèi)部才可以調(diào)用改成員(成員是以兩個下劃線開頭,則表示該成員為私有)。
class Foo(object): def __init__(self, name, age): self.__name = name self.age = age def get_data(self): return self.__name def get_age(self): return self.age obj = Foo("華青水上", 123) # 公有成員 print(obj.age) v1 = self.get_age() print(v1) # 私有成員 # print(obj.__name) # 錯誤,由于是私有成員,只能在類中進行使用。 v2 = obj.get_data() print(v2)
特別提醒:父類中的私有成員,子類無法繼承。
class Base(object): def __data(self): print("base.__data") def num(self): print("base.num") class Foo(Base): def func(self): self.num() self.__data() # # 不允許執(zhí)行父類中的私有方法 obj = Foo() obj.func()
class Base(object): def __data(self): print("base.__data") def num(self): print("base.num") self.__data() # 不允許執(zhí)行父類中的私有方法 class Foo(Base): def func(self): self.num() obj = Foo() obj.func()
按理說私有成員是無法被外部調(diào)用,但如果用一些特殊的語法也可以(Flask源碼中有這種寫法,大家寫代碼不推薦這樣寫)。
class Foo(object): def __init__(self): self.__num = 123 self.age = 19 def __msg(self): print(1234) obj = Foo() print(obj.age) print(obj._Foo__num) obj._Foo__msg()
成員是否可以作為獨立的功能暴露給外部,讓外部調(diào)用并使用。
- 可以,公有。
- 不可以,內(nèi)部其他放的一個輔助,私有。
三、對象嵌套
在基于面向對象進行編程時,對象之間可以存在各種各樣的關系,例如:組合、關聯(lián)、依賴等(Java中的稱呼),用大白話來說就是各種嵌套。
情景一:
class Student(object): """ 學生類 """ def __init__(self, name, age): self.name = name self.age = age def message(self): data = "我是一名學生,我叫:{},我今年{}歲".format(self.name, self.age) print(data) s1 = Student("華青水上", 19) s2 = Student("殊途同歸", 19) s3 = Student("春花秋月", 19) class Classes(object): """ 班級類 """ def __init__(self, title): self.title = title self.student_list = [] def add_student(self, stu_object): self.student_list.append(stu_object) def add_students(self, stu_object_list): for stu in stu_object_list: self.add_student(stu) def show_members(self): for item in self.student_list: # print(item) item.message() c1 = Classes("三年二班") c1.add_student(s1) c1.add_students([s2, s3]) print(c1.title) print(c1.student_list)
情景二:
class Student(object): """ 學生類 """ def __init__(self, name, age, class_object): self.name = name self.age = age self.class_object = class_object def message(self): data = "我是一名{}班的學生,我叫:{},我今年{}歲".format(self.class_object.title, self.name, self.age) print(data) class Classes(object): """ 班級類 """ def __init__(self, title): self.title = title c1 = Classes("Python全棧") c2 = Classes("Linux云計算") user_object_list = [ Student("華青水上", 19, c1), Student("殊途同歸", 19, c1), Student("春花秋月", 19, c2) ] for obj in user_object_list: print(obj.name,obj.age, obj.class_object.title)
情景三:
class Student(object): """ 學生類 """ def __init__(self, name, age, class_object): self.name = name self.age = age self.class_object = class_object def message(self): data = "我是一名{}班的學生,我叫:{},我今年{}歲".format(self.class_object.title, self.name, self.age) print(data) class Classes(object): """ 班級類 """ def __init__(self, title, school_object): self.title = title self.school_object = school_object class School(object): """ 學校類 """ def __init__(self, name): self.name = name s1 = School("北京校區(qū)") s2 = School("上海校區(qū)") c1 = Classes("Python全棧", s1) c2 = Classes("Linux云計算", s2) user_object_list = [ Student("華青水上", 19, c1), Student("殊途同歸", 19, c1), Student("春花秋月", 19, c2) ] for obj in user_object_list: print(obj.name, obj.class_object.title , obj.class_object.school_object.name)
四、特殊成員
在Python的類中存在一些特殊的方法,這些方法都是 __方法__
格式,這種方法在內(nèi)部均有特殊的含義,接下來我們來講一些常見的特殊成員:
__init__
,初始化方法
class Foo(object): def __init__(self, name): self.name = name obj = Foo("華青水上")
__new__
,構造方法
class Foo(object): def __init__(self, name): print("第二步:初始化對象,在空對象中創(chuàng)建數(shù)據(jù)") self.name = name def __new__(cls, *args, **kwargs): print("第一步:先創(chuàng)建空對象并返回") return object.__new__(cls) obj = Foo("華青水上")
__call__
class Foo(object): def __call__(self, *args, **kwargs): print("執(zhí)行call方法") obj = Foo() obj()
__str__
class Foo(object): def __str__(self): return "哈哈哈哈" obj = Foo() data = str(obj) print(data)
__dict__
class Foo(object): def __init__(self, name, age): self.name = name self.age = age obj = Foo("華青水上",19) print(obj.__dict__)
__getitem__
、__setitem__
、__delitem__
class Foo(object): def __getitem__(self, item): pass def __setitem__(self, key, value): pass def __delitem__(self, key): pass obj = Foo("華青水上", 19) obj["x1"] obj['x2'] = 123 del obj['x3']
__enter__
、__exit__
class Foo(object): def __enter__(self): print("進入了") return 666 def __exit__(self, exc_type, exc_val, exc_tb): print("出去了") obj = Foo() with obj as data: print(data)
# 面試題(補充代碼,實現(xiàn)如下功能)
class Context: def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): pass def do_something(self): # __enter__返回self才可以調(diào)用執(zhí)行do_something方法 pass with Context() as ctx: ctx.do_something()
上述面試題屬于上下文管理的語法。
__add__
等
class Foo(object): def __init__(self, name): self.name = name def __add__(self, other): return "{}-{}".format(self.name, other.name) v1 = Foo("alex") v2 = Foo("sb") # 對象+值,內(nèi)部會去執(zhí)行 對象.__add__方法,并將+后面的值當做參數(shù)傳遞過去。 v3 = v1 + v2 print(v3)
__iter__
迭代器
# 迭代器類型的定義: 1.當類中定義了 __iter__ 和 __next__ 兩個方法。 2.__iter__ 方法需要返回對象本身,即:self 3. __next__ 方法,返回下一個數(shù)據(jù),如果沒有數(shù)據(jù)了,則需要拋出一個StopIteration的異常。 官方文檔:https://docs.python.org/3/library/stdtypes.html#iterator-types # 創(chuàng)建 迭代器類型 : class IT(object): def __init__(self): self.counter = 0 def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == 3: raise StopIteration() return self.counter # 根據(jù)類實例化創(chuàng)建一個迭代器對象: obj1 = IT() # v1 = obj1.__next__() # v2 = obj1.__next__() # v3 = obj1.__next__() # 拋出異常 v1 = next(obj1) # obj1.__next__() print(v1) v2 = next(obj1) print(v2) v3 = next(obj1) print(v3) obj2 = IT() for item in obj2: # 首先會執(zhí)行迭代器對象的__iter__方法并獲取返回值,一直去反復的執(zhí)行 next(對象) print(item)
迭代器對象支持通過next取值,如果取值結束則自動拋出StopIteration。
for循環(huán)內(nèi)部在循環(huán)時,先執(zhí)行__iter__方法,獲取一個迭代器對象,然后不斷執(zhí)行的next取值(有異常StopIteration則終止循環(huán))。
生成器
# 創(chuàng)建生成器函數(shù) def func(): yield 1 yield 2 # 創(chuàng)建生成器對象(內(nèi)部是根據(jù)生成器類generator創(chuàng)建的對象),生成器類的內(nèi)部也聲明了:__iter__、__next__ 方法。 obj1 = func() v1 = next(obj1) print(v1) v2 = next(obj1) print(v2) v3 = next(obj1) print(v3) obj2 = func() for item in obj2: print(item)
如果按照迭代器的規(guī)定來看,其實生成器類也是一種特殊的迭代器類(生成器也是一個中特殊的迭代器)。
可迭代對象
# 如果一個類中有__iter__方法且返回一個迭代器對象 ;則我們稱以這個類創(chuàng)建的對象為可迭代對象。 class Foo(object): def __iter__(self): return 迭代器對象(生成器對象) obj = Foo() # obj是 可迭代對象。 # 可迭代對象是可以使用for來進行循環(huán),在循環(huán)的內(nèi)部其實是先執(zhí)行 __iter__ 方法,獲取其迭代器對象,然后再在內(nèi)部執(zhí)行這個迭代器對象的next功能,逐步取值。 for item in obj: pass
可迭代對象是可以使用for來進行循環(huán),在循環(huán)的內(nèi)部其實是先執(zhí)行 __iter__ 方法,獲取其迭代器對象,然后再在內(nèi)部執(zhí)行這個迭代器對象的next功能,逐步取值。
class IT(object): def __init__(self): self.counter = 0 def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == 3: raise StopIteration() return self.counter class Foo(object): def __iter__(self): return IT() obj = Foo() # 可迭代對象 for item in obj: # 循環(huán)可迭代對象時,內(nèi)部先執(zhí)行obj.__iter__并獲取迭代器對象;不斷地執(zhí)行迭代器對象的next方法。 print(item)
# 基于可迭代對象&迭代器實現(xiàn):自定義range class IterRange(object): def __init__(self, num): self.num = num self.counter = -1 def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == self.num: raise StopIteration() return self.counter class Xrange(object): def __init__(self, max_num): self.max_num = max_num def __iter__(self): return IterRange(self.max_num) obj = Xrange(100) for item in obj: print(item)
class Foo(object): def __iter__(self): yield 1 yield 2 obj = Foo() for item in obj: print(item)
# 基于可迭代對象&生成器 實現(xiàn):自定義range class Xrange(object): def __init__(self, max_num): self.max_num = max_num def __iter__(self): counter = 0 while counter < self.max_num: yield counter counter += 1 obj = Xrange(100) for item in obj: print(item)
常見的數(shù)據(jù)類型:
from collections.abc import Iterator, Iterable v1 = [11, 22, 33] print( isinstance(v1, Iterator) ) # false,判斷是否是迭代器;判斷依據(jù)是__iter__ 和 __next__。 v2 = v1.__iter__() print( isinstance(v2, Iterator) ) # True v1 = [11, 22, 33] print( isinstance(v1, Iterable) ) # True,判斷依據(jù)是是否有 __iter__且返回迭代器對象。 v2 = v1.__iter__() print( isinstance(v2, Iterable) ) # True,判斷依據(jù)是是否有 __iter__且返回迭代器對象。
至此,Python進階面向對象之成員總結完畢,如有不當之處歡迎指正。
到此這篇關于Python面向對象之成員相關知識總結的文章就介紹到這了,更多相關Python成員內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mac PyCharm添加Python解釋器及添加package路徑的方法
今天小編就為大家分享一篇mac PyCharm添加Python解釋器及添加package路徑的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10超詳細注釋之OpenCV Haar級聯(lián)檢測器進行面部檢測
這篇文章主要介紹了OpenCV Haar級聯(lián)檢測器進行面部檢測,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09解決pycharm啟動后總是不停的updating indices...indexing的問題
今天小編就為大家分享一篇解決pycharm啟動后總是不停的updating indices...indexing的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11