文档章节

python 中的函式定义

lemos
 lemos
发布于 2017/08/31 15:59
字数 1590
阅读 15
收藏 0

示例:定义一个斐波拉契数列

>>> def fib(n):    # 打印 Fibonacci 序列到 n
...     """打印到 n 的 Fibonacci 序列."""
...     a, b = 0, 1
...     while a < n:
...         print(a, end=' ')
...         a, b = b, a+b
...     print()
...
>>> # 现在调用我们刚定义的函式:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

 

几个概念:

文档字串(docstring),用于文档注释。

符号表(symbol table),函数中的符号表用于该函式的局部变量,因此称作局部符号表。在函式中被赋值的变量会存储在局部符号表中。变量引用会先在局部符号表中寻找,然后才是闭包函式的局部符号表,再然后是全局变量,最后是内建名字表。在函式中的全局变量尽管可以引用,但是不能赋值。函数内赋值只会创建一个新的同名的局部变量。

函式的实参,在它被调用时被引入到这个函式的局部变量表。并且参数是按值传递( 总是对象的一个 引用 , 而不是对象本身的值)。当一个函式调用另一个时, 对应这次调用,一个新的局部符号表就会被创建.

函式定义会在当前的符号表里引入该函式的名字. 函式名对应的值被解释器认定为自定义函式类型 函式名的值可以被赋予另一个名字, 使其也能作为函式使用. 

若函数没有返回值,默认返回 None(内建名字)。如果要唯一输出的值是 None, 那么解释器会正当的抑制这次返回. 如你实在想看看这个值,可以使用 print():

>>> fib(0)
>>> print(fib(0))
None

* 关于符号表

import dis

c = 3

def abc():
    a = 1
    b = a + c

dis.dis(abc)

输出

 19           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)

 20           6 LOAD_FAST                0 (a)
              9 LOAD_GLOBAL              0 (c)
             12 BINARY_ADD
             13 STORE_FAST               1 (b)
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE

 

默认参数

使用默认参数,可以方便进行调用

def meet(you='lisi', him='wangwu'):
    print(you,'meet',him)

meet()
meet('wo')
meet('wo','zhangsan')

重要警告: 默认参数的值只会被求一次值. 但这在默认参数是可变参数的情况下就不一样了, 如列表, 字典, 或大多类的对象时. 例如, 下面的函式在随后的调用中会累积参数值:

通常情况

i = 5

def f(arg=i):
    print(arg)

i = 6
f()

# output:
5

特殊情况

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))

# output:
[1]
[1, 2]
[1, 2, 3]

如果不希望参数值被后续调用共享:

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

* 为什么默认参数会变?

默认参数和函数对象本身是一一对应的,一个函数拥有一个默认参数的 tuple。这也很好理解,默认参数随函数一起定义,并且出现在函数签名里,理所应当是函数的一部分。

问题的点在于 Python 中对象传递全部为“引用”,list 对象又都是 mutable 的,所以函数调用时往 list 对象作为的默认参数中 append 会造成额外副作用。

事实上,Python 开发是倡导用 immutable 对象作为默认参数的。比如用 None 就是个不错的选择:

def foo(bar=None):
    bar = bar or []

又或者用了 mutable 参数一定记得创建副本:

def foo(bar=[]):
    bar = list(bar)

 

关键字参数

函数在定义或者调用时,可以指定参数名称

def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print("-- This parrot wouldn't", action, end=' ')
    print("if you put", voltage, "volts through it.")
    print("-- Lovely plumage, the", type)
    print("-- It's", state, "!")

可以使用下列方法调用(在函式调用时, 关键字参数必须跟在位置参数之后. )

parrot(1000)
parrot(action = 'VOOOOOM', voltage = 1000000)
parrot('a thousand', state = 'pushing up the daisies')
parrot('a million', 'bereft of life', 'jump')

