我正在使用dict对象来保存类中的实例值。我喜欢使用dict,因为我经常想要同时设置或获取一堆值,并且很容易通过列表或字典来完成此操作。例如,为了获得几个实例值,我可以传递一个[键列表]并返回{这些键的值:值}。据我所知,使用每个键的单独属性执行此操作需要跳过很多代码箍(如果可能的话)。
无论如何,我正在寻找这样的东西:
class SomeClass(object):
def __init__(self):
self._desc = {
'hair': 'brown'
'eyes': 'blue'
'height': 1.55
}
到目前为止,这一切都非常简单,但有些值需要特殊的“设置”条件。我的第一次尝试是这样的:
class SomeClass(object):
def __init__(self):
self._haircolor = 'blonde'
self._eyecolor = 'green'
self._desc = {
'haircolor': self.haircolor
'eyecolor': self.eyecolor
'height': 1.55
}
@property
self.haircolor(self):
return self._haircolor
@haircolor.setter
self.haircolor(self, color):
if color.lower() in ['blonde', 'brunette', 'brown', 'black', 'auburn', 'red']:
self._haircolor = color
else: raise ValueError()
# Same type of property construct for eyecolor
这不起作用。 self._desc ['haircolor']会初始化为'blonde',但它与属性构造或self._haircolor属性没有动态关系。我尝试用
替换它class SomeClass(object):
def __init__(self):
self._haircolor = 'blonde'
self._eyecolor = 'green'
self._desc = {
'haircolor': property(self.get_haircolor, self.set_haircolor)
'eyecolor': property(self.get_eyecolor, self.set_eyecolor)
'height': 1.55
}
self.get_haircolor(self):
return self._haircolor
self.set_haircolor(self, color):
if color.lower() in ['blonde', 'brunette', 'brown', 'black', 'auburn', 'red']:
self._haircolor = color
else: raise ValueError()
但是这种方式以不同的方式失败了。
print self._desc['haircolor']
将为属性对象返回 str ,并
self._desc['haircolor'] = 'brunette'
销毁了属性对象并将其替换为字符串。
我研究了一些类似的问题,例如this one和this one。
然而,这两种情况都在词典层面运作。问题在于,当我定义自定义dict类时,我需要了解很多有关dict的知识,因为我需要预测键名并在 setitem (第一个示例)或dict级别中切换它们属性对象(第二个例子)。理想情况下,我想将setter与值对象本身相关联,因此dict不需要知道key可以引用的值有什么特别之处。
答案 0 :(得分:3)
Python对象已经在dict中存储了属性,那么在这里使用另一个dict有什么意义呢?只需按常规方式存储属性(使用有意义的属性),并在需要时动态构建desc
dict。
class SomeClass(object):
HAIRCOLORS = set(['blonde', 'brunette', 'brown', 'black', 'auburn', 'red'])
EYECOLORS = set(['green', 'blue', 'brown', 'gray'])
def __init__(self, haircolor="blond", eyecolor="green"):
self.haircolor = haircolor
self.eyecolor = eyecolor
self.height = 1.55 # you didn't mention any validation here
@property
def haircolor(self):
return self._haircolor
@haircolor.setter
def haircolor(self, color):
color = color.lower()
if color not in self.HAICOLORS:
raise ValueError("'%s' is not a valid hair color" % color)
self._haircolor = color
# same thing for eyecolor
@property
def desc(self):
return dict(
haircolor=self.haircolor,
eyecolor=self.eyecolor,
height=self.height)
如果这是一个重新安排模式,你最终可以编写自己的描述符:
class ChoiceDescriptor(object):
def __init__(self, key, choices):
self.key = key
self.storage = "_%s" % key
self.choices = set(choices)
def __get__(self, instance, cls=None):
if instance is None:
return self
return getattr(instance, self.storage)
def __set__(self, instance, value):
value = value.lower()
if value not in self.choices:
raise ValueError(
"'%s' is not a valid value for '%s'" % (value, self.key))
setattr(instance, self.storage, value)
class SomeClass(object):
haircolor = ChoiceDescriptor("haircolor",
['blonde', 'brunette', 'brown', 'black', 'auburn', 'red'])
eyecolor = ChoiceDescriptor("eyecolor",
['green', 'blue', 'brown', 'gray'])
答案 1 :(得分:1)
如果使用self._desc['haircolor']
来获取/设置其值,它将调用dict的__getitem__()
/ __setitem__()
方法,无论该值是否为描述符。
如果您想访问描述符,访问它的方法是使用类似instance.descrip
的内容,因为此时它会调用__getattribute__()
方法,如果描述是描述符,它将使用相应的setter
和getter
方法,否则会将其视为普通属性。这是关于descriptor
您只想控制在dict中调用键的方式?您可以参考此问题Python: How to “perfectly” override a dict来覆盖类似dict的类中的__getitem__()
和__setitem__()
方法。这并不复杂,您应该做的就是创建一个这样的类,然后使用它就好像它是一个 dict 类型变量。
之后,使用新的类似dict的类生成self._desc
变量,并根据需要获取或设置self._desc['haircolor']
之类的内容。
答案 2 :(得分:0)
如前所述:Python对象已经将属性存储在dict中,因此您可以在" desc"中代理它。
class SomeClass(object):
def __init__(self, d):
self.__dict__ = d
@property
def desc(self):
return self.__dict__
你也可以从这个类继承,以更新对象:
class objdict(dict):
def __getattr__(self, name):
if name in self:
return self[name]
else:
raise AttributeError("No such attribute: " + name)
def __setattr__(self, name, value):
self[name] = value
def __delattr__(self, name):
if name in self:
del self[name]
else:
raise AttributeError("No such attribute: " + name)
或使用named tuples
答案 3 :(得分:0)
我有一个类似的案例并使用descriptor管理它:
class Description(object):
""" Descriptor which gets/sets value from instances _desc attribute via key."""
def __init__(self,key):
self.key = key
def __get__( self, instance, owner ):
return instance._desc[self.key]
def __set__( self, instance, value ):
if self.key in instance._constraints:
if value in instance._constraints[self.key]:
instance._desc[self.key] = value
else:
print('Not allowed.')
else:
instance._desc[self.key] = value
class Person(object):
_constraints = {'hair':['brown','blonde']}
def __init__(self):
self._desc = {
'hair': 'brown',
'eyes': 'blue',
'height': 1.55,
}
hair = Description('hair')
eyes = Description('eyes')
height = Description('height')
现在我们可以:
p = Person()
p.hair = 'purple'
将打印'不允许。'因为价值'紫色'不符合约束条件。
p.eyes = 1
设置眼睛'到1。