所以我试图实现一个包含字典值和延迟评估属性的混合类。我希望在语法上能够通过__getitem__
和__getattr__
访问类中的项目,并以相同的方式设置它们的值,但在存在时使用属性when和setter。
我设想如何实现这个的一些示例代码:
class C(object):
def __init__(self):
self.data = {'akey':'avalue'}
self.att1 = '1st attribute'
self._prop1 = None
def __getitem__(self,key):
try:
self.__dict__[key]
except KeyError:
return self.data[key]
def __setitem__(self,key,val):
self.data[key] = val
def __getattr__(self,name):
try:
self.__dict__[name]
except KeyError:
return self.data[name]
def __setattr__(self,name,val):
try:
self.__dict__[name] = val
except KeyError:
self.data[name] = val
@property
def prop1(self):
#do expensive stuff here in real class
return self._prop1
@prop1.setter
def prop1(self,newval):
#check/change value for prop1
self._prop1 = str(newval).upper()
属性访问适用于属性,但不适用于__getitem__
方法。
In [35]: c = C()
In [36]: c.prop1
Out[36]: 'Prop1 Calc Value'
In [37]: c['prop1']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
C:\Users\someuser\somepath\foo.py in __getitem__(self, key)
8 try:
----> 9 self.__dict__[key]
10 except KeyError:
KeyError: 'prop1'
During handling of the above exception, another exception occurred:
KeyError Traceback (most recent call last)
C:\Users\someuser\somepath\foo.py in <module>()
----> 1 c['prop1']
C:\Users\someuser\somepath\foo.py in __getitem__(self, key)
9 self.__dict__[key]
10 except KeyError:
---> 11 return self.data[key]
12
13 def __setitem__(self,key,val):
KeyError: 'prop1'
我认为这是因为我不完全理解@property
装饰器在课堂上是如何工作的,但如果有一种惯用的方法可以解决这个问题,我很乐意听到它!我知道它真的是语法糖,但是对于类具有灵活的属性访问并且仍然能够支持不是有效的python变量名的键会很好。 pandas.DataFrame / collections.namedtuple api是这方面的灵感来源。
Thansk向@Jim Fasarakis-Hilliard指出我正确的方向,以下代码在我的系统上工作(python 3.5):
class C(object):
def __init__(self):
self.data = {'akey':'avalue'}
self.att1 = '1st attribute'
self._prop1 = None
def __getitem__(self,key):
try:
return self.__dict__[key]
except KeyError:
try:
return getattr(type(self), key).__get__(self)
except AttributeError:
return self.data[key]
__getattr__ = __getitem__
def __setitem__(self,key,value):
#note order is look for property 1st so that any
#setter methods get used insead of attribute access
try:
getattr(type(self), key).__set__(self,value)
except AttributeError:
try:
self.__dict__[key] = value
except KeyError:
self.data[key] = value
__setattr__ = __setitem__
@property
def prop1(self):
#do expensive stuff here in real class
if not self._prop1:
self._prop1='Prop1 Calc Value'
return self._prop1
@prop1.setter
def prop1(self,newval):
#check/change value for prop1
print('using setter')
self._prop1 = str(newval).upper()
In [62]: c = C()
In [63]: c['prop1']
Out[63]: 'Prop1 Calc Value'
In [64]: c['prop1'] = 'new value'
using setter
In [65]: c['prop1']
Out[65]: 'NEW VALUE'
In [66]: c.akey
Out[66]: 'avalue'
In [67]: c.att1
Out[67]: '1st attribute'
答案 0 :(得分:2)
我猜你希望你的实例能够通过下标符号访问描述符;我不知道你为什么要这么做,但属性存在于类名称空间中,所以你需要看看那里。
试着从类的dict中获取描述符并调用它:
def __getitem__(self,key):
try:
return self.__dict__[key]
except KeyError:
try:
return getattr(type(self), key).__get__(self)
except KeyError:
return self.data[key]
然后(我猜)你可以做你想做的事:
>>> c = C()
>>> c['prop1']
'prop1'