Python對(duì)象屬性管理

  • _dict_
  • _slots_
  • 屬性管理
    hasattr()函數(shù)
    getattr()函數(shù)
    setattr()函數(shù)
    delattr()函數(shù)

Python下一切皆對(duì)象,每個(gè)對(duì)象都有多個(gè)屬性(attribute),Python對(duì)屬性有一套統(tǒng)一的管理方案。dict是用來(lái)存儲(chǔ)對(duì)象屬性的一個(gè)字典,其鍵為屬性名,值為屬性的值。

_dict_

class Spring(object):
    #season 為類的屬性
    season = "the spring of class"

>>> Spring.__dict__
mappingproxy({'__module__': '__main__', 'season': 'the spring of class', '__dict__': <attribute '__dict__' of 'Spring' objects>, '__weakref__': <attribute '__weakref__' of 'Spring' objects>, '__doc__': None})

>>> Spring.__dict__['season']
'the spring of class'
>>> Spring.season
'the spring of class'

Spring._dict_['season']就是訪問(wèn)類屬性,同時(shí)通過(guò).號(hào)也可以訪問(wèn)該類屬性

# 類實(shí)例化
s = Spring()
>>>s.__dict__
{}

實(shí)例屬性的dict是空的,因?yàn)閟eason是屬于類屬性

>>> s.season
'the spring of class'

s.season是指向了類屬性中Spring.season

#建立實(shí)例對(duì)象
>>> s.season = 'the spring of instance'
>>> s.__dict__
{'season': 'the spring of instance'}

這樣實(shí)例屬性里面就不空了,這時(shí)候建立的s.season屬性與上面s.season(類屬性)重名,并且把原來(lái)的“遮蓋了”。

#查看類屬性
>>> Spring.season
'the spring of class'
>>> Spring.__dict__['season']
'the spring of class'

由上我們看到Spring類season屬性并沒(méi)有受到實(shí)例影響,其原因是實(shí)例s對(duì)象建立時(shí)s.season未初始化則會(huì)自動(dòng)指向類屬性,如果實(shí)例屬性被修改那么就不指向類屬性,同時(shí)類屬性也不會(huì)受到影響

#定義其它實(shí)例屬性
>>> s = Spring()
>>> s.lang = 'python'
>>> Spring.lang
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    Spring.lang
AttributeError: type object 'Spring' has no attribute 'lang'

上明錯(cuò)誤表面 實(shí)例對(duì)象添加內(nèi)容,不是類屬性

#定義一個(gè)類
>>> class Spring:
    def tree(self,x):
        self.x = x
        print(self.x)

>>> Spring.__dict__['tree']
<function Spring.tree at 0x036E4AE0>

在類屬性是存在tree方法

>>> s.__dict__['tree']
Traceback (most recent call last):
  File "<pyshell#33>", line 1, in <module>
    s.__dict__['tree']
KeyError: 'tree'

但是實(shí)例對(duì)象sdict 方法里不存在tree方法

>>> s.tree('123')
123

但是s能調(diào)用tree方法,其原因是s.tree指向了Spring.tree方法。 實(shí)例s與self新建了對(duì)應(yīng)關(guān)系,兩者是一個(gè)外一個(gè)內(nèi),在方法中self.x = x 。 將x值賦給了self.x,也就是實(shí)例應(yīng)該擁有這么一個(gè)屬性。self相當(dāng)于java中this指針。

>>> s.__dict__
{'x': '123'}

即實(shí)例方法(s.tree('123'))的第一個(gè)參數(shù)(self,但沒(méi)有寫(xiě)出來(lái))綁定實(shí)例s,透過(guò)self.x來(lái)設(shè)定值,給s.dict添加屬性值

換一個(gè)角度來(lái)看

class Spring:
    def tree(self,x):
        print(x)

這個(gè)方法沒(méi)有self.x = x 直接輸出x

>>> s = Spring()
>>> s.tree('123')
123
>>> s.__dict__
{}

再看一個(gè)例子

class Person(object):                      
    name = 'python'                        
    age = 18                               

    def __init__(self):                    
        self.sex = 'boy'                   
        self.like = 'papapa'               

    @staticmethod                          
    def stat_func():                       
        print 'this is stat_func'          

    @classmethod                           
    def class_func(cls):                   
        print 'class_func'                 


