国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python基礎(chǔ)IV---類

2019-11-09 19:29:52
字體:
供稿:網(wǎng)友

這篇博客主要是閱讀python之旅 時(shí)做的筆記。提取出最主要的知識(shí)點(diǎn),供個(gè)人在以后中快速查閱。

類基本定義方式

屬性或方法名稱前面加上兩個(gè)下劃線,則外部無法訪問。如果是__xx__形式,則變量是特殊變量,就能拿直接訪問。。所有的類最終繼承自object類。class Animal(object): def __init__(self, name): self.name = name def greet(self): 獲取對(duì)象信息type(obj)isinstance(obj, type)hasattr(obj, attr)/getattr/setattrdir(obj)

繼承和多態(tài)

class Animal(object): def __init__(self, name): self.name = name def greet(self): print 'Hello, I am %s.' % self.nameclass Dog(Animal): def greet(self): #對(duì)父類的方法進(jìn)行重寫 print 'WangWang.., I am %s. ' % self.name def run(self): #添加新的方法 print 'I am running.I am running'>>> dog = Dog('dog')>>> dog.greet()WangWang.., I am dog.>>> dog.run()I am running

多態(tài):對(duì)不同類型的變量進(jìn)行相同的操作,它會(huì)根據(jù)對(duì)象(或類)類型的不同而表現(xiàn)出不同的行為。 直接看例子吧,因?yàn)樘唵瘟恕?/p>class Animal(object): def __init__(self, name): self.name = name def greet(self): print 'Hello, I am %s.' % self.nameclass Dog(Animal): def greet(self): print 'WangWang.., I am %s.' % self.nameclass Cat(Animal): def greet(self): print 'MiaoMiao.., I am %s' % self.namedef hello(animal): animal.greet()>>> dog = Dog('dog')>>> hello(dog)WangWang.., I am dog.>>>>>> cat = Cat('cat')>>> hello(cat)MiaoMiao.., I am cat

類方法和靜態(tài)方法

類方法使用 @classmethod 裝飾器,可以使用類(也可使用實(shí)例)來調(diào)用方法。靜態(tài)方法使用 @staticmethod 裝飾器,它是跟類有關(guān)系但在運(yùn)行時(shí)又不需要實(shí)例和類參與的方法,可以使用類和實(shí)例來調(diào)用。

類方法

class A(object): bar = 1 @classmethod def class_foo(cls): print 'Hello, ', cls print cls.bar>>> A.class_foo() # 直接通過類來調(diào)用方法Hello, <class '__main__.A'>1

注意:類方法可有類或者實(shí)例調(diào)用,不過定義該方法時(shí)要傳入cls參數(shù),該參數(shù)代表了類本身,通過cls可以調(diào)用類中的屬性和方法。

靜態(tài)方法

class A(object): bar = 1 @staticmethod def static_foo(): print 'Hello, ', A.bar>>> a = A()>>> a.static_foo()Hello, 1>>> A.static_foo()Hello, 1

靜態(tài)方法主要是運(yùn)行時(shí)不需要實(shí)例和類參與,不需要傳入任何參數(shù)。

定制類與特殊方法

在python中,經(jīng)常會(huì)看到前后兩個(gè)下劃線的方法。這些方法稱為魔法方法或者特殊方法。有特殊的功能,下面是常用的特殊方法:

__new____str__ , __repr____iter____getitem__, __setitem__, __delitem____getattr__, __setattr__, __delattr____call__

__new__ —— 自定義實(shí)例化

創(chuàng)建實(shí)例時(shí),調(diào)用__new__, 再 __init__對(duì)實(shí)例(self)進(jìn)行初始化 - __new__ 是在 __init__ 之前被調(diào)用的; - __new__ 是類方法,__init__ 是實(shí)例方法; - 重載 __new__ 方法,需要返回類的實(shí)例;

一般情況下,我們不需要重載 __new__ 方法。但在某些情況下,我們想控制實(shí)例的創(chuàng)建過程,這時(shí)可以通過重載 __new_ 方法來實(shí)現(xiàn)。

class A(object): _dict = dict() def __new__(cls): if 'key' in A._dict: print "EXISTS" return A._dict['key'] else: print "NEW" return object.__new__(cls) def __init__(self): print "INIT" A._dict['key'] = self

在上面,我們定義了一個(gè)類 A,并重載了 __new__ 方法:當(dāng) key 在 A._dict 中時(shí),直接返回 A._dict[‘key’],否則創(chuàng)建實(shí)例。

>>> a1 = A()NEWINIT>>> a2 = A()EXISTSINIT>>> a3 = A()EXISTSINIT

__str__ & __repr__ —— 讓對(duì)象輸出信息

