如何使用动态名称实现property()(在python中)

时间:2009-01-05 12:19:46

标签: python oop parameters properties

我正在为单个神经元编程模拟。因此我必须处理很多参数。现在的想法是我有两个类,一个用于SingleParameter,一个用于参数集合。我使用property()来轻松访问参数值并使代码更具可读性。这适用于sinlge参数,但我不知道如何为集合实现它,因为我想在SingleParameter之后命名Collection中的属性。这是一个例子:

class SingleParameter(object):
  def __init__(self, name, default_value=0, unit='not specified'):
    self.name = name
    self.default_value = default_value
    self.unit = unit
    self.set(default_value)
  def get(self):
    return self._v
  def set(self, value):
    self._v = value
  v = property(fget=get, fset=set, doc='value of parameter')

par1 = SingleParameter(name='par1', default_value=10, unit='mV')
par2 = SingleParameter(name='par2', default_value=20, unit='mA')

# par1 and par2 I can access perfectly via 'p1.v = ...'
# or get its value with 'p1.v'

class Collection(object):
  def __init__(self):
    self.dict = {}
  def __getitem__(self, name):
    return self.dict[name] # get the whole object
    # to get the value instead:
    # return self.dict[name].v
  def add(self, parameter):
    self.dict[parameter.name] = parameter
    # now comes the part that I don't know how to implement with property():
    # It shoule be something like
    # self.__dict__[parameter.name] = property(...) ?

col = Collection()
col.add(par1)
col.add(par2)
col['par1'] # gives the whole object

# Now here is what I would like to get:
# col.par1 -> should result like col['par1'].v
# col.par1 = 5 -> should result like col['par1'].v = 5

我理解属性()的其他问题:

7 个答案:

答案 0 :(得分:10)

查看内置函数getattrsetattr。你可能会更开心。

答案 1 :(得分:7)

对两个类使用相同的get / set函数会强制您使用参数列表进行丑陋的黑客攻击。非常粗略,我就是这样做的:

在Class SingleParameter中,像往常一样定义get和set:

def get(self):
  return self._s
def set(self, value):
  self._s = value

在类Collection中,在创建属性之前无法知道这些信息,所以你要定义metaset / metaget函数,稍后再使用lambda函数对它们进行详细说明:

def metaget(self, par):
  return par.s
def metaset(self, value, par):
  par.s = value
def add(self, par):
  self[par.name] = par
  setattr(Collection, par.name,
    property(
      fget=lambda x : Collection.metaget(x, par),
      fset=lambda x, y : Collection.metaset(x,y, par))

答案 2 :(得分:5)

属性用于动态评估属性或使其成为只读属性。您需要的是自定义属性访问。 __getattr____setattr__做得非常好,如果__getattribute__还不够,还有__getattr__

有关详细信息,请参阅Python docs on customizing attribute access

答案 3 :(得分:3)

你看过traits package了吗?看来你正在用你的参数类重新发明轮子。特征还具有可能对您的应用类型有用的其他功能(我非常熟悉一个在神经模拟中愉快地使用特征的人)。

答案 4 :(得分:2)

现在我用set- / getattr实现了一个解决方案:

class Collection(object):
...
  def __setattr__(self, name, value):
    if 'dict' in self.__dict__:
      if name in self.dict:
        self[name].v = value
    else:
      self.__dict__[name] = value
  def __getattr__(self, name):
    return self[name].v

有一件事我不太喜欢:属性不在__dict__中。如果我在那里也有它,我会得到一个价值的副本 - 这可能是危险的......

答案 5 :(得分:0)

最后,我成功使用property()实现了这些类。非常感谢您的建议。我花了很多时间来解决它 - 但我可以向你保证,这个练习可以帮助你理解更好的蟒蛇OOP。

我也使用__getattr__和__setattr__实现了它,但仍然不知道属性解决方案的优点和缺点。但这似乎值得另一个问题。物业解决方案似乎已经放弃了。

所以这是代码:

class SingleParameter(object):
  def __init__(self, name, default_value=0, unit='not specified'):
    self.name = name
    self.default_value = default_value
    self.unit = unit
    self.set(default_value)
  def get(*args):
    self = args[0]
    print "get(): "
    print args
    return self._v
  def set(*args):
    print "set(): "
    print args
    self = args[0]
    value = args[-1]
    self._v = value
  v = property(fget=get, fset=set, doc='value of parameter')

class Collection(dict):
  # inheriting from dict saves the methods: __getitem__ and __init__
  def add(self, par):
    self[par.name] = par
    # Now here comes the tricky part.
    # (Note: this property call the get() and set() methods with one
    # more argument than the property of SingleParameter)
    setattr(Collection, par.name,
      property(fget=par.get, fset=par.set))

# Applying the classes:
par1 = SingleParameter(name='par1', default_value=10, unit='mV')
par2 = SingleParameter(name='par2', default_value=20, unit='mA')
col = Collection()
col.add(par1)
col.add(par2)
# Setting parameter values:
par1.v = 13
col.par1 = 14
# Getting parameter values:
par1.v
col.par1
# checking identity:
par1.v is col.par1
# to access the whole object:
col['par1']

我是新手,我不知道如何继续前进: 如何处理后续问题(像这样):

  • get()似乎被调用了两次 - 为什么?
  • oop-design:property vs.“__ getattr__& __setattr__” - 我什么时候应该使用什么?
  • 接受时检查自己对自己问题的答案是不礼貌的?
  • 是否建议重新命名标题,以便将相同的问题或用同一个例子详细阐述的问题放在同一个背景中?

我理解属性()的其他问题:

答案 6 :(得分:0)

我有一个类似的东西,但我在集合对象中做了以下事情:

setattr(self,par.name,par.v)