Python学习笔记:函数

本片参考官方文档: 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值