简介
函数是结构化编程的根底,也是代码复用的基石。Python中通过def来自定义函数。本文将会深刻摸索Python中函数的机密。
内置函数
除了用户的自定义函数之外,Python内置了一些十分有用的函数:
内置函数 | ||||
---|---|---|---|---|
abs() | delattr() | hash() | memoryview() | set() |
all() | dict() | help() | min() | setattr() |
any() | dir() | hex() | next() | slice() |
ascii() | divmod() | id() | object() | sorted() |
bin() | enumerate() | input() | oct() | staticmethod() |
bool() | eval() | int() | open() | str() |
breakpoint() | exec() | isinstance() | ord() | sum() |
bytearray() | filter() | issubclass() | pow() | super() |
bytes() | float() | iter() | print() | tuple() |
callable() | format() | len() | property() | type() |
chr() | frozenset() | list() | range() | vars() |
classmethod() | getattr() | locals() | repr() | zip() |
compile() | globals() | map() | reversed() | __import__() |
complex() | hasattr() | max() | round() |
自定义函数
Python中应用def来定义函数,并应用return来返回特定的值。
看一个简略的函数的例子:
def my_function(x, y, z): if z > 1: return z * (x + y) else: return z / (x + y)
把咱们之前讲的斐波拉赫数列的例子从新用函数来定义,能够这样写:
def fib(n): a, b = 0, 1 while a < n: print(a, end=' ') a, b = b, a+b print() # 调用函数fib(1000)
函数的内容须要应用空格或者tab来进行缩进。
参数的默认值
在Python中,咱们能够给参数设置默认值,这样如果在函数调用的过程中没有传递参数的时候,就会应用默认值作为参数。
在咱们之前定义的函数my_function中,咱们能够给z设置一个默认值:
def my_function(x, y, z=10): if z > 1: return z * (x + y) else: return z / (x + y)
这样咱们在调用my_function能够只用传递两个参数,最初的z能够应用默认的参数值。
留神,默认值只会执行一次,如果你传入的参数是可变对象(列表,字典和类实例)的话,咱们须要留神这个问题:
def f(a, L=[]): L.append(a) return Lprint(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
关键字参数
咱们能够应用key=value的形式对函数进行调用。
还是后面的函数:
def my_function(x, y, z=10): if z > 1: return z * (x + y) else: return z / (x + y)
咱们能够这样调用:
my_function(1,y=3,z=5)my_function(1,y=3)
然而不能这样用:
my_function(y=3,1)
关键字的参数必须要放在非关键词参数的前面。也不能对参数进行屡次赋值:
>>> def function(a):... pass...>>> function(0, a=0)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: function() got multiple values for keyword argument 'a'
通过下面的探讨咱们能够看出,Python函数中的参数有两种,一种是带默认值的参数,一种是不带默认值的参数。
留神,不带默认值的参数肯定要在带默认值的参数之前 。
看一个谬误的例子:
In [69]: def fa(a=100,b,c=200): ...: pass File "<ipython-input-69-d5678b64f352>", line 1 def fa(a=100,b,c=200): ^SyntaxError: non-default argument follows default argument
而向函数传递参数也有两种形式,一种是不带关键字的传递,一种是带关键字的传递。
留神,非关键词参数的传递肯定要在关键词参数传递之前。
举个谬误的例子:
In [70]: def fa(a,b=100,c=200): ...: pass ...:In [71]: fa(a=100,30) File "<ipython-input-71-5a229b8e420e>", line 1 fa(a=100,30) ^SyntaxError: positional argument follows keyword argument
那么问题来了,如果有多个关键词参数和多个非关键词参数,有没有简便的办法来定义这样的函数呢?
有的,那就是 *arguments
和 **keywords
*arguments
用来接管所有多余的非关键词参数。而**keywords
用来接管所有额定的关键词参数。
留神,*arguments
肯定要呈现在**keywords
的后面。
举个例子:
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) for kw in keywords: 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 LimburgerIt's very runny, sir.It's really very, VERY runny, sir.----------------------------------------shopkeeper : Michael Palinclient : John Cleesesketch : Cheese Shop Sketch
非凡参数
函数能够按地位传参,能够依照关键词传参,也能够混合传参。
在某些状况下,咱们可能须要限度传参的类型,比方只接管按地位传递,只接管按关键词传递,或者只承受混合传递。
看下非凡参数的定义:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2): ----------- ---------- ---------- | | | | 按地位或者关键词 | | - 只容许按关键词传递 -- 只容许按地位传递
留神,参数之间是以 / 和 * 来进行辨别的。
咱们举个例子:
>>> def standard_arg(arg):... print(arg)...>>> def pos_only_arg(arg, /):... print(arg)...>>> def kwd_only_arg(*, arg):... print(arg)...>>> def combined_example(pos_only, /, standard, *, kwd_only):... print(pos_only, standard, kwd_only)
下面定义了4种传参形式的函数。
第一个函数就是规范模式,能够按地位传递,也能够按关键词传递。
第二个函数只容许依照地位传递。
第三个函数只容许依照关键词来传递。
第四个函数是混合模式。
参数解包
有时候咱们须要将列表或者字典的值转换为函数的参数。那么就须要用到参数解包的性能。
*
操作符 能够用来解包列表和元组。
>>> 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]
**
操作符 能够用来解包字典。
>>> 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)
Lambda
相熟java的敌人可能晓得,在JDK8中,Java引入了Lambda表达式。同样的Python中也有Lambda。
你能够将Lambda看做是匿名函数。能够在任何须要函数的中央应用Lambda表达式。
看一个Lambda的例子:
>>> def make_incrementor(n):... return lambda x: x + n...>>> f = make_incrementor(42)>>> f(0)42>>> f(1)43
还能够将lambda的返回值作为参数:
>>> 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')]
函数标注
之前咱们探讨的是简略的自定义函数模式,咱们并不知道函数的参数类型和返回值类型,其实函数能够写得更加具体一些,这就要用到函数标注了。
所谓函数标注就是用户自定义函数中的类型的可选元数据信息。
函数标注是以字典的模式寄存在 __annotations__
属性中的。咱们在参数的名称前面加上冒号,前面跟一个表达式,那么这个表达式会被求值为标注的值。对于返回值来说,返回值标注的定义是加上一个组合符号 ->
,前面跟一个表达式,该标注位于形参列表和示意 def 语句完结的冒号之间。
举个例子:
>>> def f(ham: str, eggs: str = 'eggs') -> str:... print("Annotations:", f.__annotations__)... print("Arguments:", ham, eggs)... return ham + ' and ' + eggs...>>> f('spam')Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}Arguments: spam eggs'spam and eggs'
其实应用函数标注写进去的程序更加清晰,可读性更高。
本文已收录于 http://www.flydean.com/05-python-function/最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!