- 一,函数的定义
- 二,函数的优点是什么
- 三,函数的组成部分
- 四,执行函数
- 函数的参数
- 这里形参定义了默认值,引用函数时没有进行传参,则用默认值
- 这里形参定义了默认值,引用函数时进行传参,则默认值没有作用
- 可以不按照形参定义的顺序进行传递,直接根据参数名进行参数传递
- 位置参数和关键字参数可以混合使用,但是必须将位置参数写在前面
- 函数在调用时,解析器不会检查实参的类型
# 实参可以传递任意类型的对象 - !/usr/bin/python
- -- coding: UTF-8 --
- 下面可以依次测试,都可以顺利执行
- 如果形参执行的是一个对象,当我们通过形参去修改对象时,会影响所有指向该对象的变量。
- 带星号的参数只能有一个
# 带星号的参数,可以与其他参数配合使用
# 第一个参数给a,第二个参数给b,剩余的全部给C - 可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递
- 所有位置参数都给a,则b和c都需要使用关键字参数
- 如果在形参的开头直接写一个*,则要求所有参数必须以关键字参数进行传递
- *形参只能接受位置参数,不能接受关键字参数,如下:
- **形参可以接受其他的关键字参数,它会将这些参数保存到一个字典中,字典的key就是参数的名字,字典的value就是参数的值
- !/usr/bin/python
- -- coding: UTF-8 --
- 定义函数
- **形参只能有一个,并且必须写在所有参数的最后
- !/usr/bin/python
- -- coding: UTF-8 --
- 定义函数
- 创建1个元组
- !/usr/bin/python
- -- coding: UTF-8 --
- 定义函数
- 创建1个元组
- !/usr/bin/python
- -- coding: UTF-8 --
- -- coding: utf-8 --
- @Atthor: fei
- 变量是先声明,再引用的
- 错误的原因在于 print(x),解释器会在局部作用域找,会找到x=5(函数已经加载到内存),但x使用在声明前了,所以报错:
- local variable ‘x’ referenced before assignment.如何证明找到了x=5呢?简单:注释掉x=5,x=6
- 报错为:name ‘x’ is not defined
- 同理
- x+=1:x = x + 1;x 已经被声明了,x=6,这里等于 6 = 6 + 1,发生报错
- -- coding: utf-8 --
- @Atthor: fei
- -- coding: utf-8 --
- @Atthor: fei
- -- coding: utf-8 --
- @Author: afei
一,函数的定义
函数最只要的目的:封装一个功能。
函数对象由函数定义创建。函数对象上的唯一操作是调用它:FUNC(参数列表)。
函数对象实际上有两种风格:内置函数和用户定义函数。两者都支持相同的操作(调用函数),但实现不同,因此对象类型不同。
二,函数的优点是什么
三,函数的组成部分
def my_len(): #关键字,函数名,括号,冒号
list1 = [1, 2, 3, 4]
count = 0
for i in list1:
count = count + 1
print(count)
my_len()
四,执行函数
my_len() #函数名+括号
函数的参数
位置参数
案例1:
求变动的两数之和:
# 函数在传参时,会根据位置一一对应进行传递
def sum(a,b): # a,b为形参
print(a+b)
sum(2,4) # 2,4为实参
>
6
形参默认值
这里形参定义了默认值,引用函数时没有进行传参,则用默认值
def sum(a=2,b=2,c=3):
print(a+b+c)
return
sum()
>
7
这里形参定义了默认值,引用函数时进行传参,则默认值没有作用
def sum(a=2,b=2,c=3):
print(a+b+c)
return
sum(4,5,6)
>
15
关键字参数
可以不按照形参定义的顺序进行传递,直接根据参数名进行参数传递
def sum(a=2,b=2,c=3):
print('a:',a)
print('b:',b)
print('c:',c)
return
sum(b=4,a=5,c=7)
>
a: 5
b: 4
c: 7
位置参数和关键字参数可以混合使用,但是必须将位置参数写在前面
def sum(a=2,b=2,c=3):
print('a:',a)
print('b:',b)
print('c:',c)
return
sum(4,b=5,c=9)
>
a: 4
b: 5
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)
<a name="IUHL5"></a>
### 函数的重新赋值
# 在函数中对形参进行重新赋值,不会影响其他变量
```python
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(a):
a = 10;
print('a = ', a)
c = 30
fn1(c)
print(c)
>
a = 10
30
将c修改为20
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(a):
a = 10;
print('a = ', a)
c = 20
fn1(c)
print(c)
>
a = 10
20
如果形参执行的是一个对象,当我们通过形参去修改对象时,会影响所有指向该对象的变量。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(a):
a[0] = 10;
print('a = ', a)
c = [1,2,3]
fn1(c)
print(c)
a = [10, 2, 3]
[10, 2, 3]
不定长参数(*)
问题:想求几个数的和,但是几个数字不确定
# 定义函数时,在形参前面加一个,这样这个形参将会获取到所有的实参,它会将所有的实参保存到一个元组中 ```python def fn1(a): print(‘a = ‘,a,type(a))
fn1(2,3,4)
>>>
```python
a = (2, 3, 4) <class 'tuple #类型为元组
那么,思路:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(*nums):
# 定义1个变量,保存和的结果
result = 0
# 遍历出每个元素的值
for i in nums:
result += i
print(result)
fn1(2,3,4) # 这里就可以传任意个参数
>
9
带星号的参数只能有一个
# 带星号的参数,可以与其他参数配合使用
# 第一个参数给a,第二个参数给b,剩余的全部给C
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(a,b,*c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn1(2,3,4,5,6)
>
a = 2
b = 3
c = (4, 5, 6)
可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(a,*b,c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn1(2,3,4,5,c=6) # 这里由于*b在中间,c必须指定值,否则会报错
>
a = 2
b = (3, 4, 5)
c = 6
所有位置参数都给a,则b和c都需要使用关键字参数
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(*a,b,c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn1(2,3,4,b=5,c=6)
>
a = (2, 3, 4)
b = 5
c = 6
如果在形参的开头直接写一个*,则要求所有参数必须以关键字参数进行传递
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(*,a,b,c):
print('a = ',a)
print('b = ',b)
print('c = ',c)
fn1(a=4,b=5,c=6)
>
a = 4
b = 5
c = 6
不定长参数(**)
*形参只能接受位置参数,不能接受关键字参数,如下:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(*a):
print('a = ',a)
fn1(a=4,b=5,c=6)
>
Traceback (most recent call last):
File "py01.py", line 8, in <module>
fn1(a=4,b=5,c=6)
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)
>>>
```python
a = {'b': 5, 'c': 6} <class 'dict'>
**形参只能有一个,并且必须写在所有参数的最后
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(b,c,**a):
print('a = ',a,type(a))
print('b = ', b)
print('c = ', c)
fn1(b=1,c=2,d=8,f=9)
>
a = {'d': 8, 'f': 9} <class 'dict'>
b = 1
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个参数
更改:
```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[0],t[1],t[2])
>
a = 10
b = 20
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) #解包元组用
>>>
```python
a = 10
b = 20
c = 30
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn1(a,b,c):
print('a = ', a)
print('b = ', b)
print('c = ', c)
# 创建1个字典
dict1 = {'a': 100, 'b':200, 'c':300}
fn1(**dict1) # 解包字典用**
>
a = 100
b = 200
c = 300
函数的返回值:
return 的作用停止函数体的运行。和break的功能一样。并且返回给这个函数一个值。
1> return 空或者没有return时,打印函数执行者时,为None ```python def func1(): print (888) return
def func2(): print(9)
print(func1()) print(func2())
>>>
```python
888
None
9
None
2,return 加一个值,返回给函数这个值,这个值是什么类型就返回什么类型
3,return 加多个值是,返回给函数一个由这些值组成的元组,如
def func2():
name = 'python'
return name
def func3():
name = 'python'
money = 19990
return name,money
print(func2())
print(func3())
>
python
('python', 19990)
函数多个返回值
# -*- coding: utf-8 -*-
# @Author: afei
def func1(a, b):
x = a // b
y = a % b
return x,y # 实际上返回一个元组
print(func1(12,7))
>
(1, 5)
文档字符串
DocStrings 文档字符串是一个重要工具,用于解释文档程序,帮助你的程序文档更加简单易懂。
我们可以在函数体的第一行使用一对三个单引号 ‘’’ 或者一对三个双引号 “”” 来定义文档字符串。
你可以使用 doc(注意双下划线)调用函数中的文档字符串属性。 ```python!/usr/bin/python
-- coding: UTF-8 --
def printMax(x,y): ‘’’打印两个数中的最大值。
两个值必须都是在整形数。'''
x=int(x)
y=int(y)
if x>y:
print(x,'最大')
else:
print(y,'最大')
printMax(3,5)
>>>
```python
5 最大
打印两个数中的最大值。
两个值必须都是在整形数。
help函数
查看某个函数的使用说明书
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 定义函数
def fn4(*a):
return a
result1 = fn4(1,2,3)
#print(result1)
help(print)
> ```python Help on built-in function print in module builtins:
print(…) print(value, …, sep=’ ‘, end=’\n’, file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
<a name="c2wky"></a>
### 函数作用域
也叫名称空间<br />全局名称空间:创建的存储“变量名与值的关系”的空间叫做**全局名称空间**<br />局部名称空间:在函数的运行中开辟的临时的空间叫做**局部名称空间**<br />内置名称空间:内置名称空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
---
python中的作用域分4种情况:
- L:local,局部作用域,即函数中定义的变量;
- E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的(闭包常见);
- G:globa,全局变量,就是模块级别定义的变量;
- B:built-in,系统固定模块里面的变量,比如int, bytearray等。
加载变量的优先级顺序依次是:py 内置作用域>当前模块中的全局(文件从上而下读取)>外层作用域>局部作用域<br />搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。<br />当然,local 和 enclosing 是相对的,enclosing 变量相对上层来说也是 local 。
```python
# -*- coding: utf-8 -*-
# @Atthor: fei
def fn1():
a = 18
print('a = ', a)
def fn2():
print('a = ', a)
fn1()
fn2() # 会报错,因为fn2识别不到a
>
D:\Python-study>python py01.py
a = 18
Traceback (most recent call last):
File "py01.py", line 10, in <module>
fn2()
File "py01.py", line 8, in fn2
print('a = ', a)
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,发生报错
<a name="Y93c3"></a>
### 变量的修改
<a name="lx8QE"></a>
#### 关键字global:
```python
# -*- coding: utf-8 -*-
# @Atthor: fei
x=6
def f2():
global x
print(x)
x+=1
f2()
print(x)
>
6
7
但是Global只能修改全部变量,下面就会报错: ```python
-- coding: utf-8 --
@Atthor: fei
def f2(): x=6 def f3(): global x print(x) x+=1 f2() print(x)
>>>
```python
Traceback (most recent call last):
File "py01.py", line 11, in <module>
print(x)
NameError: name 'x' is not defined
关键字nonlocal:
global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量怎么办呢,这时就需要nonlocal关键字了
# -*- coding: utf-8 -*-
# @Atthor: fei
x = 100
def f2():
x=6
def f3():
nonlocal x
x = 9
print(x)
f3()
f2()
print(x)
>
9 #
100 # 这里能证明nonlocal修改的只是上一层的
函数内部调用函数
```python
-- coding: utf-8 --
@Atthor: fei
def fn1(): print(‘hello Python’)
def fn2(): print(‘hello Python’) fn1() print(‘hello Linux’)
fn2()
>>>
```python
hello Python
hello Python
hello Linux
练习题:
问题1:定义函数,求n到m之和
# -*- coding: utf-8 -*-
# @Author: afei
def add(n,m):
sum = 0
for i in range(n,m+1):
sum += i
return sum
resutl1 = add(1,9)
print(resutl1)
问题2:求一个n的阶乘
# -*- coding: utf-8 -*-
# @Author: afei
def fac(n):
x = 1
for i in range(1,n+1):
x *= i
return x
print(fac(4))
问题3: 计算m阶乘的和
m=4 ==> 1! + 2! + 3! + 4!
# -*- coding: utf-8 -*-
# @Author: afei
def fac(n):
x = 1
for i in range(1,n+1):
x *= i
return x
# print(fac(4))
def fac2(m):
x = 0
for i in range(1,m+1):
x += fac(i)
return x
print(fac2(4))
递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归函数特性:
必须有一个明确的结束条件;
每次进入更深一层递归时,问题规模相比上次递归都应有所减少
相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入)。
递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
问题1:求1到n的和
# -*- coding: utf-8 -*-
# @Author: afei
num = 0
def outer():
global num
num += 1
print(num)
if num < 5:
outer()
outer()
>
1
2
3
4
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))
>>>
```python
6