Python基础(六):函数

定义函数

函数说明:

  1. 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

  2. 函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。

定义函数

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号 : 起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。

无参无返回值

def fun():
    语句

有参无返回值

def fun(x,y):
    z=x+y

无参有返回值

def fun():
    x=1
    return x+1

有参有返回值

def fun(x,y):
    return x+y

注:如果没有return语句,函数执行完毕后也会返回结果,只是结果为Nonereturn None可以简写成return

空函数

如果想定义一个什么事也不做的空函数,可以用pass语句。不知道怎么写函数的代码可以先放一个pass,让代码能运行起来

def nop():
    pass

pass还可以用在其他语句,比如

if age>=18:
    pass

多个返回值

return多个值,其实是返回一个元组

def move(x,y)
    return x,y

print(move(1,2))


(1,2)

小结

  • 定义函数时,需要确定函数名和参数个数;

  • 如果有必要,可以先对参数的数据类型做检查;

  • 函数体内部可以用return随时返回函数结果;

  • 函数执行完毕也没有return语句时,自动return None

  • 函数可以同时返回多个值,但其实就是一个tuple。

调用函数

定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。

这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从 Python 命令提示符执行。

# 定义函数
def printme( str ):
   # 打印任何传入的字符串
   print (str)
   return
 
## 调用函数
printme("我要调用用户自定义函数!")
printme("再次调用同一函数")

调用函数的时候,如果传入的参数数量不对,会报TypeError的错误,并且python会明确告诉你参数数量错误

>>> abs(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: abs() takes exactly one argument (2 given)

调用函数的时候,如果传入的参数类型不能被函数所接受,也会报TypeError的错误,并且给出错误信息:str是错误的参数类型:

>>> abs('a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'

函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”:

>>> a = abs # 变量a指向abs函数
>>> a(-1) # 所以也可以通过a调用abs函数
1

函数的参数

必选参数

  • def foo(x, y, z):pass

默认参数

  • def foo(x=1):pass
  • 假如不传x参数的话,x默认是等于1
  • 必选参数在前,默认参数在后,否则Python的解释器会报错
  • 定义默认参数要牢记一点:默认参数必须指向不变对象!

可变参数(*

  • 允许你传入0个或任意个参数(参数个数不确定)

  • 不定长传参

    • 定义:def foo(*args):pass
    • 调用:foo(1,2,3,4,5)
  • 传入元组或列表

    • 定义:def foo(*args):pass
    • 调用:foo(*(1,2,3,4,5)) or foo(*[1,2,3,4,5])

关键字参数(**)

  • 允许你传入0或任意个含参数名的参数,(除必填参数外可增加其他参数名)
  • 定义:def foo(nam,age,**kwargs):pass,其中kwargs是一个字典
  • 调用:

>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> foo('Jack', 24, **extra)


>>> foo('Jack', 24, city="hhh")

命名关键字参数

  • 限制关键字参数的名字,就可以用命名关键字参数,例如,只接收cityjob作为关键字参数
  • 和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数
  • 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*
  • 命名关键字参数必须传入参数名
  • 命名关键字参数可提供默认值
  • 定义:
def person(name,age,*,city='hhh',job):
    print(name,age,city,job)
  • 调用:
person('sxy',10,job='11')

参数组合

  • 在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
  • 定义:def fun(parameter,*args,keyparameter,**kwargs):pass
  • 调用
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, '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}
def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)


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

函数的递归

典型案例:斐波那契数列

def fib_recursion(idx):
    if idx <= 2:
        return 1
    else:
        return fib_recursion(idx-1) + fib_recursion(idx-2)
  • 递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰
  • 必须设置函数终止条件
  • 使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出

尾递归

  • 通过尾递归解决递归调用栈溢出
  • 尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式

列如:计算阶乘n! = 1 x 2 x 3 x ... x n

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

尾递归

def fact(n):
    return fact_iter(n, 1)

def fact_iter(num, product):
    if num == 1:
        return product
    return fact_iter(num - 1, num * product)

函数的作用域

  • python 提供了内存管理,函数内的变量只在函数运行时才被创建,在函数运行之前会结束后根本不存在。在函数运行时会创建新的变量在函数中使用,当函数完成的时候他们会被删除。

  • 函数运行时,函数之外的变量会被搁置,只有函数内部的名字会被用到。程序中使用变量的部分称为这个变量的作用域。

  • 外部不能访问函数内部变量

  • 函数内部能够访问外部变量

  • 函数内部和函数外部变量名可以相同,但需要注意访问优先级

  • 函数内部不能修改外部变量,强行修改需要加 global 外部变量 = 新值

局部变量

只在函数内部存在

全局变量

有更大作用域的变量,更大指程序的主部分。

可以在函数内部打印全局变量,但是当你试图改变它时,会创建一个新的局部变量

 def Tax(price,rate):  # price,rate,total是局部变量

  total = price + price * rate

 return total

 Mytotal = Tax(60.6) # Mytotal 是全局变量

 print(Mytotal)

Python 不会建立名为 Myprice的局部变量,而是会使用名为 Myprice的全局变量。

强制为全局变量

  • global 关键字
def Tax(price, rate):
	global   Myprice

nonlocal 关键字

如果遇到函数内部局部变量和全局变量同名的情况,那么在函数内部,局部变量会覆盖全局变量,比如下面这种:


MIN_VALUE = 1
MAX_VALUE = 10
def validation_check(value):
    MIN_VALUE = 3
    ...

在函数 validation_check() 内部,我们定义了和全局变量同名的局部变量 MIN_VALUE,那么,MIN_VALUE 在函数内部的值,就应该是 3 而不是 1 了。

类似的,对于嵌套函数来说,内部函数可以访问外部函数定义的变量,但是无法修改,若要修改,必须加上 nonlocal 这个关键字:


def outer():
    x = "local"
    def inner():
        nonlocal x # nonlocal关键字表示这里的x就是外部函数outer定义的变量x
        x = 'nonlocal'
        print("inner:", x)
    inner()
    print("outer:", x)
outer()
# 输出
inner: nonlocal
outer: nonlocal
posted @ 2022-12-30 16:02  是小鱼呀  阅读(87)  评论(0编辑  收藏  举报