如何使用 Python3 以优雅的方式修改作为函数中的**参数传递的不可变对象?
How to modify immutable objects passed as **arguments in functions with Python3 the elegant way?
我不确定这里的问题是什么,所以我真的不知道应该如何称呼该问题的主题。如果您知道,请提供更好的主题。
下面的代码是原始代码的极端简化示例。但它很好地重现了这个问题。 test()
调用后foo
应该是sieben
.
我想我不知道 Python 中关于变量范围的一些特殊情况。了解更多信息可能是一个很好的问题。但是我不知道我应该关注哪个 Python 主题来找到适合我自己的解决方案。
#!/usr/bin/env python3
def test(handlerFunction, **handlerArgs):
handlerFunction(**handlerArgs)
def myhandler(dat):
print('dat={}'.format(dat))
dat = 'sieben'
print('dat={}'.format(dat))
foo = 'foo'
test(myhandler, dat=foo)
print('foo={}'.format(foo))
当然我可以使 foo
成为 global
变量。但这不是目标。目标是将这个变量携带到内部并通过不同级别的子功能并将结果带回来。在原始代码中,我使用了一些更复杂的数据结构 **handlerArgs
.
一种解决方案是使用 list()
作为持有不可变对象的可变对象。但这真的是优雅还是pythonic?
#!/usr/bin/env python3
def test(handlerFunction, **handlerArgs):
handlerFunction(**handlerArgs)
def myhandler(dat):
print('dat={}'.format(dat))
# MODIFIED LINE
dat[0] = 'sieben'
print('dat={}'.format(dat))
# MODIFIED LINE
foo = ['foo']
test(myhandler, dat=foo)
print('foo={}'.format(foo))
**
语法与此无关。 dat
是 myhandler
的局部变量,分配它不会更改同名的全局变量。如果要从函数内部更改模块变量,请在函数体的开头将变量声明为 global
:
def myhandler(): # you don't need to pass dat as argument
global dat
print('dat={}'.format(dat))
dat = 'sieben'
print('dat={}'.format(dat))
这是来自 the docs 的相关部分:
If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.
If the global
statement occurs within a block, all uses of the name specified in the statement refer to the binding of that name in the top-level namespace. Names are resolved in the top-level namespace by searching the global namespace, i.e. the namespace of the module containing the code block, and the builtins namespace, the namespace of the module builtins
. The global namespace is searched first. If the name is not found there, the builtins namespace is searched. The global
statement must precede all uses of the name.
在您编辑后,问题显示为:“如何改变不可变对象?”
好吧,我想你已经猜到了:你没有。以这种方式使用可变对象对我来说似乎是合理的。
我不确定这里的问题是什么,所以我真的不知道应该如何称呼该问题的主题。如果您知道,请提供更好的主题。
下面的代码是原始代码的极端简化示例。但它很好地重现了这个问题。 test()
调用后foo
应该是sieben
.
我想我不知道 Python 中关于变量范围的一些特殊情况。了解更多信息可能是一个很好的问题。但是我不知道我应该关注哪个 Python 主题来找到适合我自己的解决方案。
#!/usr/bin/env python3
def test(handlerFunction, **handlerArgs):
handlerFunction(**handlerArgs)
def myhandler(dat):
print('dat={}'.format(dat))
dat = 'sieben'
print('dat={}'.format(dat))
foo = 'foo'
test(myhandler, dat=foo)
print('foo={}'.format(foo))
当然我可以使 foo
成为 global
变量。但这不是目标。目标是将这个变量携带到内部并通过不同级别的子功能并将结果带回来。在原始代码中,我使用了一些更复杂的数据结构 **handlerArgs
.
一种解决方案是使用 list()
作为持有不可变对象的可变对象。但这真的是优雅还是pythonic?
#!/usr/bin/env python3
def test(handlerFunction, **handlerArgs):
handlerFunction(**handlerArgs)
def myhandler(dat):
print('dat={}'.format(dat))
# MODIFIED LINE
dat[0] = 'sieben'
print('dat={}'.format(dat))
# MODIFIED LINE
foo = ['foo']
test(myhandler, dat=foo)
print('foo={}'.format(foo))
**
语法与此无关。 dat
是 myhandler
的局部变量,分配它不会更改同名的全局变量。如果要从函数内部更改模块变量,请在函数体的开头将变量声明为 global
:
def myhandler(): # you don't need to pass dat as argument
global dat
print('dat={}'.format(dat))
dat = 'sieben'
print('dat={}'.format(dat))
这是来自 the docs 的相关部分:
If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations.
If the
global
statement occurs within a block, all uses of the name specified in the statement refer to the binding of that name in the top-level namespace. Names are resolved in the top-level namespace by searching the global namespace, i.e. the namespace of the module containing the code block, and the builtins namespace, the namespace of the modulebuiltins
. The global namespace is searched first. If the name is not found there, the builtins namespace is searched. Theglobal
statement must precede all uses of the name.
在您编辑后,问题显示为:“如何改变不可变对象?”
好吧,我想你已经猜到了:你没有。以这种方式使用可变对象对我来说似乎是合理的。