目錄python
類即類別、種類,是面向對象設計最重要的概念,對象是屬性與方法的結合體,而類則是一系列對象類似的屬性與方法的高度歸納.即類是把類似事物進行抽象,而對象的一個具體的實例.app
在Python裏面,任何都是類,str等類型也是一種類.ssh
在程序代碼裏面,咱們必須對事物進行建模,抽象出它的屬性(特徵,好比美醜等等)與方法(動做等動態行爲),而後才能創建一個類;有了一個類以後,咱們才能創建相關的對象,即實例函數
class Dog(object): ##經過class方法能夠建立一個類 def __init__(self, name, speice, master, age): ##賦予該類屬性 self.name = name self.speice = speice self.master = master self.age = age def dog_bark(self): ##賦予方法 print("%s正在汪汪汪....." %self.name) def eat_food(self): ##必須寫self這種形參,關聯類 print("%s正在吃飯"%self.name) dog_1 = Dog("旺財", "哈士奇", "Jack", 7) ##實例化一個對象出來 print(dog_1.name) dog_1.dog_bark() ##經過"."來調方法和屬性 旺財 旺財正在汪汪汪..... print(dog_1.__dict__) ##能夠打印出對象的屬性字典,另外類裏面並無方法,它須要到類裏面調用 print(Dog.__dict__) ##打印Dog類的屬性字典 {'name': '旺財', 'speice': '哈士奇', 'master': 'Jack', 'age': 7} {'__module__': '__main__', '__init__': <function Dog.__init__ at 0x0000027E895CCF28>, 'dog_bark': <function Dog.dog_bark at 0x0000027E895D6048>, 'eat_food': <function Dog.eat_food at 0x0000027E895D60D0>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None} dog_1.name = "二哈" print(dog_1.__dict__) ##能夠這樣修改屬性值,而若是在類裏面找不到就會向上找,但不會出類的範圍; ##"__dict__"方法是調出對象的屬性字典 {'name': '二哈', 'speice': '哈士奇', 'master': 'Jack', 'age': 7}
#python爲類內置的特殊屬性 類名.__name__# 類的名字(字符串) 類名.__doc__# 類的文檔字符串 類名.__base__# 類的第一個父類(在講繼承時會講) 類名.__bases__# 類全部父類構成的元組(在講繼承時會講) 類名.__dict__# 類的字典屬性 類名.__module__# 類定義所在的模塊 類名.__class__# 實例對應的類(僅新式類中) ###__init__方法 # 一、該方法內能夠有任意的python代碼 # 二、必定不能有返回值 ##當咱們創建對象時,就會觸發__init__方法
繼承是一種建立新類的方式,新類能夠繼承一種基類(父類),在Python裏面能夠繼承多個類;新建的類又叫作派生類或子類.在Python裏面class創建的類,也繼承於一個叫作「object」的基類.咱們可使用繼承來減小重用性,使得代碼量減小.工具
class Create(object): ##建立一個基類 def __init__(self, name, speice, age): self.name = name self.speice = speice self.age = age def eat_food(self): print("%s is eating!"%self.name) def sleep(self): print("%s is sleeping!"%self.name) class Dog(Create): ##經過這個方式,繼承基類 dog = Dog("二哈", "哈士奇", 5) dog.sleep() 二哈 is sleeping!
>>> SubClass1.__bases__ #__base__只查看從左到右繼承的第一個子類,__bases__則是查看全部繼承的父類 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
在python2中,沒有顯式的繼承object類的類,以及該類的子類,都是經典類;顯式地聲明繼承object的類,以及該類的子類,都是新式類
在python3中,不管是否繼承object,都默認繼承object,即python3中全部類均爲新式類this
然子類也能夠添加本身新的屬性或者在本身這裏從新定義這些屬性(不會影響到父類),須要注意的是,一旦從新定義了本身的屬性且與父類重名,那麼調用新增的屬性時,就以本身爲準了設計
class Create(object): def __init__(self, name, speice, age): self.name = name self.speice = speice self.age = age def eat_food(self): print("%s is eating!"%self.name) def sleep(self): print("%s is sleeping!"%self.name) class Dog(Create): def __init__(self, name, master, age): ##覆蓋了原來的 self.name = name self.master = master self.age = age def eat_food(self): print("%s的狗狗正在吃飯" %self.master) dog = Dog("金毛", "Hermaeus", 15) dog.eat_food() print(dog.master)
在一個類中以另一個類的對象做爲數據屬性,稱爲類的組合代理
class Hand(object): pass class Head(object): pass class Body(object): pass class People(object): def __init__(self): self.hand = Hand() ##即把其餘類導入進來 self.head = Head() self.body = Body()
接口指的是本身提供給使用者來調用本身功能的方式\方法\入口code
接口提取了一羣類共同的函數,能夠把接口當作一個函數的集合;而後讓子類去實現接口中的函數。orm
這麼作的意義在於歸一化,什麼叫歸一化,就是隻要是基於同一個接口實現的類,那麼全部的這些類產生的對象在使用時,從用法上來講都同樣。
歸一化的好處在於:
抽象類是一個特殊的類,它的特殊之處在於只能被繼承,不能被實例化
import abc ##調用該方法實現抽象類 class All_file(metaclass=abc.ABCMeta): @abc.abstractmethod def read(self): pass @abc.abstractmethod def write(self): pass class Disk(All_file): def read(self): print('disk read') def write(self): print('disk write') class Cdrom(All_file): def read(self): print('cdrom read') def write(self): print('cdrom write') class Mem(All_file): def read(self): print('mem read') def write(self): print('mem write') m1=Mem() m1.read() m1.write() mem read mem write
當類是經典類時會遵循深度優先;是新類是會遵循廣度優先
對於你定義的每個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的全部基類的線性順序列表
class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): pass print(F.__mro__)
那麼就會產生一個和下列同樣的MRO列表,查找的順序是按着從左到右實現的,而子類會先於父類被檢查;若是有多個父類會根據它們在列表中的順序被檢查;當存在兩個合法的選擇,選擇第一個父類
(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
class Create(object): def __init__(self, name, speice, age): self.name = name self.speice = speice self.age = age def eat_food(self): print("%s is eating!"%self.name) def sleep(self): print("%s is sleeping!"%self.name) class Dog(Create): def __init__(self, name, speice, age, master): Create.__init__(self, name, speice, age) ##直接經過名字引用,須要self參數 self.master = master def eat_food(self): print("%s的狗狗正在吃飯" %self.master) dog = Dog("二哈", "哈士奇", 18, "Hermaeus") dog.sleep()
class Create(object): def __init__(self, name, speice, age): self.name = name self.speice = speice self.age = age def eat_food(self): print("%s is eating!"%self.name) def sleep(self): print("%s is sleeping!"%self.name) class Dog(Create): def __init__(self, name, speice, age, master): super().__init__(name, speice, age) ##經過super()來調用,可是絕對不能有self self.master = master def eat_food(self): print("%s的狗狗正在吃飯" %self.master) dog = Dog("二哈", "哈士奇", 18, "Hermaeus") dog.sleep()
在面向對象方法中通常是這樣表述多態性:向不一樣的對象發送同一條消息,不一樣的對象在接收時會產生不一樣的行爲(即方法)。也就是說,每一個對象能夠用本身的方式去響應共同的消息。所謂消息,就是調用函數,不一樣的行爲就是指不一樣的實現,即執行不一樣的函數;分爲靜態多態和動態多態.
>>> class Cat(Animal): #屬於動物的另一種形態:貓 ... def talk(self): ... print('say miao') ... >>> def func(animal): #對於使用者來講,本身的代碼根本無需改動 ... animal.talk() ... >>> cat1=Cat() #實例出一隻貓 >>> func(cat1) #甚至連調用方式也無需改變,就能調用貓的talk功能 say miao
#其實這僅僅這是一種變形操做且僅僅只在類定義階段發生變形 #類中全部單下劃線開頭的名稱如_x在約定上被認爲是封裝,讓人們在使用的過程當中不要調用,可是實際上沒有任何用 class A: _N=0 #約定不要使用 def __init__(self): self._X=10 def _foo(self): print('from A') def bar(self): self._foo() #這種,在外部是能夠經過_x這個名字訪問到
#其實這僅僅這是一種變形操做且僅僅只在類定義階段發生變形 #類中全部雙下劃線開頭的名稱如__x都會在類定義時自動變造成:_類名__x的形式: class A: __N=0 #類的數據屬性就應該是共享的,可是語法上是能夠把類的數據屬性設置成私有的如__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() #只有在類內部才能夠經過__foo的形式訪問到. #A._A__N是能夠訪問到的, #這種,在外部是沒法經過__x這個名字訪問到
封裝的真諦在於明確地區份內外,封裝的屬性能夠直接在內部使用,而不能被外部直接使用,然而定義屬性的目的終歸是要用,外部要想用類隱藏的屬性,須要咱們爲其開闢接口,讓外部可以間接地用到咱們隱藏起來的屬性
封裝數據:將數據隱藏起來這不是目的.隱藏起來而後對外提供操做該數據的接口,而後咱們能夠在接口附加上對該數據操做的限制,以此完成對數據屬性操做的嚴格控制
封裝方法:目的是隔離複雜度,讓程序的一些細節不須要被使用者知道
在導入模塊的過程當中,from module import *時不能被導入,可是你from module import _private_module依然是能夠導入的
property是一種特殊的裝飾器,使用它時會執行一段功能(函數)而後返回值
class People: def __init__(self,name,weight,height): self.name=name self.weight=weight self.height=height @property def bmi(self): return self.weight / (self.height**2) p1=People('Hermaeus',60,1.7) print(p1.bmi)
將一個類的函數定義成特性之後,對象再去使用的時候obj.name,根本沒法察覺本身的name是執行了一個函數而後計算出來的,這種特性的使用方式遵循了統一訪問的原則
綁定到類的方法:用classmethod裝飾器裝飾的方法
爲類量身定製,自動將類看成第一個參數傳入(其實對象也可調用,但仍將類看成第一個參數傳入)
綁定到對象的方法:沒有被任何裝飾器裝飾的方法
爲對象量身定製,自動將對象看成第一個參數傳入(屬於類的函數,類能夠調用,可是必須按照函數的規則來,沒有自動傳值那麼一說)
class Room(object): tag=1 def __init__(self,name,owner,width,length,heigh): self.name=name self.owner=owner self.width=width self.length=length self.heigh=heigh @classmethod def tell_info(cls,x): print(cls) print('-->',cls.tag,x) Room.tell_info(10) <class '__main__.Room'> --> 1 10
不與類或對象綁定,類和對象均可以調用,可是沒有自動傳值那麼一說;就是一個普通工具而已
class Room(object): tag=1 def __init__(self,name,owner,width,length,heigh): self.name=name self.owner=owner self.width=width self.length=length self.heigh=heigh @staticmethod ##變成一個獨立的方法 def get_area(x, y): res = x*y print("Area is %s" %res) Room.get_area(2, 3) Area is 6
isinstance(obj,cls)判斷obj是不是類cls的對象
issubclass(sub,super)判斷sub類是不是super類的派生類
############ class Foo(object): pass obj = Foo() print(isinstance(obj, Foo)) ############ class Func(object): pass class Func1(Func): pass print(issubclass(Func1, Func)) True True
經過字符串的形式操做對象相關的屬性.Python中的一切事物都是對象(均可以使用反射)
class Dog(object): def __init__(self, name, master, species): self.name = name self.master = master self.species = species def dog_bark(self): print("%s is barking!" %self.name) def eat_food(self): print("%s is eating!" %self.name) dog = Dog("二哈", "Hermaeus", "哈士奇") #####hasattr(object, attr)######### ##判斷在對象裏是否有某屬性 print(hasattr(dog, "name")) True #####getattr(object, name, default=None)######### ##獲得對象裏的某屬性,若是沒有返回default print(getattr(dog, "name")) print(getattr(dog, "afjaljf", "沒有")) 二哈 沒有 #####getattrsetattr(x, y, v)######### ##設置屬性 setattr(dog, "hobby", "拆家") print(dog.__dict__) {'name': '二哈', 'master': 'Hermaeus', 'species': '哈士奇', 'hobby': '拆家'} #####delattr(x, y)######### ##刪除某屬性 delattr(dog, "name") print(dog.__dict__) {'master': 'Hermaeus', 'species': '哈士奇', 'hobby': '拆家'}
若是須要使用該方法的對象文件就是本身,那麼能夠調用sys模塊裏面的modules方法
import sys def func1(): print("From func1") def func2(): print("From func2") this_module = sys.modules[__name__] print(hasattr(this_module, "func1")) True
import importlib importlib.import_module("名字")
class Foo(object): x = 1 def __init__(self, y): self.y = y def __getattr__(self, item): print("From __getattr__") def __setattr__(self, key, value): print("From __getattr__") def __delattr__(self, item): print("From __delattr") ##__setattr__添加/修改屬性會觸發它的執行 ## 由於你重寫了__setattr__,凡是賦值操做都會觸發它的運行,那麼根本沒賦值,除非你直接操做屬性字典,不然永遠沒法賦值 ##self.__dict__[key] = value ===> 會把值直接添加到對象的屬性字典 ##__delattr__刪除屬性的時候會觸發 ##self.__dict__.pop(item) ===> 直接刪除對象字典裏的值 ##__getattr__只有在使用點調用屬性且屬性不存在的時候纔會觸發
經過繼承派生的手段,基於標準數據類型來定製咱們本身的數據類型,新增或者改寫方法
class List(list): def append(self,p_object): if isinstance(p_object, int): raise TypeError("不支持int類型") #raise方法能夠拋出錯誤 super().append(p_object) s1 = List(("a", 'b', 'c')) print(s1) s1.append(12) ##報錯 ………………………………………………………………………………………… raise TypeError("不支持int類型") TypeError: 不支持int類型
受權是包裝的一個特性, 包裝一個類型一般是對已存在的類型的一些定製,這種作法能夠新建,修改或刪除原有產品的功能.其它的則保持原樣。受權的過程,便是全部更新的功能都是由新類的某部分來處理,但已存在的功能就受權給對象的默認屬性.而實現受權的關鍵點就是覆蓋__getattr__方法
import time class HandleFile(object): def __init__(self, filename, mode, encoding = "UTF-8"): self.file = open(filename, mode) def write(self, context): t = time.strftime("%Y-%m-%d %T") self.file.write("%s %s" %(t, context)) def __getattr__(self, item): ##覆蓋了原來的方法,使得沒有的方法到open裏面找 return getattr(self.file, item) f1 = HandleFile("b.txt", "w") f1.write("Hello, World!") f1.close()
當__getattribute__與__getattr__同時存在,只會執行__getattrbute__,除非__getattribute__在執行過程當中拋出異常AttributeError
class Foo: def __init__(self,x): self.x=x def __getattr__(self, item): print('執行的是我') def __getattribute__(self, item): print('不論是否存在,我都會執行') raise AttributeError('哈哈') ##會執行一次__getattr__ f1=Foo(10) f1.x f1.xxxxxx
描述符本質就是一個新式類,在這個新式類中,至少實現了__get__(),__set__(),__delete__()中的一個,這也被稱爲描述符協議
__get__():調用一個屬性時,觸發
__set__():爲一個屬性賦值時,觸發
__delete__():採用del刪除屬性時,觸發
而其又被分爲:
數據描述符:至少實現了__get__()和__set__()
非數據描述符:沒有實現__set__()
class Str(object): def __get__(self): print("From __get__") def __set__(self, instance, value): print("From __set__") def __delete__(self, instance): print("From __delete__") class People(object): name = Str() ##在其餘類裏面被當作屬性時,纔有被調用,name被Str類代理了 def __init__(self, name): self.name = name p1 = People("qq") From __set__ ##觸發了Str類裏面的__set__
描述符自己應該定義成新式類,被代理的類也應該是新式類
必須把描述符定義成這個類的類屬性,不能爲定義到構造函數中
要嚴格遵循該優先級,優先級由高到底分別是
類屬性
數據描述符
實例屬性
非數據描述符
找不到的屬性觸發__getattr__()
一個靜態屬性property本質就是實現了get,set,delete三種方法
class Foo: @property def AAA(self): print('get的時候運行我啊') @AAA.setter def AAA(self,value): print('set的時候運行我啊') @AAA.deleter def AAA(self): print('delete的時候運行我啊') ##AAA=property(get_AAA,set_AAA,delete_AAA) #內置property三個參數與get,set,delete一一對應 #只有在屬性AAA定義property後才能定義AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA
__setitem__,__getitem__,__delitem__
class Foo(object): def __getitem__(self, key): print('__getitem__', key) def __setitem__(self, key, value): print('__setitem__', key, value) def __delitem__(self, key): print('__delitem__', key) obj = Foo() ##類字典的操做將觸發這些 result = obj['k1'] # 自動觸發執行 __getitem__ obj['k2'] = 'Hermaeus' # 自動觸發執行 __setitem__ del obj['k1'] # 自動觸發執行 __delitem__
str函數或者print函數--->obj.__str__()
repr或者交互式解釋器--->obj.__repr__()
若是__str__沒有被定義,那麼就會使用__repr__來代替輸出
注意:這倆方法的返回值必須是字符串,不然拋出異常
formated_time = { "YY":"{obj.year}-{obj.month}-{obj.date}", "MM":"{obj.year}/{obj.month}/{obj.date}", "DD": "{obj.year}:{obj.month}:{obj.date}" } class Time(object): def __init__(self, year, month, date): self.year = year self.month = month self.date = date def __str__(self): return "From __str__" def __repr__(self): return "From __repr__" def __format__(self, format_spec): if not format_spec or format_spec not in formated_time.keys(): format_spec = "DD" res_spec = formated_time[format_spec] return res_spec.format(obj = self) try_time = Time(2018, 5, 23) print(try_time) print(try_time.__format__("YY")) From __str__ 2018-5-23
__slots__是一個類變量,其中變量值能夠是列表,元祖,或者可迭代對象,也能夠是一個字符串(意味着全部實例只有一個數據屬性);使用點來訪問屬性本質就是在訪問類或者對象的__dict__屬性字典(類的字典是共享的,而每一個實例的是獨立的);字典會佔用大量內存,若是你有一個屬性不多的類,可是有不少實例,爲了節省內存可使用__slots__取代實例的__dict__
class Foo(object): __slots__ = ["name", "age"] f1 = Foo() f1.name = "Hermaeus" f1.age = 19 print(f1.__dir__()) print(f1.__slots__) ##對象裏面沒有了__dict__,只有了__slots__,這樣有利於減小內存負擔 ['__module__', '__slots__', 'age', 'name', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__init__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__'] ['name', 'age']
##有了__next__和__iter__,即是一個迭代器了 class func(object): def __init__(self, x): self.x = x def __iter__(self): return self def __next__(self): self.x += 1 return self.x test_func = func(2) print(test_func.__next__()) print(test_func.__next__()) print(test_func.__next__()) print(test_func.__next__())
class Fib(object): def __init__(self): self.a = 0 self.b = 1 def __iter__(self): return self def __next__(self): self.a , self.b = self.b , self.a + self.b return self.a f1 = Fib() print(f1.__next__()) print(f1.__next__()) print(f1.__next__())
class Func(object): """ The Infomation of Func""" pass print(Func.__doc__) ##獲取備註信息 from lib.aa import C obj = C() print obj.__module__ ##獲得是那個模塊裏的 print obj.__class__ ##獲得是那個類裏的 The Infomation of Func lib.aa 即:輸出模塊 lib.aa.C 即:輸出類
析構方法,當對象在內存中被釋放時,自動觸發執行
class Foo(object): def __del__(self): print("Over") f1 = Foo() ##不過怎麼樣,只要一釋放內存,就會觸發__del__
」with open(文件) as f「,又叫作上下文管理協議,爲了讓一個對象能使用with語句,必須在對象的類裏面申明__enter和__exit__方法
class MyOpen(object): def __init__(self, filename, mode, encoding = "UTF-8"): self.filename = filename self.mode = mode self.encoding = encoding def __enter__(self): ##出現with,則觸發__enter__,有返回值就賦予給as申明瞭的變量 self.f = open(self.filename, self.mode, encoding = self.encoding) return self.f def __exit__(self, exc_type, exc_val, exc_tb): ##with執行完以後,觸發__exit__ self.f.close() ##exc_type ==>異常類型 exc_val ==>異常值 exc_tb ==>追溯信息 return True def __getattr__(self, item): ##避免找不到指定方法而觸發默認的__getattr__ return self, item with MyOpen("b.txt", "r") as f: print(f.read())
在對象後面加括號執行
class Foo(object): def __call__(self, *args, **kwargs): print("Come from __call__") f1 = Foo() ##不能直接Foo(),不會執行 f1() Come from __call__
在Python裏面一切皆對象,那麼類調用的類咱們就叫作元類,那麼默認的元類是type
class Foo(object): pass print(type(Foo))
能夠直接使用type創建新類
##type(name, bases, dict) -> a new type def __init__(self, name, age): self.name = name self.age = age Foo = type("Foo", (object,), {"x":11, "__init__":__init__}) f1 = Foo("Hermaeus", 19) print(f1.__dict__) {'name': 'Hermaeus', 'age': 19}
本身創建元類
class MyType(type): def __init__(cls, x, y, z): print("Runing....") def __call__(self, *args, **kwargs): obj = self.__new__(self) ##創建一個空的對象 self.__init__(obj, *args, **kwargs) ##從新使用type return obj class Foo(metaclass=MyType): ## "metaclass="指定元類 def __init__(self, name): self.name = name f1 = Foo("Hermaeus") print(f1.name) Runing.... Hermaeus