Python 函数 2

函数的参数

位置参数(普通,正常的参数)

随便编写一个求x^n的值的函数power(x, n)

def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s

我们调用这个函数,需要传入两个参数,这个两个参数也叫做位置参数

>>> power(5, 2)
25

如果我们给power()函数只传入1个参数,会这样:

>>> power(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: power() missing 1 required positional argument: 'n'

显然会报错,这个时候,提示的错误大概意思是说:你需要在传入一个n参数。

如果我们就像给power(x, n)函数传入1个参数,要怎么做?这个时候,就是要是默认参数了。

默认参数

默认参数在其他高级语言里也用,C/C++也有,你可以一时想不起来,但是,只要上代码,你就知道什么是默认参数了:

def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s

现在,这个形参n就是默认参数

Q:使用默认参数有什么好处?

A:最大的好处是能降低调用函数的难度。

怎么就降低了函数的调用难度呢:一共两个方面:

1. 参数的数量。对于power(x, n)函数,参数数量可以是1个,也可以是2个。

2. 参数的顺序。如果有更多的参数,我们可以这样使用函数power(2, n=2)默认参数对输入顺序没有要求。


对于默认参数一定要注意一点:必须使用不变对象,想:list这种可变的参数:不要使用。举例:

def add_end(L=[]):
L.append('END')
return L

这个函数,你不给它传入参数时,如果你多次调用,会得到下面的结果:

>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']

如果你给它参数参数,它却可以正常的使用,不会出现上面的错误结果:

>>> add_end([1, 2, 3])
[1, 2, 3, 'END']
>>> add_end(['x', 'y', 'z'])
['x', 'y', 'z', 'END']

Q:这是为什么?

A:解释:每次调用该函数,如果改变了L的内容,则下次调用时,默认参数内容就变了,不再是函数定义时的[]了。

所以,结论就是,add_end()函数你写的不对,正确的写法是这样的:

def add_end(L=None):
if L is None:
L = []
L.append('END')
return L

现在就对了,你可以试试,不管你调用几次,都没有问题。

可变参数

Q:什么是可变参数?

A:就是指针!

举个例子,看下面的程序:

def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum

这个calc(*numbers)函数,我可以随便个它传入参数:

>>> calc(*[1, 2, 3])
14
>>> calc(*(1, 3, 5, 7))
84
>>> nums = [1, 2, 3]
>>> calc(nums[0], nums[1], nums[2])
14
>>> calc(1, 2, 3)
14
>>> calc(1, 3, 5, 7)
84
>>> calc()
0

这个可变参数几乎无敌,它允许你传入0个或任意个参数。(解释:这些可变参数在函数调用时自动组装为一个tuple。)所以说,玩转指针,你就牛逼了。

关键字参数

Q:什么是关键字参数

A:**para这样的参数就是所谓的关键字参数

举例:

def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)

这个**kw参数可以不赋值,也可以随便赋值:

>>> person('Michael', 30)
name: Michael age: 30 other: {}
>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

看到了吧,这就是关键字参数

Q:那它究竟有什么作用?

A:也是,降低了函数的调用难度,并且可以扩展函数的功能。比如,这个person()函数,我们只需要保证能够接受到nameage这个两个参数就可以,如果调用者愿意提供更多的参数,我们也能收到。使用起来相当的灵活。

>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, city=extra['city'], job=extra['job'])
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

注意:kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。

命名关键字参数

命名关键字参数就是:调用者依然可以不受限制的向person()函数传入形参,但是我们只接受指定的几个参数。

def person(name, age, *, city, job):
print(name, age, city, job)

其中*后面的参数就命名关键字参数。(命名关键字参数需要一个特殊分隔符*)。

第2种写法:

def person(name, age, *args, city, job):
print(name, age, args, city, job)

如果函数定义中已经有了一个可变参数,那么后面跟的形参就都是命名关键字参数,不需要特意在指定特殊分隔符*

严重注意:

命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,即使参数的顺序正确,调用依然报错:

>>> person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: person() takes 2 positional arguments but 4 were given
>>> person('Jack', 24, city = 'Beijing', job = 'Engineer')
Jack 24 Beijing Engineer

解释:

如果命名关键字参数没有写参数名,Python解释器把这4个参数均视为位置参数

所以,既然命令关键字参数是可选输入的,所以命令关键字参数需要些默认值。程序还要改:

def person(name, age, *, city='Beijing', job='Engineer'):
print(name, age, city, job)

这样,程序就完美了。


总结:

1. 必须使用*作为特殊分隔符,它是为Python解释器识别位置参数命名关键字参数用的。

2. 如果有可变参数,就不需要特意在加*了,可变参数后面跟着的默认为命名关键字参数

3. 命名关键字参数必须赋默认值。

参数组合

Python中,函数的形参是上面这么多的形式。如果组合使用,顺序必须注意:必选参数默认参数可变参数命名关键字参数关键字参数, 这样的顺序。

def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw) def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

调用:

>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}

更可气的是:通过一个tuple和dict,你也可以调用上述函数:

>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}

小技巧:

对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。


  • 可见Python语言的灵活。如果使用C++取实现一个这种函数的功能,需要写多少重载方法啊!
  • Python非常适合实验室做程序。就是,突然有一个灵感涌现,我们快速的使用Python编写一段脚本程序,来测试一下这个灵感的可行性。

