成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

PyTips 0x14 - Python 描述符

since1986 / 1207人閱讀

摘要:項目地址本篇主要關(guān)于三個常用內(nèi)置方法,,在語言的設(shè)計中,通常的語法操作最終都會轉(zhuǎn)化為方法調(diào)用,例如相當(dāng)于中的描述符就是將對象屬性的獲取賦值以及刪除等行為轉(zhuǎn)換為方法調(diào)用的協(xié)議例如我們要獲取一個對象的屬性,可以通過的方式取得而通過的

項目地址:https://git.io/pytips

本篇主要關(guān)于三個常用內(nèi)置方法:property()staticmethod(),classmethod()

在 Python 語言的設(shè)計中,通常的語法操作最終都會轉(zhuǎn)化為方法調(diào)用,例如:

a = 1
b = 2
print("a + b = {}".format(a+b))

# 相當(dāng)于
print("a.__add__(b) = {}".format(a.__add__(b)))
a + b = 3
a.__add__(b) = 3

Python 中的描述符(Descriptor)就是將對象屬性的獲取、賦值以及刪除等行為轉(zhuǎn)換為方法調(diào)用的協(xié)議:

descr.__get__(self, obj, type=None) --> value

descr.__set__(self, obj, value) --> None

descr.__delete__(self, obj) --> None

例如我們要獲取一個對象的屬性,可以通過o.x的方式取得:

class Int:
    ctype = "Class::Int"
    def __init__(self, val):
        self._val = val
        
a = Int(1)
print(a.ctype)
Class::Int

而通過.的方式尋找屬性的值實際上調(diào)用了object.__getattribute__(self, name)方法:

