DarkMatter in Cyberspace
  • Home
  • Categories
  • Tags
  • Archives

Python函数的参数传递机制


Python中一切皆对象,包括函数,函数的参数是函数对象的一个属性(这个属性仍然是一个对象)。 函数及其默认参数在定义(执行函数的def语句)时被初始化,且只被初始化一次。

调用函数时,传递的是参数对象的地址,下面的代码演示了不论参数是否为可变对象, 形式参数和实际参数的地址是完全一致的:

def immutable(pb):
    print('id of pb: %s' % id(pb))
    pb += 1
    print('id of pb: %s' % id(pb))
    print('value of pb: %d' % pb)

def mutable(pb):
    print('id of pb: %s' % id(pb))
    pb.append(1)
    print('id of pb: %s' % id(pb))
    print('value of pb: %s' % pb)

b = 1
b2 = b
print('id of b: %s' % id(b))
immutable(b)
print('id of b: %s' % id(b))
print('value of b: %d' % b)
print('value of b2: %d' % b)

mb = [1]
mb2 = mb
print('id of mb: %s' % id(mb))
mutable(mb)
print('id of mb: %s' % id(mb))
print('value of mb: %s' % mb)
print('value of mb2: %s' % mb2)

这种机制导致当函数使用可变对象作为默认参数时,且调用函数时使用可变对象, 前面的调用会影响后面的调用,因为前面的调用修改了默认参数的值:

def default_param_emplist(b=[]):
    print('param before modified: %s' % b)
    b += [1]
    print('param after modified: %s' % b)

default_param_emplist([3])
print(default_param_emplist.__defaults__)
default_param_emplist()
print(default_param_emplist.__defaults__)
default_param_emplist()
print(default_param_emplist.__defaults__)
default_param_emplist()
print(default_param_emplist.__defaults__)
default_param_emplist([3])
print(default_param_emplist.__defaults__)
print('-----------------')

def default_param_none(b=None):
    print('param before modified: %s' % b)
    b = b or []
    b += [1]
    print('param after modified: %s' % b)

default_param_none([3])
print(default_param_none.__defaults__)
default_param_none()
print(default_param_none.__defaults__)
default_param_none()
print(default_param_none.__defaults__)
default_param_none()
print(default_param_none.__defaults__)
default_param_none([3])
print(default_param_none.__defaults__)
print('-----------------')

def no_default_param(b: str):
    print('param before modified: %s' % b)
    b += [1]
    print('param after modified: %s' % b)

no_default_param([3.1])
print(no_default_param.__defaults__)
no_default_param([3.2])
print(no_default_param.__defaults__)

解决这个问题的方法:不要用可变对象作为参数的默认值, 必须使用复合型数据作为参数值时,可以用tuple等不可变对象, 在函数体里根据该参数的类型判断如何处理。

Ref:

  • “Least Astonishment” and the Mutable Default Argument

  • Common Gotchas



Published

Jun 6, 2018

Last Updated

Jun 6, 2018

Category

Tech

Tags

  • default parameter 1
  • python 136

Contact

  • Powered by Pelican. Theme: Elegant by Talha Mansoor