本片参考官方文档: The PythonTutorial
函数的作用域(scope)
函数的运行引入了一个新的符号表(symbol table)以用于这个函数的本地变量。更确切地,函数中所有的变量赋值都把值储存在本地符号表里;而变量引用首先查找本地变量表,然后查找上一层函数的本地变量表,然后查找全局变量表,最后查找内建(built-in)变量表。所以,全局变量不能直接在一个函数中被赋值(除非声明
global
),即使它们可以被引用。
这里符号表是编译原理里的概念,简而言之就是一个标识符(identifier)和值之间对应的表,想知道一个标识符是什么值就在这个表里查找。每次新函数被调用,都会有一个新的符号表创立,函数参数就在这个符号表里。
按值传送
参数是按值传送的(pass by value)(这个值总是一个对象引用,不是对象的值)。实际上,说成按对象引用传递(pass by object reference)更恰当,因为如果一个mutable对象被传入,调用者(caller)会看见任何被调用者(callee)对这个mutable对象的改变。
不要纠结名称了,只要知道这个是按引用传递就好了。Python里的引用就是标识符。mutable也是Python独有的概念,关于对象,值,引用,mutable,可参考我的另一篇博客 Python学习笔记:对象,值和类型.
函数作为对象
一个函数的定义在当前符号表引入了这个函数名。函数名的值有一个被解释器认为是用户定义函数的类型(The value of the function name has a type that is recognized by the interpreter as a user-defined function)。这个值可以赋给其他名字然后那个名字就也可以当做函数用了。这是一般的重命名机制。
>>> fib <function fib at 10042ed0> >>> f = fib >>> f(100) 0 1 1 2 3 5 8 13 21 34 55 89
Python中一切都是对象,是对象就有名字(也叫标识符,引用),类型和值。一个对象可以有多个名字,名字可以赋予。
返回值
return
语句返回一个值。如果return
后面没有表达式(expression),就返回None
。函数没运行到最后也返回None
。
默认参数值
最有用的形式就是对一个或多个参数明确一个参数值。这样函数就可以以较少的参数调用函数。例如:
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): while True: ok = raw_input(prompt) if ok in ('y', 'ye', 'yes'): return True if ok in ('n', 'no', 'nop', 'nope'): return False retries = retries - 1 if retries < 0: raise IOError('refusenik user') print complaint
这个函数可以用几种方式调用:
- 只给一个必须的参数: ask_ok(‘Do you really want to quit?’)
- 给其中一个可选择的参数:ask_ok(‘OK to overwrite the file?’, 2)
- 或给全部参数:ask_ok(‘OK to overwrite the file?’, 2, ‘Come on, only yes or no!’)
默认值在函数定义的时候就被估值(evalueated),所以
i = 5 def f(arg=i): print arg i = 6 f()
会输出
5
重要的警告:默认值只被估值一次。例如:
def f(a, L=[]): L.append(a) return L print f(1) print f(2) print f(3)
会输出
[1] [1, 2] [1, 2, 3]
如果你不想默认值在后续的调用中被分享,你可以这样写:
def f(a, L=None): if L is None: L = [] L.append(a) return L
这大段我整段翻译来的,没什么可以精简,也没什么需要解释的。
关键字参数
例如:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print "-- This parrot wouldn't", action, print "if you put", voltage, "volts through it." print "-- Lovely plumage, the", type print "-- It's", state, "!"
这个函数可以这样调用:
parrot(1000) # 1 positional argument parrot(voltage=1000) # 1 keyword argument parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments parrot('a million', 'bereft of life', 'jump') # 3 positional arguments parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
但是不能这样调用:
parrot() # required argument missing parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument parrot(110, voltage=220) # duplicate value for the same argument parrot(actor='John Cleese') # unknown keyword argument
关键字参数和默认值参数在定义上都是一样的,区别在于当你在调用的时候写清楚关键字,它就是关键字参数;如果调用函数的时候不加关键字只按位置加值,那就是默认值参数。
tuple和dictionary作为参数
当一个参数是
**name
形式,它表示接收一个包含所有关键字参数的字典。这可以跟形如*name
的参数相结合,它接收一个包含位置参数的tuple(*name
一定要出现在**name**
之前)。例如:
def cheeseshop(kind, *arguments, **keywords): print "-- Do you have any", kind, "?" print "-- I'm sorry, we're all out of", kind for arg in arguments: print arg print "-" * 40 keys = sorted(keywords.keys()) for kw in keys: print kw, ":", keywords[kw]
如果被这样调用:
cheeseshop("Limburger", "It's very runny, sir.", "It's really very, VERY runny, sir.", shopkeeper='Michael Palin', client="John Cleese", sketch="Cheese Shop Sketch")
那么会输出:
-- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- client : John Cleese shopkeeper : Michael Palin sketch : Cheese Shop Sketch
所以 *name
可以用作任意数量参数。
Lamda表达式
lamda表达式是函数式编程语言的特性,因为其简单易用,其他语言也加入了lamda表达式。在Python里,lamda表达式就是函数定义的语法糖,可以使简短的函数定义的更加简洁。lamda arguments:expression
产生一个函数对象,它跟下面的正规函数定义是一个效果:
def name(arguments):
return expression