class Int:
    ctype = "Class::Int"
    def __init__(self, val):
        self._val = val
    def __getattribute__(self, name):
        print("? doesn"t want to give `{}" to you!".format(name))
        return "?"
a = Int(2)
print(a.ctype)
? doesn"t want to give `ctype" to you!
?

而這里的__getattribute__(self, name)方法實際上就是將.的屬性獲取方法轉(zhuǎn)化為描述符協(xié)議定義的descr.__get__(self, key)

class Str:
    def __init__(self, val):
        self._val = val
    def __get__(self, name, ctype=None):
        print("You can __get__ anything from here!")
        return self._val
class Int:
    ctype = Str("Class::Int")
    def __init__(self, val):
        self._val = val
    def __getattribute__(self, name):
        return type(self).__dict__[name].__get__(None, type(self))
a = Int(2)
print(a.ctype)
You can __get__ anything from here!
Class::Int

這里的 a.ctype = (Int.__dict__["ctype"]).__get__(None, Int),即通過描述符的方式獲取了 ctype 屬性的值。同樣的道理,你也可以通過 descr.__set__(self, obj, val) 設(shè)置屬性的值:

class Str:
    def __init__(self, val):
        self._val = val
    def __get__(self, name, ctype=None):
        print("You can __get__ anything from here!")
        return self._val
    def __set__(self, name, val):
        print("You can __set__ anything to me!")
        self._val = val
class Int:
    ctype = Str("Class::Int")
    def __init__(self, val):
        self._val = val
a = Int(3)
print(a.ctype)
a.ctype = "Class::Float"
print(a.ctype)
You can __get__ anything from here!
Class::Int
You can __set__ anything to me!
You can __get__ anything from here!
Class::Float

將這些取值、賦值的操作轉(zhuǎn)換為方法調(diào)用讓我們有辦法在做這些操作的過程中插入一些小動作,這么好用的東西自然是已加入豪華內(nèi)置函數(shù)陣容,正是我們常見的

property()

classmethod()

staticmethod()

property

property(fget=None, fset=None, fdel=None, doc=None) 方法簡化了上面的操作:

class Int:
    def __init__(self, val):
        self._val = val
        self._ctype = None
        
    def get_ctype(self):
        print("INFO: You can get `ctype`")
        return self._ctype
    def set_ctype(self, val):
        print("INFO: You"re setting `ctype` =", val)
        self._ctype=val
    ctype = property(fget=get_ctype, fset=set_ctype, doc="Property `ctype`")
    
a = Int(4)
print(a.ctype)
a.ctype = "Class::Int"
print(a.ctype)
INFO: You can get `ctype`
None
INFO: You"re setting `ctype` = Class::Int
INFO: You can get `ctype`
Class::Int

顯然,更方便一些的用法是將 property 當(dāng)做修飾器:

class Int:
    _ctype = None
    def __init__(self, val):
        self._val = val
    @property
    def ctype(self):
        print("INFO: You can get `ctype` from me!")
        return self._ctype
    @ctype.setter
    def ctype(self, val):
        print("INFO: You"re setting `ctype` =", val)
        self._ctype = val
a = Int(5)
print(a.ctype)
a.ctype = "Class::Int"
print(a.ctype)
INFO: You can get `ctype` from me!
None
INFO: You"re setting `ctype` = Class::Int
INFO: You can get `ctype` from me!
Class::Int

staticmethod & classmethod

顧名思義,property 是關(guān)于屬性的全部操作,如果是要獲取類中的方法,則需要用到 staticmethodclassmethod。顧名思義,staticmethod 將方法變成靜態(tài)方法,即類和實例都可以訪問,如果不用 staticmethod 我們可以用下面這種別扭的方法實現(xiàn):

class Int:
    def __init__(self, val):
        self._val = val
    def _get_ctype(self=None):
        print("INFO: You can get `ctype` from here!")
        return "Class::Int"
    
    @staticmethod
    def get_ctype():
        print("INFO: You can get `ctype` from here!")
        return "Class::StaticInt"       
    
a = Int(6)
print(a._get_ctype())
print(Int._get_ctype())

print(a.get_ctype())
print(Int.get_ctype())
INFO: You can get `ctype` from here!
Class::Int
INFO: You can get `ctype` from here!
Class::Int
INFO: You can get `ctype` from here!
Class::StaticInt
INFO: You can get `ctype` from here!
Class::StaticInt

可以看到,靜態(tài)方法與類和實例無關(guān),也就不再(不能)需要 self 關(guān)鍵詞;與之相反,當(dāng)我們需要在方法中保留類(而非實例)的引用時,則需要用 classmethod

class Int:
    _ctype = ""
    def __init__(self, val):
        self._val = val
        
    @classmethod
    def set_ctype(klass, t):
        klass._ctype = t
        return "{}.ctype = {}".format(klass.__name__, t)
a = Int(7)
print(a.set_ctype("Class::Int"))
print(Int.set_ctype("Class::Float"))
b = Int(8)
print(b._ctype)
Int.ctype = Class::Int
Int.ctype = Class::Float
Class::Float
總結(jié)

Python 的描述符給出一種通過方法調(diào)用來實現(xiàn)屬性(方法)獲取、賦值等操作的規(guī)則,通過這一規(guī)則可以方便我們深入程序內(nèi)部并實施操控,因此 property/staticmethod/classmethod 在 Python 是通過底層(如 CPython 中的 C)實現(xiàn)的,如果想要進一步深入了解其實現(xiàn)原理,可以訪問參考鏈接的教程,其中包括了這三個內(nèi)置方法的 Python 實現(xiàn)版本,我也把它們 copy 過來方便查看。


歡迎關(guān)注公眾號 PyHub 每日推送

參考

Descriptor HowTo Guide

class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can"t set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can"t delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f
        
    def __get__(self, obj, objtype=None):
        return self.f

class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"
    
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, klass=None):
        if klass is None:
            klass = type(obj)
        def newfunc(*args):
            return self.f(klass, *args)
        return newfunc

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/45427.html

相關(guān)文章

  • PyTips 0x02 - Python 中的函數(shù)式編程

    摘要:項目地址中的函數(shù)式編程函數(shù)式編程英語或稱函數(shù)程序設(shè)計,又稱泛函編程,是一種編程范型,它將電腦運算視為數(shù)學(xué)上的函數(shù)計算,并且避免使用程序狀態(tài)以及易變對象。 項目地址:https://git.io/pytips Python 中的函數(shù)式編程 函數(shù)式編程(英語:functional programming)或稱函數(shù)程序設(shè)計,又稱泛函編程,是一種編程范型,它將電腦運算視為數(shù)學(xué)上的函數(shù)計算,并且...

    FrozenMap 評論0 收藏0
  • PyTips 0x15 - Python `__future__` 模塊

    摘要:模塊的導(dǎo)入一定要放在最上方,也就是在所有其它模塊之前導(dǎo)入。最后一列是每個新特性所對應(yīng)的及簡單描述。相對導(dǎo)入則可以使用為標(biāo)記導(dǎo)入相對目錄中的模塊,具體可以參考這篇文章導(dǎo)入模塊的幾種姿勢。 項目地址:https://git.io/pytips 我們經(jīng)常從一些組織良好的 Python 項目中看到 __future__ 的身影,例如: from __future__ import absolu...

    klinson 評論0 收藏0
  • PyTips 0x08 - Python 字節(jié)與字節(jié)數(shù)組

    摘要:回到對字節(jié)和字節(jié)數(shù)組的定義為了用計算機可以理解的數(shù)字描述人類使用的字符,我們需要一張數(shù)字與字符對應(yīng)的表。由于和字符串一樣是序列類型,字節(jié)和字節(jié)數(shù)組可用的方法也類似,這里就不一一列舉了。 項目地址:https://git.io/pytips 0x07 中介紹了 Python 中的字符串類型,字符串類型是對人類友好的符號,但計算機只認識一種符號,那就是二進制(binary)數(shù),或者說是數(shù)字...

    Leo_chen 評論0 收藏0
  • PyTips 0x0a - Python串的格式化

    摘要:項目地址相信很多人在格式化字符串的時候都用的語法,提出一種更先進的格式化方法并成為的標(biāo)準(zhǔn)用來替換舊的格式化語法,從開始已經(jīng)實現(xiàn)了這一方法其它解釋器未考證。 項目地址:https://git.io/pytips 相信很多人在格式化字符串的時候都用%s % v的語法,PEP 3101 提出一種更先進的格式化方法 str.format() 并成為 Python 3 的標(biāo)準(zhǔn)用來替換舊的 %s ...

    luqiuwen 評論0 收藏0
  • PyTips 0x 12 - Python 線程與協(xié)程(1)

    摘要:中關(guān)于線程的標(biāo)準(zhǔn)庫是,之前在版本中的在之后更名為,無論是還是都應(yīng)該盡量避免使用較為底層的而應(yīng)該使用。而與線程相比,協(xié)程尤其是結(jié)合事件循環(huán)無論在編程模型還是語法上,看起來都是非常友好的單線程同步過程。 項目地址:https://git.io/pytips 要說到線程(Thread)與協(xié)程(Coroutine)似乎總是需要從并行(Parallelism)與并發(fā)(Concurrency)談起...

    el09xccxy 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<