【问题标题】:Is there any way to change variables or functions defined outer in a function有什么方法可以更改函数外部定义的变量或函数
【发布时间】:2019-06-17 03:09:51
【问题描述】:

假设我有foo.py,如下所示。 这个文件不是我创建的,所以我既不想修改也不想复制它。 换句话说,foo.py 在我安装的某个额外包中。

# foo.py

def bar():
  print('This is bar')

def foo():
  print('something')
  bar()
  print('something')

然后,我想实现 foo_as_baz() 行为为 cmets。

# baz.py

from foo import foo

def baz():
  print('This is baz')

def foo_as_baz():
"""
This function is expected to behave as below
  print('something')
  baz()
  print('something')
"""  
  pass

我尝试了以下一种,但由于名称范围不同,它不起作用。

def foo_as_baz():
  bar = baz # I expect this `baz` affects `bar` function in `foo`
  foo()

【问题讨论】:

  • 看我几天前的另一个回答。看起来不同,但实际上是相同的问题。
  • 根本问题与那个问题相同,但我认为这里可能存在一些关于模拟和模块属性如何工作的细微差别。
  • @JoshKarpel 我认为了解根本问题是关键。之后,您可以通过任何可能的技巧为所欲为。
  • @LiuXiMin 谢谢。如果a 显示为零,则此问题与您的问题相同。 ``` 在 [5] 中:a = np.zeros(shape=(4, 2)) 在 [6] 中:func() [666. 1.] [1. 1.] [1. 1.] [1. 1.] ```

标签: python


【解决方案1】:

郑重声明:不要在普通代码中做低于水平线的事情。这令人困惑,而且在很大程度上毫无意义。

如果你正在做这种事情来测试你的代码,我推荐标准库unittest.mock 包,它提供了一种系统的方法来用假的 Python 对象替换 Python 对象以进行测试。

如果您认为您有一些真正的非测试用例,请详细说明...


# foo.py

def bar():
    print("This is bar")

def foo():
    print("something")
    bar()
    print("something")

然后在另一个文件中:

import foo


def baz():
    print("This is baz")


def foo_as_baz():
    original = foo.bar  # save a copy of the original bar()

    foo.bar = baz       # make foo.bar point to baz()

    foo.foo()           

    foo.bar = original  # cleanup by restoring bar()


foo_as_baz()

与您的尝试的主要区别在于我执行了import foo,这让我可以查看实际的模块命名空间foo。我将foo.bar 换成baz,然后调用foo.foo(),然后将foo.bar 切换回原来的bar 函数。

这是因为函数实际上是模块的属性。因此,我们可以重新分配这些属性,就好像它们是任何其他对象的属性一样(因为在 Python 中,包括模块在内的一切都是对象)。

【讨论】:

  • 如你所说,这是一个非常危险的代码。您认为复制上面显示的所有foo 函数或您的实现哪个更好? @JoshKarpel
  • @Hironori 你能澄清一下“复制所有foo 函数”是什么意思吗?
  • 当我写这篇文章时,我的意思是将foo的所有源代码复制到另一个文件中。但现在,我意识到还有另一种基于new_foo = foo.copy() 的方法。我认为这比其他人更好。谢谢。
【解决方案2】:

您可以通过稍微修改foo 的工作方式将函数本身作为参数传递给foo

def foo(func=bar):
   print('something')
   func()
   print('something')

def foo_as_baz():
   foo(baz)

通过将bar 添加为foo 的默认参数,您可以保留原始行为

【讨论】:

  • 是的,但是foo() 没有参数,如果可能的话,我不想修改foo。我知道这个问题很奇怪。
  • 但是 foo 在没有任何参数的情况下调用时仍然表现出相同的行为。那么会有什么问题呢?
  • @Hironori rebind an object to bar in your file 不会影响foo中的bar,这是Python的作用域规则。
猜你喜欢
  • 1970-01-01
  • 2021-10-28
  • 2011-08-10
  • 1970-01-01
  • 2017-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-20
相关资源
最近更新 更多