日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python中的self描述符__set__和__get__简单总结

發布時間:2024/9/20 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python中的self描述符__set__和__get__简单总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. python中的self用法總結

class Student(object):def __init__(self, name, score):self.name = nameself.score = score
  • __init__方法的第一參數永遠是self,表示創建的類實例本身,因此,在__init__方法內部,就可以把各種屬性綁定到self,因為self就指向創建的實例本身。
  • 有了__init__方法,在創建實例的時候,就不能傳入空的參數了,必須傳入與init方法匹配的參數,但self不需要傳,Python解釋器會自己把實例變量傳進去。
  • 和普通數相比,在類中定義函數只有一點不同,就是第一參數永遠是類的本身實例變量self,并且調用時,不用傳遞該參數。除此之外,類的方法(函數)和普通函數沒啥區別,你既可以用默認參數、可變參數或者關鍵字參數(*args是可變參數,args接收的是一個tuple,**kw是關鍵字參數,kw接收的是一個dict)
  • 如果要讓內部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線,在Python中,實例的變量名如果以開頭,就變成了一個私有變量(private),只有內部可以訪問,外部不能訪問。
  • 需要注意的是,在Python中,變量名類似xxx的,也就是以雙下劃線開頭,并且以雙下劃線結尾的,是特殊變量,特殊變量是可以直接訪問的,不是private變量,所以,不能用__name__、__score__這樣的變量名
  • 有些時候,你會看到以一個下劃線開頭的實例變量名,比如_name,這樣的實例變量外部是可以訪問的,但是,按照約定俗成的規定,當你看到這樣的變量時,意思就是,“雖然我可以被訪問,但是,請把我視為私有變量,不要隨意訪問”。

下面是self的一些詳細用法:

(1)self代表類的實例,而非類

In [19]: class Test:...: def ppr(self):...: print(self)...: print(self.__class__)...: In [20]: t = Test()In [21]: t.ppr() <__main__.Test instance at 0x000000000D3D4E88> __main__.Test

self代表的是類的實例。而self.__class__則指向類。
注意:把self換成this,結果也一樣,但Python中最好用約定俗成的self。

(2)self可以不寫嗎
在Python解釋器的內部,當我們調用t.ppr()時,實際上Python解釋成Test.ppr(t),也就是把self替換成了類的實例。

In [22]: class Test:...: def ppr():...: print(self)...: In [23]: t=Test()In [24]: t.ppr() Traceback (most recent call last):File "<ipython-input-24-178e9dc94925>", line 1, in <module>t.ppr()TypeError: ppr() takes no arguments (1 given)

這里實際上已經部分說明了self在定義時不可以省略。

當然,如果我們的定義和調用時均不傳類實例是可以的,這就是類方法。

>>> class Test:def ppr():print(__class__)>>> Test.ppr() <class '__main__.Test'> >>>

但這里要注意下:對于python 2.7版本來說會報錯,必須先創建對象。

In [31]: class Test:...: def ppr():...: print('i am here')...: In [32]: Test.ppr() Traceback (most recent call last):File "<ipython-input-32-f7a5b2f2ccd9>", line 1, in <module>Test.ppr()TypeError: unbound method ppr() must be called with Test instance as first argument (got nothing instead)

(3)在繼承時,傳入的是哪個實例,就是那個傳入的實例,而不是指定義了self的類的實例

>>> class Parent:def pprt(self):print(self)>>> class Parent:def pprt(self):print(self)>>> class Child(Parent):def cprt(self):print(self)>>> c=Child() >>> c.cprt() <__main__.Child object at 0x00000244B8769860> >>> c.pprt() <__main__.Child object at 0x00000244B8769860> >>> p = Parent() >>> p.pprt() <__main__.Parent object at 0x00000244B8769A58> >>>

(4)在描述符類中,self指的是描述符類的實例

class Desc2:def __get__(self, ins, cls):print ('self in Desc: %s ' % self )print (self, ins, cls)class Test2:x = Desc2() # 而該屬性是描述符屬性,為Desc類的實例def prt(self):print ('self in Test: %s' % self)t2 = Test2() t2.prt() t2.x # 這里是調用類屬性 Test2.x # 注意和上面一行的區別

運行結果:

