【发布时间】:2014-03-17 15:27:12
【问题描述】:
问题
如何扩展 python 属性?
子类可以通过在重载版本中调用超类的功能,然后对结果进行操作来扩展超类的功能。下面是我所说的“扩展函数”的一个例子:
# Extending a function (a tongue-in-cheek example)
class NormalMath(object):
def __init__(self, number):
self.number = number
def add_pi(self):
n = self.number
return n + 3.1415
class NewMath(object):
def add_pi(self):
# NewMath doesn't know how NormalMath added pi (and shouldn't need to).
# It just uses the result.
n = NormalMath.add_pi(self)
# In NewMath, fractions are considered too hard for our users.
# We therefore silently convert them to integers.
return int(n)
是否有类似于扩展函数的操作,但对于使用属性装饰器的函数?
我想在获得计算成本高的属性后立即进行一些额外的计算。我需要保持属性的访问惰性。我不希望用户必须调用一个特殊的例程来进行计算。基本上,我不希望用户知道计算是首先进行的。但是,该属性必须保留为属性,因为我有需要支持的遗留代码。
也许这是装饰师的工作?如果我没记错的话,装饰器是一个包装另一个函数的函数,我希望用更多的计算来包装一个属性,然后再次将其呈现为一个属性,这似乎是一个类似的想法......但我不太清楚。
我的具体问题
我有一个基类 LogFile,它具有构造成本高的属性 .dataframe。我已经将它实现为一个属性(使用属性装饰器),所以在我请求数据帧之前它实际上不会解析日志文件。到目前为止,它工作得很好。我可以构造一堆(100 多个)LogFile 对象,并使用更便宜的方法来过滤并仅选择要解析的重要对象。每当我一遍又一遍地使用同一个 LogFile 时,我只需要在第一次访问数据帧时解析它。
现在我需要编写一个 LogFile 子类 SensorLog,它在基类的数据帧属性中添加了一些额外的列,但我不太清楚调用超类的数据帧构造的语法例程(对它们的内部工作一无所知),然后对生成的数据帧进行操作,然后然后缓存/返回它。
# Base Class - rules for parsing/interacting with data.
class LogFile(object):
def __init__(self, file_name):
# file name to find the log file
self.file_name = file_name
# non-public variable to cache results of parse()
self._dataframe = None
def parse(self):
with open(self.file_name) as infile:
...
...
# Complex rules to interpret the file
...
...
self._dataframe = pandas.DataFrame(stuff)
@property
def dataframe(self):
"""
Returns the dataframe; parses file if necessary. This works great!
"""
if self._dataframe is None:
self.parse()
return self._dataframe
@dataframe.setter
def dataframe(self,value):
self._dataframe = value
# Sub class - adds more information to data, but does't parse
# must preserve established .dataframe interface
class SensorLog(LogFile):
def __init__(self, file_name):
# Call the super's constructor
LogFile.__init__(self, file_name)
# SensorLog doesn't actually know about (and doesn't rely on) the ._dataframe cache, so it overrides it just in case.
self._dataframe = None
# THIS IS THE PART I CAN'T FIGURE OUT
# Here's my best guess, but it doesn't quite work:
@property
def dataframe(self):
# use parent class's getter, invoking the hidden parse function and any other operations LogFile might do.
self._dataframe = LogFile.dataframe.getter()
# Add additional calculated columns
self._dataframe['extra_stuff'] = 'hello world!'
return self._dataframe
@dataframe.setter
def dataframe(self, value):
self._dataframe = value
现在,当在交互式会话中使用这些类时,用户应该能够以相同的方式与其中任何一个进行交互。
>>> log = LogFile('data.csv')
>>> print log.dataframe
#### DataFrame with 10 columns goes here ####
>>> sensor = SensorLog('data.csv')
>>> print sensor.dataframe
#### DataFrame with 11 columns goes here ####
我有很多现有代码,它们采用 LogFile 实例,该实例提供 .dataframe 属性并执行一些有趣的操作(主要是绘图)。我希望 SensorLog 实例呈现相同的界面,以便它们可以使用相同的代码。是否可以扩展超类的数据帧获取器以利用现有例程?如何?还是我最好换一种方式?
感谢您阅读那堵巨大的文字墙。亲爱的读者,您是互联网超级英雄。有什么想法吗?
【问题讨论】:
标签: python inheritance properties extends