10 函数 Function

##1 函数的定义 使用关键字`def = define`来进行定义 定义函数的目的: 1.最大化代码重用,dry原则(don't repeat yourself) 2.最小化代码冗余 3.过程分解 函数的定义:`def 函数名称(形参):`

2 函数的调用

函数名称(实参)

def learning(name, course, start, end):
    print('{} is learning {}'.format(name, course))
    print('{} to {}'.format(start, end))

learning('Jerry', 'python入门经典', '2018/7', '2018/9')

3 函数的返回值

使用return来返回函数的值,python具有多态的特性,而可以实现不同类型的计算,然后返回。

def add_num(x, y): return (x + y)
print(add_num(3, 5))

例子,找出两个序列中的重复部分:
这个例子可以实现多态的特性,实参只要是序列就可以了,可以是list也可以str类型

def intersect(seq1, seq2):
    res = []

    for x in seq1:
        if x in seq2:
            res.append(x)

    return res


seqA = [1, 5, 65, 8, 4, 5, 4]
seqB = [1., 2, 45, 1, 65, 4]

print(intersect(seqA, seqB))
结果:[1, 65, 4, 4]

同样也可以通过集合set来实现得出两个不同的元素

seqA = [1, 5, 65, 8, 4, 5, 4]
seqB = [1, 2, 45, 1, 65, 4]

s1 = set(seqA) & set(seqB)
print(s1)
结果:{65, 4, 1}

4 函数的作用域

4.1 函数内的变量的作用域

1.函数里面定义的变量成为local,作用域为函数内部。
2.函数外部定义的是global全局的变量
3.另外的是built-in内置的类型,其作用域最高

# 函数内的变量的值和外部变量重复了
# 函数内的变量的作用域的问题

x = 50

def fun():
    x = 99
    return x

print('函数运行后的x的值是{}'.format(fun()))
print('全局的x的值是{}'.format(x))
结果:
函数运行后的x的值是99
全局的x的值是50

4.2 在函数的内部使用global关键字的变量

可以在函数中使用global关键字来声明该变量为全局的变量

# 函数内的变量的值和外部变量重复了
# 函数内的变量的作用域的问题

x = 50

def fun():
    global x
    x = 99
    return x

print('函数运行后的x的值是{}'.format(fun()))
print('全局的x的值是{}'.format(x))
结果:
函数运行后的x的值是99
全局的x的值是99

4.3 python3中的封装enclosure

使用场景为函数中又嵌套了函数,嵌套的函数变量和上一层的函数的变量名称相同,可以使用nonlocal关键字。
优先级的顺序:LEGB
img

4.3.1 函数中嵌套函数的作用域

从下面的例子可以看出函数变量的作用域,其中enclosure的优先级是最低的,其次是local,然后是global,最后是built-in

x = 10
def f1():
    x = 99
    
    def f2():
        x = 100
        print(x)
        
    print(x)  # 打印的是f1 local的x
    f2()  # 打印的是f2 local的x
    print(x)  # 打印的是f1 local的x
    
f1()
print(x)
结果:
99  # 打印的是f1的
100 # 打印的是f2的
99  # 打印的是f1的
10  # 打印的是global的

如果要在嵌套的函数中使用全局的,就使用global的关键字,如果只是想使用外侧的,就使用nonlocal的关键字来实现。

x = 10
def f1():
    x = 99
    
    def f2():
        nonlocal x
        x = 100
        print(x)
        
    print(x)  # 打印的是f1 local的x
    f2()  # 打印的是f2 local的x
    print(x)  # 打印的是f1 local的x
    
f1()
print(x)

结果:
99
100
100
10

4.3.2 Built-in

如果定义了一个方法,将built-in覆盖了,就会使用定义的函数,编写的时候特别注意,不要覆盖了built-in的函数。

5 函数的参数传递

变量类型,大致可以分为2种,一种是可变类型,另外一种是不可变类型。

5.1 传递实参是不可变类型

不可改变的类型,如int类型,作为参数传递到函数,此时是作为副本传递,实参的值是不会改变的。
例子1,传递的是一个int类型

def change_num(x):
    x += 10
x = 5
change_num(x)
print(x)
结果:
5

例子2,传递的是一个str类型

def change_num(x):
    x += 'abc'
x = 'Hellokitty'
change_num(x)
print(x)
结果:Hellokitty

5.2传递实参是可变类型

可改变类型作为实参,传递给函数,函数进行的操作,会改变可变类型的本身的值,如下的list的类型。

def change_num(x):
    x[0] = '99'
x = [1,2,3]
change_num(x)
print(x)
结果:['99', 2, 3]

