插件是否应该添加新的实例方法猴子补丁或子类/混合并替换父类?

2023-12-20

举一个简单的例子,以一个类为例Polynomial

class Polynomial(object):
     def __init__(self, coefficients):
         self.coefficients = coefficients

对于以下形式的多项式p(x) = a_0 + a_1*x + a_2*x^2 + ... + a_n*x^n列表在哪里coefficients = (a_0, a_1, ..., a_n)存储这些系数。

一个插件模块horner然后可以提供一个函数horner.evaluate_polynomial(p, x)评估一个Polynomial实例p按价值x,即返回值p(x)。但不是以这种方式调用函数,而是调用p.evaluate(x)(或者更直观地p(x) via __call__ http://docs.python.org/2/reference/datamodel.html#emulating-callable-objects) 会更好。但应该怎么做呢?

a) 猴子补丁,即

Polynomial.evaluate = horner.evaluate_polynomial
# or Polynomial.__call__ = horner.evaluate_polynomial

b) 子类化和替换类,即

orgPolynomial = Polynomial
class EvaluatablePolynomial(Polynomial):
    def evaluate(self, x):
        return horner.evaluate_polynomial(self, x)
Polynomial = EvaluatablePolynomial

c) 混合+替换,即

orgPolynomial = Polynomial
class Evaluatable(object):
    def evaluate(self, x):
        return horner.evaluate_polynomial(self, x)
class EvaluatablePolynomial(Polynomial, Evaluatable):
    pass
Polynomial = EvaluatablePolynomial

果然,猴子补丁是最短的(特别是因为我没有包含任何检查)hasattr(Polynomial, 'evaluate'),但类似地,子类应该调用super()那么...),但它是最 Pythonic 的吗?或者还有其他更好的选择吗?

特别是考虑多个插件提供相同功能的可能性,例如zeros要么使用numpy或者自制的二分法,当然只应该使用一个实现插件,哪种选择可能不太容易出错?


将函数直接修补到原始类而不是替换它的一个可能也是最重要的属性是,在加载插件之前对原始类的引用/实例现在也将具有新属性。在给定的示例中,这很可能是所需的行为,因此应该使用。

然而,在其他情况下,猴子补丁可能会以与其原始实现不兼容的方式修改现有方法的行为,并且修改后的类的先前实例应使用原始实现。诚然,这种情况不仅罕见,而且设计很糟糕,但您应该记住这种可能性。由于某些复杂的原因,代码甚至可能依赖于absence添加猴子补丁的方法,尽管这里似乎很难想出一个非人工的例子。

总之,除了少数例外,将方法猴子修补到原始类中(最好使用hasattr(...)修补之前检查)应该是首选方式。


edit我当前的做法:创建一个子类(用于更简单的代码完成和修补),然后使用以下内容patch(patching_class, unpatched_class) method:

import logging
from types import FunctionType, MethodType


logger = logging.getLogger(__name__)
applied_patches = []


class PatchingError(Exception):
    pass


def patch(subcls, cls):
    if not subcls in applied_patches:
        logger.info("Monkeypatching %s methods into %s", subcls, cls)
        for methodname in subcls.__dict__:
            if methodname.startswith('_'):
                logger.debug('Skipping methodname %s', methodname)
                continue
            # TODO treat modified init
            elif hasattr(cls, methodname):
                raise PatchingError(
                    "%s alrady has methodname %s, cannot overwrite!",
                    cls, methodname)
            else:
                method = getattr(subcls, methodname)
                logger.debug("Adding %s %s", type(method), methodname)
                method = get_raw_method(methodname, method)
                setattr(cls, methodname, method)
        applied_patches.append(subcls)


def get_raw_method(methodname, method):
    # The following wouldn't be necessary in Python3...
    # http://stackoverflow.com/q/18701102/321973
    if type(method) == FunctionType:
        logger.debug("Making %s static", methodname)
        method = staticmethod(method)
    else:
        assert type(method) == MethodType
        logger.debug("Un-bounding %s", methodname)
        method = method.__func__
    return method

悬而未决的问题是各个子类的模块是否应该直接调用patch导入时或应手动完成。我也在考虑为这样的修补子类编写一个装饰器或元类......

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

