乐趣区

关于python:Python基础之函数

简介

函数是结构化编程的根底,也是代码复用的基石。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 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

关键字参数

咱们能够应用 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 Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : 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/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

退出移动版