簡單來說,就是如果直接print一個(gè)類的對(duì)象的話,就會(huì)得到類似 <__main__.Foo object at 0x10c37aa50> 。然而有時(shí)候我們就想顯示這個(gè)類的對(duì)象的信息,此時(shí)就可以用__str__, 該函數(shù)表示,當(dāng)print這個(gè)類的對(duì)象時(shí),所輸出該對(duì)象的信息。

class Foo(object): def __init__(self, name): self.name = name def __str__(self): return 'Foo object (name: %s)' % self.name>>> print Foo('ethan') # 使用 print, 顯示該對(duì)象的信息Foo object (name: ethan)>>>>>> str(Foo('ethan')) # 使用 str'Foo object (name: ethan)'>>>>>> Foo('ethan') # 直接顯示<__main__.Foo at 0x10c37a490>

你可能會(huì)說,哎呀, Foo(‘ethan’) 就沒法顯示這個(gè)對(duì)象的信息嗎?我看這<__main__.Foo at 0x10c37a490> 東西有啥用啊。__repr__就是讓 Foo(‘ethan’)也顯示類似加了print的效果。

class Foo(object): def __init__(self, name): self.name = name def __str__(self): return 'Foo object (name: %s)' % self.name __repr__ = __str__ #重載__repr__方法>>> Foo('ethan')'Foo object (name: ethan)'

__iter__ —— 讓對(duì)象成為迭代器

一句話:對(duì)象可用于 for … in 循環(huán),此時(shí)要定義 __iter__ 和 next (Python3中是 __next__方法)。__iter__ 返回一個(gè)迭代對(duì)象,__next__ 返回容器的下一個(gè)元素,在沒有后續(xù)元素時(shí)拋出 StopIteration 異常。

class Fib(object): def __init__(self): self.a, self.b = 0, 1 def __iter__(self): # 返回迭代器對(duì)象本身 return self def next(self): # 返回容器下一個(gè)元素 self.a, self.b = self.b, self.a + self.b return self.a >>> fib = Fib()>>> for i in fib:... if i > 10:... break... print i...112358

__getitem__ —— 將實(shí)例對(duì)象看成一項(xiàng)項(xiàng)取值

就是使用obj[n]的方式對(duì)實(shí)例對(duì)象取值

class Fib(object): def __getitem__(self, n): if isinstance(n, slice): # 如果 n 是 slice 對(duì)象 a, b = 1, 1 start, stop = n.start, n.stop L = [] for i in xrange(stop): if i >= start: L.append(a) a, b = b, a + b return L if isinstance(n, int): # 如果 n 是 int 型 a, b = 1, 1 for i in xrange(n): a, b = b, a + b return a>>> fib = Fib()>>> fib[0:3][1, 1, 2]>>> fib[2:6][2, 3, 5, 8]

getattr —— 對(duì)獲取不存在的屬性的行為進(jìn)行特殊處理

當(dāng)我們獲取對(duì)象的某個(gè)屬性,如果該屬性不存在,會(huì)拋出 AttributeError 異常,而__getattr__就能避免這個(gè)異常。

class Point(object): def __init__(self, x=0, y=0): self.x = x self.y = y def __getattr__(self, attr): if attr == 'z': return 0 raise AttributeError("Point object has no attribute %s" % attr)>>> p = Point(3, 4)>>> p.z #只有調(diào)用不存在的屬性時(shí),/__getattr__才會(huì)起作用0>>> p.w AttributeError: Point object has no attribute w

__call__ —— 讓實(shí)例直接調(diào)用方法

這個(gè)比較有意思。一般來說obj.method()來調(diào)用對(duì)象的方法。 能不能簡單點(diǎn)啊,直接obj()來啊。

class Point(object): def __init__(self, x, y): self.x, self.y = x, y def __call__(self, z): return self.x + self.y + z>>> p = Point(3, 4)>>> callable(p) # 使用 callable 判斷對(duì)象是否能被調(diào)用True>>> p(6) # 傳入?yún)?shù),對(duì)實(shí)例進(jìn)行調(diào)用,對(duì)應(yīng) p.__call__(6)13 # 3+4+6

__slots —— 限定實(shí)例允許綁定的屬性

是是是是,我們可以定義類的時(shí)候加上屬性和方法,但是有時(shí)候我們有了個(gè)實(shí)例,只想給這個(gè)實(shí)例加上一些新的屬性和方法。。(要求真多。。)當(dāng)然了,最簡單的方法直接弄就行。有時(shí)候我們也不希望別人亂加屬性。 slots:限定允許綁定的屬性

class Point(object): __slots__ = ('x', 'y') # 只允許使用 x 和 y屬性 def __init__(self, x=0, y=0): self.x = x self.y = y>>> p = Point(3, 4)>>> p.z = 5AttributeError: 'Point' object has no attribute 'z'

