成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

關(guān)于Python Magic Method的若干腦洞

fizz / 3461人閱讀

摘要:先從最初的腦洞開始吧。這樣做的目的在于,把調(diào)用過程中的狀態(tài)存儲起來,借此實現(xiàn)帶狀態(tài)的調(diào)用。這種實例我們稱之為函數(shù)對象。在里面也有同樣的機制。對于真正的而言,肯定不會用這種的判斷方式。

有一天閑著無聊的時候,腦子里突然冒出一個Magic Method的有趣用法,可以用__getattr__來實現(xiàn)Python版的method_missing。
順著這個腦洞想下去,我發(fā)現(xiàn)Python的Magic Method確實有很多妙用之處。故在此記下幾種有趣(也可能有用的)Magic Method技巧,希望可以拋磚引玉,打開諸位讀者的腦洞,想出更加奇妙的用法。

如果對Magic Method的了解僅僅停留在知道這個術(shù)語和若干個常用方法上(如__lt__,__str__,__len__),可以閱讀下這份教程,看看Magic Method可以用來做些什么。

Python method_missing

先從最初的腦洞開始吧。曾幾何時,Ruby社區(qū)的人總是夸耀Ruby的強大的元編程能力,其中method_missing更是不可或缺的特性。通過調(diào)用BaseObject上的method_missing,Ruby可以實現(xiàn)在調(diào)用不存在的屬性時進行攔截,并動態(tài)生成對應(yīng)的屬性。

Ruby例子

# 來自于Ruby文檔: http://ruby-doc.org/core-2.2.0/BasicObject.html#method-i-method_missing
class Roman
  def roman_to_int(str)
    # ...
  end
  def method_missing(methId)
    str = methId.id2name
    roman_to_int(str)
  end
end

r = Roman.new
r.iv      #=> 4
r.xxiii   #=> 23
r.mm      #=> 2000

method_missing的應(yīng)用是如此地廣泛,以至于只要是成規(guī)模的Ruby庫,多多少少都會用到它。像是ActiveRecord就是靠這一特性去動態(tài)生成關(guān)聯(lián)屬性。

其實Python一早就內(nèi)置了這一功能。Python有一個Magic Method叫__getattr__,它會在找不到屬性的時候調(diào)用,正好跟Ruby的method_missing是一樣的。
我們可以這樣動態(tài)添加方法:

class MyClass(object):
    def __getattr__(self, name):
        """called only method missing"""
        if name == "missed_method":
            setattr(self, name, lambda : True)
            return lambda : True

myClass = MyClass()
print(dir(myClass))
print(myClass.missed_method())
print(dir(myClass))

于是乎,前面的Ruby例子可以改寫成下面的Python版本:

class Roman(object):
    roman_int_map = {
            "i": 1, "v": 5, "x": 10, "l": 50,
            "c":100, "d": 500, "m": 1000
    }

    def roman_to_int(self, s):
        decimal = 0
        for i in range(len(s), 0, -1):
            if (i == len(s) or
                    self.roman_int_map[s[i-1]] >= self.roman_int_map[s[i]]):
                decimal += self.roman_int_map[s[i-1]]
            else:
                decimal -= self.roman_int_map[s[i-1]]
        return decimal

    def __getattr__(self, s):
        return self.roman_to_int(s)

r = Roman()
print(r.iv)
r.iv #=> 4
r.xxiii #=> 23
r.mm #=> 2000

很有可能你會覺得這個例子沒有什么意義,你是對的!其實它就是把方法名當(dāng)做一個羅馬數(shù)字字符串,傳入roman_to_int而已。不過正如遞歸不僅僅能用來計算斐波那契數(shù)列,__getattr__的這一特技實際上還是挺有用的。你可以用它來進行延時計算,或者方法分派,抑或像基于Ruby的DSL一樣動態(tài)地合成方法。這里有個用__getattr__實現(xiàn)延時加載的例子。

函數(shù)對象

在C++里面,你可以重載掉operator (),這樣就可以像調(diào)用函數(shù)一樣去調(diào)用一個類的實例。這樣做的目的在于,把調(diào)用過程中的狀態(tài)存儲起來,借此實現(xiàn)帶狀態(tài)的調(diào)用。這種實例我們稱之為函數(shù)對象。

在Python里面也有同樣的機制。如果想要存儲的狀態(tài)只有一種,你需要的是一個生成器。通過send來設(shè)置存儲的狀態(tài),通過next來獲取調(diào)用的結(jié)果。不過如果你需要存儲多個不同的狀態(tài),生成器就不夠用了,非得定義一個函數(shù)對象不可。

Python里面可以重載__call__來實現(xiàn)operator ()的功能。下面的例子里面,就是一個存儲有兩個狀態(tài)value和called_times的函數(shù)對象:

class CallableCounter(object):
    def __init__(self, initial_value=0, start_times=0):
        self.value = initial_value
        self.called_times = start_times

    def __call__(self):
        print("Call the object and do something with value %d" % self.value)
        self.value += 1
        self.called_times += 1

    def reset(self):
        self.called_times = 0


cc = CallableCounter(initial_value=5)
for i in range(10):
    cc()
print(cc.called_times)
cc.reset()
偽造一個Dict

最后請允許我奉上一個大腦洞,偽造一個Dict類。(這個可就沒有什么實用價值了)

首先確定下把數(shù)據(jù)存在哪里。我打算把數(shù)據(jù)存儲在類的__dict__屬性中。由于__dict__屬性的值就是一個Dict實例,我只需把調(diào)用在FakeDict上的方法直接轉(zhuǎn)發(fā)給對應(yīng)的__dict__的方法。代價是只能接受字符串類型的鍵。