如果我想传递一个list但是又不想改变,可以手动传递副本,而不是直接传递值,这里本质上浅拷贝,如果有列表嵌套也不会奏效。

def change_num(x):
    x[0] = '99'
x = [1, 2, 3]
change_num(x[:])
print(x)

5.3传递可变和不可变实参的原理

传递可变类型,实际是传递的一个值,而不可变的类型传递的是一个引用。
img

6 函数的参数的匹配

6.1传递安装顺序传递,位置匹配

默认情况下是安装位置的顺序进行匹配的

def func(a, b, c):
    print(a, b, c)

func(1, 2, 3)
func('a', 'b', 'c')

6.2传递参数,按照变量的值匹配

也可以通过指定参数的值来进行参数的传递

def func(a, b, c):
    print(a, b, c)
func(1, 2, 3)
func('a', 'b', 'c')
func(c=15, a=16, b=55)

6.3默认值传递值

在定义函数的时候,就可以将参数赋予默认值,在传递实参的时候可以传递部分值给形参。
但是要注意一点:定义函数的默认值只能放在最后面

def func(a, b=1, c=1):
    print(a, b, c)

func(18)
func(1,15)
结果:
18 1 1
1 15 1

6.4函数接收多个不确定个数的参数*arg

python是一个动态类型,可以传递事先不确定个数的任意参数。
没有函数的重载,但是python设计可以在声明函数时,表明可以接收任意个数的参数,其中会将多余的参数以tuple的形式传递给arg

6.4.1python在定义函数的时候,在形参的前面加上*来表明可以接收可变个数的参数:

def avg(*score):
    return sum(score) / len(score)


print(avg(99, 100, 87, 75, 62))
print(avg(87, 99, 85, 68))

6.4.2 声明了接收可变参数,但传递的是一个元组,需解包

如果函数定义可以接收可变参数,但是将参数已经全部保存在一个tuple里面了,此时如果要传递这个tuple,需要先进行解包的操作。

# 如下会报错
def avg(*score):
    return sum(score) / len(score)

t = (87., 94, 98, 78)

avg(t)
结果:
Traceback (most recent call last):
  File "D:/str_2_unicode/str_2_unicode.py", line 7, in <module>
    avg(t)
  File "D:/str_2_unicode/str_2_unicode.py", line 2, in avg
    return sum(score) / len(score)
TypeError: unsupported operand type(s) for +: 'int' and 'tuple'

正确的操作如下,需要先进行解包的操作

def avg(*score):
    return sum(score) / len(score)


t = (87., 94, 98, 78)

print(avg(*t))
结果:89.25

如下例子,将他直接进行传递,可以看到t作为一个参数被传递了,而并未被解开

def func(*args):
    print(args)

t =(1,2,3)
func(t)
func(*t)
结果:
((1, 2, 3),)
(1, 2, 3)

img

6.4.3 函数实参为字典表

可以在定义函数的时候使用**,将多余的参数以dict的方式来呈现。
例如,如果要处理一个员工的信息,包括 name,age,job,salary,当然可以使用4个形式参数,然后传递4个实际的参数到函数进行处理,如下:

def staff_info(name, age, job, salary):
    print(name, age, job, salary)

staff_info('Jerry',20,'dev',9000.00)
结果:Jerry 20 dev 9000.0

但是有的时候,也不太确定要传递参数的个数,并且这些参数明显是具有相关性的,可以通过传递字典表来解决这个问题。

def func(**arg),使用**来表示将传递的多余部分以字典表方式处理
扩展阅读
https://www.cnblogs.com/xuyuanyuan123/p/6674645.html
要注意的是,传递的是一个键值对,其中键的值并不需要加上引号。

def staff_info(**kwargs):
    print(kwargs)
staff_info(name='Lucy', age=20, job='dev', salary=11000)
结果:{'salary': 11000, 'age': 20, 'job': 'dev', 'name': 'Lucy'}

如果要传递的参数本身就已经是一个dict类型,需要进行解包操作。

def staff_info(**kwargs):
    print(kwargs)
lucy_info = dict(name='Lucy', age=20, job='dev', salary=11000)
staff_info(**lucy_info)

如果不进行解包操作,则会报错:

def staff_info(**kwargs):
    print(kwargs)
lucy_info = dict(name='Lucy', age=20, job='dev', salary=11000)
staff_info(lucy_info)

Traceback (most recent call last):
  File "D:/str_2_unicode/str_2_unicode.py", line 7, in <module>
    staff_info(lucy_info)
TypeError: staff_info() takes 0 positional arguments but 1 was given
posted on 2022-08-01 13:57  飞飞fly  阅读(52)  评论(0编辑  收藏  举报