动态惰性 class 属性 python

Dynamic lazy class properties python

我有一个class,记录,用来包含读取文本文件的结果。该文件包含一个带有字段和标签的简单数据库。我想让每个 Record 实例只具有与其数据库关联的属性。基本上:

R1 = Record("file1")
R2 = Record("file2")
print(R1.TI) #"Record 1's title"
print(R2.TI) #AttributeError: 'Record' object has no attribute 'TI'

不幸的是,某些字段可能需要大量处理才能 return 一些有用的东西,并且可能永远不需要这些值。所以我希望在第一次调用它们时确定该值,而不是在初始化对象时确定。

因为我只知道标签名称,所以我尝试过:

 class tagWrapper(object):
     def __init__(self, tag):
         self.tag = tag
         self.data = None
     def __get__(self, instance, owner):
         if self.data == None:
             try:
                 #tagToFunc is a dictionary that maps tags to their processing function
                 self.data = tagToFunc[self.tag](instance._rawDataDict[self.tag]) 
             except KeyError: #I do not know the full list of tags
                 self.data = instance._rawDataDict[self.tag]
         return self.data

 class Record(object):
     def __init__(self, file):
         #Reading file and making _rawDataDict
         setattr(self, tag, tagWrapper(tag))

这导致 R1.TI 生成包装器对象而不是我想要的值。所以我怀疑我用 get 方法搞砸了。

注意: 我正在尝试使属性成为单个 class 实例的一部分 在需要时才进行评估。我可以实施一个或另一个,但无法确定如何同时执行这两个操作。

您正在实现描述符协议,并且描述符属于 class 而不是 class 的实例,因此您不能将其分配给实例属性。

class Tag(object):
     def __init__(self, tag):
         self.tag = tag
         self.data = None

     def __get__(self, instance, owner):
         if not instance:  # if accessed with the class directly, ie. Record.T1, just return this descriptor
             return self
         if self.data is None:
             print "Reading data"
             self.data = range(10)
         return self.data

 class Record(object):
     T1 = Tag('T1')

我有一个似乎可行的解决方案,虽然它很丑陋:

class Record(object):
   def __init__(self, file):
     self._unComputedTags = set() #needs to be initialized first
      #stuff
      self._unComputedTags = set(self._fieldDict.keys())
      for tag in self._fieldDict:
            self.__dict__[tag] = None

   def __getattribute__(self, name):
       if name == '_unComputedTags':
           #This may be unnecessary if I play with things a bit
           return object.__getattribute__(self, '_unComputedTags')
       if name in self._unComputedTags:
           try:
               tagVal = tagToFunc[name](self._fieldDict[name])
           except KeyError:
               tagVal = self._fieldDict[name]
           setattr(self, name, tagVal)
           self._unComputedTags.remove(name)
       return object.__getattribute__(self, name)

我不喜欢覆盖 __getattribute__ 但这似乎可行。