4.7.1 默认函数定义

最常用的就是为一个或多个参数设定默认值,这让函数可以用比定义时更少的参数来调用,例如:

def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
while True:
ok = 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 OSError('uncooperative 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!')

这个例子同样给出了 in 关键字,即测试一个元组里是否包含给定值。

默认值在 方法定义时 被赋值

i = 5

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

所以将会打印 5,因为 i 在方法定义时值为5

注意 ! 默认值只会被赋值一次,所以当默认值是一个可变对象例如List、Dict或多数类时会有不同,这个方法似乎每次总是记住了前一次调用的结果

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

4.7.2 关键字参数

函数同样可以通过 'kwarg=value' 这样的关键字参数形式来调用,如下:

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, "!")

这个函数只接受一个必须的参数(voltage),和三个可选参数(state, action, and type),可以通过下面任意方式调用:

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

在一次函数调用中,关键字参数必须跟在位置参数后面。所有传入的关键字参数必须符合方法能接收的参数(例如parrot方法就不接受actor参数),而顺序并不重要,这当然也包括了必须的参数(比如parrot(voltage=1000)就是通过的)。没有参数可以被第二次接受,所以下面的示例是错误的:

>>> def function(a):
... pass
...
>>> function(0, a=0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: function() got multiple values for keyword argument 'a'

当最后一个参数以 **name 的形式出现,这表示接收一个包含了所有关键字参数的Dictionary字典(看这里介绍)。它还可以结合一个 *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")

打印出来这样:

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

值得注意的是,打印出来的关键字参数是通过代码中的 sorted() 方法来排序的,因为Dictionary字典的keys 是无序的,如果不这样做打印出来的参数就是无序的

4.7.3 可变参数

最少使用的是指定函数可以传入可变参数来调用,这些参数被包装在tuple元组中(元组的概念)。

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

通常这些可变参数出现在形参的最后一个,因为它们会一股脑儿地把所有剩下的参数都传入方法。而任何出现在 *args 可变参数之后的形参必须是关键字参数(‘keyword-only’ arguments),确保它们只能被用作关键字参数而不会被当做可变参数。

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

4.7.4 使用 * 拆分参数列表

相反的情况发生在当参数已经组成一个tuple元组或是list列表却需要拆分成方法所需要的单独的位置参数。例如内置的 range() 方法接收单独的 start 和 stop 两个参数,如果手头只有list或tuple,我们可以用 * 操作符来把list或tuple拆分成关键字。

>>> list(range(3, 6))            # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]

同样的,Dictionary字典也可用 ** 操作符拆分成关键字

>>> def parrot(voltage, state='a stiff', action='voom'):
... print("-- This parrot wouldn't", action, end=' ')
... print("if you put", voltage, "volts through it.", end=' ')
... print("E's", state, "!")
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

4.7.5 Lambda表达式

通过Lambda关键字,你可以创建一些简短的匿名function。这个function就返回两个参数之和: lambda a, b: a+b 。Lambda表达式精炼地将function限制在一个表达式中,可以在任何地方替代function object来使用,从语法上来说其实就是Python中常规方法的"语法糖"。与嵌套方法定义相似,lambda表达式能够引用位于function范围内的变量。

>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43

上面的例子使用Lambda function来返回一个方法,下面的例子是传入Lambda function来代替参数

>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

4.7.6 文档字符串(Documentation Strings)

对于Doc strings,有一些约定是需要我们去遵守的。

第一行应当是对于方法目的简短且精确的概括。简要来说,既然方法的名称和返回类型可以通过其他方法获得,那么就不用再次明确地说明。
第一行应当以一个大写字母开头,以一个句号结尾。
如果有多行,那么第二行应为空,看起来像是把概括和剩下的描述部分分开。
剩下的行数则是用一行至多行来描述对象的调用规则、副作用等。

Python解释器并不会去除多行文本中的缩进,所以处理Doc strings的工具得自己去做,一般通过下面的约定来完成。
跟在文档第一行后面的第一个非空的行 A 决定了整个文档的缩进列数(我们不使用第一行作为参考是因为它通常是紧靠在文档的三个单引号'''后面,因此看起来并不明显)。相当于缩进长度的空格就被添加在所有行的前部。比 A 缩进列数更少的行不应该出现,但如果出现了,每一行前面所有的空格都会被移除。一个Tab缩进通常相当于8个空格。看下面的代码就很清楚:

>>> def my_function():
... '''Do nothing.
...
... No,really,it doesn't do anything.
... '''
... pass
...
>>> print(my_function.__doc__)
Do nothing. No,really,it doesn't do anything. >>> def less_or_more_indentation_func():
... '''Do something.
...
... second line,normal line
... less indentation line
... more indentation line
... '''
... pass
...
>>> print(less_or_more_indentation_func.__doc__)
Do something. second line,normal line
less indentation line
more indentation line

Python3 官方文档翻译 - 4.7 函数定义的更多相关文章

  1. cocos2dx 关于lua 绑定的环境配置官方文档翻译与 将自己定义c++方法绑定到lua的的方法

    网上有好多写如何讲自己定义的方法绑定到lua的文章,当中都仅仅对环境配置做了简单的介绍,看到有的帖子写在绑定中遇到了各种各样的error.大部分是因为环境配置不对导致的,下面是官方的文档有标准的说明, ...

  2. Python3 官方文档翻译 - 5 数据结构

    这章会更详细地描述了一些你已经学过的知识,同时添加一些新东西. 5.1 List进阶 下面是关于List的所有方法 list.append(x) 将元素添加至列表尾,相当于a[len(a):] = [ ...

  3. Python3.x:函数定义

    Python3.x:函数定义 1,函数定义: def 函数名称([参数1,参数2,参数3......]): 执行语句 2,实例一(不带参数和没返回值): def helloWorld(): print ...

  4. Python3.2官方文档翻译--实例对象和方法对象

    6.3.3 实例对象 如今我们用实例对象做什么呢?实例对象唯一可用的操作就是属性引用.如今有两种合法的属性名称:数据属性和方法. 数据属性相当于smallTalk中的实例变量,C++中的数据成员.数据 ...

  5. python3 参数*args 、 **args 在函数定义和调用中的应用

    一.函数调用时 说明:*args 表示解包(解包 列表.元组.字符串类型) #定义函数cn_musql def cn_musql(host,port,user,pwd,db): print(host) ...

  6. Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第一部分(Page 6)

    编写你的第一个 Django app,第一部分(Page 6)转载请注明链接地址 Django 2.0.1 官方文档翻译: Django 2.0.1.dev20171223092829 documen ...

  7. 基本控件文档-UITextField属性---iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/Ch ...

  8. 多线程---iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址(2013年12月29日更新版)   多线程  技术博客http://www.cnblo ...

  9. kong插件官方文档翻译

    kong插件官方文档翻译 目录 介绍 文件结构 编写自定义逻辑 存储配置 访问数据存储 自定义实体 缓存自定义实体 扩展Admin API 编写测试 (卸载)安装你的插件 插件开发 - 介绍 什么是插 ...

随机推荐

  1. Android导航栏ActionBar的具体分析

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/39378825 关于ActionBar,相信大家并不陌生,可是真正能够熟练使用的也不是许多,这 ...

  2. Node.js笔记1

    Node.js入门笔记 1. node -help 可以显示帮助信息2. node REPL 模式(Read-eval-print loop) 输入—求值—输出循环 直接在cmd输入node 可以进入 ...

  3. 开启新的activity获取它的返回值

    1.开始界面 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:t ...

  4. iOS:ABPeoplePickerNavigationController系统通讯录使用

    昨天因项目需求要访问系统通讯录获取电话号码,于是乎从一无所知,开始倒腾,倒腾了一下午,总算了弄好了.写这边博客是为了记录一下,自己下一次弄的时候就别在出错了.同时,有和我一样的菜鸟能够避免走一下弯路. ...

  5. C# 微信公众平台开发(4)-- 模版消息

    微信公众平台开发 --发送模版消息 发送模版消息是微信服务号给某个用户发送模版消息,类似于APP的推送通知: 1.添加模版消息 在页面的左上 有一个添加功能插件的 按钮,如题 添加完成后,我们就可以在 ...

  6. codeforces 622F. The Sum of the k-th Powers 拉格朗日插值法

    题目链接 求sigma(i : 1 to n)i^k. 为了做这个题这两天真是补了不少数论, 之前连乘法逆元都不知道... 关于拉格朗日插值法, 我是看的这里http://www.guokr.com/ ...

  7. 13-C语言字符串函数库

    目录: 一.C语言字符串函数库 二.用命令行输入参数 回到顶部 一.C语言字符串函数库 1 #include <string.h> 2 字符串复制 strcpy(参数1,参数2); 参数1 ...

  8. web乱码问题

    String data = "不见青山"; ServletOutputStream sos = response.getOutputStream(); byte b[] = dat ...

  9. MSSQL SERVER 2008 R2 无法连接到数据库,用户sa登录失败,错误:18456

    原因:勾选了强制实施密码策略,但是设置的密码很简单依然可以,比如:123456 这是为什么?原来,这个功能要用到NetValidatePasswordPolicy() API这个函数. (该功能只有在 ...

  10. Spring-data-redis: 分布式队列

    Redis中list数据结构,具有"双端队列"的特性,同时redis具有持久数据的能力,因此redis实现分布式队列是非常安全可靠的.它类似于JMS中的"Queue&qu ...