Python 嵌套函数是否存在等价的重写?

Python 嵌套函数是否存在等价的重写?,python,function,nested,overriding,Python,Function,Nested,Overriding,如果我有这个函数,我应该如何用我自己的自定义版本替换内部函数 def foo(): def bar(): # I want to change this pass # here starts a long list of functions I want to keep unchanged def baz(): pass 使用类可以很容易地覆盖该方法。不过,我不知道如何使用嵌套函数实现这一点。将foo更改为类(或任何其他

如果我有这个函数,我应该如何用我自己的自定义版本替换内部函数

def foo():
    def bar():
        # I want to change this
        pass

    # here starts a long list of functions I want to keep unchanged
    def baz():
        pass

使用类可以很容易地覆盖该方法。不过,我不知道如何使用嵌套函数实现这一点。将
foo
更改为类(或任何其他内容)不是选项,因为它来自我无法修改的给定导入模块。

您可以将其作为可选参数传入

def foo(bar=None):
    def _bar():
        # I want to change this
        pass
    if bar is None:
        bar = _bar

这里有一种方法,创建一个新的foo,通过对函数内部进行黑客攻击来“做正确的事情”。(如@DSM所述)。不幸的是,我们不能直接跳入
foo
函数并弄乱它的内部结构,因为它们大多被标记为只读,所以我们要做的是修改我们手工构建的副本

# Here's the original function
def foo():
  def bar():
    print("    In bar orig")
  def baz():
    print("  Calling bar from baz")
    bar()
  print("Foo calling bar:")
  bar()
  print("Foo calling baz:")
  baz()

# Here's using it
foo()

# Now lets override the bar function

import types

# This is our replacement function
def my_bar():
  print("   Woo hoo I'm the bar override")

# This creates a new code object used by our new foo function 
# based on the old foo functions code object.
foocode = types.CodeType(
    foo.func_code.co_argcount,
    foo.func_code.co_nlocals,
    foo.func_code.co_stacksize,
    foo.func_code.co_flags,
    foo.func_code.co_code,
    # This tuple is a new version of foo.func_code.co_consts
    # NOTE: Don't get this wrong or you will crash python.
    ( 
       foo.func_code.co_consts[0],
       my_bar.func_code,
       foo.func_code.co_consts[2],
       foo.func_code.co_consts[3],
       foo.func_code.co_consts[4]
    ),
    foo.func_code.co_names,
    foo.func_code.co_varnames,
    foo.func_code.co_filename,
    foo.func_code.co_name,
    foo.func_code.co_firstlineno,
    foo.func_code.co_lnotab,
    foo.func_code.co_freevars,
    foo.func_code.co_cellvars )

# This is the new function we're replacing foo with
# using our new code.
foo = types.FunctionType( foocode , {})

# Now use it
foo()
我很确定它不会抓住所有的案子。但是它适用于这个示例(对于我来说,它使用的是旧的python 2.5.1)

可能需要一些整理的丑陋部分包括:

  • 传递给CodeType的巨大参数列表
  • 由只覆盖一个成员的
    co_consts
    构造的丑陋元组。所有的信息都在常数中,以确定替换哪一个-因此一个更智能的函数可以做到这一点。我用
    print(foo.func\u code.co\u consts)
    手工挖掘内部结构
  • 通过使用解释器,您可以找到有关
    代码类型
    函数类型
    的一些信息 命令
    帮助(types.CodeType)

    更新: 我认为这太难看了,所以我构建了一个helper函数使它更漂亮。使用帮助器,您可以编写:

    # Use our function to get a new version of foo with "bar" replaced by mybar    
    foo = monkey_patch_fn( foo, "bar", my_bar )
    
    # Check it works
    foo()
    
    下面是monkey\u patch\u fn的实现:

    # Returns a copy of original_fn with its internal function
    # called name replaced with new_fn.
    def monkey_patch_fn( original_fn, name, new_fn ):
    
      #Little helper function to pick out the correct constant
      def fix_consts(x):
        if x==None: return None
        try:
          if x.co_name == name:
            return new_fn.func_code
        except AttributeError, e:
            pass
        return x
    
      original_code = original_fn.func_code
      new_consts = tuple( map( fix_consts, original_code.co_consts ) )
      code_type_args = [
         "co_argcount", "co_nlocals", "co_stacksize", "co_flags", "co_code",
         "co_consts", "co_names", "co_varnames", "co_filename", "co_name",
         "co_firstlineno", "co_lnotab", "co_freevars", "co_cellvars" ]
    
      new_code = types.CodeType(
         *[ ( getattr(original_code,x) if x!="co_consts" else new_consts )
            for x in code_type_args ] )
      return types.FunctionType( new_code, {} )
    

    我不太明白。你的回答不意味着改变给定的函数吗?也许我不太清楚,但是我不能改变原来的
    foo
    。顺便说一句,我要编辑一下我的问题。我想OP是在寻找某种monkeypatch选项,因为
    foo
    “来自我无法修改的给定导入模块。”在哪里使用
    bar
    ?它是否用于后面的函数(如
    baz
    ?)在这些情况下,您可能希望替换它,对吗?您可以访问functione的各种内部详细信息,因为它们只是对象。使用dir函数和语言参考了解更多信息。我通过破解
    func_code
    ,使其达到了一个层次的深度,但必须使我的替换更加智能,以允许从
    baz
    调用
    bar
    。从好的方面来说,我已经有很长时间没有看到
    SystemError:/Users/sysadmin/build/v2.7.2/Objects/cellobject.c:24:内部函数的参数不正确了
    !您有
    foo
    的源代码吗?也许你可以编写自己版本的
    foo
    ,然后monkeypatch。我是@JoelCornett的。为什么不能修改?可以复制吗?(如果它存储在GitHub之类的东西中,您甚至可以使用fork)。使用这两种编码方法可以提供两倍的洞察力。值得注意的是,FunctionType构造函数中的第二个参数表示全局变量,在本例中设置为空字典。在2.7中,调用修改后的函数时,我遇到了
    int
    未定义的问题;为了解决这个问题,我将
    {}
    替换为
    globals=globals()。但我不知道该怎么做(我已经看了8年了……),如果你对怎么做有任何想法的话,我很乐意更新这个来正确处理它。@MichaelAnderson说得好;我相信它可以通过.func_globals获得。(也是啊,很抱歉挖出了一条旧线,哈哈)