2012-08-25 27 views
3

我在我的一个类建模json数据中有许多类似的字段。所有字段初始化为无,以帮助静态工具知道它们存在,然后帮助函数帮助基于他们正在建模的一块json数据对它们进行初始化(如果您想知道,请参考The SecondHandSongs API)。有没有更好的方法来为动态命名属性做一个getter属性?

某些数据只会检索您必须提取的额外数据的URI。所以我想使用将隐藏变量初始化为None并在首次请求时获取/解码数据的旧技巧。但setattr(self.__class__)看起来很丑。

有没有更好的方法来做(在python中动态设置属性)?

def _initialize_url_fields(self, attrNamesToFactoryFunction, json_data): 
    for (name, factoryFunction) in attrNamesToFactoryFunction.iteritems(): 
     try: 
      url = json_data[name] 
     except KeyError: 
      continue 
     setattr(self, name + "_url", url) 
     setattr(self, "_" + name, None)  
     setattr(self.__class__, name, property(lambda s: s._getter("_" + name, url, factoryFunction)))   

def _getter(self, hidden_prop_name, url, factoryFunction): 
    if not getattr(self, hidden_prop_name): 
     json_data = SHSDataAcess.getSHSData(url) 
     setattr(self, hidden_prop_name, factoryFunction(json_data)) 
    return getattr(self, hidden_prop_name) 

编辑: 我刚刚意识到我试图从称为实例方法初始化 设置属性。可以预料,它第二次失败了。

编辑2:

这里的意识到我设置每个对象的属性(不可能的,如果没有一个单独的类)

class ShsData(object): 
    def _initialize_url_fields(self, attrNamesToFactoryFunctions, json_data): 
     for (name, factoryFunction) in attrNamesToFactoryFunctions.items(): 
      self._getter_factory_functions[name] = factoryFunction 
      uri = None 
      try: 
       uri = json_data[name] 
      except KeyError: 
       pass 
      setattr(self, name + "_uri", uri) 
      setattr(self, "_" + name, None) 

def _fetch_shs_data_on_first_access_getter(base_prop_name): 
    def getter(self): 
     factoryFunction = self._getter_factory_functions[base_prop_name] 
     hidden_prop_name = "_" + base_prop_name 
     uri_prop_name = base_prop_name + "_uri" 
     if not getattr(self, hidden_prop_name): 
      if getattr(self, uri_prop_name): 
       json_data = SHSDataAcess.getSHSData(getattr(self, uri_prop_name)) 
       setattr(self, hidden_prop_name, factoryFunction(json_data)) 
      else: 
       return None 
     return getattr(self, hidden_prop_name) 
    return getter 

class ShsArtist(ShsData): 

    performances_data = property(_fetch_shs_data_on_first_access_getter("performances")) 
    creditedWorks_data = property(_fetch_shs_data_on_first_access_getter("creditedWorks")) 
    releases_data = property(_fetch_shs_data_on_first_access_getter("releases")) 

    def __init__(self, json_data): 
     ... 
     self._initialize_url_fields({"performances": lambda xs: [ShsPerformance(x) for x in xs], 
            "creditedWorks": lambda xs: [ShsWork(x) for x in xs], 
            "releases": lambda xs: [ShsRelease(x) for x in xs]}, 
            json_data) 
+3

另一种方法是使用自定义的'__getattr__',但不会我会说更漂亮一点。 –

+0

属性有什么问题:http://docs.python.org/howto/descriptor.html。我相信你可以使用缓存修饰器来构建它。 – Marcin

+0

@Marcin:请注意,OP已经在使用属性,动态分配它们。 –

回答

0

我可以继承财产来处理您的常见情况后,我如何修复它。事情是这样的:

class shs_klass_property(property): 

    def __init__(self, name, klass): 
     self.name = name 
     self.klass = klass 
     self.cached_name = '_%s' % name 
     super(shs_klass_property, self).__init__(self.compute) 

    def compute(self, obj): 
     if not hasattr(obj, self.cached_name): 
      if self.name in obj._json_data: 
       # if needed handle cases where this isn't a list 
       val = [self.klass(x) for x in obj._json_data[self.name]] 
      else: 
       val = None 
      setattr(obj, self.cached_name, val) 
     return getattr(obj, self.cached_name) 

class ShsData(object): 
    def __init__(self, json_data): 
     self._json_data = json_data 

class ShsWork(ShsData): 
    pass 

class ShsArtist(ShsData): 
    works = shs_klass_property('works', ShsWork) 

如果你总是要设置的URI,以及,你可以这样做:

# if you change this to pass in "_json_data" too, 
# you'd have a simple general purpose delegation decorator 
class shs_json_property(property): 

    def __init__(self, name): 
     self.name = name 
     super(shs_json_property, self).__init__(self.compute) 

    def compute(self, obj): 
     return obj._json_data.get(self.name, None) 

# a helper to set both. not necessary but saves a line of code. 
def shs_property_pair(name, klass): 
    return (shs_klass_property(name, klass), 
      shs_json_property(name)) 

class ShsArtist(ShsData): 
    works, works_uri = shs_property_pair('works', ShsWork) 
相关问题