面向對象中的全部成員以下:html
經過面向對象進行編程時,會遇到不少種狀況,也會使用不一樣的成員來實現,接下來咱們來逐一介紹成員特性和應用場景。java
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("dean",20) print(p1.name) print(p1.age) print(p1.country) # 中國 p1.show() # 中國-dean-20
提示:當把每一個對象中都存在的相同的示例變量時,能夠選擇把它放在類變量中,這樣就能夠避免對象中維護多個相同數據。python
第一題:注意讀和寫的區別。面試
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("dean",20) print(p1.name) # dean print(p1.age) # 20 print(p1.country) # 中國 p1.show() # 中國-dean-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("dean",20) print(p1.name) # dean 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("dean",19) print(obj.country) # 中國 # 寫 Base.country = "china" Person.country = "泰國" obj.country = "日本"
面試題編程
class Parent(object): x = 1 class Child1(Parent): pass class Child2(Parent): pass print(Parent.x, Child1.x, Child2.x) # 1 1 1 Child1.x = 2 print(Parent.x, Child1.x, Child2.x) # 1 2 1 Parent.x = 3 print(Parent.x, Child1.x, Child2.x) # 3 2 3
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("靜態方法") # 綁定方法(對象) obj = Foo("dean",20) obj.f1() # Foo.f1(obj) # 類方法 Foo.f2() # cls就是當前調用這個方法的類。(類) obj.f2() # cls就是當前調用這個方法的對象的類。 # 靜態方法 Foo.f3() # 類執行執行方法(類) obj.f3() # 對象執行執行方法
在Python中比較靈活,方法均可以經過對象和類進行調用;而在java、c#等語言中,綁定方法只能由對象調用;類方法或靜態方法只能由類調用。c#
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()
屬性實際上是由綁定方法 + 特殊裝飾器 組合創造出來的,讓咱們之後在調用方法時能夠不加括號,例如:app
class Foo(object): def __init__(self, name): self.name = name def f1(self): return 123 @property def f2(self): return 123 obj = Foo("dean") v1 = obj.f1() print(v1) v2 = obj.f2 print(v2)
示例:以以前開發的分頁的功能。ide
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條數據 # 內部執行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
因爲屬性和實例變量的調用方式相同,因此在編寫時須要注意:屬性名稱 不要 實例變量 重名。
class Foo(object): def __init__(self, name, age): self.name = name self.age = age @property def func(self): return 123 obj = Foo("dean", 123) print(obj.name) print(obj.func)
一旦重名,可能就會有報錯。
class Foo(object): def __init__(self, name, age): self.name = name # 報錯,錯認爲你想要調用 @name.setter 裝飾的方法。 self.age = age @property def name(self): return "{}-{}".format(self.name, self.age) obj = Foo("dean", 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) # 報錯,循環調用本身(直到層級太深報錯) @name.setter def name(self, value): print(value) obj = Foo("dean", 123) print(obj.name)
若是真的想要在名稱上建立一些關係,可讓實例變量加上一個下劃線。
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("dean", 123) print(obj._name) print(obj.name)
Python中成員的修飾符就是指的是:公有、私有。
示例一:
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("dean", 123) # 公有成員 print(obj.age) v1 = self.get_age() print(v1) # 私有成員 # print(obj.__name) # 錯誤,因爲是私有成員,只能在類中進行使用。 v2 = obj.get_data() print(v2)
示例2:
class Foo(object): def get_age(self): print("公有的get_age") def __get_data(self): print("私有的__get_data方法") def proxy(self): print("公有的proxy") self.__get_data() obj = Foo() obj.get_age() obj.proxy()
示例3:
class Foo(object): @property def __name(self): print("公有的get_age") @property def proxy(self): print("公有的proxy") self.__name return 1 obj = Foo() v1 = obj.proxy print(v1)
特別提醒:父類中的私有成員,子類沒法繼承。
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() # # 不容許執行父類中的私有方法 obj = Foo() obj.func()
class Base(object): def __data(self): print("base.__data") def num(self): print("base.num") self.__data() # 不容許執行父類中的私有方法 class Foo(Base): def func(self): self.num() obj = Foo() obj.func()
按理說私有成員是沒法被外部調用,但若是用一些特殊的語法也能夠(不推薦這樣寫)
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()
成員是否能夠做爲獨立的功能暴露給外部,讓外部調用並使用。
在基於面向對象進行編程時,對象之間能夠存在各類各樣的關係,例如:組合、關聯、依賴等
下面咱們就用示例來學習常見的嵌套的情景:
情景一:
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("dean", 19) s2 = Student("sam", 19) s3 = Student("gabral", 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("dean", 19, c1), Student("sam", 19, c1), Student("gabral", 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("北京") s2 = School("上海") c1 = Classes("Python", s1) c2 = Classes("Linux", s2) user_object_list = [ Student("dean", 19, c1), Student("sam", 19, c1), Student("gabral", 19, c2) ] for obj in user_object_list: print(obj.name, obj.class_object.title , obj.class_object.school_object.name)
在Python的類中存在一些特殊的方法,這些方法都是 __方法__
格式,這種方法在內部均有特殊的含義,接下來咱們來說一些常見的特殊成員:
__init__
,初始化方法
class Foo(object): def __init__(self, name): self.name = name obj = Foo("dean")
__new__
,構造方法
class Foo(object): def __init__(self, name): print("第二步:初始化對象,在空對象中建立數據") self.name = name def __new__(cls, *args, **kwargs): print("第一步:先建立空對象並返回") return object.__new__(cls) obj = Foo("dean")
__call__
class Foo(object): def __call__(self, *args, **kwargs): print("執行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("dean",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("dean", 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)
超前知識:數據鏈接,每次對遠程的數據進行操做時候都必須經歷。 1.鏈接 = 鏈接數據庫 2.操做數據庫 3.關閉鏈接
class SqlHelper(object): def __enter__(self): self.鏈接 = 鏈接數據庫 return 鏈接 def __exit__(self, exc_type, exc_val, exc_tb): self.鏈接.關閉 with SqlHelper() as 鏈接: 鏈接.操做.. with SqlHelper() as 鏈接: 鏈接.操做...
# 面試題(補充代碼,實現以下功能) class Context: def do_something(self): print('內部執行') def __enter__(self): self.do_something() def __exit__(self): with Context() as ctx: print('內部執行') 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("sam") v2 = Foo("sb") # 對象+值,內部會去執行 對象.__add__方法,並將+後面的值當作參數傳遞過去。 v3 = v1 + v2 print(v3)
__iter__
迭代器
# 迭代器類型的定義: 1.當類中定義了 __iter__ 和 __next__ 兩個方法。 2.__iter__ 方法須要返回對象自己,即:self 3. __next__ 方法,返回下一個數據,若是沒有數據了,則須要拋出一個StopIteration的異常。 官方文檔:https://docs.python.org/3/library/stdtypes.html#iterator-types # 建立 迭代器類型 : 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 # 根據類實例化建立一個迭代器對象: 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: # 首先會執行迭代器對象的__iter__方法並獲取返回值,一直去反覆的執行 next(對象) print(item) 迭代器對象支持經過next取值,若是取值結束則自動拋出StopIteration。 for循環內部在循環時,先執行__iter__方法,獲取一個迭代器對象,而後不斷執行的next取值(有異常StopIteration則終止循環)。
生成器
# 建立生成器函數 def func(): yield 1 yield 2 # 建立生成器對象(內部是根據生成器類generator建立的對象),生成器類的內部也聲明瞭:__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) 若是按照迭代器的規定來看,其實生成器類也是一種特殊的迭代器類(生成器也是一箇中特殊的迭代器)。
可迭代對象
# 若是一個類中有__iter__方法且返回一個迭代器對象 ;則咱們稱以這個類建立的對象爲可迭代對象。 class Foo(object): def __iter__(self): return 迭代器對象(生成器對象) obj = Foo() # obj是 可迭代對象。 # 可迭代對象是可使用for來進行循環,在循環的內部實際上是先執行 __iter__ 方法,獲取其迭代器對象,而後再在內部執行這個迭代器對象的next功能,逐步取值。 for item in obj: pass
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: # 循環可迭代對象時,內部先執行obj.__iter__並獲取迭代器對象;不斷地執行迭代器對象的next方法。 print(item)
# 基於可迭代對象&迭代器實現:自定義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)
# 基於可迭代對象&生成器 實現:自定義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)
常見的數據類型:
v1 = list([11,22,33,44]) v1是一個可迭代對象,由於在列表中聲明瞭一個 __iter__ 方法而且返回一個迭代器對象。
from collections.abc import Iterator, Iterable v1 = [11, 22, 33] print( isinstance(v1, Iterator) ) # false,判斷是不是迭代器;判斷依據是__iter__ 和 __next__。 v2 = v1.__iter__() print( isinstance(v2, Iterator) ) # True v1 = [11, 22, 33] print( isinstance(v1, Iterable) ) # True,判斷依據是是否有 __iter__且返回迭代器對象。 v2 = v1.__iter__() print( isinstance(v2, Iterable) ) # True,判斷依據是是否有 __iter__且返回迭代器對象。