Python之路9:基础函数

函数

函数是将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需要调用函数名即可

注:函数在没有执行前,内部代码不执行

特性:
减少重复的代码
使程序变得可扩展
使程序变得易维护

实例:

def hel():   # 定义函数名
    print('Hello World!') # 函数内的内容
hel()  # 调用函数

# 执行结果
Hello World!

函数的参数

  • 形参变量

只有在被调用是才分配内存单元,形参只在函数内部有效,函数调用结束后返回主程序后则不在调用此形参变量

  • 实参

可以是常亮,变量,表达式,函数等,无论实参是何种类型的变量,在进行函数调用时,它们都必须有特定的值,以便把这些值传给形参

实例:

def calc(x, y):  # x,y 为形参
    res = x**y
    return res
s = calc(2, 5)  # 2,5 是需要传送的实参数据
print(s)

# 执行结果
32

关键参数

实例:

def stu_register(name, age, country, course='CN'): #如传入的某个参数值是一样的,就可以在定义函数是指定参数值是多少,且指定的变量值的后面不允许有需要传入值的变量
    print('注册学生信息'.center(10, '-'))
    print('姓名:', name)
    print('age:', age)
    print('国籍:', course)
    print('课程:', country)

stu_register('zevin', 22, 'python') #此处传入字符串需要严格对应参数内的变量

# 执行结果
--注册学生信息--
姓名: zevin
age: 22
国籍: CN
课程: python

# 也可以在传入参数值时指定变量
def stu_register(name, age, country, course):
    print('注册学生信息'.center(10, '-'))
    print('姓名:', name)
    print('age:', age)
    print('国籍:', course)
    print('课程:', country)

stu_register('zevin',23, course='JP', country='python') #若没有指定变量的参数,需要按照函数格式传入值

# 执行结果
--注册学生信息--
姓名: zevin
age: 23
国籍:JP
课程: python

非固定参数

若函数中有些定义的变量需要传入多个参数,就可以使用非固定参数
用法:*变量, 在变量前加个 * 星号
实例:

# 变量前一个 * 星号
def stu_register(name, age, *args): # *args 会把多传入的值变成一个元祖形式
    print(name, age, args)
stu_register('zevin', 22)
# 执行结果
# zevin 22 () #后面这个()就是args的值,因为没有传入值,所以为空

stu_register('zevin', 22, 'CN', 'JP')
# 执行结果
# zevin 22 ('CN', 'JP') # 最后多传入的值变成元祖

# 变量前两个 * 星号
def stu_register(name, age, *args,  **kwargs): # **kwargs会把多传入的值变成一个字典形式
    print(name, age, args, kwargs)
stu_register('zeivn', 22, 'CN', 'JP', sex='abc', pro=123)
# 执行结果
# zeivn 22 ('CN', 'JP') {'sex': 'abc', 'pro': 123}

函数的返回值

函数外部的代码想要获取函数执行的结果,就可以在函数内用 return 语句把结果返回,不加默认返回 None
注意:
函数在执行过程中只要遇到 return 语句,就会停止执行并返回结果

实例:

def sun(x, y):
    if x > y:
        x*y
    else:
        x**y
fo = sun(5, 6)
print(fo)
# 执行结果为 None

def sun(x, y):
    if x > y:
        return x*y
    else:
       return x**y
fo = sun(5, 6)
print(fo)
# 执行结果为 15625

局部变量

在函数中定义的变量称为局部变量,在程序一开始定义的变量称为全局变量
当全局变量和局部变量同名时,在定义局部变量的函数内,局部变量起作用,在其他地方全局变量起作用

实例:

name = 'anv'  # 在程序开始定义 name = anv
def change_name():
    name = 'dsf'    # 在函数内定义 name = dsf
    print('函数内name为:', name, id(name))   #在函数内打印name
change_name()
print('函数外name为:', name, id(name))  #在函数外打印name

# 执行结果
函数内name为: dsf  140357042555120
函数外name为: anv  140357042555064


# 要想在函数内修改全局变量,需要用参数 global 修改
name = 'anv'  # 在程序开始定义 name = anv
def change_name():
    global name  # global声明需要修改的变量,建议不要更改全局变量
    name = 'dsf'    # 在函数内修改为 name = dsf
    print('函数内name为:', name, id(name))   #在函数内打印name
change_name()
print('函数外name为:', name, id(name))  #在函数外打印name

# 执行结果
函数内name为: dsf 140056539031792
函数外name为: dsf 140056539031792