如果是下面的情況

class Point(object): __slots__ = ('x', 'y','z') def __init__(self, x=0, y=0): self.x = x self.y = yp = Point(3,4) p.z = 5 #此時(shí)可以添加屬性z了

一個(gè)注意點(diǎn):__slots__只能限定當(dāng)前類,不能限定子類。除非子類也定義了 slots,這樣,子類允許定義的屬性就是自身的 slots 加上父類的 slots。

@property ——設(shè)置屬性的發(fā)生自定義訪問

有些屬性我們希望對(duì)其訪問進(jìn)行限制,比如下面的score, 我們總不能讓別人隨便設(shè)置score的值吧。所以一般要定義兩個(gè)函數(shù),set_score和get_score分別表示對(duì)score的讀取和賦值進(jìn)行限定。 比如:

class Exam(object): def __init__(self, score): self._score = score def get_score(self): return self._score def set_score(self, val): if val < 0: self._score = 0 elif val > 100: self._score = 100 else: self._score = val>>> e = Exam(60)>>> e.get_score()60>>> e.set_score(70)>>> e.get_score()70

但你不感覺這樣寫很麻煩嗎?回顧一下C#中的。不是有set和get的訪問器嗎? 比如下面的通過函數(shù)Code的get和set進(jìn)行自定義限定code屬性。

class Student { private string code = "N.A"; // 聲明類型為 string 的 Code 屬性 public string Code { get { return code; } set { code = value; } } }

當(dāng)然啊,python也有類似的。不過感覺寫起來很繁瑣。。唉唉 注意:get屬性的話直接加上@property裝飾器就行,然而set屬性的話,就要加上類似@score.setter裝飾器。。當(dāng)然類似的,如果去掉 @score.setter裝飾器的話,score就變成只讀屬性了。還敢說這樣寫不麻煩。。。

class Exam(object): def __init__(self, score): self._score = score @property def score(self): return self._score @score.setter def score(self, val): if val < 0: self._score = 0 elif val > 100: self._score = 100 else: self._score = val>>> e = Exam(60)>>> e.score60>>> e.score = 90>>> e.score90>>> e.score = 200>>> e.score100

super —— 子類調(diào)用父類方法?

class Base(object): def __init__(self, a, b): self.a = a self.b = bclass A(Base): def __init__(self, a, b, c): super(A, self).__init__(a, b) # Python3 可使用 super().__init__(a, b) self.c = c

從上面可以看出。super貌似是直接在子類中調(diào)用父類的方法,從而減少勞動(dòng)。。 然而如果是下面這樣的繼承方式。。

class Base(object): def __init__(self): print "enter Base" print "leave Base"class A(Base): def __init__(self): print "enter A" super(A, self).__init__() print "leave A"class B(Base): def __init__(self): print "enter B" super(B, self).__init__() print "leave B"class C(A, B): def __init__(self): print "enter C" super(C, self).__init__() print "leave C"
Base / / / / A B / / / / C>>> c = C()enter Center Aenter Benter Baseleave Baseleave Bleave Aleave C

可以看到,進(jìn)入A之后,再調(diào)用super,并不是進(jìn)入Base,而是進(jìn)入了B。

MRO列表

事實(shí)上,對(duì)于你定義的每一個(gè)類,Python 會(huì)計(jì)算出一個(gè)方法解析順序(Method Resolution Order, MRO)列表,它代表了類繼承的順序。mro可以獲取類的MRO列表.

>>> C.mro() # or C.__mro__ or C().__class__.mro()[__main__.C, __main__.A, __main__.B, __main__.Base, object]

MRO列表的順序是根據(jù)C3線性化算法來定的。

super原理

def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1]

cls代表類,inst代表實(shí)例 - 獲取 inst 的 MRO 列表 - 查找 cls 在當(dāng)前 MRO 列表中的 index, 并返回它的下一個(gè)類,即 mro[index + 1]

所以super(C, self).__init__() 的解析方式不就是先C, 再A,再B,最后再Base了。

metaclass

這個(gè)還是直接看原文吧


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 揭东县| 镇坪县| 巴中市| 湖南省| 临漳县| 辽宁省| 佛坪县| 绥宁县| 张家口市| 广南县| 左权县| 新余市| 花莲县| 威远县| 南岸区| 通榆县| 舒城县| 汤阴县| 石首市| 威远县| 布拖县| 山东| 彰化市| 天镇县| 积石山| 双鸭山市| 哈巴河县| 大邑县| 纳雍县| 清镇市| 什邡市| 安岳县| 乌审旗| 荃湾区| 万安县| 连州市| 闽清县| 和田县| 崇信县| 栾城县| 昭觉县|