【问题标题】:How to change default value of optional function parameter如何更改可选函数参数的默认值
【发布时间】:2019-12-30 21:22:55
【问题描述】:

我需要将a.py处的全局变量Sb.py更改为a.py处的函数中的默认值。

a.py

S = "string"


def f(s=S):
    print(s)
    print(S)

b.py

import a


def main():
    a.S = "another string"
    a.f()


if __name__ == "__main__":
    main()

python b.py 输出

string
another string

而不是预期

another string
another string

如果我像这样在b.py 中调用a.f

a.f(a.S)

这按预期工作,但有什么方法可以更改默认变量值?

【问题讨论】:

  • 这是因为默认参数是在函数定义时定义的,而不是函数执行时。这与驱动 mutable default arg 行为的机制相同

标签: python global-variables optional-arguments


【解决方案1】:

简短的回答是:你不能。

这样做的原因是函数默认参数是在函数定义时创建的,而默认值并不意味着要重新定义。变量名称绑定到一个值一次,仅此而已,您不能将该名称重新绑定到另一个值。首先,让我们看一下全局范围内的变量:

# create a string in global scope
a = "string"

# b is "string"
b = a

a += " new" # b is still "string", a is a new object since strings are immutable

您现在刚刚将一个新名称绑定到“string”,而“string new”是绑定到 a 的全新值,它不会更改 b,因为 str += str 返回一个 new str,使得ab指向不同的对象。

函数也是如此:

x = "123"

# this expression is compiled here at definition time
def a(f=x):
    print(f)

x = "222"
a()
# 123

变量f 在定义时使用默认值"123" 定义。这是无法改变的。即使有可变的默认值,例如this 问题:

x = []

def a(f=x):
    print(x)

a()
[]

# mutate the reference to the default defined in the function
x.append(1)

a()
[1]

x
[1]

默认参数已定义,名称f 绑定到值[],无法更改。您可以更改与f 关联的值,但不能将f 绑定到默认值。进一步说明:

x = []

def a(f=x):
    f.append(1)
    print(f)

a()
x
[1]

# re-defining x simply binds a new value to the name x
x = [1,2,3]

# the default is still the same value that it was when you defined the
# function, albeit, a mutable one
a()
[1, 1]

A) 将全局变量作为参数传递给函数或 B) 将全局变量用作 global 可能会更好。如果你要改变你想使用的全局变量,不要把它设置为默认参数,选择一个更合适的默认值:

# some global value
x = "some default"

# I'm choosing a default of None here
# so I can either explicitly pass something or
# check against the None singleton
def a(f=None):
    f = f if f is not None else x
    print(f)

a()
some default

x = "other default"
a()
other default

a('non default')
non default

【讨论】:

  • @c-nivs "将此与字符串不可变的事实相结合," => 这实际上几乎是不相关的-您在这里说明的是重新绑定和变异之间的区别,而不是两者之间的区别可变和不可变对象(当然除了你不能改变不可变对象的事实)。您可能想阅读这篇文章:nedbatchelder.com/text/names.html
  • 另外,您不需要global x - 只有当您想从函数中重新绑定全局时才需要。
  • @brunodesthuilliers 我将删除global。正如我所理解的那样,字符串是不可变的这一事实(对于小字符串,不确定大字符串)是python将重新绑定值而不共享可变引用的原因。如果我误解了,是否可以进行修改以做出更正确的答案?
  • 1/ 所有字符串都是不可变的,句号,并且 2/ python 不会重新绑定名称,因为字符串是不可变的,但因为 告诉它这样做(“绑定" => "分配")。在您的第二个示例(带有列表的示例)中,如果您重新绑定列表而不是对其进行变异(=> 在 sn-p 中将 x.append(1) 替换为 x = [1]),您会发现行为完全相同至于第一个(字符串)示例。 FWIW,所有这些都在我链接到的文章中进行了解释 (nedbatchelder.com/text/names.html),你肯定想阅读这篇文章(然后编辑你的帖子)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-19
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2010-09-23
  • 1970-01-01
  • 2011-09-20
相关资源
最近更新 更多