一,函数的定义

函数最只要的目的:封装一个功能。
函数对象由函数定义创建。函数对象上的唯一操作是调用它:FUNC(参数列表)。
函数对象实际上有两种风格:内置函数和用户定义函数。两者都支持相同的操作(调用函数),但实现不同,因此对象类型不同。

二,函数的优点是什么

1,减少代码重复率。
2,增强代码可阅读性。

三,函数的组成部分

  1. def my_len(): #关键字,函数名,括号,冒号
  2. list1 = [1, 2, 3, 4]
  3. count = 0
  4. for i in list1:
  5. count = count + 1
  6. print(count)
  7. my_len()

四,执行函数

  1. my_len() #函数名+括号

函数的参数

位置参数

案例1:
求变动的两数之和:
# 函数在传参时,会根据位置一一对应进行传递

  1. def sum(a,b): # a,b为形参
  2. print(a+b)
  3. sum(2,4) # 2,4为实参

>

  1. 6

形参默认值

这里形参定义了默认值,引用函数时没有进行传参,则用默认值

  1. def sum(a=2,b=2,c=3):
  2. print(a+b+c)
  3. return
  4. sum()

>

  1. 7

这里形参定义了默认值,引用函数时进行传参,则默认值没有作用

  1. def sum(a=2,b=2,c=3):
  2. print(a+b+c)
  3. return
  4. sum(4,5,6)

>

  1. 15

关键字参数

可以不按照形参定义的顺序进行传递,直接根据参数名进行参数传递

  1. def sum(a=2,b=2,c=3):
  2. print('a:',a)
  3. print('b:',b)
  4. print('c:',c)
  5. return
  6. sum(b=4,a=5,c=7)

>

  1. a: 5
  2. b: 4
  3. c: 7

位置参数和关键字参数可以混合使用,但是必须将位置参数写在前面

  1. def sum(a=2,b=2,c=3):
  2. print('a:',a)
  3. print('b:',b)
  4. print('c:',c)
  5. return
  6. sum(4,b=5,c=9)

>

  1. a: 4
  2. b: 5
  3. c: 9

参数类型

函数在调用时,解析器不会检查实参的类型
# 实参可以传递任意类型的对象

```python

!/usr/bin/python

-- coding: UTF-8 --

def func1(a): print(a) return

下面可以依次测试,都可以顺利执行

b = 123 b = True b = ‘python’ b = None b = [1,2,3] b = {‘name’: ‘feige’}

func1(b)

  1. <a name="IUHL5"></a>
  2. ### 函数的重新赋值
  3. # 在函数中对形参进行重新赋值,不会影响其他变量
  4. ```python
  5. #!/usr/bin/python
  6. # -*- coding: UTF-8 -*-
  7. # 定义函数
  8. def fn1(a):
  9. a = 10;
  10. print('a = ', a)
  11. c = 30
  12. fn1(c)
  13. print(c)

>

  1. a = 10
  2. 30

将c修改为20

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(a):
  5. a = 10;
  6. print('a = ', a)
  7. c = 20
  8. fn1(c)
  9. print(c)

>

  1. a = 10
  2. 20

如果形参执行的是一个对象,当我们通过形参去修改对象时,会影响所有指向该对象的变量。

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(a):
  5. a[0] = 10;
  6. print('a = ', a)
  7. c = [1,2,3]
  8. fn1(c)
  9. print(c)
  1. a = [10, 2, 3]
  2. [10, 2, 3]

不定长参数(*)

问题:想求几个数的和,但是几个数字不确定
# 定义函数时,在形参前面加一个,这样这个形参将会获取到所有的实参,它会将所有的实参保存到一个元组中 ```python def fn1(a): print(‘a = ‘,a,type(a))

