函数(一)

函数简介

  • 是一个对象
  • 用来保存可执行的代码,并且可以再需要时,进行多次调用
  • 函数保存的代码不能立即执行,需要调用的时候才会执行
  • 语法
1
2
def 函数名([形参1,形参2......]):
代码块
1
2
3
4
5
def a():
print('三三不得酒吖')
a()

三三不得酒吖

函数的参数

形参

  • 定义形参就相当于在函数内部生命了变量,并不是赋值

实参

  • 若函数制定了形参,那么在调用函数式必须传递实参,实参将赋值给对应的形参,有几个形参就有几个实参
1
2
3
4
5
6
def fn(a,b):
print(a+b)

fn(1,2)

3

参数传递方式

  • 定义形参时,可以为形参指定默认值,指定默认值后,如果传参,则默认值不生效,若没有传参,则默认值生效
1
2
3
4
5
6
7
8
9
10
def fn(a,b,c=10):
print('a=',a)
print('b=',b)
print('c=',c)

fn(1,2)

a= 1
b= 2
c= 10
1
2
3
4
5
6
7
8
9
10
def fn(a,b,c=10):
print('a=',a)
print('b=',b)
print('c=',c)

fn(1,2,3)

a= 1
b= 2
c= 3
  • 位置参数,位置参数就是讲对应位置的实参赋值给对应位置的形参
1
2
3
4
5
6
7
8
9
10
def fn(a,b,c):
print('a=',a)
print('b=',b)
print('c=',c)

fn(1,2,3)

a= 1
b= 2
c= 3
  • 关键字传参 可以不按照形参定义的顺序去传递,根据参数名传递
1
2
3
4
5
6
7
8
9
10
def fn(a,b,c=10):
print('a=',a)
print('b=',b)
print('c=',c)

fn(a=1,c=2,b=3)

a= 1
b= 3
c= 2
  • 混合使用未知参数和关键字参数时,必须将未知参数写到关键字参数前
1
2
3
4
5
6
7
8
9
10
def fn(a,b,c=10):
print('a=',a)
print('b=',b)
print('c=',c)

fn(1,2,c=3)

a= 1
b= 2
c= 3

实参类型

  • 实参可以传递任意类型的对象
1
2
3
4
5
6
7
8
9
def fn1():
pass

def fn(a):
print(a)

fn(fn1)

<function fn1 at 0x0000025540836048>

不定长参数

  • 定义函数时,在形参前加*,这个形参可以获取所有实参,并保存到一个元祖
  • 带*的形参只能有一个,可以配合其他参数,关键字传参放到最后
  • 形参*只能接受未知参数,不能接受关键字参数
  • **形参可以接受其它关键字参数,并统一保存到字典中,字典的key就是参数名字,value就是参数值
  • **形参只有一个,必须写在所有参数后面
1
2
3
4
5
6
7
8
def fn(a,*b):
print(a)
print(b)

fn(1,2,3)

1
(2, 3)
1
2
3
4
5
6
7
8
9
10
def fn(a,*b,c):
print(a)
print(b)
print(c)

fn(1,2,3,c=4)

1
(2, 3)
4
1
2
3
4
5
6
7
8
def fn(**b):
#print(a)
print(b)
#print(c)

fn(a = 3,c=4)

{'a': 3, 'c': 4}
1
2
3
4
5
6
7
8
9
10
def fn(a,c,**b):
print(a)
print(b)
print(c)

fn(1,2,d = 3,e = 4)

1
{'d': 3, 'e': 4}
2

参数拆包

  • 传递实参,也可以在序列类型的参数前加* 这样可以将序列中的元素一次作为参数进行传递
  • 要求序列中的个数与形参个数一致
1
2
3
4
5
6
7
8
9
10
11
def fn(a,b,c):
print(a)
print(b)
print(c)
return a,b,c
t = (1,2,3)
fn(t[0],t[1],t[2])

1
2
3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def fn(a,b,c):
print(a)
print(b)
print(c)
return a,b,c
d = {'a':1,'b':2,'c':3}
fn(**d)
print(fn(**d))

1
2
3
1
2
3
(1, 2, 3)
1
2
3
4
5
6
7
8
9
10
11
def fn(a,b,c):
print(a)
print(b)
print(c)
return a,b,c
d = {'e':1,'f':2,'g':3}
fn(*d.items())

('e', 1)
('f', 2)
('g', 3)

函数返回值

  • 返回值就是函数执行以后返回的结果
  • 通过return制定函数返回值
  • return后面可以跟任意对象,甚至一个函数
  • return后面的函数都不会进行
1
2
3
4
5
6
7
8
9
10
11
12
def fn():
for i in range(5):
if i ==3:
return
print(i)
print('打印完毕')

fn()

0
1
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def fn():
for i in range(5):
if i ==3:
break
#continue
#return
print(i)
print('打印完毕')

fn()

0
1
2
打印完毕
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def fn():
for i in range(5):
if i ==3:
#break
continue
#return
print(i)
print('打印完毕')

fn()

0
1
2
4
打印完毕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def fn(a,b,c):
'''

:param a: 作用:........
:param b: 作用:........
:param c: 作用:........
:return: 返回值
'''
return 123

help(fn)

fn(a, b, c)
:param a: 作用:........
:param b: 作用:........
:param c: 作用:........
:return: 返回值

函数作用域

  • scope
  • 作用域是指变量生效的区域
  • 有两种作用域
    • 全局作用域
    • 全局作用域在程序执行时创建,在程序执行结束时销毁
    • 所有函数以外的区域都是全局作用域
    • 在全局作用域定义的变量,是全局变量,可以在程序的任意位置访问
    • 函数作用域
    • 在函数调用时创建,在调用结束时销毁
    • 没调用一次就会产生一个新的函数作用域
    • 在函数作用域中定义的变量都是局部变量,只能在函数内部访问
    • global函数可以定义全局变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#就是变量的生效区域
