1. 程式人生 > 實用技巧 >字典屬性化訪問Dict2Obj & __setattr__的思考

字典屬性化訪問Dict2Obj & __setattr__的思考

class B:
    def __setattr__(self,key,value):
        pass
        raise NotImplementedError

類方法__setattr__覆蓋父類方法後,如果為pass, raise NotImplementedError之類的,則例項不能設定任何屬性

pass不會報錯,raise NotImplementedError會拋異常

但是類可以繼續增加屬性,__setattr__為例項方法

但是例項的__dict__為一個空dict,這是__new__方法建立例項的時候已經建立好的,在__setattr__之前,

所以可以通過直接操作例項的__dict__來變相新增屬性

class B:
    def __setattr__(self,key,value):
        raise NotImplementedError('{} can\'t set attribute!'.format(self))

b=B()
print(b.__dict__)
b.a=33

  

class B:
    def __setattr__(self,key,value):
        raise NotImplementedError('{} can\'t set attribute!
'.format(self)) b=B() print(b.__dict__) b.__dict__['v']=33 print(b.__dict__)
print(b.v)

class Dict2Obj(object):
    def __init__(self,d:dict):
        # self._dict=d
        self.__dict__={'_dict':d}
        # self.b=33

    def __getattr__(self,item):
        try:
            # def __setattr__: pass,I.__dict__ 
== {},取self._dict時,又會呼叫__getattr__ return self._dict[item] # return getattr(self._dict,item) # AttributeError: 'dict' object has no attribute 'b' # return getattr(self,item) # 本身就是.訪問 except KeyError: raise AttributeError('Attribute {!a:} not found!'.format(item)) def __setattr__(self,key,value): pass

上面的會產生迴圈呼叫

self._dict=d
self.__dict__={'_dict':d}
self.b=33

都會呼叫__setattr__,不會產生作用

getattr(object,name,default=None) 內建函式也是呼叫__getattr__

self._dict[item]本身就是訪問例項屬性

Corrent Sample:

d={
    'b':22,
    'bb':33
}

class Dict2Obj(object):
    def __init__(self,d:dict):
        # self.__dict__={'_dict':d}  # 覆蓋例項建立時的字典,依然會呼叫__setattr__
        if not isinstance(d,(dict,)):
            self.__dict__['_dict']={}
        else:
            self.__dict__['_dict']=d

    def __getattr__(self,item):
        try:
            return self._dict[item]
        except KeyError:
            raise AttributeError('Attribute {} not found!'.format(item))

    def __setattr__(self,key,value):
        raise NotImplementedError

b=Dict2Obj(d)
print(b.__dict__)
print(b.b,b.bb)

不允許動態增加屬性,通過__dict__依然可以增加,不提倡