关于python:Python基础之函数

52次阅读

共计 4222 个字符,预计需要花费 11 分钟才能阅读完成。

简介
函数是结构化编程的根底,也是代码复用的基石。Python 中通过 def 来自定义函数。本文将会深刻摸索 Python 中函数的机密。

内置函数

除了用户的自定义函数之外,Python 内置了一些十分有用的函数:

自定义函数

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'

其实应用函数标注写进去的程序更加清晰,可读性更高。

正文完
 0