person = Person()                          
print 'Person.__dict__: ', Person.__dict__ 
print 'person.__dict__: ', person.__dict__

運(yùn)行結(jié)果:

Person.__dict__:  {'__module__': '__main__', 'name': 'python', '__init__': <function __init__ at 0x000000000385B518>, 'class_func': <classmethod object at 0x0000000003847F78>, '__dict__': <attribute '__dict__' of 'Person' objects>, 'age': 18, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'stat_func': <staticmethod object at 0x00000000037CFAF8>}
person.__dict__:  {'like': 'papapa', 'sex': 'boy'}

由此可見(jiàn), 類的普通方法、類方法、靜態(tài)方法、全局變量以及一些內(nèi)置的屬性都是放在類對(duì)象dict里

而實(shí)例對(duì)象中存儲(chǔ)了一些self.xxx的一些東西

在類的繼承中,子類有自己的dict, 父類也有自己的dict,子類的全局變量和方法放在子類的dict中,父類的放在父類dict中。

class Person(object):                          
    name = 'python'                            
    age = 18                                   

    def __init__(self):                        
        self.sex = 'boy'                       
        self.like = 'papapa'                   

    @staticmethod                              
    def stat_func():                           
        print 'this is stat_func'              

    @classmethod                               
    def class_func(cls):                       
        print 'class_func'                     


class Hero(Person):                            
    name = 'super man'                         
    age = 1000                                 

    def __init__(self):                        
        super(Hero, self).__init__()           
        self.is_good = 'yes'                   
        self.power = 'fly'                     


person = Person()                              
print 'Person.__dict__: ', Person.__dict__     
print 'person.__dict__: ', person.__dict__     

hero = Hero()                                  
print 'Hero.__dict__: ', Hero.__dict__         
print 'hero.__dict__: ', hero.__dict__

運(yùn)行結(jié)果:

Person.__dict__:  {'__module__': '__main__', 'name': 'python', '__init__': <function __init__ at 0x000000000374B518>, 'class_func': <classmethod object at 0x0000000003750048>, '__dict__': <attribute '__dict__' of 'Person' objects>, 'age': 18, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, 'stat_func': <staticmethod object at 0x0000000003737FD8>}
person.__dict__:  {'like': 'papapa', 'sex': 'boy'}
Hero.__dict__:  {'age': 1000, '__doc__': None, '__module__': '__main__', '__init__': <function __init__ at 0x000000000374B668>, 'name': 'super man'}
hero.__dict__:  {'is_good': 'yes', 'like': 'papapa', 'power': 'fly', 'sex': 'boy'}

從運(yùn)行結(jié)果可以看出,類對(duì)象的dict雖然沒(méi)有繼承父類的,但是實(shí)例對(duì)象繼承了父類的實(shí)例屬性

_slots_

現(xiàn)在我們終于明白了,動(dòng)態(tài)語(yǔ)言與靜態(tài)語(yǔ)言的不同

  • 動(dòng)態(tài)語(yǔ)言:可以在運(yùn)行的過(guò)程中,修改代碼

  • 靜態(tài)語(yǔ)言:編譯時(shí)已經(jīng)確定好代碼,運(yùn)行過(guò)程中不能修改

如果我們想要限制實(shí)例的屬性怎么辦?比如,只允許對(duì)Person實(shí)例添加name和age屬性。

為了達(dá)到限制的目的,Python允許在定義class的時(shí)候,定義一個(gè)特殊的slots變量,來(lái)限制該class實(shí)例能添加的屬性:

class Person:
    __slots__ = ("name", "age")
    def __init__(self,name,age):
        self.name = name
        self.age = age

p = Person("老王",20)
p.score = 100

輸出

Traceback (most recent call last):
  File "C:/Users/Administrator/PycharmProjects/test/app.py", line 8, in <module>
    p.score = 100
AttributeError: 'Person' object has no attribute 'score'

注意: 使用slots要注意,slots定義的屬性僅對(duì)當(dāng)前類實(shí)例起作用,對(duì)繼承的子類是不起作用的

class Person:
    __slots__ = ("name", "age")
    def __init__(self,name,age):
        self.name = name
        self.age = age

class GoodPerson(Person):
    pass

p = GoodPerson("老王",20)
p.score = 100

