摘要:的魔術(shù)方法是中那些預(yù)定義的像類型的函數(shù)。使用的魔術(shù)方法的最大優(yōu)勢(shì)在于提供了簡(jiǎn)單的方法讓對(duì)象可以表現(xiàn)得像內(nèi)置類型一樣。廖雪峰老師教程里寫的是方法,不知道為啥。
Python的魔術(shù)方法是Python中那些預(yù)定義的像__XXX__類型的函數(shù)。
使用Python的魔術(shù)方法的最大優(yōu)勢(shì)在于python提供了簡(jiǎn)單的方法讓對(duì)象可以表現(xiàn)得像內(nèi)置類型一樣。
__str__函數(shù)用于處理打印實(shí)例本身的時(shí)候的輸出內(nèi)容。如果沒有覆寫該函數(shù),則默認(rèn)輸出一個(gè)對(duì)象名稱和內(nèi)存地址。
例如:
>>> class Student(object): ... def __init__(self,name): ... self._name = name ... >>> print Student()
輸出:<__main__.Student object at 0x0000000002A929E8>.
那么我們?nèi)绾巫屳敵龅慕Y(jié)果可讀性更高一點(diǎn)呢?我們可以覆寫__str__函數(shù)。例如
>>> class Student(object): ... def __init__(self, name): ... self._name = name ... def __str__(self): ... return "I"m a student, named %s" % self._name ... >>> print Student("Charlie")
輸出結(jié)果就是:I"m a student, named Charlie.
我們將str()函數(shù)作用于該對(duì)象的時(shí)候,其實(shí)是調(diào)用了該對(duì)象的__str__函數(shù)。
__repr__也是將對(duì)象序列化,但是__repr__更多的是給python編譯器看的。__str__更多的是可讀性(readable)。
我們將repr()函數(shù)作用于摸某一個(gè)對(duì)象的時(shí)候,調(diào)用的其實(shí)就是該函數(shù)的__repr__函數(shù)。
與repr()成對(duì)的是eval()函數(shù)。eval()函數(shù)是將序列化后的對(duì)象重新轉(zhuǎn)為對(duì)象。前提是該對(duì)象實(shí)現(xiàn)了__repr__函數(shù)。
上面這一段話基于自己的理解,不知道對(duì)錯(cuò)。
>>> item = [1,2,3] >>> repr(item) "[1, 2, 3]" >>> other_item = eval(repr(item)) >>> other_item[1] 2__iter__函數(shù)
我們經(jīng)常對(duì)list或者tuple使用for...in...來迭代。那是list繼承自Iterable。Iterable實(shí)現(xiàn)了__iter__函數(shù)。
要想將一個(gè)自定義的對(duì)象變成一個(gè)可迭代的對(duì)象,那么必須要實(shí)現(xiàn)兩個(gè)方法:__iter__和next.
__iter__函數(shù)返回一個(gè)對(duì)象。迭代的時(shí)候則會(huì)不斷地調(diào)用next函數(shù)拿到下一個(gè)值,直到捕獲到StopIteration停止。
廖雪峰老師教程里寫的是__next__方法,不知道為啥。
class Fib(object): def __init__(self): self.a, self.b = 0, 1 def __iter__(self): return self def next(self): self.a, self.b = self.b, self.a + self.b if self.a > 10000: raise StopIteration return self.a for i in Fib(): print i__getitem__函數(shù)
上面通過實(shí)現(xiàn)__iter__函數(shù)實(shí)現(xiàn)對(duì)象的迭代。
那么如何實(shí)現(xiàn)對(duì)象按下標(biāo)取出元素呢。
這是通過實(shí)現(xiàn)對(duì)象的__getitem__方法。
我們來舉一個(gè)?子。我們新建了一個(gè)類MyList,我們要辦它實(shí)現(xiàn)普通list的一些功能,比如(1)根據(jù)下標(biāo)獲取值;(2)正數(shù)順序單步長(zhǎng)切片 (3)任意步長(zhǎng)切片
class MyList(object): def __init__(self, *args): self.numbers = args def __getitem__(self, item): return self.numbers[item] my_list = MyList(1, 2, 3, 4, 6, 5, 3) print my_list[2]
當(dāng)然,上面實(shí)現(xiàn)了根據(jù)下標(biāo)獲取值。但是這還不夠。我們還需要實(shí)現(xiàn)切片功能。例如my_list[1:3].
我們對(duì)對(duì)象進(jìn)行切片操作的時(shí)候,調(diào)用的氣勢(shì)也是__getitem__函數(shù)。此時(shí),該函數(shù)獲取到的并不是int對(duì)象,而是slice對(duì)象。
例如下面的代碼
class MyList(object): def __init__(self, *args): self.numbers = args def __getitem__(self, item): if isinstance(item, int): return self.numbers[item] elif isinstance(item, slice): # 寫習(xí)慣了其他語(yǔ)言,差點(diǎn)忘記了三元運(yùn)算符的格式了,吼吼吼。 # 下面句三元運(yùn)算符的意思是,若為空,則為切片從0開始。 start = item.start if item.start is not None else 0 # 下面句三元運(yùn)算符的意思是,若為空,則為切片到最末端結(jié)束。 stop = item.stop if item.stop is not None else len(self.numbers) return self.numbers[start:stop] my_list = MyList(1, 2, 3, 4, 6, 5, 3) print my_list[2:5]
上面的代碼終于實(shí)現(xiàn)了切片功能,但是還沒考慮負(fù)數(shù)呢。那么我們加一把勁再來改一下。代碼如下:
class MyList(object): def __init__(self, *args): self.numbers = args def __getitem__(self, item): if isinstance(item, int): return self.numbers[item] elif isinstance(item, slice): start = item.start if item.start is not None else 0 stop = item.stop if item.stop is not None else len(self.numbers) length = len(self.numbers) start = length + start + 1 if start < 0 else start stop = length + stop + 1 if stop < 0 else stop return self.numbers[start:stop] my_list = MyList(1, 2, 3, 4, 6, 5, 3) print my_list[1:-1]
哇塞,寫完了,棒棒棒
_getattar_在調(diào)用某一個(gè)對(duì)象不存在的屬性或者方法的時(shí)候,會(huì)拋出一個(gè)一個(gè)AttributeError錯(cuò)誤。
但是如果我們實(shí)現(xiàn)了類中的魔術(shù)方法__getattar__,那么在調(diào)用不存在的屬性或者方法的時(shí)候,就會(huì)調(diào)用該魔術(shù)方法。
class Apple(object): def __getattr__(self, item): if item == "attar1": return "print" if item == "method1": return lambda x: "hello %s" % x apple = Apple() print apple.attar1 print apple.method1
__getattar__函數(shù)一個(gè)重要的適用場(chǎng)景就是實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用。例如我們?cè)谡{(diào)用某一個(gè)api的時(shí)候:
GET users/articles/index
那么我們就希望我們的代碼可以實(shí)現(xiàn)`Api.users.articles.index這么調(diào)用。
思考一下,要實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,最重要的就是每一個(gè)調(diào)用都是返回一個(gè)實(shí)例~~。
# coding=utf-8 class Api(object): def __init__(self, path=""): self._path = path def __getattr__(self, name): return Api("%s/%s" % (self._path, name)) # 定義一個(gè)Post方法來發(fā)送請(qǐng)求 def post(self): print self._path api = Api() api.user.articles.index.post()
廖雪峰在他的教程中給我們出了一個(gè)題目:
例如調(diào)用github的api:users/:user/repos一樣,中間的user名需要?jiǎng)討B(tài)替換。
我們希望能api.users("charlie").repos這么調(diào)用。那么代碼該如何實(shí)現(xiàn)呢?這可能需要用到另一個(gè)方法__call__
一個(gè)對(duì)象既有屬性,又有方法。我們?cè)谡{(diào)用一個(gè)實(shí)例的方法的時(shí)候,我們可以使用instance.method()的形式調(diào)用。
其實(shí)也可以將實(shí)例本身看成一個(gè)函數(shù)用來調(diào)用,我們需要做的就是實(shí)現(xiàn)__call__函數(shù)本身。
class Apple(object): def __call__(self, *args, **kwargs): return args apple = Apple() print apple("yes", "no")
此時(shí)我們?cè)賮砜匆幌律厦嫣岬降膶?shí)現(xiàn)api.users("charlie").repos鏈?zhǔn)秸{(diào)用的方法。
# coding=utf-8 class Api(object): def __init__(self, path=""): self._path = path def __getattr__(self, name): return Api("%s/%s" % (self._path, name)) def __call__(self, args): self._path = "%s/%s" % (self._path, args) return Api(self._path) # 定義一個(gè)Post方法來發(fā)送請(qǐng)求 def post(self): print self._path api = Api() api.users("Charlie").index.post()
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/38334.html
摘要:由此看來,的官方文檔就把當(dāng)成內(nèi)置函數(shù),這個(gè)認(rèn)識(shí)錯(cuò)誤是有根源的等到的時(shí)候,官方把錯(cuò)誤改正過來了,然而改得并不徹底。使用進(jìn)行判斷,結(jié)果為的才是內(nèi)置函數(shù)。 showImg(https://segmentfault.com/img/bVbm3Bu?w=5184&h=3456);有群友問過,是什么原因使我開始寫技術(shù)公眾號(hào),又是什么動(dòng)力讓我堅(jiān)持寫的。 在我看來,寫作是一件不能敷衍的事,通過寫作來學(xué)...
摘要:本篇繼續(xù)學(xué)習(xí)之路,實(shí)現(xiàn)更多的特殊方法以讓自定義類的行為跟真正的對(duì)象一樣。之所以要讓向量不可變,是因?yàn)槲覀冊(cè)谟?jì)算向量的哈希值時(shí)需要用到和的哈希值,如果這兩個(gè)值可變,那向量的哈希值就能隨時(shí)變化,這將不是一個(gè)可散列的對(duì)象。 《流暢的Python》筆記。本篇是面向?qū)ο髴T用方法的第二篇。前一篇講的是內(nèi)置對(duì)象的結(jié)構(gòu)和行為,本篇?jiǎng)t是自定義對(duì)象。本篇繼續(xù)Python學(xué)習(xí)之路20,實(shí)現(xiàn)更多的特殊方法以讓...
摘要:它是語(yǔ)言的第七種數(shù)據(jù)類型前六種是布爾值字符串?dāng)?shù)值對(duì)象。為了防止沖突這就是引入的原因。指向了這個(gè)內(nèi)部方法調(diào)用了返回對(duì)象的屬性等于一個(gè)布爾值,表示該對(duì)象使用時(shí),是否可以展開。數(shù)組的默認(rèn)行為是可以展開返回對(duì)象的屬性,指向當(dāng)前對(duì)象的構(gòu)造函數(shù)。 es6學(xué)習(xí)筆記-Symbol_v1.0 基本抄了一次內(nèi)容,有很多只是知道其然并不知其所以然,不過也算是加深了一次印象,另外每段代碼我都有手動(dòng)執(zhí)行過. E...
閱讀 2323·2021-11-25 09:43
閱讀 2465·2021-11-24 09:39
閱讀 1756·2021-11-22 12:02
閱讀 3116·2021-11-17 09:33
閱讀 3583·2021-11-15 11:38
閱讀 3041·2021-10-13 09:40
閱讀 1237·2021-09-22 15:41
閱讀 1813·2019-08-30 10:58