递归函数

这的重点是讲Python,而不是递归。要说起递归,那是有很多好讲的,有许多的技巧。递归的思想很简单,但是写起程序来很绕。

随便写一个:

def fact(n):
if n==1:
return 1
return n * fact(n - 1)

Python使用自己写的递归函数时,注意的事情就是:传入的值不要太大,容易产生栈溢出错误。

>>> fact(1000)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in fact
...
File "<stdin>", line 4, in fact
RuntimeError: maximum recursion depth exceeded in comparison

参考网站:

http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014316784721058975e02b46cc45cb836bb0827607738d000

Learning Python 010 函数 2的更多相关文章

  1. Learning Python 010 函数 1

    Python 函数 1 调用函数 举个例子 多于Python内部的函数,你可以在Python的交互式终端中使用help()函数来查看函数的使用方法.比如:abs()函数,如果你不知道如何使用它,你可以 ...

  2. day python 010 函数(1)

    一 函数 定义 : def () 函数是对功能或者动作的封装 def yue (): # 形参列表 # print("拿出手机") # print("打开陌陌" ...

  3. Python学习教程(learning Python)--2.3.3 Python函数型参详解

    本节讨论Python下函数型参的预设值问题. Python在设计函数时,可以给型参预设缺省值,当用户调用函数时可以不输入实参.如果用户不想使用缺省预设值则需要给型参一一赋值,可以给某些型参赋值或不按型 ...

  4. Python学习入门基础教程(learning Python)--2.3.3Python函数型参详解

    本节讨论Python下函数型参的预设值问题. Python在设计函数时,可以给型参预设缺省值,当用户调用函数时可以不输入实参.如果用户不想使用缺省预设值则需要给型参一一赋值,可以给某些型参赋值或不按型 ...

  5. python第六天 函数 python标准库实例大全

    今天学习第一模块的最后一课课程--函数: python的第一个函数: 1 def func1(): 2 print('第一个函数') 3 return 0 4 func1() 1 同时返回多种类型时, ...

  6. Learning Python 002 print() 和 input()

    Python print() 和 input() print()函数 print()函数可以向终端中输入指定的内容. 输出当个字符串 .py文件中,输入下面的代码,并保存: print('hello ...

  7. python的函数

    函数一词起源于数学,但是在编程中的函数和数学中的有很大不同.编程中的函数式组织好的,可重复使用的,用于实现单一功能或相关联功能的代码块. 我们在学习过程中已经使用过一些python内建的函数,如pri ...

  8. python strip()函数 介绍

    python strip()函数 介绍,需要的朋友可以参考一下   函数原型 声明:s为字符串,rm为要删除的字符序列 s.strip(rm)        删除s字符串中开头.结尾处,位于 rm删除 ...

  9. python split()函数

    Python split()函数 函数原型: split([char][, num])默认用空格分割,参数char为分割字符,num为分割次数,即分割成(num+1)个字符串 1.按某一个字符分割. ...

随机推荐

  1. [原创]Scala学习:Tuple,Array,Map ,文件操作

    1.Tuple:元祖.是一个有用的容器对象. 1)特点:  ① 元祖是不可变的,即,当声明完了一个元祖,那么它的长度就不可以在改变:  ② 元祖可以包含不同类型的数据,对象:   ③ 索引是从 '_1 ...

  2. linux FAQ(zz)

    1.Which is the command used to find the available shells in your Operating System Linux ? Ans : $ech ...

  3. How MapReduce Works(转)

    原文地址:http://www.cnblogs.com/ggjucheng/archive/2012/04/23/2465820.html 一.从Map到Reduce MapReduce其实是分治算法 ...

  4. Linux初识(命令, 文件, 系统管理)

    Linux初识(命令, 文件) 文件系统 在Linux系统下,没有驱动器磁盘,只有一个根目录 / ,所有的文件都在根目录下面. 相关文件夹介绍 bin : 程序相关 boot : 开机启动相关 cdr ...

  5. Entity Framework在Asp.net MVC中的实现One Context Per Request(转)

    上篇中"Entity Framework中的Identity map和Unit of Work模式", 由于EF中的Identity map和Unit of Work模式,EF体现 ...

  6. 算法(Algorithms)第4版 练习 1.5.10

    Yes, but it could increase the tree height, so the performance guarantee would be invalid.

  7. Docker-使用Dockerfile创建镜像

    Dockerfile是一个文本格式的配置文件,用户可以使用Docker来快速创建自定义的镜像 基本结构 Dockerfile由一行行命令语句组成,并且支持以#开头的注释行 一般而言,Dockerfil ...

  8. ubuntu下搭建Scrapy框架简单办法

    1. 先执行以下命令 sudo apt-get install python-lxml sudo apt-get install libxslt1-dev sudo apt-get install p ...

  9. QT MVC 模型/视图

    1. 模型视图实例一, QFileSystemModel  QTreeView ,model/view示例. #include <QApplication> #include <QF ...

  10. Android 基础-2.0 拔打电话号码

    1.添加权限 在AndroidManifest.xml 添加打电话权限 <uses-permission android:name="android.permission.CALL_P ...