class FakeDict:
    def __init__(self, iterable=None, **kwarg):
        if iterable is not None:
            if isinstance(iterable, dict):
                self.__dict__ = iterable
            else:
                for i in iterable:
                    self[i] = None
        self.__dict__.update(kwarg)

    def __len__(self):
        """len(self)"""
        return len(self.__dict__)

    def __str__(self):
        """it looks like a dict"""
        return self.__dict__.__str__()
    __repr__ = __str__

接下來開始做點實事。Dict最基本的功能是給一個鍵設(shè)置值和返回一個鍵對應(yīng)的值。通過定義__setitem____getitem__方法,我們可以重載掉[]=[]。

    def __setitem__(self, k, v):
        """self[k] = v"""
        self.__dict__[k] = v

    def __getitem__(self, k):
        """self[k]"""
        return self.__dict__[k]

別忘了del方法:

    def __delitem__(self, k):
        """del self[k]"""
        del self.__dict__[k]

Dict的一個常用用途是允許我們迭代里面所有的鍵。這個可以通過定義__iter__實現(xiàn)。

    def __iter__(self):
        """it iterates like a dict"""
        return iter(self.__dict__)

Dict的另一個常用用途是允許我們查找一個鍵是否存在。其實只要定義了__iter__,Python就能判斷if x in y,不過這個過程中會遍歷對象的所有值。對于真正的Dict而言,肯定不會用這種O(n)的判斷方式。定義了__contains__之后,Python會優(yōu)先使用它來判斷if x in y。

    def __contains__(self, k):
        """key in self"""
        return k in self.__dict__

接下要實現(xiàn)==的重載,不但要讓FakeDict和FakeDict之間可以進行比較,而且要讓FakeDict和正牌的Dict也能進行比較。

    def __eq__(self, other):
        """
        implement self == other FakeDict,
        also implement self == other dict
        """
        if isinstance(other, dict):
            return self.__dict__ == other
        return self.__dict__ == other.__dict__

要是繼續(xù)實現(xiàn)了__subclass____class__,那么我們的偽Dict就更完備了。這個就交給感興趣的讀者自己動手了。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/37635.html

相關(guān)文章

  • Python中Mock和MagicMock區(qū)別

    摘要:也就是說,如果不需要,兩者使用起來并沒有什么分別。來看個例子,先定義個類,里面只有一個成員方法,返回倍的數(shù)值使用類來掉這個成員方法使用類來兩者沒有任何區(qū)別,都成功了了成員方法。再看下兩者的區(qū)別因為使用類時,默認不會創(chuàng)建這個的,所以報錯。 Python的unittest.mock模塊中提供了兩個主要的mock類,分別是Mock和MagicMock. 先看一下官方文檔的定義: MagicM...

    TigerChain 評論0 收藏0
  • Python單例模式(Singleton)N種實現(xiàn)

    摘要:本篇文章總結(jié)了目前主流的實現(xiàn)單例模式的方法供讀者參考。使用實現(xiàn)單例模式同樣,我們在類的創(chuàng)建時進行干預(yù),從而達到實現(xiàn)單例的目的。 很多初學(xué)者喜歡用 全局變量 ,因為這比函數(shù)的參數(shù)傳來傳去更容易讓人理解。確實在很多場景下用全局變量很方便。不過如果代碼規(guī)模增大,并且有多個文件的時候,全局變量就會變得比較混亂。你可能不知道在哪個文件中定義了相同類型甚至重名的全局變量,也不知道這個變量在程序的某...

    Maxiye 評論0 收藏0
  • 介紹Python魔術(shù)方法 - Magic Method

    摘要:所以準(zhǔn)確來說是和共同構(gòu)成了構(gòu)造函數(shù)是用來創(chuàng)建類并返回這個類的實例而只是將傳入的參數(shù)來初始化該實例在創(chuàng)建一個實例的過程中必定會被調(diào)用但就不一定,比如通過的方式反序列化一個實例時就不會調(diào)用。 前言 在Python中,所有以__雙下劃線包起來的方法,都統(tǒng)稱為魔術(shù)方法。比如我們接觸最多的__init__. 有些魔術(shù)方法,我們可能以后一輩子都不會再遇到了,這里也就只是簡單介紹下; 而有些魔術(shù)方法...

    animabear 評論0 收藏0
  • php magic method 具體應(yīng)用和 phpdoc 結(jié)合

    摘要:關(guān)于的介紹自行查閱官方文檔,這里不再贅述。使用的同學(xué)注意了,如果在我們的代碼中使用到了中相關(guān)的魔術(shù)方法,需要在文件中指明告訴應(yīng)該如何來跟蹤變量屬性。下面我們來具體實踐分析。確實這個樣子可以實現(xiàn),但沒有利用到這一魔術(shù)方法的特性。 關(guān)于 Magic Methods 的介紹自行查閱官方文檔,這里不再贅述。http://php.net/manual/en/lang... 使用 phpstorm...

    csRyan 評論0 收藏0
  • Python Tricks 若干

    摘要:在代碼中可以看到一些常見的,在這里做一個簡單的小結(jié)。的妙用在某些場景下我們需要判斷我們是否是從一個循環(huán)中跳出來的,并且只針對跳出的情況做相應(yīng)的處理。這時候我們通常的做法是使用一個變量來標(biāo)識是否是從循環(huán)中跳出的。 在 python 代碼中可以看到一些常見的 trick,在這里做一個簡單的小結(jié)。 json 字符串格式化 在開發(fā) web 應(yīng)用的時候經(jīng)常會用到 json 字符串,但是一段比...

    lovXin 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<