文章预览:
- 1. 值从哪里来
- 2. 我能修改参数吗
- 1. 为何要修改参数
- 2. 如果参数是不变的
1. 值从哪里来
定义函数时,你可能心存疑虑,参数的值是怎么来的呢?
在def语句中,位于函数名后面的变量通常称为形式参数,在调用函数时提供的值称为实参,但在本书不做严格区分。
2. 我能修改参数吗
函数通过参数获得了一些列值,你能对其修改吗?如果这样做,结果将如何?参数不过变量而已,行为与你的预期完全相同。在函数内部给参数赋值对外部没有任何影响。
>>> def try_to_change(n):
... n='sss'
...
>>> name='dsda'
>>> try_to_change(name)
>>> name
'dsda'
在try_to_chage内,将新值赋给了参数n,但如你所见,这对变量name没有影响。说到底这是一个完全不同的变量。
字符串(以及数和元组)是不可变的,这意味这你不能修改它们(即只能替换为新值)。因此这些类型作为参数项没什么可说的。但如果参数为可变的数据结构(如列表呢)
>>> def chage(n):
... n[0]='cao'
...
>>> names=['haha','end']
>>> chage(names)
>>> names
['cao', 'end']
在上面的示例中,也在函数内修改了参数,但这个示例与前一个示例存在一个重要不同,前一个示例只是给局部变量赋了新值,而在这个示例中修改了变量关联到的列表。这并不奇怪,这次不用函数,再做一次
>>> names=['abc','bscd']
>>> n=names
>>> n[0]='111'
>>> names
['111', 'bscd']
这样的情况你早就见过。将一个列表赋值给俩个变量,这俩个变量将同时指向这个列表就这么简单。要避免这样的结果,必须创建列表的副本。对序列执行切片操作时,返回的切片是副本。因此,如果你创建覆盖整个列表的切片,得到的将是列表的副本
>>> n=names[:]
>>> n
['111', 'bscd']
>>> names is n
False
>>> n==names
True
现在如果修改n,将不会影响names。
>>> n[0]=222
>>> n
[222, 'bscd']
>>> names
['111', 'bscd']
下面来尝试结合使用这种技巧和函数change。
>>> def change(name):
... name[0]='111'
...
>>> names
['111', 'bscd']
>>> names[0]='2222'
>>> names
['2222', 'bscd']
>>> change(names[:])
>>> names
['2222', 'bscd']
当然copy方法也是可以的
1. 为何要修改参数
在提高程序的抽象程度方面,使用函数来修改数据结构是一种不错的方式。假设你要编写一个程序,让它存储姓名,并让用户能根据名字,中间名或姓找人。为此,你可能使用一个类似下面的数据结构:
>>> storage['first']={}
>>> storage['middle']={}
>>> storage['last']={}
>>>
数据结构storage是一个字典,包含3个键:first,middle和last。在每个键下面存储了一个字典。这些子字典的键为姓名,值为随便瞎写
>>> me='随便瞎写'
>>> storage['first']['magnus']=me
>>> storage['middle']['lie']=me
>>> storage['last']['lie']=me
>>> storage
{'first': {'magnus': '随便瞎写'}, 'middle': {'lie': '随便瞎写'}, 'last': {'lie': '随便瞎写'}}
>>> storage['first']['magnus']
'随便瞎写'
如果我们这里使用函数代替重复的代码,整体将会整洁很多
>>> def init(data):
... data['first']={}
... data['middle']={}
... data['last']={}
>>> def lookup(data,label,name):
... return data.get(label,{}).get(name,{})
>>> lookup(s,'first','magnus')
'随便瞎写'
>>> lookup(s,'first','magn')
{}
2. 如果参数是不变的
在有些语言,经常需要给参数赋值并让这种参数修改影响函数外部的变量。在python中,没法直接这样做,只能修改参数对象本身。但如果参数是不可变的呢。
不好意思,没办法。在这种情况下,应从函数返回所有需要的值(如果需要返回多个值,就以元组的方式返回它们)。例如,可以像下面这样编写将变量的值加一的函数。
>>> def inc(x): return x+1
...
>>> foo =10
>>> foo=inc(foo)
>>> foo
11
如果一定要修改参数,可玩点花样,比如将值放在列表当中,如下所示:
>>> def ind(x): x[0]+=1
...
>>> foo=[10]
>>> ind(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> ind(foo)
>>> foo
[11]
但更清晰的解决方案是返回修改后的值。