Python - 像扩展函数一样扩展属性

2023-11-22

Question

如何扩展 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 子类,传感器日志,这向基类的数据帧属性添加了一些额外的列,但我无法完全弄清楚调用超类的数据帧构造例程的语法(不知道其内部工作原理),然后对生成的数据帧进行操作,并且then缓存/返回它。

# 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属性并做一些有趣的事情(主要是绘图)。我很想拥有传感器日志实例呈现相同的接口,因此它们可以使用相同的代码。是否可以扩展超类的数据帧获取器以利用现有例程?如何?或者我最好以不同的方式来做这件事?

感谢您阅读那面巨大的文字墙。亲爱的读者,您是互联网超级英雄。有什么想法吗?


您应该调用超类属性,而不是通过绕过它们self._dataframe。这是一个通用示例:

class A(object):

    def __init__(self):
        self.__prop = None

    @property
    def prop(self):
        return self.__prop

    @prop.setter
    def prop(self, value):
        self.__prop = value

class B(A):

    def __init__(self):
        super(B, self).__init__()

    @property
    def prop(self):
        value = A.prop.fget(self)
        value['extra'] = 'stuff'
        return value

    @prop.setter
    def prop(self, value):
        A.prop.fset(self, value)

并使用它:

b = B()
b.prop = dict((('a', 1), ('b', 2)))
print(b.prop)

Outputs:

{'a': 1, 'b': 2, 'extra': 'stuff'}

我通常建议将副作用放在 setters 而不是 getters 中,如下所示:

class A(object):

    def __init__(self):
        self.__prop = None

    @property
    def prop(self):
        return self.__prop

    @prop.setter
    def prop(self, value):
        self.__prop = value

class B(A):

    def __init__(self):
        super(B, self).__init__()

    @property
    def prop(self):
        return A.prop.fget(self)

    @prop.setter
    def prop(self, value):
        value['extra'] = 'stuff'
        A.prop.fset(self, value)

通常也应该避免在 getter 中进行昂贵的操作(例如解析方法)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python - 像扩展函数一样扩展属性 的相关文章

随机推荐

  • Roslyn 中的委托缓存行为发生变化

    给出以下代码 public class C public void M var x 5 Action
  • 在 numpy 中索引 3d 网格数据的球形子集

    我有一个带有坐标的 3d 网格 x linspace 0 Lx Nx y linspace 0 Ly Ny z linspace 0 Lz Nz 我需要在位置 x0 y0 z0 的某个半径 R 内索引点 即 x i y j z k N i
  • 使用 Django-storages 删除 Amazon S3 中的文件

    在我的 Django 项目中 我使用 Django storageS 将媒体文件保存在我的 Amazon S3 中 我跟着这个tutorial 我也使用 Django rest framework 这对我来说效果很好 我可以上传一些图像 并
  • 离线观看带字幕的 HTML5 视频

    我正在尝试实现一个 HTML5 视频播放器 用于使用本地 HTML 文件观看本地视频 并且我希望具有 VTT 字幕和字幕功能 我目前正在使用VideoJS进行播放 但是 我的问题不是具体实施的 当我尝试使用 VTT 文件时 收到跨域错误 指
  • IQueryable、List、IEnumerator 之间的区别?

    我想知道 IQueryable List IEnumerator 之间有什么区别以及何时应该使用它们 例如 当使用 Linq to SQL 时 我会这样做 public List
  • 将 Google 表中的日期区域设置从公历转换为 Jalali 日历

    我想知道谷歌表格中是否可以使用函数将公历转换为贾拉利历 事实上 我有一些日期 例如 February 20 2021 4 30 AM 我需要以 Jalali 格式 没有时间 在其前面的单元格中显示此日期 即 1399 12 02 or Es
  • Node.js 什么时候会阻塞?

    我已经使用 Node js 一段时间了 我刚刚意识到它可能会阻塞 我就是无法理解 Node js 在什么情况下会发生阻塞 因此 Node js 是单线程的 因为 i Javascript 是并且 ii 避免了所有多线程陷阱 要同时做很多事情
  • Gitlab 与 Github 相比有何不同?

    我试图从经验丰富的开发人员的角度来理解两者的优缺点 当然 Github 是两者中使用更广泛的一个 但如果有人能概括性地解释一下他们发现其中哪一个更好 缺乏什么 那就太好了 顺便说一句 我现在使用 Github Gitlab 是一个自托管的
  • 退出iPhone应用程序的正确方法?

    我正在编写一个 iPhone 应用程序 由于某些用户操作 我需要强制它退出 清理应用程序分配的内存后 调用什么适当的方法来终止应用程序 在 iPhone 上 没有退出应用程序的概念 导致应用程序退出的唯一操作是触摸手机上的 主页 按钮 而开
  • Azure Active Directory 是否具有 OAuth/OpenID Connect 令牌自省端点?

    Azure Active Directory 是否具有自省端点 如中定义 RFC7662 用于验证 OpenID Connect 或 OAuth 访问令牌 否 您可以通过以下方式检查支持的所有端点OpenID 提供商配置对于 Azure A
  • 如何计算直方图的标准差? (Python、Matplotlib)

    假设我有一个数据集并使用 matplotlib 绘制该数据集的直方图 n bins patches plt hist data normed 1 如何使用以下公式计算标准差n and bins价值观hist 回报 我目前正在这样做来计算平均
  • Android 触摸秤按钮

    我知道如何将按钮缩放到确定的值 但是有没有办法在用户触摸按钮时每次增加 减小按钮大小 像这样的东西 Button myButton Button findViewById R id myButton myButton setOnTouchL
  • 检索泛型方法的正确重载的 MethodInfo

    我的这种类型包含一个泛型方法的两个重载 我喜欢检索其中一个重载 使用Func
  • 为什么“python -m pip install ...”需要“-m”?

    我最近使用pip安装了requestspython 2 7 中的包 但是为了做到这一点 我必须使用 python m pip install requests 而不仅仅是 python pip install requests 这给了我一个
  • jquery .bind() 是否已弃用?

    是 jquerybind 已弃用还是可以安全使用 我在评论和答案中看到很多关于 bind 被弃用的评论 例如 Jquery Event 检测 div 的 html text 的更改 是否有 JavaScript jQuery DOM 更改侦
  • 如何将 DataGridView 定位到特定行(以便所选行位于底部)?

    作为一个类似的问题这个问题 我还有一个带有 DataGridView 的应用程序 我想定位行 使特定行位于列表可见部分的底部 这是对将一行向下移动一位的按钮单击的响应 我想保留我正在移动的行上的选择 我已经让这部分工作 如果有很多行 所选行
  • 将数组从一页传递到另一页

    我有一个包含一些值的数组 比如说 arr one one value here arr two second value here arr three third value here 我这个值位于页面 home php 中 在页面末尾 它
  • dart:js 和 js 包有什么区别?

    Dart 文档中的所有地方都建议使用js用于 JavaScript 互操作性的包 然而 我最近发现dart jsSDK 中存在似乎具有相似 但不相同 接口的包 这些包之间有什么区别吗 它们的功能相同吗 推荐哪一款 Js 互操作始于包 js
  • application.yml 中的 @Value 返回错误值

    In my application yml文件声明 service a b 011600 c 011200 从中选择值 yml via Value注解 Value service a c private String VALUE 我得到的不
  • Python - 像扩展函数一样扩展属性

    Question 如何扩展 python 属性 子类可以通过在重载版本中调用超类的函数来扩展超类的函数 然后对结果进行操作 下面是我所说的 扩展函数 的一个例子 Extending a function a tongue in cheek