七、函数
函数分类
- 内置函数 : 可以直接用函数名调用,如len(),type()等
- 模块函数 : 通过模块名进行调用,如math.sin()等 (前提是先导入第三方模块)
- 自定义函数 : 按照用户需求随用随定义
7.1 内置函数
内置在Python解释器中的函数,可以直接通过函数名进行调用(不需要提供所属模块名)
https://docs.python.org/zh-cn/3/library/functions.html 官方文档
https://www.runoob.com/python3/python3-built-in-functions.html 菜鸟教程文档
7.1.1 数据类型相关函数
int() , bool() , float() , str() , list() , set() , tuple() ,dict() type()
7.1.2 逻辑判断相关函数
all()函数用于判断给定的可迭代参数 (iterable) 中的所有元素是否都为 TRUE,如果是,返回 True,否则返回 False。 元素除了是 0、空、FALSE 外都算 TRUE。
all("a")
True
all(1) #判断对象必须是可迭代的
![8ede2de44d3ce4b5a5eac977dae8cd99.png](https://i-blog.csdnimg.cn/blog_migrate/3d362250dde7aeb90fbe4fa8f886e3c0.png)
all([1])
True
all([0])
False
all("ab","cd") #只接收一个参数
![cc7a0799ffd43bd127e7e47916cda6d7.png](https://i-blog.csdnimg.cn/blog_migrate/244f36383ce4348ff936426369887436.png)
all(["ab","cd"]) #打包成列表
True
all(("ab","cd")) #打包成元组
True
all({"ab","cd"}) #打包成集合
True
all(1>2) #参数必须可迭代
![ebe7e4643af42bbce7cd6206a99f8c6c.png](https://i-blog.csdnimg.cn/blog_migrate/1ed7b62e98e5bcff3dea217992110d39.png)
all([1>2])
False
all([1<2,"a",0])
False
all([1<2,"a",1])
True
any()函数用于判断给定的可迭代参数 iterable 是否全部为 False,如果是返回 False,如果有一个为 True,则返回 True。
any([1<2,"a",0])
True
any([1>2])
False
any([1>2,0])
False
any([1>2,0,"a"])
True
any("0")
True
any([0])
False
# all([])
True
# any([])
False
list1 = [1,2,"b","cc"]
if list1:
print("全部为真")
全部为真
list2 = [0,1,2]
if list2:
print("全部为真")
全部为真
if all(list2): #list2中有0,所以判断为false
print("全部为真")
all(list2)
False
7.1.3 数学相关
sum() , abs() , min() , max() , pow() , round() , len() , range() ,divmod() 同时取得商和余数
list3 = [1,2,3,4,5]
sum(list3) #传入可迭代序列
15
sum(set(list3))
15
sum(1,2,3,4,5)
![b9b10b266fce258d87df9b45ac6c5375.png](https://i-blog.csdnimg.cn/blog_migrate/681ce2f392c415fdfc7c9cfd952eb279.png)
abs(-1)
1
min(1,2,3)
1
max(1,2,3)
3
pow(2,3)
8
round(4.5)
4
round(5.5)
6
divmod(10,3)
(3, 1)
ord()和chr() : ASCII码转换
ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符
ASCII_百度百科![46bf4e080d537f88dec0f18991859eff.png](https://i-blog.csdnimg.cn/blog_migrate/08016f906f4d14f1fbc14c64a74a7c99.png)
ord("a")
97
chr(97)
'a'
7.2 模块函数
定义在(第三方)库中的函数,通过模块名进行调用
注意:使用模块函数时,需要先导入相对应的库
在Python中用关键字import来引入某个模块,比如要引用模块math,就可以在文件最开始的地方用import math来引入。
形如:
import module1,mudule2...
当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。
在调用math模块中的函数时,必须这样引用:
模块名.函数名
模块函数使用方法
- 通过库(模块)名读取模块函数
- 通过别名读取模块函数
- 直接通过函数名读取
#通过第三方库名读取模块函数,格式 : 库名.函数名 方法一
import math
math.fabs(-1)
1.0
# 通过别名读取模块函数,格式 : 库的别名.函数名 方法二 as
import math as mt
mt.fabs(-1)
1.0
import matplotlib.pyplot
matplotlib.pyplot.plot([1,2,3])
[<matplotlib.lines.Line2D at 0x27927b627b8>]
![ea5e676e5f24af6d6f6f36c053d69924.png](https://i-blog.csdnimg.cn/blog_migrate/81d85d8131e74efd991d91499a14e1cf.png)
import matplotlib.pyplot as plt
plt.plot([1,2,3,7,6,4])
[<matplotlib.lines.Line2D at 0x27927b0ec88>]
![70b2b990b2151a0a7be4c69f1b2aa15a.png](https://i-blog.csdnimg.cn/blog_migrate/4d91eecd9371a706d52d9216aae2fbc1.png)
有时候我们只需要用到模块中的某个函数,只需要引入该函数即可,此时可以用下面方法实现:
from 模块名 import 函数名1,函数名2....
注意:
通过这种方式引入的时候,调用函数时只用给出函数名,不用给出模块名,但是当两个模块中含有相同名称函数的时候,后面一次引入会覆盖前一次引入。也就是说假如模块A中有函数function( ),在模块B中也有函数function( ),如果引入A中的function在先、B中的function在后,那么当调用function函数的时候,是去执行模块B中的function函数。
如果想一次性引入math中所有的东西,还可以通过from math import *来实现
# 直接通过函数名读取,格式 : from 库名 import 函数名 ,函数运用时不用加库名前缀 方法三
from math import sin
sin(1.5)
0.9974949866040544
from math import * #通过math库导入库中所有的函数,和第一种方法的区别,使用函数时不用加库的名字,直接通过函数名进行调用
cos(1.5)
0.0707372016677029
想一想:
为什么必须加上模块名调用呢?
答:
因为可能存在这样一种情况:在多个模块中含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名
import math
#这样会报错
print sqrt(2)
#这样才能正确输出结果
print (math.sqrt(2))
7.2.1 random模块
import random
random.random() # #元素取值从[0,1)随机浮点数
0.24554342501784987
random.seed(1) #设置随机数种子,保证每次取到的数值不变
random.randint(1,5) #在指定范围内生成随机整数
2
random.uniform(20,50) #在指定范围内生成浮点数
40.804399566978034
random.randrange(1,10) # 返回(1-10)随机数据
5
random.randrange(2,20,3) #在指定范围内按照要求步长随机生成一个整数,实际取数范围时从起始值开始到终止值结束,加上步长倍数的所有整数
2
list1=[1,3,6,4,9,11,34,27]
random.choice(list1) #从指定的有序列里随机取数
27
tp1 = (2,4,3,6,67,33,9,0,1)
random.choice(tp1)
9
set1 = {1,34,6,7,0}
random.choice(set1) #集合是无序的
![8992f4fbfef93ba053301510b0391f21.png](https://i-blog.csdnimg.cn/blog_migrate/b4b653f473d6197f038b14c6acd2abe8.png)
random.sample(list1,2) #从指定序列中抽取指定数量的样本
[34, 9]
random.sample(random)
random.sample(tp1,3)
[67, 0, 3]
7.3 自定义函数
为什么需要自定义函数?
在开发程序时,有可能需要某块代码多次,为了提高编写的效率以及代码的重用,通过def关键字把具有独立功能的代码块组织为一个小模块,这就是函数
对于大型的项目, 比较长的代码, 即使是代码的编写者也不可能对内部的每个逻辑记得很清楚.
但是对于一个封装好的函数, 我们只需要知道函数需要传入的参数, 以及函数输出的结果就可以了, 并不需要了解内部逻辑原理是如何实现这一功能的.大大简化了程序开发的难度.
定义函数的格式如下:
def 函数名(参数1,参数2,......):
代码块
return 返回值
参数和返回值都不是必须的
7.3.1 自定义函数的定义和调用
# 定义一个函数,能够完成打印指定信息的功能 定义函数的时候,函数不会被调用,但是会写入内存
def PR():
print ('====================')
print ('人生苦短,我用Python')
print ('====================')
PR() #虽然没有设置参数,不要忘了加括号
====================
人生苦短,我用Python
====================
# 定义一个函数,能够输出自己的姓名和年龄,并且调用这个函数让它执行
def NA():
print("姓名:李雷")
print("年龄:12")
NA()
姓名:李雷
年龄:12
7.3.2 函数的参数
思考题:通过自定义函数计算1234和4321两数之和
def ADD():
print(1234+4321)
ADD()
5555
7.3.2.1 参数的作用
为了让一个函数更通用,即可以随意计算任意两个数字之和,在定义函数的时候需要让函数能够接收数据,即设置函数的参数
def ADD(x,y):
print(x+y)
ADD(1234,4321)
5555
# 定义一个函数,完成前2个数完成加法运算,然后对第3个数,进行减法;然后调用这个函数
def ABC(x,y,z):
a = x + y - z
print(a)
ABC(2,4,8)
-2
# 完成一个函数, 功能和abs相同
def abs_1(x):
if x >= 0:
print(x)
else:
print(-x)
abs_1(-1)
1
abs_1(1)
1
abs_1(0)
0
# 完成一个函数, 功能和sum函数相同,提示:需要用循环
def sum_1(x): #这里的x是指一个可迭代的序列
k = 0
for i in x:
k+=i
print(k)
sum_1([1,2,3,4,5])
15
7.3.2.2 参数的种类
- 形参和实参
- 位置参数和关键字参数
- 参数默认值
形参和实参
实参是实际占用内存地址的实实在在的参数,而形参只是意义上的一种参数,在定义的时候是不占内存地址的
例如自定义函数ABC中,x,y,z就是形参,2,4,8在调用函数时传入的实参,它的值被存储在形参x,y,z中。
位置参数和关键字参数
函数的调用中,可能存在多个实参,在给函数传递参数的时候有两种方式,位置实参和关键字实参
def ABC(x,y,z):
a = x + y - z
print(a)
ABC(2,4,8) #按照位置一一对应传入参数 位置参数
-2
ABC(y=4,z=8,x=2) #关键字参数,为每一个形参传入实参,不用考虑参数的位置
-2
ABC(2,z=8,y=4) #位置参数和关键字参数可以混合使用,
-2
ABC(x=2,4,8) #所有关键字参数必须在位置参数之后
![1cb0a6c4a0bfa67efffa00ab8fc9eaa1.png](https://i-blog.csdnimg.cn/blog_migrate/984545e6cf0c7c80893952a0304a4b9c.png)
参数默认值
def sum_2(x,start=0): #设置参数start的默认值,调用函数的时候可以传入该参数,也可以不传入,不传入时按默认值处理
for i in x:
start+=i
print(start)
sum_2([1,2,3])
6
sum_2([1,2,3],10)
16
#更明显一点的例子
def ABC(x,y,z):
a = x + y - z
print(a)
def abc(x=1,y=1,z=1):
b = x + y - z
print(b)
ABC(1,1,1)
abc() #设置了默认值的参数可以不传参数值
1
1
ABC() #不设置参数默认值,所有参数值都需要传入
![cb9603c97836db99b607c068eeac3ac3.png](https://i-blog.csdnimg.cn/blog_migrate/beda7ae3aab5b8788ecbb0cdac79a22d.png)
abc(2,4,6) #设置了默认值的参数,也可以传入新的参数,函数以新传入的参数为准进行运算
0
# 完成一个函数, 功能和sum函数相同,提示:需要用循环
def sum_1(x): #这里的x是指一个可迭代的序列
k = 0
for i in x:
k+=i
print(k)
sum_1([1,2,3,4,5])
15
7.3.2.3 收集和分配参数
收集参数
所谓的收集参数,就是说只指定一个参数,然后允许调用函数时传入任意数量的参数。
1、收集位置参数
sum(0,1,2) #参数过多会报错
![7aae04a49e59a45a04323714dff0a0d2.png](https://i-blog.csdnimg.cn/blog_migrate/03a099034ebd795183143b8c2fb1c5e5.png)
list2 #把需要计算的数值打包到列表中,作为一个参数传入sum函数中
[0, 1, 2]
sum(list2) #sum函数只能接受两个参数,作为累加的对象必须是一个元素,如果用不定长参数,就可以传递多个参数
3
# 加了星号(*)的变量名会存放所有未命名的位置变量参数
def sum_change(*args):
a = 0
for i in args:
a += i
print(a)
sum_change(1,2,3,4,5)
15
sum_change(4,5,6)
15
sum_change(1,2,3,4,5,6,7,8,9,10)
55
sum_change(*range(0,101))
5050
# 参数前面的星号将提供的所有值都打包放在一个元组中,也就是将这些值都收集起来
def fun(x,*y):
print(x,y)
fun(1,2,3,4,5)
1 (2, 3, 4, 5)
fun(1) #星号意味着收集余下的位置参数,如果没有提供可收集的参数,y将会是一个空元组
1 ()
带星号的参数可以放在任何位置,但是需要使用关键字来指定后续参数
def fun(x,*y,z):
print(x,y,z)
fun(1,2,3,4,5) #星号不能收集关键字参数
![f7a20f860a897f196d5418a1adc5f9fa.png](https://i-blog.csdnimg.cn/blog_migrate/11f75a46fab471c5108115ba8167f9b1.png)
fun(1,2,3,4,z=5)
1 (2, 3, 4) 5
def func1(x,*y,**z):
print(x,y,z)
func1(1,2,3,4,5)
1 (2, 3, 4, 5) {}
2、收集关键字参数
def canshu(**kwargs):
print (kwargs)
canshu(n=1,m=2)
{'n': 1, 'm': 2}
canshu(n=1,m=2,x=4,y=5)
{'n': 1, 'm': 2, 'x': 4, 'y': 5}
#上边收集位置参数时提到*不能收集关键字参数而导致报错,用两个*来收集关键字参数
def func1(x,*y,**z):
print(x,y,z)
func1(1,2,3,4,5)
1 (2, 3, 4, 5) {}
def canshu_1(*args,**kwargs):
print(args,kwargs)
canshu_1(1,2,3,4,5,6,n=1,m=2)
(1, 2, 3, 4, 5, 6) {'n': 1, 'm': 2}
canshu_1(1,2,3,name = "李雷",score = 90)
((1, 2, 3), {'name': '李雷', 'score': 90})
def fun(a, b, *args, **kwargs):
"""可变参数演示示例"""
print ("a =", a)
print ("b =", b)
print ("args =", args)
print ("kwargs: ")
print(kwargs)
fun(1,2)
a = 1
b = 2
args = ()
kwargs:
{}
fun(1,2,3,4,5,6)
a = 1
b = 2
args = (3, 4, 5, 6)
kwargs:
{}
fun(1,2,3,4,5,name = "李雷",score = 90)
a = 1
b = 2
args = (3, 4, 5)
kwargs:
{'name': '李雷', 'score': 90}
分配参数
和收集参数对应的相对应的操作是分配参数,而分配参数同样可以用 和*来实现
def add(x,y):
print(x+y)
add(1,2)
3
cs = (1,2)
add(*cs)
3
def fun1(name,score):
print(name,score)
cj = {'name' :'jim','score':90}
fun1(**cj)
jim
90
# 给定一组数字a,b,c……,请计算$a^2 + b^2 + c^2 + ……$
def s_q(*args):
sum = 0
for n in args:
sum = sum + n * n
print(sum)
s_q(1,2,3,4,5)
55
7.3.3 函数的返回值
- 用return语句指定返回值,不用return而是用print显示出来的函数运行只有in,没有out
- 如果没有return语句,返回值为None
- Python函数可以同时返回多个值
#有return语句
def jia_t(i):
j = i - 2
return j
jia_t(3)
1
# 无return语句
def jia(i):
j = i - 2
jia(3)
def jia(i):
j = i - 2
print(jia(3)) #为什么加了print也还是不能打印出结果?
# 前边定义的可以返回结果的函数,都是直接print了结果变量(比如jia函数中的j),而不是print的函数
None
#在函数中加了打印结果变量的语句,就可以显示函数运行结果,但是不加return语句,
# 自定义的函数就不能作为其他自定函数中的变量或者参数使用,因为返回值是None
def jia_p(i):
j = i - 2
print(j)
jia_p(3)
1
#返回多个值
def jia_d(i):
j = i - 2
return i , j
jia_d(3) #需要注意的是, 当函数执行到return语句, 函数的调用就会结束, 后面的语句不会再执行,所以注意缩进位置
(3, 1)
def ADD(x,y,bools):
if bools == False:
return "请修改条件至符合函数要求"
return x+y
ADD(2,3,0) #0等同于false
'请修改条件至符合函数要求'
ADD(2,3,1) #1等同于true
5
ADD(2,3,"a")
5
# 模仿divmod自定义一个函数,两个参数相除,返回商和余数
def di(a, b):
sh = a // b
yu = a % b
return sh, yu
di(10,3)
(3, 1)
定一个函数,实现字母大小写互换
思路:先判断大小写再进行转换
def change_1(x):
if x.isupper():
return x.lower()
elif x.islower():
return x.upper()
else:
return "请输入符合要求的字符串"
change_1("a")
'A'
change_1("A")
'a'
change_1("abc")
'ABC'
change_1("abcDEF")
'请输入符合要求的字符串'
def change_2(x):
s = "" #定义一个空字符串用于实现字符的转换后字符的拼接
for i in x: #挨个遍历字符串中的字母进行判断和转换
if i.isupper():
y = i.lower()
elif i.islower():
y = i.upper()
else:
return "请输入符合要求的字符串"
s += y
return s #注意return的缩进位置
change_2("abcDEF")
'ABCdef'
# 写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
L = [4, 5, 6, 7, '3434']
L1 = [3, 4]
def lenth_c(x):
if len(x) > 2:
return x[0:2]
else:
return x
lenth_c(L1)
[3, 4]
lenth_c(L)
[4, 5]
# 写函数,检查传入字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
dic = {"k1": "v1v1", "k2": [11,22,33,44], 'k3':'gogogo','k4':'a','k5':"bc"}
dic.items() #帮助理解自定义函数中的for i,j in x.items()
dict_items([('k1', 'v1v1'), ('k2', [11, 22, 33, 44]), ('k3', 'gogogo'), ('k4', 'a'), ('k5', 'bc')])
def dic_l(x):
for i, j in x.items():
if len(j) > 2:
x[i] = j[0:2]
return x
dic_l(dic)
{'k1': 'v1', 'k2': [11, 22], 'k3': 'go', 'k4': 'a', 'k5': 'bc'}
7.3.4 函数的文档说明
如何让其他人能看懂函数功能及用法
def ADD(a,b):
"""用来完成对2个数求和
参数:
a:参数一,要求为数值型数据
b:参数二,要求为数值型数据
return
没有return语句,返回None"""
print(a+b)
ADD(1,2)
3
print(ADD.__doc__)
用来完成对2个数求和 参数: a:参数一,要求为数值型数据 b:参数二,要求为数值型数据 return 没有return语句,返回None
7.3.5 匿名函数lambda
Lambda函数是自定义函数的一种,专指用关键字” lambda”定义的无名短函数。这种函数得名于省略了用def声明函数的标准步骤
lambda函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
简单表达一下: lambda 形式参数 : 函数表达式 (lambda表达式汇总的参数不需要用括号括起来)
sum_1 = lambda arg1, arg2: arg1 + arg2 # lambda是一个表达式,可以被命名,其中arg1, arg2是形式参数,arg1 + arg2 函数返回值
sum_1(1,2)
3
# 等同于
def sum2(arg1, arg2):
return arg1 + arg2
sum2(1,2)
3
(lambda x,y : x + y)(1,2) # lambda表达式不命名也可以直接调用
3
注: Lambda函数能接收任何数量的参数但只能返回一个表达式的值
匿名函数不能直接调用print,也不需要return
# lambda函数可以作为其他函数的实际参数使用
def fun(a, b, c):
print ("a =", a)
print ("b =", b)
print ("c =", c(a, b))
# 主要是为了图省事
fun(2, 4, lambda a,b:pow(a, b))
a = 2
b = 4
c = 16
fun(2, 4, lambda a,b:a+b)
a = 2
b = 4
c = 6
a = [(1, 2), (4, 1), (9, 10), (13, -3)] #列表排序
reverse=False)
Docstring: Stable sort *IN PLACE*.
a.sort(key=lambda x: x[1]) #根据列表中元组的第二个数字进行排序
print(a)
[(13, -3), (4, 1), (1, 2), (9, 10)]
a.sort(key=lambda x: x[1],reverse=True) #倒序排序
print(a)
[(9, 10), (1, 2), (4, 1), (13, -3)]
a.sort(key=lambda x: x[0],reverse=True) #根据列表中元组的第一个数字进行倒序排序
print(a)
[(13, -3), (9, 10), (4, 1), (1, 2)]
Lambda函数经常与高阶函数一起使用,它将一个或多个函数作为参数或返回一个或多个函数。
lambda与map函数
对列表中每一个元素的遍历操作
#将列表中的元素每个都计算平方
list1 = [1, 2, 3, 4, 5]
list2 = []
for i in list1:
list2.append(i**2)
list2
[1, 4, 9, 16, 25]
list1 = [1, 2, 3, 4, 5]
list2 = map(lambda x: x**2, list1) # Map会将一个函数映射到一个输入列表的所有元素上
list(list2)
[1, 4, 9, 16, 25]
[x**2 for x in list1] #也可以用列表推导式实现
[1, 4, 9, 16, 25]
list(map(str,list1)) #map函数不止可以与匿名函数联合使用,也可以和其他函数联合使用
['1', '2', '3', '4', '5']
list(map(lambda x,y:x+y,[1,2,3],[3,2,1]))
#传入lambda的参数是可迭代的序列时,需要用map函数进行映射
[4, 4, 4]
[x+y for x in [1,2,3] for y in [3,2,1]] #列表推导式会把所有元素遍历相加,不能单纯的实现对应元素相加
[4, 3, 2, 5, 4, 3, 6, 5, 4]
#实现列表对应元素相加还可以用之前学过的循环
l1 = [1,2,3]
l2 = [3,2,1]
l3 = []
for i in range(len(l1)):
l3.append(l1[i]+l2[i])
l3
[4, 4, 4]
lambda与filter函数
指定过滤列表元素的条件
list3 = [1,2,3,4,5,6,7,8,9]
list4=[]
for i in list3:
if i > 5:
list4.append(i)
list4
[6, 7, 8, 9]
list5 = filter(lambda x: x > 5 ,list3) #filter条件过滤
list(list5)
[6, 7, 8, 9]
[x for x in list3 if x > 5] #条件过滤也可用列表推导式实现
[6, 7, 8, 9]
list6 = filter(lambda x: x % 2 == 0,list3)
list(list6)
[2, 4, 6, 8]
[x for x in list3 if x % 2 ==0]
[2, 4, 6, 8]
lambda与reduce函数
指定列表中两两相邻元素的结合条件
from functools import reduce
sum1 = reduce( (lambda x, y: x + y), [1, 2, 3, 4] ) #实现原理(((1+2)+3)+4)
sum1
10
sum([1,2,3,4]) #累计求和不必动用reduce和lambda函数
10
#把1,2,3,4转变成1234
reduce((lambda x ,y : x * 10 + y),[1,2,3,4])
1234
[x*10+y for x in [1,2,3,4] for y in [1,2,3,4]] #列表推导式x和y都要遍历一遍,与reduce原理不同
[11, 12, 13, 14, 21, 22, 23, 24, 31, 32, 33, 34, 41, 42, 43, 44]
reduce( (lambda x, y: x * y), [1, 2, 3, 4] )
24
7.4 局部变量和全局变量
函数有两种连接变量的方式:全局和局部。
这里的全局和局部是相对于单个的自定义函数而言的。
全局变量的作用域(命名空间)是全局,而局部变量的作用域(命名空间)仅限于单个的自定义函数内部。
7.4.1 局部变量
函数内部赋值的变量,不同的函数可以赋值相同名字的局部变量,但是各个名称相同的局部变量之间不会产生影响
局部变量的作用:为了临时保存数据的需要,在函数中定义变量来进行存储
def test1():
m = 300
return m+1
test1()
301
m
![549fd0a98b7bd0724889f275e91eda2f.png](https://i-blog.csdnimg.cn/blog_migrate/5838161c3468cabe81e2b78eb5dd1651.png)
变量m在函数test1内部进行的赋值,所以m的作用域仅限于test1函数内部,m为局部变量
局部作用域在函数被调用时生成,并立即由函数的参数填充,一般情况下,当函数执行结束后,局部作用域就会被注销。
所以,局部变量m在test1函数退出时就被注销了,在函数外部调用m的时候会报错。
# 不同的函数可以定义相同名字的局部变量,但是各个名称相同的局部变量之间不会产生影响
def test2():
a = 300
print("在test1中的变量a=", a)
def test3():
a = 400
print("在test2中的变量a=", a)
test2()
test3()
在test1中的变量a= 300 在test2中的变量a= 400
7.4.2 全局变量
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量
b = 200
def test4():
return b
test4()
200
# 变量b在函数test2外部进行的赋值,所以b的作用域不仅限于test2内部,b为全局变量
b
200
7.4.3 全局变量和局部变量名字相同
全局变量和局部变量名字相同对于函数的定义和调用没有影响,函数内部有局部变量的用局部变量,没有局部变量的,用全局变量
# 定义全局变量
n = 100
def test5():
n = 300
print("test5中的变量n是: ", n)
def test6():
print("test6中的变量n是: ", n)
test5()
test6()
print("全局变量n是",n)
test5中的变量n是: 300 test6中的变量n是: 100 全局变量n是 100
综上
- 在函数外边定义的变量叫做全局变量
- 全局变量能够在所有的函数中进行访问
- 如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错
- 如果全局变量的名字和局部变量的名字相同,那么函数内使用的是局部变量的
7.4.4 修改全局变量
一个自然而然的需求, 能不能在函数内部修改全局变量呢?
# 定义全局变量
x = 100
def test7():
global x #通过global修改全局变量
x = 300
print("test7中的变量x是: ", x)
def test8():
print("test8中的变量x是: ", x)
test7()
test8()
print("全局变量x是:",x)
test7中的变量x是: 300 test8中的变量x是: 300 全局变量x是: 300
global关键字的本质作用是把局部变量转化成全局变量,在没有定义全局变量的情况下来看会更明显的显示global关键字的作用
def test9():
global e
e = 90
return e
test7()
test7中的变量x是: 300
e #虽然提前定义全局变量,通过global关键字,将局部变量转化成全局变量,在函数体外调用变量e不会报错
90
7.4.5 可变类型的全局变量
在函数中不使用global声明全局变量时不能修改全局变量的本质是不能修改全局变量的指向,即不能将全局变量指向新的数据。
对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使用global时无法修改全局变量。
对于可变类型的全局变量来说,因其指向的数据可以修改,所以不使用global时也可修改全局变量。
a = 1
def f():
a += 1 #不用global,不能对全局变量进行更改 a = a+1 报错在赋值之前引用的局部变量'a',等号后的a是全局变量,等号前的a是局部变量
print (a)
f()
![a759e56b8bf5c7a13543ae2c1b873a59.png](https://i-blog.csdnimg.cn/blog_migrate/85237dc07caabbc36511c512e5c316a2.png)
a = 1
def f():
global a
a += 1
print (a)
f()
2
li = [1]
id(li)
def f2():
li.append(1)
print (li)
f2()
3136797143752 [1, 1]
li
id(li)
[1, 1] 3136797143752
表面上看是没有通过global就改变了全局变量,实际上全局变量的地址没有变:
变量名称的定义说明,变量是指向了值,其本质是“值的一个引用”,而不是“变量的取值”。
虽然显示全局变量是从[1]变到了[1,1],实际上不是全局变量的指向发生了变化,能看到前后指向的ID是一样的!
发生变化的原因在于定义的全局变量是可变的数据类型而已!
八、I/O操作
8.1 文件的新建\写入和关闭
在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件
open(文件名,访问模式)
注意文件地址在当前文件夹
#新建一个文件,并写入数据
f = open('test.txt', 'w')
f.write('''range是python内置函数,返回值是range对象,是一个迭代器,可以用list函数强制转换查看对象中的元素,;
arange是扩展模块numpy中的函数,返回值是numpy中的array
np.array(range(1,10))和np.arange(1,10)功能一样,但是后者运行速度更快,占用内存更小
''')
f.close() #关闭文件,如果不关闭,不显示写入内容
t = open('test1.txt', 'w')
t.write("hello world, i am here!") #显示写入了多少字符
23
t.close() #关闭文件后才会显示写入内容
8.2 文件的读取
a = open('test.txt', 'r')
a.read()
'range是python内置函数,返回值是range对象,是一个迭代器,可以用list函数强制转换查看对象中的元素,;\narange是扩展模块numpy中的函数,返回值是numpy中的array\nnp.array(range(1,10))和np.arange(1,10)功能一样,但是后者运行速度更快,占用内存更小\n'
a.close()
a = open('test.txt', 'r')
a.readlines() #分行阅读
['range是python内置函数,返回值是range对象,是一个迭代器,可以用list函数强制转换查看对象中的元素,;\n', 'arange是扩展模块numpy中的函数,返回值是numpy中的array\n', 'np.array(range(1,10))和np.arange(1,10)功能一样,但是后者运行速度更快,占用内存更小\n']
a.close()
如果不关闭文件:
会导致内存始终被占用, 得不到释放
会导致文件被占用中, 无法删除, 剪切等操作m
# 这样打开的文件, 代码运行结束后会自动关闭
with open('test.txt') as f:
data = f.readlines()
data
['range是python内置函数,返回值是range对象,是一个迭代器,可以用list函数强制转换查看对象中的元素,;\n', 'arange是扩展模块numpy中的函数,返回值是numpy中的array\n', 'np.array(range(1,10))和np.arange(1,10)功能一样,但是后者运行速度更快,占用内存更小\n']
8.3 文件的重命名与删除
需要导入os模块
import os
os.rename('test1.txt','测试.txt')
os.remove('测试.txt')