self in Test: <__main__.Test2 object at 0x00000239CE269128> self in Desc: <__main__.Desc2 object at 0x00000239CE2690B8> <__main__.Desc2 object at 0x00000239CE2690B8> <__main__.Test2 object at 0x00000239CE269128> <class '__main__.Test2'> self in Desc: <__main__.Desc2 object at 0x00000239CE2690B8> <__main__.Desc2 object at 0x00000239CE2690B8> None <class '__main__.Test2'>

由于在很多時候描述符類中仍然需要知道調用該描述符的實例是誰,所以在描述符類中存在第二個參數ins,用來表示調用它的類實例,所以t.x時可以看到第三行中的運行結果中第二項為<__main__.Test2 object at 0x00000239CE269128>

2. 描述符__set__和__get__ 的用法

可以先參考下:https://blog.csdn.net/lilong117194/article/details/80111803

上面有疑問的地方應該是__get__(self, ins, cls),下面總結一下:
首先說下python中存在的幾種方法:對象方法、靜態方法、類方法等,歸屬權分別為obj、cls、cls
其實可以從他們的參數中就可以看的出來,靜態方法使用@staticmethod來修飾,可以通過類或類的實例對象來調用而已。

class A(object):def foo1(self):print ("Hello",self)@staticmethoddef foo2():print ("hello")@classmethoddef foo3(cls):print ("hello",cls) # cls就是類A本身 a = A() a.foo1()A.foo1(a) #這里傳入實例a,相當于普通方法的selfA.foo2() #這里,由于靜態方法沒有參數,故可以不傳東西A.foo3() #這里,由于是類方法,因此,它的第一個參數為類本身。print (A) #可以看到,直接輸入A,與上面那種調用返回同樣的信息

結果:

Hello <__main__.A object at 0x0000016D1774B860> Hello <__main__.A object at 0x0000016D1774B860> hello hello <class '__main__.A'> <class '__main__.A'>

Python中,對象的方法也是也可以認為是屬性,所以下面所說的屬性包含方法在內。
看一個實例:

class T(object):name = 'name'def hello(self):print ("hello") t = T() print ('dir(t):',dir(t)) print ('t.__class__:',t.__class__) print ('t.__dict__:',t.__dict__) print ('T.__dict__:',dict(T.__dict__)) # T.__dict__并沒有直接返回dict對象,這里轉換為字典print ('t.name:',t.name) print ('T.name:',T.name) print ('T.dict[‘name’]:',T.__dict__['name'])print ('T.hello:',T.hello) # 是個unbound method print ("T.__dict__['hello']:",T.__dict__['hello']) # 是個function print ('t.hello:',t.hello) # 是個bound method

運行結果:

dir(t): ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'hello', 'name'] t.__class__: <class '__main__.T'> t.__dict__: {} T.__dict__: {'name': 'name', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'T' objects>, '__module__': '__main__', 'hello': <function T.hello at 0x000002BB9572B400>, '__dict__': <attribute '__dict__' of 'T' objects>} t.name: name T.name: name T.dict[‘name’]: name T.hello: <function T.hello at 0x000002BB9572B400> T.__dict__['hello']: <function T.hello at 0x000002BB9572B400> t.hello: <bound method T.hello of <__main__.T object at 0x000002BB97B49860>>

注意:

  • 有些內建類型,如list和string,它們沒有dict屬性,隨意沒辦法在它們上面附加自定義屬性
  • t.__dict__: {}:到現在為止t.dict是一個空的字典,因為我們并沒有在t上自定義任何屬性,它的有效屬性hello和name都是從T得到的。

t.name的查找過程:

  • 首先,Python判斷name屬性是否是個自動產生的屬性,如果是自動產生的屬性,就按特別的方法找到這個屬性,當然,這里的name不是自動產生的屬性,而是我們自己定義的,Python于是到t的dict中尋找。還是沒找到。
  • 接著,Python找到了t所屬的類T,搜索T.dict,找到后返回name的值:字符串‘name’。如果在T.dict中還沒有找到,Python會接著到T的父類(如果T有父類的話)的dict中繼續查找。