插件是否应该添加新的实例方法猴子补丁或子类/混合并替换父类? 的相关文章

  • 使用 PIP 从 Github 安装 Python 包

    我已经看到文档表明您可以通过以下方式使用 pip 安装托管 Python 包的 Github sudo pip install e git git github com myuser myproject git egg myproject
  • 带有元数据的 scipy kdtree

    我目前正在寻找一种方法来构建几个 kd 树以快速查询一些 n 维数据 但是 我对 scipy KD 树算法有一些问题 我的数据包括id gt data somedata coordinate x y 我希望能够基于坐标和 k 最近邻居的 i
  • 这段代码中list[:]的含义是什么? [复制]

    这个问题在这里已经有答案了 这段代码来自Python的文档 我有点困惑 words cat window defenestrate for w in words if len w gt 6 words insert 0 w print wo
  • numba.prange 性能不佳

    我试图整理一个简单的例子来说明使用的好处numba prange对于我自己和一些同事来说 但我无法获得像样的加速 我编写了一个简单的一维扩散求解器 它本质上是在一个长数组上循环 组合元素i 1 i and i 1 并将结果写入element
  • XGBoost 产生预测结果和概率

    我可能正在文档中查看它 但我想知道 XGBoost 是否有办法生成结果的预测和概率 就我而言 我正在尝试预测多类分类器 如果我能返回Medium 88 那就太好了 分类器 中 预测概率 88 参数 params max depth 3 ob
  • 在 Windows 7 上安装 Python Fabric 时出现问题

    我正在尝试使用以下指南在 Windows 7 上安装 Python Fabric在 Windows 上安装 Python 和 Fabric http www jonnyreeves co uk 2011 08 getting python
  • PyPDF2 复制后返回空白 PDF

    def EncryptPDFFiles password directory pdfFiles success 0 Get all PDF files from a directory for folderName subFolders f
  • 使用 Pandas 解析时避免 Excel 的科学记数法舍入

    我有一个自动生成的 Excel 文件 其中偶尔包含非常大的数字 例如135061808695 在 Excel 文件中 当您单击单元格时 它会显示完整的数字135061808695然而 在视觉上 使用自动 常规 格式 数字显示为1 35063
  • 加速 Numpy 数组上的循环

    在我的代码中 我有一个 for 循环 它对多维 numpy 数组进行索引 并使用每次迭代时获得的子数组进行一些操作 看起来像这样 for sub in Arr do stuff using sub 现在使用完成的东西sub是完全矢量化的 所
  • 如何将字符串列表转换为正确的 Python 类型?

    给定一个 python 字符串列表 如何自动将它们转换为正确的类型 意思是 如果我有 hello 3 3 64 1 我希望将其转换为列表 hello 3 3 64 1 其中第一个元素是字符串 第二个元素是 int 第三个元素是 float
  • Python OO程序结构规划

    我是 OOP 的初学者 我想创建一个包含三个类 A B 和 C 的程序 该类的每个实例都由一组特征 Achar1 Achar2 等定义 该程序应该创建uses由 A 元素 B 元素和 C 元素以及开始日期和结束日期组成 A 和 B 都有子类
  • 按共同日期对数组数据进行排序

    我有一个包含许多行和 3 列的 csv 文件 日期 代表和销售额 我想使用 Python 生成一个新数组 该数组按日期对数据进行分组 并且对于给定日期 按销售额对代表进行排序 例如 我的输入数据如下所示 salesData 201703 B
  • 如何在 Pandas 中将多列乘以一列

    我想拥有 df income 1 income 2 df mtaz proportion 返回这些列乘以df mtaz proportion 这样我就可以设置 df mtaz income 1 mtaz income 2 df income
  • 如何从 google place api for python 中的地点 id 获取地点详细信息

    我正在使用 Google Places API 和 Python 来构建一个食品集体智能应用程序 例如周围有哪些餐馆 他们的评级如何 营业时间是什么 等等 我正在Python中执行以下操作 from googleplaces import
  • 如何根据python中的文件名检索每个文件的datemodtime?

    我当前的流程涉及循环遍历源目录并将每个文件的名称添加到 python 中的数据帧中 我也想获取每个文件的修改日期 import datetime import os import pandas as pd set src directory
  • 树莓派上的 /dev/mem 访问被拒绝

    我正在使用我的 Raspberry Pi 并且正在编写一个 cgi python 脚本 该脚本创建一个网页来控制我的 gpio 输出引脚 当我尝试将 RPi GPIO 作为 GPIO 导入时 我的脚本崩溃了 这是我收到的错误 File co
  • 使用 South 更改 Django 模型列默认值

    我在 Django 项目中使用 South 和 Postgresql DB 我想更改一个模型字段的默认值以供继续使用 我不需要以前的记录 刚刚新记录 我是否需要为此进行迁移 或者只是更改模型 旧场详细信息 background style
  • Python,socket.error:[Errno 10049]

    在开发一个简单的聊天客户端的基础上 遇到以下错误 socket error Errno 10049 The requested address is not valid in its context 代码是 from socket impo
  • 将 pandas DataFrame 写入 unicode 中的 JSON

    我正在尝试将包含 unicode 的 pandas DataFrame 写入 json 但是内置的 to json函数对字符进行转义 我该如何解决 Example import pandas as pd df pd DataFrame a
  • 如何使用 google.oauth2 python 库?

    我试图对谷歌机器学习项目的安全预测端点进行简单的休息调用 但它找不到 google oauth2 模块 这是我的代码 import urllib2 from google oauth2 import service account Cons

随机推荐