当最后一个形参的形式为 **name 时, 则排除其他的形参的值, 它将以字典 (参阅 映射类型——字典) 的形式包含所有剩余关键字参数. 这种调用可以与具有 *name 形式的形式参数 (在下一小节中介绍) 联合使用, 这种形参接受所有超出函式接受范围的位置参数. ( *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")

打印结果(注意, 关键字参数名的列表是通过之前对字典 keys() 进行排序操作而创建的; 如果不这样做, 参数打印的顺序是不确定的.)

-- 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

 

任意参数列表

指定函式能够在调用时接受任意数量的参数. 这些参数会被包装进一个元组 (参看 元组和序列). 在变长参数之前, 可以使用任意多个正常参数。

def write_multiple_items(file, separator, *args):
    file.write(separator.join(args))

一般地, 这种 variadic 参数必须在形参列表的末尾, 因为它们将接收传递给函式的所有剩余输入参数.除此之外,任何出现在 *arg 之后的形式参数只能是关键字参数

>>> def concat(*args, sep="/"):
...    return sep.join(args)
...
>>> concat("earth", "mars", "venus")
'earth/mars/venus'
>>> concat("earth", "mars", "venus", sep=".")
'earth.mars.venus'

 

参数列表解包

当参数存在于一个既存的列表或者元组之中, 但却需要解包以若干位置参数的形式被函数调用。

下面是一个利用 * 操作符解从列表或者元组中解包参数以供函数调用的例子

def cute(sex, age, height):
    print(sex,age,height,end=' ')
    print()

t = ['female', 18, 167]
cute(*t)

# output:
female 18 167 

同样的, 字典可以通过 ** 操作符来解包参数:

d = {'sex': 'male', 'age':18, 'height': 172}
cute(**d)

# output:
male 18 172 

* 或 **操作符有两个作用:

*arg 表示分散的参数,接受分散的参数。解析后的 arg 表示tuple或者map,可以传入函数参数为元组的函数。

© 著作权归作者所有

共有 人打赏支持
上一篇: docker 的基本命令
下一篇: Redux - example
lemos
粉丝 8
博文 184
码字总数 92482
作品 0
芜湖
后端工程师
私信 提问
Lubuntu 14.04 下 安装Ulipad

Ulipad – 超级好用的国产Python IDE,开发者是limodou。此IDE本身就是用Python + wxPython编写的。在Windows系统中一直使用Ulipad,最近想在Linux(Ubuntu 12.04)进行学习和实验,安装过程还...

yeyunxiaopan
2014/11/20
0
0
解析Kotlin 函数用法与函数式编程

导读 本篇文章主要介绍Kotlin函数的用法,以及自己对函数式编程的一些理解。并且会和Python,C++做一些比较。 自从Google爸爸宣布Kotlin为自己的干儿子之后,Kotlin被各大社区炒的火热。 如果...

问题终结者
2017/10/19
0
0
Porting OpenCV 2.3.1 to iPhone 3GS/4/4S

Porting OpenCV 2.3.1 to iPhone 3GS/4/4S - 如何使用cmake+Xcode編譯OpenCV 2.3.1函式庫給iOS使用 要能在Xcode中使用OpenCV 2.3.1函式庫來實作自己的程式首要之務當然是要能建立出符合iOS使...

晨曦之光
2012/05/28
572
0
Python函数式编程指南(一):概述

这大概算是Python最难啃的一块骨头吧。在我 Python生涯的这一年里,我遇到了一些Pythoner,他们毫无例外地完全不会使用函数式编程(有些人喜欢称为Pythonic),比如,从来不会 传递函数,不知...

icheer
2012/05/31
0
0
Install gevent in AIX with gcc

greenlet Download greenlet-0.4.1.zip from https://github.com/python-greenlet/greenlet libev Download libev-4.15.tar.gz from http://dist.schmorp.de/libev/ c-ares Download c-ares ......

querychinesesto
2013/12/31
0
0

没有更多内容

加载失败,请刷新页面

加载更多

前嗅ForeSpider教程:采集黄页88

以黄页88为例,采集当前列表页新闻的正文数据: 第一步:新建任务 ①点击左上角“加号”新建任务,如图1: 【图1】 ②在弹窗里填写采集地址,任务名称,如图2: 【图2】 ③点击下一步,选择进...

forespider
15分钟前
1
0
Spring Cloud Alibaba基础教程:Nacos 生产级版本 0.8.0

昨晚Nacos社区发布了第一个生产级版本:0.8.0。由于该版本除了Bug修复之外,还提供了几个生产管理非常重要的特性,所以觉得还是有必要写一篇讲讲这次升级,在后续的文章中也都将以0.8.0版本为...

程序猿DD
23分钟前
1
0
HTML+CSS实现div的高度自适应填满剩余空间的7种方法

如图上下两部分,上面部分适应内容的高度,下面部分填充剩余部分。 当下面内容不够时,在下面部分出现滚动条 有2种情况 1.上面内容的高度适应内容,只有2种方法(flex、quirks+table) 2.上面...

linsk1998
27分钟前
1
0
Oracle学习日志-8(查询结果排序)

要用到的表如下 书上写到,上面的查询结果排序是随机的,再执行几次结果可能不同,但是我执行多次后,查询结果的排序都是如此,是因为oracle的默认处理方式是按照物理储存顺序查询的,而我在...

白话
34分钟前
1
0
Data truncation: Incorrect datetime value: '0000-00-00 00:00:00' for column xxx

1. 错误提示 Data truncation: Incorrect datetime value: '0000-00-00 00:00:00' for column xxx 2. 问题分析 从上面的描述我们可以看出原因是:我们给类型是datetime的xxx字段赋值0000-00......

易冥天
36分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部