當(dāng)你定義 slots 后,Python就會(huì)為實(shí)例使用一種更加緊湊的內(nèi)部表示。 實(shí)例通過(guò)一個(gè)很小的固定大小的數(shù)組來(lái)構(gòu)建,而不是為每個(gè)實(shí)例定義一個(gè)字典。所以slots是創(chuàng)建大量對(duì)象時(shí)節(jié)省內(nèi)存的方法。slots的副作用是作為一個(gè)封裝工具來(lái)防止用戶給實(shí)例增加新的屬性。 盡管使用slots可以達(dá)到這樣的目的,但是這個(gè)并不是它的初衷。

屬性管理

hasattr()函數(shù)

hasattr()函數(shù)用于判斷對(duì)象是否包含對(duì)應(yīng)的屬性

語(yǔ)法:

  hasattr(object,name)

參數(shù):

  object--對(duì)象

  name--字符串,屬性名

返回值:

  如果對(duì)象有該屬性返回True,否則返回False

示例:

class People:
    country='China'
    def __init__(self,name):
        self.name=name

    def people_info(self):
        print('%s is xxx' %(self.name))

obj=People('aaa')

print(hasattr(People,'country'))
#返回值:True
print('country' in People.__dict__)
#返回值:True
print(hasattr(obj,'people_info'))
#返回值:True
print(People.__dict__)
##{'__module__': '__main__', 'country': 'China', '__init__': <function People.__init__ at 0x1006d5620>, 'people_info': <function People.people_info at 0x10205d1e0>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}

1.3.2. getattr()函數(shù)

描述:

  getattr()函數(shù)用于返回一個(gè)對(duì)象屬性值

語(yǔ)法:

  getattr(object,name,default)

參數(shù):

  object--對(duì)象

  name--字符串,對(duì)象屬性

  default--默認(rèn)返回值,如果不提供該參數(shù),在沒(méi)有對(duì)于屬性時(shí),將觸發(fā)AttributeError。

返回值:

  返回對(duì)象屬性值
class People:
    country='China'
    def __init__(self,name):
        self.name=name

    def people_info(self):
        print('%s is xxx' %(self.name))

obj=getattr(People,'country')
print(obj)
#返回值China
#obj=getattr(People,'countryaaaaaa')
#print(obj)
#報(bào)錯(cuò)
# File "/getattr()函數(shù).py", line 32, in <module>
#     obj=getattr(People,'countryaaaaaa')
# AttributeError: type object 'People' has no attribute 'countryaaaaaa'
obj=getattr(People,'countryaaaaaa',None)
print(obj)
#返回值None

1.3.3. setattr()函數(shù)

描述:

  setattr函數(shù),用于設(shè)置屬性值,該屬性必須存在

語(yǔ)法:

  setattr(object,name,value)

 參數(shù):

  object--對(duì)象

  name--字符串,對(duì)象屬性

  value--屬性值

返回值:

  無(wú)
class People:
    country='China'
    def __init__(self,name):
        self.name=name

    def people_info(self):
        print('%s is xxx' %(self.name))

obj=People('aaa')

setattr(People,'x',111) #等同于People.x=111
print(People.x)

#obj.age=18
setattr(obj,'age',18)
print(obj.__dict__)
#{'name': 'aaa', 'age': 18}
print(People.__dict__)
#{'__module__': '__main__', 'country': 'China', '__init__': <function People.__init__ at 0x1007d5620>, 'people_info': <function People.people_info at 0x10215d1e0>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None, 'x': 111}

1.3.4. delattr()函數(shù)

描述:

  delattr函數(shù)用于刪除屬性

  delattr(x,'foobar)相當(dāng)于del x.foobar

語(yǔ)法:

  setattr(object,name)

參數(shù):

  object--對(duì)象

  name--必須是對(duì)象的屬性

返回值:

  無(wú)

示例:

class People:
    country='China'
    def __init__(self,name):
        self.name=name

    def people_info(self):
        print('%s is xxx' %(self.name))

delattr(People,'country') #等同于del People.country
print(People.__dict__)
{'__module__': '__main__', '__init__': <function People.__init__ at 0x1006d5620>, 'people_info': <function People.people_info at 0x10073d1e0>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
補(bǔ)充示例

class Foo:
    def run(self):
        while True:
            cmd=input('cmd>>: ').strip()
            if hasattr(self,cmd):
                func=getattr(self,cmd)
                func()

    def download(self):
        print('download....')

    def upload(self):
        print('upload...')

# obj=Foo()
# obj.run()
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容