fn1(2,3,4)

  1. >>>
  2. ```python
  3. a = (2, 3, 4) <class 'tuple #类型为元组

那么,思路:

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(*nums):
  5. # 定义1个变量,保存和的结果
  6. result = 0
  7. # 遍历出每个元素的值
  8. for i in nums:
  9. result += i
  10. print(result)
  11. fn1(2,3,4) # 这里就可以传任意个参数

>

  1. 9

带星号的参数只能有一个
# 带星号的参数,可以与其他参数配合使用
# 第一个参数给a,第二个参数给b,剩余的全部给C

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(a,b,*c):
  5. print('a = ',a)
  6. print('b = ',b)
  7. print('c = ',c)
  8. fn1(2,3,4,5,6)

>

  1. a = 2
  2. b = 3
  3. c = (4, 5, 6)

可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(a,*b,c):
  5. print('a = ',a)
  6. print('b = ',b)
  7. print('c = ',c)
  8. fn1(2,3,4,5,c=6) # 这里由于*b在中间,c必须指定值,否则会报错

>

  1. a = 2
  2. b = (3, 4, 5)
  3. c = 6

所有位置参数都给a,则b和c都需要使用关键字参数

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(*a,b,c):
  5. print('a = ',a)
  6. print('b = ',b)
  7. print('c = ',c)
  8. fn1(2,3,4,b=5,c=6)

>

  1. a = (2, 3, 4)
  2. b = 5
  3. c = 6

如果在形参的开头直接写一个*,则要求所有参数必须以关键字参数进行传递

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(*,a,b,c):
  5. print('a = ',a)
  6. print('b = ',b)
  7. print('c = ',c)
  8. fn1(a=4,b=5,c=6)

>

  1. a = 4
  2. b = 5
  3. c = 6

不定长参数(**)

*形参只能接受位置参数,不能接受关键字参数,如下:

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(*a):
  5. print('a = ',a)
  6. fn1(a=4,b=5,c=6)

>

  1. Traceback (most recent call last):
  2. File "py01.py", line 8, in <module>
  3. fn1(a=4,b=5,c=6)
  4. TypeError: fn1() got an unexpected keyword argument 'a'

**形参可以接受其他的关键字参数,它会将这些参数保存到一个字典中,字典的key就是参数的名字,字典的value就是参数的值

```python

!/usr/bin/python

-- coding: UTF-8 --

定义函数

def fn1(**a): print(‘a = ‘,a,type(a))

fn1(b=5,c=6)

  1. >>>
  2. ```python
  3. a = {'b': 5, 'c': 6} <class 'dict'>

**形参只能有一个,并且必须写在所有参数的最后

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(b,c,**a):
  5. print('a = ',a,type(a))
  6. print('b = ', b)
  7. print('c = ', c)
  8. fn1(b=1,c=2,d=8,f=9)

>

  1. a = {'d': 8, 'f': 9} <class 'dict'>
  2. b = 1
  3. c = 2

参数的解包

```python

!/usr/bin/python

-- coding: UTF-8 --

定义函数

def fn1(a,b,c): print(‘a = ‘, a) print(‘b = ‘, b) print(‘c = ‘, c)

创建1个元组

t= (10,20,30)

fn1(t) #这样会报错,会将t认为是1个参数

  1. 更改:
  2. ```python
  3. #!/usr/bin/python
  4. # -*- coding: UTF-8 -*-
  5. # 定义函数
  6. def fn1(a,b,c):
  7. print('a = ', a)
  8. print('b = ', b)
  9. print('c = ', c)
  10. # 创建1个元组
  11. t= (10,20,30)
  12. fn1(t[0],t[1],t[2])

>

  1. a = 10
  2. b = 20
  3. c = 30

但是上面写法比较不便
传递实参时,也可以在序列类型的参数前加*号,这样它会自动将序列中的元素依次作为参数传递
这里要求序列中元素的个数必须和形参的个数保持一致 ```python

!/usr/bin/python

-- coding: UTF-8 --

定义函数

def fn1(a,b,c): print(‘a = ‘, a) print(‘b = ‘, b) print(‘c = ‘, c)

创建1个元组

t= (10,20,30)

