Python 對象學習一
阿新 • • 發佈:2018-03-10
ase 整體 func args result 變量 -方法 其他 pos
# 對象的基本理論 # 什麽是對象? # 萬物皆對象 # 對象是具體物體 # 擁有屬性 # 擁有行為 # 把很多零散的東西,封裝成為一個整體 # 舉例:王二小 # 屬性 # 姓名 # 年齡 # 身高 # 體重# 行為 # 走路 # 吃飯 # 放羊 # Python中的體現 # 是一門特別徹底的面向對象編程(OOP)的語言 # 其他語言:基本數據類型,對象類型 # python全部類型都是對象類型# 面向對象是面向過程的封裝 # 對象和類的關系:對象 可以抽象為類 類可以實例化為對象 class Money: pass print(Money) #<class ‘__main__.Money‘> one = Money() print(one, type(one)) #<__main__.Money object at 0x030CFBB0> <class ‘__main__.Money‘> class Person: pass # 對象的操作:增 p = Person() # 查看對象的所有屬性print(p.__dict__) #{} p.age = 18 p.height = 180 print(p.__dict__) #{‘age‘: 18, ‘height‘: 180} # 對象的操作:刪 del p.age # 對象的操作:改 p.height = 185 # 對象裏面如果有這個屬性,就是修改,否則就是增加這個屬性 # 類裏面的 __dict__ 不可以修改,只讀的 # 對象裏的 __dict__ 可以修改 class Test: age = 18 #Test.__dict__["age"] = 20 #TypeError: ‘mappingproxy‘ object does not support item assignment one = Test() one.__dict__ = {"name":"abc", "height":180} # __dict__字典裏面生存儲屬性的變量 print(one.__dict__) #{‘name‘: ‘abc‘, ‘height‘: 180} # 理解下面的內容 class Person: age = 10 p = Person() print(Person.age) # 10 print(p.age) # 10 p.age += 5 # p.age = p.age + 5 # 要理解這個在對象和類的操作方法:首先是計算右邊的值,p.age 在對象p中沒有,所以他要到類中去取age = 10 # 然後變成10+5 = 15, 然後在p對象中新增加個age屬性(以前說過,對象沒有就是新增,有的話就是修改) print(Person.age) # 10 print(p.age) # 15 # __slots__ class Person: __slots__ = {"age"} #只能加入age的屬性 p1 = Person() p1.age = 18 print(p1.age) # 方法:實例方法,類方法,靜態方法 class Person: def eat(self): print("這是個實例方法", self) @classmethod def eat2(cls): print("這是個類方法", cls) @staticmethod def eat3(): print("這是個靜態方法") p = Person() print(p) p.eat() p.eat2() p.eat3() # <__main__.Person object at 0x032F54F0> # 這是個實例方法 <__main__.Person object at 0x032F54F0> # 這是個類方法 <class ‘__main__.Person‘> # 這是個靜態方法 print("-" * 30) #另外的調用方式: Person.eat("123") #這裏必須要有個參數,才能調用成功 Person.eat2() Person.eat3() print("-" * 30) # 實例方法,類方法,靜態方法的訪問權限問題(包括類屬性,實例屬性) class Person: age = 10 # 實例方法 def shilie(self): print(self) print(self.age) print(self.num) # 類方法 @classmethod def leifangfa(cls): print(cls) print(cls.age) print(cls.num) # 不可以使用實例屬性 # 靜態方法 @staticmethod def jingtai(): print(Person.age) # 能使用類裏面的屬性,但很少這樣去調用的 p = Person() p.num = 11 p.shilie() # 實例方法:可以調用實例屬性和類屬性 #p.leifangfa() # 類方法:不可以使用實例屬性 p.jingtai() # 靜態方法:可以使用類屬性,不可以使用實例屬性 # 元類 num = 123 str = "abc" print(num.__class__.__class__) # <class ‘type‘> print(str.__class__.__class__) # <class ‘type‘> print(Person.__class__) # <class ‘type‘> print(Person.__class__.__class__)# <class ‘type‘> print(p.__class__.__class__) # <class ‘type‘> # ----------------------------另外一種創建類的方式------------------------- def run(self): print(self) dog = type("Dog",(),{"name":"abc","run":run}) #字典裏面可以是類屬性,或者類方法 print(dog.name) #abc print(dog.run) #<function run at 0x02B56C90> # ---------------------------類的創建流程---------------------------------- class Animal: # __metaclass__ = xxx pass class Person(Animal): # __metaclass__ = xxx pass # -------------------------類的描述, pydoc 模塊--------------------------------------- class Person: """ 關於類的描述,類的左右,類的構造函數 Attribute: 屬性的描述 """ def run(self, distence, step): """ 函數的作用 :param distence:參數含義,數據類型,默認值 :param step: :return: 返回值類型 """ return distence / step # help(Person) # 可以這樣看幫助文檔 # ------------------------ 私有化屬性(類的內部,子類內部,模塊內部,模塊外部)4大塊 ------- class Animal: x = 10 _y = 20 __z = 30 def test(self): print(Animal.x) print(self.x) print(Animal._y) print(self._y) print(Animal.__z) print(self.__z) print("-" * 30) class Dog(Animal): def test2(self): print(Dog.x) print(self.x) print(Dog._y) print(self._y) # print(Dog.__z) # 錯誤 # print(self.__z) # 錯誤 print("-" * 30) # 類的內部訪問 a = Animal() a.test() # 成功打印x # 子類的內部訪問 d = Dog() d.test2() # 成功打印x # 模塊內部訪問 # print(Animal.x) # 成功打印x # print(Dog.x) # 成功打印x # print(a.x) # 成功打印x # print(d.x) # 成功打印x # print(a.__z) # 有錯誤 # # print(Animal._y) # 成功打印_y,但有警告 # print(Dog._y) # 成功打印_y,但有警告 # print(a._y) # 成功打印_y,但有警告 # print(d._y) # 成功打印_y,但有警告 # print(a.__z) # 有錯誤 # print(d.__z) # 有錯誤 print(Animal.__dict__) print(Animal._Animal__z) # 偽私有 30 # 模塊外的訪問 import public print(public.num) # 成功打印num print(public._num2) # 另外一種模塊導入方法 from public import * # 直接寫public 模塊中的變量 print(num) # 成功打印num # print(_num2) # 有錯誤 # ------------------------ 私有化屬性應用場景 --------------------------------- # 數據保護,數據過濾 class Person: def __init__(self): self.__age = 18 def setAge(self, value): if isinstance(value, int) and 0 < value < 200 : self.__age = value else: print("you input data error!!!") def getAge(self): print("you age is ", self.__age) return self.__age p = Person() p.setAge(100) print(p.getAge()) # --------------- 私有化的2個規範--------------------- # 1. x_ 這樣命名的主要是區分系統的關鍵字,但又想用這個名字,所以在下面加下劃線,比如 int_, class_ # 2. __x__ 這種命名的主要是系統的內置命名功能的變量 # --------------- 只讀屬性------------------------- # __x 這樣在類中命名的變量,既不能在實例屬性中讀取和修改,除非通過間接的辦法來實現; # 比如在類中通過寫個函數來讀取類中的 __x 變量;如果現在來改寫一下只能讀取的方式; class Person: def __init__(self): self.__age = 18 @property def age(self): # 這樣就可以像正常通過實例屬性來訪問,但卻不能通過實例屬性來修改和增加 return self.__age p = Person() print(p.age) # 18 # p.age = 111 # AttributeError: can‘t set attribute # 上面的只讀屬性,也不是安全的,可以通過設置__dict__來修改 # p.__dict__["_Person__age"] = 999 p._Person__age = 888 print(p.age) # 888 # --------------新式類(python 3.xx,繼承object) 和 經典類(python 2.xxx 默認形式不繼承object) ---------- class Person: pass print(Person.__bases__) # (<class ‘object‘>,) 3.xx默認情況 # 也可以顯示的顯示如下,最好這樣寫,可以兼容2.xx: class Person(object): pass print(Person.__bases__) # (<class ‘object‘>,) # ------------- 設置只讀屬性的正確方法 --------------------------- class Person: # 需要只讀的key 列表 attr_key = ["age","name"] # 當我們通過:實例.key = value 操作的時候都會調用這個方法 __setattr__ # 在這個方法的內部,在會把key : value 這些值存儲到__dict__對象裏面 def __setattr__(self, key, value): print(key, value) if key in self.attr_key and key in self.__dict__.keys() : print("this is {} attrute only read ".format(key)) else: # self.key = value # 這樣寫會有問題,涉入死循環 self.__dict__[key] = value p = Person() p.age = 18 #執行到這裏,就會打印 age 18 print(p.age) # 18 print(p.__dict__) # {‘age‘: 18} p.age = 19 # 這裏賦值後就會提示上面的錯誤 this is age attrute only read # --------------------------內置特殊屬性---------------------- #類屬性 # __dict__ 類的屬性 # __bases__ 類的所有父類構成的屬性 # __doc__ 類的文檔字符串 # __name__ 類名 # __module__ 類定義中的模塊 # __str__ 類定義字符串 #__call__ 實例直接調用 p() #實例屬性 # __dict__ 實例屬性 # __class__ 實例屬性對應的類 class Person: def __call__(self, *args, **kwargs): print(args,kwargs) def __str__(self): return "這個是個人類的類(字符串)" def __repr__(self): return "這是個_repr_" p = Person() p() # 類中有了__call__,就可以這樣調用了,打印() {} p("123","abc", name="cctv") #(‘123‘, ‘abc‘) {‘name‘: ‘cctv‘} print(p.__str__()) #這個是個人類的類(字符串) print(p) #這個是個人類的類(字符串) print(p.__repr__()) #這是個_repr_ print(repr(p)) #這是個_repr_ # ------------------------ 索引操作 -------------------------------- class Person: def __init__(self): self.cache = {} def __setitem__(self, key, value): print(key, value) self.cache[key] = value def __getitem__(self, key): print(key) return self.cache[key] def __delitem__(self, key): print(key) del self.cache[key] p = Person() p["name"] = "abc" print(p["name"]) del p["name"] print(p.cache) #{} # --------------------- 比較操作 ----------------------------------- class Person: # == ,!= , >, >= , < , =< def __init__(self, age, height): self.age = age self.height = height def __eq__(self, other): # print(self.age, other.age) return self.age == other.age def __ne__(self, other): return self.age != other.age def __gt__(self, other): #大於 pass def __ge__(self, other): #大於等於 pass def __lt__(self, other): #小於 pass def __le__(self, other): #小於等於 pass p1 = Person(18, 180) p2 = Person(18, 190) print(p1 == p2) # True print(p1 != p2 ) # False # -------------------- 上下文的布爾判斷 ----------------------------- class Person: def __init__(self): self.age = 19 def __bool__(self): return self.age >= 18 p1 = Person() if (p1): print("p Ture") # p Ture # --------------------遍歷操作 -------------------------------------- class Person: def __init__(self): self.result = 0 # 和上面的索引操作一樣 def __getitem__(self, item): self.result += 1 if (self.result > 5 ): raise StopIteration("停止遍歷") return self.result # 這個要優先於__getitem__ 運行 def __iter__(self): self.result = 0 # 叠代器次重復使用 return self def __next__(self): self.result += 1 if (self.result > 5): raise StopIteration("next停止遍歷") return self.result p = Person() for v in p : print(v) # 1 2 3 4,5 # ----------------------- 描述器 --------------------------- # 方法一:舉例 class Person: def __int__(self): self.__age = 18 def get_age(self): return self.__age def set_age(self, value): if value < 0 : value = 0 self.__age = value def del_age(self): del self.__age # 方法一 age = property(get_age, set_age, del_age) p = Person() p.age = 10 # 一定要賦值,不然下面調用就會錯誤 print(p.age) class Person: def __int__(self): self.__age = 18 @property def age(self): return self.__age @age.setter def age(self, value): if value < 0: value = 0 self.__age = value @age.deleter def del_age(self): del self.__age p = Person() p.age = 20 # 一定要賦值,不然下面調用就會錯誤 print(p.age) # -------------------方法二------------------------ class Age: def __get__(self, instance, owner): print("get") return instance.v def __set__(self, instance, value): print("set") instance.v = value def __delete__(self, instance): print("delete") class Person: age = Age() p = Person() p.age = 10 print(p.age) # -------------------使用類,實現裝飾器 ----------------------- # 以前學過通過函數來實現裝飾器,如: def checkLogin(func): def inner(): print("正在登陸認證") func() return inner @checkLogin def fashuoshuo(): print("發說說") fashuoshuo() #正在登陸認證 發說說 # 現在換成類的形式 class Check: def __init__(self, func): self.f = func def __call__(self, *args, **kwargs): print("正在登陸認證") self.f() @Check def fatupian(): print("發圖片") fatupian() # 正在登陸認證 發圖片 # ---------- 幾個監聽對象生命周期的方法------------- class Person: # def __new__(cls, *args, **kwargs): # print("新建一個對象的時候, 但被我攔截了") def __init__(self): print("這個類被初始化了") def __del__(self): print("這個對象被釋放了") p = Person() # 新建一個對象的時候, 但被我攔截了 print(p) # None p = Person() #這裏要把 __new__ 給註釋掉,不然會被攔截 # ---------- 幾個監聽對象生命周期的方法:小案例------------- # Person, 打印一下,當前這個時刻,由Person類,產生的實例,有多少個 # 創建了一個實例,計數+1,如果刪除了一個實例 計數-1 class Person: __personCount = 0 def __init__(self): self.__class__.__personCount += 1 # 和下面的Person.__personCount 的方法是一樣的 def __del__(self): # Person.__personCount -= Person.__personCount - 1 有些問題 self.__class__.__personCount -= 1 @staticmethod def log(): # print("當前創建人的實例有{}個".format(Person.__personCount)) print("當前創建人的實例有%d個"%Person.__personCount) # 或者寫成下面的形式 @classmethod def log2(cls): print("當前創建人的實例有%d個" % cls.__personCount) p = Person() p2 = Person() Person.log() # 當前創建人的實例有2個 Person.log2() # 當前創建人的實例有2個 del p2 Person.log() # 當前創建人的實例有1個 Person.log2() # 當前創建人的實例有1個 # ----------------對象 內存管理機制 存儲 --------------------- num1 = 1 num2 = 1 print(id(num1), id(num2) ) #相同數值的變量地址一樣,訪問的是同一個地址,這是Python的機制決定的,優化訪問時間 class Person: pass p = Person() p2 = Person() print(id(p), id(p2)) # 打印地址不一樣 # ----------------引用計數器 --------------------- import sys # class Person: pass p1 = Person() # 獲得對象的引用次數 print(sys.getrefcount(p1)) # 2 p2 = p1 print(sys.getrefcount(p1)) # 3 print(sys.getrefcount(p2)) # 3 del p1 del p2 # ------------- 引用計數器機制-特殊場景--循環引用問題----------- # 內存管理機制:引用計數器機制 + 垃圾回收機制 # 當一個對象被引用時 +1, 刪除一個引用 -1 ,0:自動釋放 # objgraph # objgraph.count(), 可以查看,垃圾回收器,跟蹤的對象個數 import objgraph class Person: pass class Dog: pass p = Person() d = Dog() p.pet = d d.master = p print(objgraph.count("Person")) # 1 print(objgraph.count("Dog")) # 1 del p del d print(objgraph.count("Person")) # 1 這樣就造成了內存泄露 print(objgraph.count("Dog")) # 1 # --------------內存管理機制 垃圾回收 如何檢測循環引用 ----------- # --------------垃圾回收機制 分代回收 ------------ # --------------垃圾回收機制中 新增的對象個數 - 消亡的對象個數 達到一定個數才會觸發垃圾檢測 import gc #查看閥值,700個對象,10次 print(gc.get_threshold()) # (700, 10, 10) gc.set_threshold(200,5,5) # 設置參數 print(gc.get_threshold()) # (200, 5, 5) # --------------垃圾回收機制 觸發時機(自動,和手動) import gc # 自動回收 # 查看垃圾回收機制是否開啟,默認是開啟的 print(gc.isenabled()) # True # 達到一定的閥值才會執行 # 關閉垃圾回收機制 gc.disable() # 手動回收 import gc import objgraph class Person: pass class Dog: pass p = Person() d = Dog() p.pet = d d.master = p del p del d gc.disable() #關閉垃圾回收後,下面語句也有效果 # 通過“引用計數器機制”無法回收;需要借助“垃圾回收機制”進行回收 gc.collect() # 參數有:空,0,1,2 空代表全部代的回收,0,代表0代回收,2,代表0,1,2代都回收 # 查看 print(objgraph.count("Person")) # 0 print(objgraph.count("Dog")) # 0
Python 對象學習一