#global 声明全局变量
b = 222
def fn():
global a
a = 123
print('函数内部a=',a)
print('函数内部b=',b)

fn()
print('函数外部a=',b)
print('函数外部b=',a)

def fn2():


def fn3():
print('函数内部',a)
fn3()

fn2()

函数内部a= 123
函数内部b= 222
函数外部a= 222
函数外部b= 123
函数内部 123

命名空间

  • 实际上就是一个字典,专门用来春村变量
  • locals()用来获取当前作用域明明空间
1
2
3
4
5
6
7
a = 111
b = 222

scope = locals()
print(scope)

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000263B81CB0F0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/殷少轩/PycharmProjects/untitled1/python/函数/命名空间1.py', '__cached__': None, 'a': 111, 'b': 222, 'scope': {...}}
  • 如果全局作用域中调用locals()则获取全局命名空间,如果函数作用域中调用locals()则获取函数内命名空间
  • 返回值是一个字典
  • globas()声明全局命名空间
1
2
3
4
5
6
7
8
9
10
11
a = 111
b = 222

scope = locals()
#print(scope)
print(scope['a'])
scope['d'] = 110
print(d)

111
110
1
2
3
4
5
6
7
8
9
10
11
def fn():
a = 123
b = 456
c = 789
scope = locals()
scope['d'] = 110
print(d)

fn()

报错!!!
1
2
3
4
5
6
7
8
9
10
11
12
13
a = 123
b = 456
c = 789

def fn():
scope = globals()
scope['d'] = 110
print(d)

fn()

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001FB1F5EB0F0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/殷少轩/PycharmProjects/untitled1/python/函数/命名空间.py', '__cached__': None, 'fn': <function fn at 0x000001FB1F4F6048>}
110

递归函数

  • 递归是解决问题的一种方式没他的整体思想是讲一个大问题分解为一个个小问题,直到无法分解时,再去解决问题
  • 有两个条件
    • 1.基线条件:问题可以被分解为最小问题,当满足基线条件时,递归不执行
    • 2.递归条件:可以将问题继续分解的条件
1
2
3
4
5
6
7
8
9
def fn(b):
if b == 1:
return 1
return b * fn(b-1)

fn(10)
print(fn(10))

3628800
  • 回文字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def fn(s):
if len(s) == 1:
return True
elif s[0] != s[-1]:
return False
elif s[0] == s[-1]:
return fn(s[1:-1])


s = 'abcdcba'
b = fn(s)
print(b)

True

高阶函数

  • 接收函数作为参数,或者将函数作为返回值返回的函数就是高阶函数

    • 接收一个或多个函数作为参数
    • 将函数作为返回值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    a = [1,2,3,4,5,6,7,8,9]
    def fn1(i):
    if i % 2 == 0:
    return True

    def fn():
    b = []
    for i in a :
    if fn1(i):
    b.append(i)
    return b

    c = fn()
    print(c)

    [2, 4, 6, 8]

匿名函数

  • filter()函,过滤的作用,需要传递两个参数

    • 传递一个函数
    • 需要过滤的序列
    • 他有一个返回值,就是过滤后的新的序列(对象)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    a = [1,2,3,4,5,6,7,8,9]

    def fn(i):
    if i % 3 ==0:
    return True
    return False

    print(list(filter(fn,a)))

    [3, 6, 9]
  • 匿名函数:lambda

    • lambda 参数,参数2:表达式
    1
    2
    3
    4
    5
    a = [1,2,3,4,5,6,7,8,9]
    s = lambda x : x%3 ==0
    print(list(filter(s,a)))

    [3, 6, 9]

闭包

  • 将函数作为返回值 也是高阶函数 我们也称为闭包
  • 好处:
    • 通过闭包可以创建一些只有当前函数能访问的变量
    • 可以将一些私有的数据藏到闭包中
  • 函数嵌套
    • 将内部函数作为返回值返回
    • 内部函数必须要是哟经外部函数的变量和参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def func_out(num1):

def func_inner(num2):
num1 = 10
a = num1 + num2
print('结果',a)

print(num1)
func_inner(1)
print(num1)

return func_inner

f = func_out(1)

1
结果 11
1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def func_out(num1):

def func_inner(num2):
nonlocal num1 #修改外部num1的值 实际上实在内部函数定义一个局部变量num1
num1 = 10
a = num1 + num2
print('结果',a)

print(num1)
func_inner(1)
print(num1)

return func_inner

f = func_out(1)

1
结果 11
10

装饰器的引入

  • 我们可以直接通过修改函数中的代码来完成需求但是会产生下一些问题
    • 如果修改函数多,修改起来会比较麻烦
    • 不方便后期维护
    • 违反开闭原则(ocp)
      • 程序的设计,要求开发对程序的扩展,要关闭对程序的修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def fn():
print('我是fn')

def fn1():
print('fn1开始')
fn()
print('fn1结束')

fn1()

fn1开始
我是fn
fn1结束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def add(a,b):

return a + b

def acc(a,b):
print('函数开始计算')
r = add(a,b)
print('函数计算结束')
return r

r = acc(1,2)
print(r)

函数开始计算
函数计算结束
3
  • 装饰器语法糖的一个写法 @a 等价于 ss = a(ss)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def a(old):

def new_fun(*args,**kwargs):
print('start')
r = old(*args,**kwargs)
print('end')
return r

return new_fun

@a
def ss():
print('滴滴滴')

ss()

start
滴滴滴
end