【问题标题】:Override inner function [duplicate]覆盖内部函数[重复]
【发布时间】:2015-09-26 11:51:36
【问题描述】:

我知道如何重写方法:

class Foo(object):
    def bar(self):
        return True


def damn_monkeys(self):
    return False

Foo.bar = damn_monkeys

有没有可能用函数实现类似的东西?

def foo(arg1):
    def bar(arg2):
        return 1
    return bar(arg1)

foo.bar = monkeys  # doesn't work as bar obviously isn't an attribute

我找到了一些钩子 (func_code),但这些似乎是专供检查员使用的,摆弄它们似乎相当可疑。

我还注意到函数有 __init____call__ 引用,但它们似乎指向 __builtin__.__function 对象。我没有进一步检查,但似乎函数也是对象(这很有意义,阅读 python 中的所有内容都是一个对象)。我想函数已经是 __function 对象的实例,这就是为什么 foo.__init__ 不会引发错误,但它从未被调试器触及。

有没有办法在不复制或修补代码的情况下覆盖内部函数?

编辑与答案重复:Can you patch *just* a nested function with closure, or must the whole outer function be repeated?

【问题讨论】:

  • 我认为您应该阅读更多关于一般命名空间的信息。如果 oject 有一个类型或另一个类型,这并没有太大的区别。为了达到它,python 必须在命名空间中查找它。
  • 如果你需要"override"它,你为什么不把它改造成不是一个内部函数呢?请注意,您实际上可以为函数赋予任意属性,因此您可以将bar 变为foo.bar
  • @jonrsharpe 背景信息代码实际上要长得多,并且在第 3 方包中,我不能那样更改它
  • 你能提供一个不那么抽象的例子吗?你真正想要达到什么目的?嵌套函数的全部意义在于,它仅在函数内部是必需的,作为一个实现细节,其他代码都不应该关心,所以它们很难理解。
  • 内层函数其实是外层函数的局部变量。所以你的问题相当于_“我可以从函数外部更改函数局部变量吗?”。 AFAIK,答案是:不,除非您愿意修改函数本身的字节码。

标签: python function oop


【解决方案1】:

除非调用外部函数,否则您的内部函数甚至都不存在。并且仅在通话期间。看看这个关于在函数中有一个静态变量的问题,然后将答案从一个计数器修改为你的内部函数。

What is the Python equivalent of static variables inside a function?

您还可以使用不同定义的内部函数修改外部函数。

【讨论】:

    【解决方案2】:

    我不相信这是可能的。

    即使你这样做,它也行不通:

    def test_func():
        def inner():
            print("inner")
        test_func.inner = inner
        test_func.inner()
    
    test_func()    # inner
    test_func.inner()    # inner
    
    def outer(): 
        print("outer")
    
    test_func.inner = outer
    test_func.inner()    # outer
    # AH HA!! SUCCESS?
    test_func()    # inner
    # NOPE!! 
    

    这个结果的原因是,即使函数是对象,甚至可以有属性,函数对象的内容(即它的本地命名空间)也会被计算一次。事后你不能改变它(也就是说,不把它包装在另一个函数中,这不是你要问的),因为它永远不会被重新评估——除非你重新定义它。查看this famous question last section of this article,进一步阐明函数对象成为一等对象的含义。

    这实际上是任何对象的情况。考虑:

    class test_class(): 
        print("test_class evaluation")
        class_attribute = None
        def inner(self):
            print("inner")
    
    # test_class evaluation
    test_class
    test_class()
    

    评估消息只打印一次,因为命名空间被评估一次,就像它与任何其他对象一样。

    现在,正如您在问题中所说,您可以使用test_class.inner = my_func 覆盖test_class 类的inner 方法。但是,您首先可以这样做的原因是类对象test_classtype 的一个实例(所有类也是如此),并且type 对象自动将本地对象作为属性添加到父对象中,比如上面例子中的test_class.innertest_class.class_attribute

    对于不是type 实例的函数对象,情况并非如此。您必须显式地将属性添加到函数对象。然而,即使你这样做了,函数的命名空间已经被求值,所以更新函数对象属性对函数的求值没有影响,如test_func 示例所示。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-04
      • 2020-07-18
      • 1970-01-01
      • 2012-11-10
      • 2021-04-17
      • 1970-01-01
      相关资源
      最近更新 更多