嵌套函数

函数内部可以再次定义函数,执行需要调用

# 实例 1
age = 18      # 全局定义 age = 18
def func1():
    age = 73  # 函数内定义 age = 73
    print('func1:', age)
    def func2():
        age = 84
        print('func2:', age)
func1()   # 调用 func1()

# 执行结果,未调用 func2() 所有以输出 func1 的值
func1:73
# 实例 2
age = 18      # 全局定义 age = 18
def func1():
    age = 73  # 函数内定义 age = 73
    print('func1:', age)
    def func2():
        age = 84
        print('func2:', age)
    func2()  # 调用 func2()
func1()   # 调用 func1()

# 执行结果
func1:73
func2:84
# 实例 3
age = 18      # 全局定义 age = 18
def func1(): # 函数内定义 age = 73
    print('func1:', age)  # 此age 直接调用的是全局变量 age 值
    def func2():
        print('func2:', age) 
    func2()  # 调用 func2()
func1()   # 调用 func1()

# 执行结果
func1: 18
func2: 18
# 实例 4
age = 18      # 全局定义 age = 18
def func1(): # 函数内定义 age = 73
    age = 73   # 函数内定义 age = 73
    print('func1:', age)
    def func2():
        print('func2:', age) # func2()函数内的age从上一层父级获取 age 值,如果上一层 age未赋值,则在往上一层查找
    func2()  # 调用 func2()
func1()   # 调用 func1()

# 执行结果
func1: 73
func2: 73

匿名函数

把多行语句提供成一行,不需要函数名,支持三元运算,主要是和其他方式搭配运算

# 如以下代码
def calc(x, y):
    return x*y

print(calc(2, 5))
# 执行结果
10

# 换成匿名函数
calc = lambda x, y: x*y
print(calc(2, 5))
# 执行结果
10

# 还可以进行三元运算
calc = lambda x, y: x*y if x < y else x/y
print(calc(16, 8))
# 执行结果
2.0

# 匿名函数主要搭配其他函数使用
# map(func, list) 是将后面列表中的每一个值交给前面的函数去执行一边
res = map(lambda x: x*2, [1, 5, 6, 7]) #将后面的列表内每一个值交给前面的 lamba 函数进行自乘
for line in res:
    print(line)
# 执行结果
2
10
12
14

高阶函数

变量可以指向函数,函数的参数能接受变量,那么一个函数可以接受另一个函数作为参数,这种就是 高阶函数

  • 接受一个或多个函数作为输入
  • return 返回另外一个函数
def calc(x, y):
    return x*y

def func(x):
    return x+x

print(calc(func(4), 5)) # 将func(4)返回的函数结果作为calc函数的参数

# 执行结果
40

作用域

Python 中作用域,变量会由内向外查找,先在自己作用域查找,如果没有就再去上级查找,依次向上,直到找不到就报错

# 先看这段代码
name = 'li'
def f1():
    print(name)
def f2():
    name = 'al'
  return f1

res = f2()
res()
# 输出:li

# 分析上面的代码,先执行f2()函数,而f2()执行结果返回的 f1 的内存地址,所以res=f1,在后面执行res()就等于执行f1(),而执行f1()时和执行f2()没有关系,f1()内并没有定义变量name的值,所以f1()就上级查找name变量的值,所有 name = "li" 就是和 f1()为一个作用域链,最后返回的结果为 li

# 最后看这段代码
name = 'li'
def f1():
    print(name)
def f2():
    name = 'al'
    f1()
f2()
# 输出: li

# 此段代码和上面的基本是一样的,执行f2()后调用了f1(),最后的结果为f1()向上级查找name变量值,最后返回name变量值
# 在函数未执行之前,作用域已经形成了,而作用域链也生成了

作用域的查找顺序:
LEGB:

  • locals: 函数内部的名称空间,包括局部变量和形参
  • enclosing: 外部嵌套函数的名称空间
  • globals: 全局变量,函数定义所在模块的名称空间
  • builtins 内置模块的名称空间

递归

在函数内部可以调用其他函数,如果一个函数在内部调用自己本身时,这个函数就一个递归函数

递归特性:

  • 必须要有一个明确的结束条件
  • 每次进入更深一层递归时,问题规模应该比上级递归减少
  • 递归的效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。)
# 递归的用法
# 计算 介乘,
def num(n):
    if n == 1:
        return 1
  return n * num(n - 1)
print(num(5))
# 输出:120

你可能感兴趣的:(Python之路9:基础函数)