t.hello:

  • 方法在類的dict中是以函數的形式存在的
  • 關于unbound和bound可以這樣:方法是要從實例調用的,如果從類中訪問,如T.hello,hello沒有和任何實例發生聯系,也就是沒綁定(unbound)到任何實例上,所以是個unbound,對t.hello的訪問方式,hello和t發生了聯系,因此是bound。

下面再看一個例子:

class Descriptor(object):def __get__(self, obj, type=None):return 'get', self, obj, typedef __set__(self, obj, val):print ('set', self, obj, val)def __delete__(self, obj):print ('delete', self, obj)class T(object):# d是T的類屬性,作為Descriptor的實例,它有get等方法,是一個描述符d = Descriptor() t = T()# T是一個類,t是它的一個實例,d是T的一個descriptor屬性 print (' t.d:', t.d) # t.d,返回的實際是d.__get__(t, T) print (' T.d:', T.d) # T.d,返回的實際是d.__get__(None, T),所以obj的位置為None t.d = 'hello' # 在實例上對descriptor設置值,在__set__方法中print語句輸出的。 print (' t.d:', t.d) # 可見,調用了Python調用了__set__方法,并沒有改變t.d的值 T.d = 'hello' # 沒有調用__set__方法 print (' T.d:', T.d) # t.d的值也變了,這可以理解,按我們上面說的屬性查找策略,t.d是從T.__dict__中得到的T.__dict__['d']的值是'hello',t.d當然也是'hello' print (' t.d:', t.d)

運行結果:

t.d: ('get', <__main__.Descriptor object at 0x000001F403DF9860>, <__main__.T object at 0x000001F403E5B6D8>, <class '__main__.T'>)T.d: ('get', <__main__.Descriptor object at 0x000001F403DF9860>, None, <class '__main__.T'>) set <__main__.Descriptor object at 0x000001F403DF9860> <__main__.T object at 0x000001F403E5B6D8> hellot.d: ('get', <__main__.Descriptor object at 0x000001F403DF9860>, <__main__.T object at 0x000001F403E5B6D8>, <class '__main__.T'>)T.d: hellot.d: hello

這里需要說明幾點:

  • self當然不用說,指的是當前Descriptor類的實例。obj值擁有屬性的對象。這應該不難理解,前面已經說了,descriptor是對象的稍微有點特殊的屬性,這里的obj就是擁有它的對象。要注意的是,如果是直接用類訪問descriptor(descriptor是個屬性,直接用類訪問descriptor就是直接用類訪問類的屬性),obj是None,此時type就是類本身。
  • 讀取屬性時,如T.d,返回的是d.get(None, T)的結果,t.d返回的是d.get(t, T)的結果。
  • 設置屬性時,t.d = value,實際上調用d.set(t, value)
  • T.d = value,這是真正的賦值,T.d的值從此變成value。刪除屬性和設置屬性類似。

data descriptor和non-data descriptor:
象上面的d,同時具有get和set方法,這樣的descriptor叫做data descriptor,如果只有get方法,則叫做non-data descriptor。容易想到,由于non-data descriptor沒有set方法,所以在通過實例對屬性賦值時,會直接賦值。

屬性查找策略
1.如果attr是一個Python自動產生的屬性,找到!(優先級非常高!)
2.查找obj.class.dict,如果attr存在并且是data descriptor,返回data descriptor的get方法的結果,如果沒有繼續在obj.class的父類以及祖先類中尋找data descriptor
3.在obj.dict中查找,這一步分兩種情況,第一種情況是obj是一個普通實例,找到就直接返回,找不到進行下一步。第二種情況是obj是一個類,依次在obj和它的父類、祖先類的dict中查找,如果找到一個descriptor就返回descriptor的get方法的結果,否則直接返回attr。如果沒有找到,進行下一步。
4.在obj.class.dict中查找,如果找到了一個descriptor(插一句:這里的descriptor一定是non-data descriptor,如果它是data descriptor,第二步就找到它了)descriptor的get方法的結果。如果找到一個普通屬性,直接返回屬性值。如果沒找到,進行下一步。
5.很不幸,Python終于受不了。在這一步,它raise AttributeError

到這里已經差不多了,但還是有些不是理解的很透徹,以后慢慢再學習。

參考:https://blog.csdn.net/u014015972/article/details/51168268

總結

以上是生活随笔為你收集整理的python中的self描述符__set__和__get__简单总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。