摘要:魔法方法類構(gòu)造方法魔法方法初始化對(duì)象創(chuàng)建對(duì)象的過程創(chuàng)建一個(gè)對(duì)象解釋器會(huì)自動(dòng)的調(diào)用方法返回創(chuàng)建的對(duì)象的引用,給實(shí)例實(shí)例化執(zhí)行該方法,返回值。當(dāng)引用計(jì)數(shù)為時(shí),該對(duì)象生命就結(jié)束了。
define class
class的三個(gè)組成部分:
類的名稱:類名
類的屬性: 一組數(shù)據(jù)
類的方法:允許對(duì)進(jìn)行操作的方法(行為)
定義
class Student (object): pass
class后面定義類名(類名通常是大寫開頭的單詞)
(object),表示該類是從哪個(gè)類繼承下來的
實(shí)例化
創(chuàng)建實(shí)例是通過類名+()實(shí)現(xiàn)
stu = Student()
class Stu (): # 定義class age = 10 # 屬性 def show (self): # 方法 print(self.age) # 類中獲取屬性 print(self, "self") print(stu.name) # 獲取類外添加屬性 stu = Stu() # 實(shí)例化 stu.name = "sf" # 添加屬性 stu.show() # 調(diào)用方法self
self當(dāng)前實(shí)例化的對(duì)象
在定義函數(shù)的時(shí)候,第一個(gè)參數(shù)需要self
class Stu (): def show_name (self): print(self.name) stu = Stu() stu.name = "sf" stu.show_name()
self在定義時(shí)需要定義,但是在調(diào)用時(shí)會(huì)自動(dòng)傳入。
self的名字并不是規(guī)定寫死的,但是最好還是按照約定是self。
self總是指調(diào)用時(shí)的類的實(shí)例。
init魔法方法:
["__class__", "__delattr__", "__dict__", "__dir__", "__doc__", "__eq__", "__format__", "__ge__", "__getattribute__", "__gt__", "__hash__", "__init__", "__init_subclass__", "__le__", "__lt__", "__module__", "__ne__", "__new__", "__reduce__", "__reduce_ex__", "__repr__", "__setattr__", "__sizeof__", "__str__", "__subclasshook__", "__weakref__"]
__init__: 類構(gòu)造方法(魔法方法)
class Stu (): # 初始化對(duì)象 def __init__ (self, new_name, new_age): self.name = new_name self.age = new_age def show (self): print("name: %s, age: %d" % (self.name, self.age)) stu = Stu("sf", 23) stu.show()
創(chuàng)建對(duì)象的過程:
創(chuàng)建一個(gè)對(duì)象
Python解釋器會(huì)自動(dòng)的調(diào)用__init__方法
返回創(chuàng)建的對(duì)象的引用,給實(shí)例
__str__: 實(shí)例化執(zhí)行該方法,返回值。
當(dāng)需要print一個(gè)類的時(shí)候,需要先在類中定義__str__方法,返回值,就是print()輸出的值
class Stu (): def __init__ (self, new_name): self.name = new_name def __str__ (self): return self.name
__new__: 方法主要是當(dāng)繼承一些不可變的class時(shí)(比如int, str, tuple), 提供一個(gè)自定義這些類的實(shí)例化過程.
class Stu(object): def __new__(cls): return object.__new__(cls) # 自定義實(shí)例化過程 # 自身沒有能力創(chuàng)建實(shí)例,可以讓父類創(chuàng)建 def __init__(self): print("init") stu = Stu()
創(chuàng)建單例對(duì)象
class Single(object): __instance = None def __new__(cls): if cls.__instance != None: return cls.__instance else: cls.__instance = object.__new__(cls) return cls.__instance s1 = Single() s2 = Single()私有方法和私有屬性
私有屬性
按照約定俗成的規(guī)定__開頭的屬性表示私有屬性, 不可以直接類名.變量名訪問
在類中存儲(chǔ)的形式為:_Stu__age, _類名__變量名
class Stu(): def __init__(self, new_name): self.name = new_name self.__age = 0 # 定義了一個(gè)私有的屬性,屬性的名字是`__age`
在類中訪問形式:self.__變量名
私有方法(private)
按照約定俗成的規(guī)定__開頭的屬性表示私有方法, 不可以直接類名.方法名訪問
存儲(chǔ)的形式為:_Stu__get_age, _類名__方法名
class Stu(): def __test(self): # 定義私有方法 pass
在類中調(diào)用私有方法:self.__方法名()
有些時(shí)候,會(huì)看到以一個(gè)下劃線開頭的實(shí)例變量名,比如_name,這樣的實(shí)例變量外部是可以訪問的,但是,按照約定俗成的規(guī)定,當(dāng)看到這樣的變量時(shí),意思就是,“雖然我可以被訪問,但是,請(qǐng)把我視為私有變量,不要隨意訪問”。
del
__del__: 當(dāng)刪除一個(gè)對(duì)象時(shí),python解釋器會(huì)默認(rèn)調(diào)用一個(gè)魔術(shù)方法,__del__()
class Stu(): def __del__ (self): print("remove obj") stu = Stu() del stu
在類的生命周期中,如果類銷毀了,python會(huì)自動(dòng)調(diào)用__del__方法。也就是說,不管是手動(dòng)調(diào)用del還是由python自動(dòng)回收都會(huì)觸發(fā)__del__方法執(zhí)行。
對(duì)象引用個(gè)數(shù)
模塊sys中有一個(gè)getrefcount方法可以測(cè)試對(duì)象的引用個(gè)數(shù)
返回的結(jié)果,會(huì)比實(shí)際結(jié)果大1.
import sys sys.getrefcount("變量/方法")繼承
class Animal(object): def run(self): print("Animal is running") class Dog(Animal): # 繼承 def run(self): print("Dog is running") class Cat(Animal): pass dog = Dog() cat = Cat() dog.run() cat.run()
當(dāng)子類和父類都存在相同的run()方法時(shí),子類的run()覆蓋了父類的run(),在代碼運(yùn)行的時(shí)候,總是會(huì)調(diào)用子類的run() -- 多態(tài)
重寫
重寫父類的方法,繼承之后,子類定義和父類方法名一樣的方法
class Animal(object): def run(self): print("Animal is running") class Dog(Animal): def run(self): # 重寫 print("Dog is running") class Cat(Animal): pass dog = Dog() cat = Cat() dog.run() cat.run()
調(diào)用父類方法
類名調(diào)用
super關(guān)鍵字調(diào)用
class Animal(): def run(self): print("Animal is running") class Dog (Animal): def say(self): # 第一種,類名調(diào)用。 # Animal.run(self) #方法必須傳遞參數(shù)`self` # 第二種,super關(guān)鍵字 super().run() print("Gog is running") dog = Dog() dog.say()
私有方法,私有屬性在繼承中的表現(xiàn):
私有方法并不會(huì)被繼承(子類外和子類內(nèi)都不會(huì)讓使用)
私有屬性并不會(huì)被繼承(子類外和子類內(nèi)都不會(huì)讓使用)
多繼承
子類具有多個(gè)父類
class A(object): # object是所有最終類的終點(diǎn) def test(self): print("A") class B: def test(self): print("B") class C(A, B): # 多繼承 (如果繼承類中方法名或者屬性名相同,生效的是參數(shù)先后順序,`類名.__mro__`中的順序) pass print(C.__mro__) # (多態(tài), , , ) # C3算法 c = C() # 子類也會(huì)重寫父類的方法
定義時(shí)的類型和運(yùn)行時(shí)的類型不一樣。
執(zhí)行的時(shí)候確定
class D(object): def _print(self): print("D") class X(D): def _print(self): print("X") def introduce(temp): temp._print() d = D() x = X() introduce(d) introduce(x)
isinstance()判斷一個(gè)對(duì)象是否是某種類型
實(shí)例屬性屬于各個(gè)實(shí)例所有,互不干擾;
類屬性屬于類所有,所有實(shí)例共享一個(gè)屬性;
不要對(duì)實(shí)例屬性和類屬性使用相同的名字,否則將產(chǎn)生難以發(fā)現(xiàn)的錯(cuò)誤。
類屬性 & 實(shí)例屬性
class A(): num = 1 # 類屬性 def __init(self): print(self.num) a = A() a.name = 100 # 實(shí)例屬性 print(A.num) # 獲取類屬性
實(shí)例方法 & 類方法 & 靜態(tài)方法
class A(): # 定義類方法 @classmethod def add_num(cls): # 保存類的引用 pass def get_num(self): # 實(shí)例方法 pass @staticmethod def set_num(): # 靜態(tài)方法 # 可以沒有任何參數(shù)引用 pass a = A() A.add_num() # 調(diào)用類方法 # a.add_num() # 實(shí)例調(diào)用類方法 A.set_num() # 調(diào)用靜態(tài)方法 a.set_num() # 實(shí)例調(diào)用靜態(tài)方法
私有化
xx: 公有變量
_x: 單前置下劃線,私有化屬性或方法,from somemodule import *禁止導(dǎo)入,類對(duì)象和子類可以訪問
__xx: 雙前置下劃線,避免與子類中的屬性名命名沖突,無法在外部直接訪問
__xx__: 雙前后下劃線,命名空間的魔法對(duì)象或?qū)傩浴?b>__init__。(開發(fā)時(shí),不要使用這種定義變量方式)
xx_: 單后置下劃線,用于避免與Python關(guān)鍵詞的沖突
property
作用:獲取與設(shè)置自動(dòng)調(diào)用方法
類屬性方式調(diào)用property:
class Money(object): def __init(self): pass def getMoney(self): pass def setMoney(self, value): pass money = property(getMoney, setMoney) # key 為調(diào)用時(shí)候的key m = Money() m.money = 10
裝飾器方式使用property:
class Money(object): def __init__(self): self.__num = 0 @property def money(self): # 函數(shù)名和調(diào)用key對(duì)應(yīng) # 獲取 return self.__money @money.setter def money(self, value): # 獲取 self.__num = value m = Money() print(m.money)垃圾回收
小整數(shù)對(duì)象池
作用:為了優(yōu)化速度,使用了小整數(shù)對(duì)象池,避免為整數(shù)頻繁申請(qǐng)和銷毀內(nèi)存空間。
Python對(duì)小整數(shù)的定義是[-5, 257)這些整數(shù)對(duì)象都是提前建立好的,不會(huì)被垃圾回收。在一個(gè)Python的程序中,所有位于這個(gè)范圍內(nèi)的整數(shù)使用的都是同一個(gè)對(duì)象。
單個(gè)字母也是這樣,但是定義2歌相同字符串時(shí),引用計(jì)數(shù)為0,觸發(fā)垃圾回收。
小整數(shù)[-5,257)共用對(duì)象,常駐內(nèi)存
單個(gè)字符共用對(duì)象,常駐內(nèi)存
大整數(shù)對(duì)象池
每一個(gè)大整數(shù),均創(chuàng)建一個(gè)新的對(duì)象。
大整數(shù)不共用內(nèi)存,引用計(jì)數(shù)為0,銷毀
數(shù)值類型和字符串類型在Python中都是不可變的,意味著無法修改這個(gè)對(duì)象的值,每次對(duì)變量對(duì)修改,實(shí)際上是創(chuàng)建一個(gè)新的對(duì)象
intern機(jī)制
a1 = "HelloWorld" a2 = "HelloWorld" a3 = "HelloWorld"
intern機(jī)制,讓它只占用一個(gè)”HelloWorld”所占的內(nèi)存空間???strong>引用計(jì)數(shù)去維護(hù)何時(shí)釋放。
單個(gè)單詞,不可修改,默認(rèn)開啟intern機(jī)制,共用對(duì)象,引用計(jì)數(shù)為0,則銷毀
字符串(含有空格),不可修改,沒開啟intern機(jī)制,不共用對(duì)象,引用計(jì)數(shù)為0,銷毀
Garbage collection(GC垃圾回收)
Python采用對(duì)是引用計(jì)數(shù)機(jī)制為主,標(biāo)記-清除和分代收集兩種機(jī)制為輔的策略
引用計(jì)數(shù)機(jī)制
Python里每一個(gè)東西都是對(duì)象,它們的核心就是一個(gè)結(jié)構(gòu)體: PyObject
typedef struct_object { int ob_refcnt; // 引用計(jì)數(shù) struct_typeobject *ob_type; } PyObject;
PyObject是每個(gè)對(duì)象必有的內(nèi)容,其中ob_refcnt就是作為引用計(jì)數(shù)。當(dāng)一個(gè)對(duì)象有新的引用時(shí),它的ob_refcnt就會(huì)增加,當(dāng)引用它的對(duì)象被刪除,它的ob_refcnt就會(huì)減少。
當(dāng)引用計(jì)數(shù)為0時(shí),該對(duì)象生命就結(jié)束了。
引用計(jì)數(shù)機(jī)制的優(yōu)點(diǎn):
簡單
實(shí)時(shí)性: 一旦沒有引用,內(nèi)存就直接釋放了。不用像其它機(jī)制等待特定實(shí)際。
處理回收內(nèi)存的時(shí)間分?jǐn)偟搅似綍r(shí)。
引用計(jì)數(shù)機(jī)制的缺點(diǎn):
維護(hù)引用計(jì)數(shù)消耗資源
循環(huán)引用
垃圾回收機(jī)制
Python中的垃圾回收是以引用計(jì)數(shù)為主,分代收集為輔
導(dǎo)致引用計(jì)數(shù)+1的情況
對(duì)象被創(chuàng)建,例如: a = 23
對(duì)象被引用,例如: b = a
對(duì)象被作為參數(shù),傳入到一個(gè)函數(shù)中,例如: func(a)
對(duì)象作為一個(gè)元素,存儲(chǔ)在容器中,例如: list1 = [a,a]
導(dǎo)致引用計(jì)數(shù)-1的情況
對(duì)象的別名被顯式銷毀,例如: del a
對(duì)象的別名被賦予新的對(duì)象,例如: a = 24
一個(gè)對(duì)象離開它的作用域,例如f函數(shù)執(zhí)行完畢時(shí),func函數(shù)中的局部變量(全局變量不會(huì))
對(duì)象所在的容器被銷毀,或從容器中刪除對(duì)象
查看一個(gè)對(duì)象的引用計(jì)數(shù)
import sys a = "hello world" sys.getrefcount(a)
可以查看a對(duì)象的引用計(jì)數(shù),但是比正常計(jì)數(shù)大1,因?yàn)檎{(diào)用函數(shù)的時(shí)候傳入a,這會(huì)讓a的引用計(jì)數(shù)+1
循環(huán)引用導(dǎo)致內(nèi)存泄露
引用計(jì)數(shù)的缺陷是循環(huán)引用的問題
import gc class ClassA(): def __init__(self): print("object born,id:%s"%str(hex(id(self)))) def f2(): while True: c1 = ClassA() c2 = ClassA() c1.t = c2 c2.t = c1 del c1 del c2 # 把python的gc關(guān)閉 gc.disable() f2()
執(zhí)行f2(),進(jìn)程占用的內(nèi)存會(huì)不斷增大。
創(chuàng)建了c1, c2后這兩塊內(nèi)存的引用計(jì)數(shù)都是1,執(zhí)行c1.t = c2和c2.t = c1后,這兩塊內(nèi)存的引用計(jì)數(shù)變成2.
在del c1后,內(nèi)存1的對(duì)象的引用計(jì)數(shù)變?yōu)?,由于不是為0,所以內(nèi)存1的對(duì)象不會(huì)被銷毀,所以內(nèi)存2的對(duì)象的引用數(shù)依然是2,在del c2后,應(yīng)用計(jì)數(shù)也是1,內(nèi)存1的對(duì)象,內(nèi)存2的對(duì)象的引用數(shù)都是1.
雖然他們兩個(gè)對(duì)象都是可以被銷毀的,但是由于循環(huán)引用,導(dǎo)致垃圾回收器不會(huì)回收它們,就導(dǎo)致內(nèi)存泄漏.
垃圾回收
垃圾回收 = 垃圾檢查 + 垃圾回收
有三種情況會(huì)觸發(fā)垃圾回收:
調(diào)用gc.coolect()
當(dāng)gc模塊的計(jì)數(shù)器達(dá)到閥值的時(shí)候
程序退出的時(shí)候
gc模塊
gc模塊作用:解決循環(huán)引用的問題
常用函數(shù):
gc.set_debug(flags)設(shè)置gc的debug日志。一般設(shè)置為gc.DEBUG_LEAK
gc.collect([generation]) 顯式進(jìn)行垃圾回收,可以輸入?yún)?shù),0表示只檢查第一代的對(duì)象,1代表檢查一,二代對(duì)象,2代表檢查一,二,三代的對(duì)象。如果不傳入?yún)?shù),執(zhí)行一個(gè)full collection,也就是等于2,返回不可達(dá)(unreachable objects)對(duì)象的數(shù)目
gc.get_threshold()獲取的gc模塊中自動(dòng)執(zhí)行垃圾回收的頻率
gc.set_threshold(threshold0[, threshold1[, threshold2])設(shè)置自動(dòng)執(zhí)行垃圾回收的頻率
gc.get_count()獲取當(dāng)前自動(dòng)執(zhí)行垃圾回收的計(jì)數(shù)器,返回一個(gè)長度為3的列表
Note:
gc模塊唯一處理不了的是循環(huán)引用的類都有__del__方法,項(xiàng)目中要避免定義__del__方法。
class ClassA(): pass # def __del__(self): # print("object born,id:%s"%str(hex(id(self))))
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41387.html
閱讀 5296·2021-09-22 15:50
閱讀 1880·2021-09-02 15:15
閱讀 1177·2019-08-29 12:49
閱讀 2553·2019-08-26 13:31
閱讀 3471·2019-08-26 12:09
閱讀 1220·2019-08-23 18:17
閱讀 2747·2019-08-23 17:56
閱讀 2937·2019-08-23 16:02