【问题标题】:What are the rules for adding members to Python methods safely?安全地向 Python 方法添加成员的规则是什么?
【发布时间】:2021-02-11 10:29:25
【问题描述】:

我正在查看这样的代码:

def foo():
    return 42

foo.x = 5

这显然为函数对象添加了一个名为foo 的成员。我发现这非常有用,因为它使这些函数对象看起来与具有__call__ 函数的对象非常相似。

我必须遵守哪些规则以确保在以后的 Python 更新中不会出现问题,例如我必须避免使用的名称?也许有一个 PEP 或文档部分提到了规则?

【问题讨论】:

  • 在 Python 中,这称为猴子补丁。搜索该词会带来大量信息。
  • @FrankYellin 不,这不是猴子修补的例子。没有功能被替换。
  • @MartijnPieters。我已经看到该术语既指对现有代码的修改,也指添加新属性。我会注意到下一个回答者也将其称为猴子补丁。
  • @FrankYellin:早在 1999 年,我就在发明该术语的公司工作。我们特别提到了替换或增强现有功能。这可能涉及在某处设置属性,但这就像将钉子钉在钉子上称为“制作椅子”。 OP 所做的只是在支持属性的对象上设置属性。

标签: python function dynamic attributes


【解决方案1】:

除了考虑reserved classes of identifiers 之外,没有其他规则。具体来说,尽量避免使用dunder 名称:

系统定义的名称,非正式地称为“dunder”名称。 [...]任何__*__名称的使用,在任何情况下,如果没有明确记录使用,可能会在没有警告的情况下被破坏。

对于接受任意属性的函数,没有什么特别的;如果有放置它们的位置,Python 中的几乎所有东西都接受任意属性(几乎总是一个__dict__ 属性)。

在 Python 标准库中,函数属性用于将装饰器包装函数链接到原始包装函数(通过 functools.update_wrapper() function 和它的附属工具 @functools.wraps() decorator function),并将状态和方法附加到函数当被装饰器增强时(例如,singledispatch() decorator 向装饰函数添加了几个方法和一个注册表)。

【讨论】:

    【解决方案2】:

    这是一个很好的技术。规则不影响任何具有特殊含义的dunder名称。

    这是实现单例的好方法:

    import faker
    
    def my_fake_data():
          if not getattr(my_fake_data, 'factory', None):
              my_fake_data.factory = faker.Faker()
          return my_fake_data.factory
    

    Monkey 修补使用类似的技术(设置类属性而不是函数属性),但出于更“狡猾”的原因,例如更改先前定义的类的实现。

    【讨论】:

    • 函数属性与monkeypatching几乎无关。为什么还要提这个?在所有带有属性的对象中,函数对象是最不可能参与绝大多数猴子修补操作的。
    • 已更新答案以使其更准确。 @MartijnPieters
    猜你喜欢
    • 1970-01-01
    • 2019-07-09
    • 1970-01-01
    • 2022-06-11
    • 1970-01-01
    • 2022-08-09
    • 2020-02-06
    • 2011-02-13
    • 1970-01-01
    相关资源
    最近更新 更多