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. c++之helloworld与命名空间

    首先在linux中需要安装g++编译器. 在中端输入 uname -a,可以查看版本信息. 输入g++,如果提示错误.则需要使用sudo apt-get install g++. #include&l ...

  2. python cookbook 字符串和文本

    使用多个界定符分隔字符串 import re line = 'asdf fjdk; afed, fjek,asdf, foo' print(re.split(r'[;,\s]\s*', line)) ...

  3. 【leetcode刷题笔记】Reverse Words in a String

    Given an input string, reverse the string word by word. For example,Given s = "the sky is blue& ...

  4. 【四】MongoDB索引管理

    一.索引介绍 在mongodb中,索引用来支持高效查询.如果没有索引,mongodb必须在整个集合中扫描每个文档来查找匹配的文档.但是如果建立合适的索引,mongodb就可以通过索引来限制检查的文档数 ...

  5. 某国际知名IT公司笔试

    原文地址:http://blog.csdn.net/lazy_tiger/article/details/1790986 这段时间没怎么顾及自己的这个“一寸土地”, 实在惭愧.因为这些天小弟又经历了“ ...

  6. Vim 标签定义

    一.单个文件: m+标记字符 打上标记,如在开头行按ms(start),标记开头: 如需返回到自己的标记点,按`+标记字符就行: 二.多个文件: m+大写标记字符 如果删除了标签的行,同时也删除了标签 ...

  7. NOIP前的一些计划

    一些想法 距离NOIP2018只剩下一个星期的时间了,通过这几天在长郡的考试,渐渐感觉还有好多东西自己还不够熟练,也有些东西到现在还不会,现将NOIP前的一些计划列在这里,希望能在考前把他们全部完成吧 ...

  8. Hibernate学习---第十二节:Hibernate之锁机制&乐观锁实现

    1.悲观锁 它指的是对数据被外界修改保持保守态度,因些,在整个数据处理过程中,将数据牌锁定状态.悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层的锁机制才能保证数据访问的排他性,否则,即使在本 ...

  9. Agc016_D XOR Replace

    传送门 题目大意 给定两个长为$n$的序列$A,B$你可以进行若干组操作,每次操作选定一各位置$x$,令$A_x$等于$A$的异或和. 问能否通过一定操作使得$A$成为$B$,如果能,求最小操作书数. ...

  10. luogu1801 黑匣子

    惊了呀 Splay Treap 这都什么玩意 两个优先队列搞定 #include <bits/stdc++.h> using namespace std; #define LL long ...