fn1(t) #解包元组用

  1. >>>
  2. ```python
  3. a = 10
  4. b = 20
  5. c = 30
  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn1(a,b,c):
  5. print('a = ', a)
  6. print('b = ', b)
  7. print('c = ', c)
  8. # 创建1个字典
  9. dict1 = {'a': 100, 'b':200, 'c':300}
  10. fn1(**dict1) # 解包字典用**

>

  1. a = 100
  2. b = 200
  3. c = 300

函数的返回值:

return 的作用停止函数体的运行。和break的功能一样。并且返回给这个函数一个值。
1> return 空或者没有return时,打印函数执行者时,为None ```python def func1(): print (888) return

def func2(): print(9)

print(func1()) print(func2())

  1. >>>
  2. ```python
  3. 888
  4. None
  5. 9
  6. None

2,return 加一个值,返回给函数这个值,这个值是什么类型就返回什么类型
3,return 加多个值是,返回给函数一个由这些值组成的元组,如

  1. def func2():
  2. name = 'python'
  3. return name
  4. def func3():
  5. name = 'python'
  6. money = 19990
  7. return name,money
  8. print(func2())
  9. print(func3())

>

  1. python
  2. ('python', 19990)

函数多个返回值

  1. # -*- coding: utf-8 -*-
  2. # @Author: afei
  3. def func1(a, b):
  4. x = a // b
  5. y = a % b
  6. return x,y # 实际上返回一个元组
  7. print(func1(12,7))

>

  1. (1, 5)

文档字符串

DocStrings 文档字符串是一个重要工具,用于解释文档程序,帮助你的程序文档更加简单易懂。
我们可以在函数体的第一行使用一对三个单引号 ‘’’ 或者一对三个双引号 “”” 来定义文档字符串。
你可以使用 doc(注意双下划线)调用函数中的文档字符串属性。 ```python

!/usr/bin/python

-- coding: UTF-8 --

def printMax(x,y): ‘’’打印两个数中的最大值。

  1. 两个值必须都是在整形数。'''
  2. x=int(x)
  3. y=int(y)
  4. if x>y:
  5. print(x,'最大')
  6. else:
  7. print(y,'最大')

printMax(3,5)

  1. >>>
  2. ```python
  3. 5 最大
  4. 打印两个数中的最大值。
  5. 两个值必须都是在整形数。

help函数
查看某个函数的使用说明书

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. # 定义函数
  4. def fn4(*a):
  5. return a
  6. result1 = fn4(1,2,3)
  7. #print(result1)
  8. help(print)

> ```python Help on built-in function print in module builtins:

print(…) print(value, …, sep=’ ‘, end=’\n’, file=sys.stdout, flush=False)

  1. Prints the values to a stream, or to sys.stdout by default.
  2. Optional keyword arguments:
  3. file: a file-like object (stream); defaults to the current sys.stdout.
  4. sep: string inserted between values, default a space.
  5. end: string appended after the last value, default a newline.
  6. flush: whether to forcibly flush the stream.
  1. <a name="c2wky"></a>
  2. ### 函数作用域
  3. 也叫名称空间<br />全局名称空间:创建的存储“变量名与值的关系”的空间叫做**全局名称空间**<br />局部名称空间:在函数的运行中开辟的临时的空间叫做**局部名称空间**<br />内置名称空间:内置名称空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
  4. ---
  5. python中的作用域分4种情况:
  6. - L:local,局部作用域,即函数中定义的变量;
  7. - E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的(闭包常见);
  8. - G:globa,全局变量,就是模块级别定义的变量;
  9. - B:built-in,系统固定模块里面的变量,比如int, bytearray等。
  10. 加载变量的优先级顺序依次是:py 内置作用域>当前模块中的全局(文件从上而下读取)>外层作用域>局部作用域<br />搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。<br />当然,local 和 enclosing 是相对的,enclosing 变量相对上层来说也是 local 。
  11. ```python
  12. # -*- coding: utf-8 -*-
  13. # @Atthor: fei
  14. def fn1():
  15. a = 18
  16. print('a = ', a)
  17. def fn2():
  18. print('a = ', a)
  19. fn1()
  20. fn2() # 会报错,因为fn2识别不到a

>

  1. D:\Python-study>python py01.py
  2. a = 18
  3. Traceback (most recent call last):
  4. File "py01.py", line 10, in <module>
  5. fn2()
  6. File "py01.py", line 8, in fn2
  7. print('a = ', a)
  8. NameError: name 'a' is not defined

```python

-- coding: utf-8 --

@Atthor: fei

x=6 def f2(): print(x) x=5 f2()

变量是先声明,再引用的

错误的原因在于 print(x),解释器会在局部作用域找,会找到x=5(函数已经加载到内存),但x使用在声明前了,所以报错:

local variable ‘x’ referenced before assignment.如何证明找到了x=5呢?简单:注释掉x=5,x=6

报错为:name ‘x’ is not defined

同理

x=6 def f2(): x+=1 #local variable ‘x’ referenced before assignment. x 使用之前已经被声明了

x+=1:x = x + 1;x 已经被声明了,x=6,这里等于 6 = 6 + 1,发生报错

  1. <a name="Y93c3"></a>
  2. ### 变量的修改
  3. <a name="lx8QE"></a>
  4. #### 关键字global:
  5. ```python
  6. # -*- coding: utf-8 -*-
  7. # @Atthor: fei
  8. x=6
  9. def f2():
  10. global x
  11. print(x)
  12. x+=1
  13. f2()
  14. print(x)

>

  1. 6
  2. 7

但是Global只能修改全部变量,下面就会报错: ```python

-- coding: utf-8 --

@Atthor: fei

def f2(): x=6 def f3(): global x print(x) x+=1 f2() print(x)

  1. >>>
  2. ```python
  3. Traceback (most recent call last):
  4. File "py01.py", line 11, in <module>
  5. print(x)
  6. NameError: name 'x' is not defined

关键字nonlocal:

global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量怎么办呢,这时就需要nonlocal关键字了

  1. # -*- coding: utf-8 -*-
  2. # @Atthor: fei
  3. x = 100
  4. def f2():
  5. x=6
  6. def f3():
  7. nonlocal x
  8. x = 9
  9. print(x)
  10. f3()
  11. f2()
  12. print(x)

>

  1. 9 #
  2. 100 # 这里能证明nonlocal修改的只是上一层的

函数内部调用函数

```python

-- coding: utf-8 --

@Atthor: fei

def fn1(): print(‘hello Python’)

def fn2(): print(‘hello Python’) fn1() print(‘hello Linux’)

fn2()

  1. >>>
  2. ```python
  3. hello Python
  4. hello Python
  5. hello Linux

练习题:
问题1:定义函数,求n到m之和

  1. # -*- coding: utf-8 -*-
  2. # @Author: afei
  3. def add(n,m):
  4. sum = 0
  5. for i in range(n,m+1):
  6. sum += i
  7. return sum
  8. resutl1 = add(1,9)
  9. print(resutl1)

问题2:求一个n的阶乘

  1. # -*- coding: utf-8 -*-
  2. # @Author: afei
  3. def fac(n):
  4. x = 1
  5. for i in range(1,n+1):
  6. x *= i
  7. return x
  8. print(fac(4))

问题3: 计算m阶乘的和
m=4 ==> 1! + 2! + 3! + 4!

  1. # -*- coding: utf-8 -*-
  2. # @Author: afei
  3. def fac(n):
  4. x = 1
  5. for i in range(1,n+1):
  6. x *= i
  7. return x
  8. # print(fac(4))
  9. def fac2(m):
  10. x = 0
  11. for i in range(1,m+1):
  12. x += fac(i)
  13. return x
  14. print(fac2(4))

递归函数

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

递归函数特性:

必须有一个明确的结束条件;
每次进入更深一层递归时,问题规模相比上次递归都应有所减少
相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入)。
递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

问题1:求1到n的和

  1. # -*- coding: utf-8 -*-
  2. # @Author: afei
  3. num = 0
  4. def outer():
  5. global num
  6. num += 1
  7. print(num)
  8. if num < 5:
  9. outer()
  10. outer()

>

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5

问题2:求n的阶乘 ```python

-- coding: utf-8 --

@Author: afei

def fun1(n): if n == 0: return 1 return n * fun1(n-1) print(fun1(3))

  1. >>>
  2. ```python
  3. 6