函数&模块
1.函数
1.函数入门
1.1初识函数
-
函数,可以当做一大堆功能代码的集合
''' 函数格式 def 函数名(): 函数内执行的业务代码 函数名() ''' def info(): print("输出第一行数据") print("输出第二行数据") print("输出第三行数据") info()
输出第一行数据 输出第二行数据 输出第三行数据
-
函数在项目开发中用到的两种应用场景
-
有重复代码,用函数增加代码的重用性
# 重复代码 def send_message(): # 执行业务 pass cpuview = 0.0 memoryview = 0.0 diskview = 00.0 print("欢迎使用计算机监控系统".center(20, "*")) if cpuview > 90 / 100: send_message() if memoryview > 98 / 100: send_message() if diskview > 99 / 100: send_message()
-
代码太长,用函数增强代码的可读性
# 代码太长 def calculate_same_num_rule(): pass def calculate_same_color_rule(): pass def calculate_straight_rule(): pass def calculate_double_card_rule(): pass def calculate_single_card_rule(): pass
-
1.2函数的参数
1.参数
-
在定义函数时,如果括号中添加变量,称为它函数的形式参数
# 定义函数 def func(a1, a2, a3): print(a1+a2+a3) # 4 # 执行函数并传入参数 func(1, 2,1)
-
位置传参
''' 执行函数时,传入参数一一对应函数的形参 ''' # 位置传参 def add(a1, a2): print(a1 + a2) # 3 # 执行函数 add(1, 2)
-
关键字传参
# 关键字传参 def adds(n1, n2): print(n1 + n2) # 5 adds(n1=1, n2=4)
2.默认参数
# 默认参数
def add_default(a1, a2, a3=15):
print(a1 + a2 + a3)
# 位置传参-有默认参数的函数,可以忽略默认参数,不传实参
add_default(1, 2) # 18
add_default(1, 2, 3) # 6
# 关键字传参- 位置和关键字混合搭配时,关键字传参要放在后面
add_default(1, 2, a3=12) # 15
3.动态参数
"""
注意点:
- **必须放在*后面
- 参数和动态参数混合使用时,动态参数只能放在后面
- 默认值参数和动态参数同时存在,默认值参数放在动态参数前
"""
def add_other_Args(a1, a2, a3=15, *args, num=10, **kwargs):
print(a1, a2, a3, num, args, kwargs)
# 默认值参数 num,在实际应用中,并不能修改其值,默认值参数放在动态参数前面
add_other_Args(12, 56, 89, 12, 45, 56, 78, name="Terry", email="hjf***@gmail.com")
1.3函数返回值
-
开发过程中,函数可以解决一些实际业务,某些业务的功能实现之后需要反馈结果,因此函数有了返回值的概念
def xml_to_list(city): data_list = [] url = "http://ws.webxml.com.cn//WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName={}".format(city) res = requests.get(url=url) ''' <?xml version="1.0" encoding="utf-8"?> <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://WebXml.com.cn/"> <string>直辖市</string> <string>北京</string> <string>54511</string> <string>54511.jpg</string> <string>2024/3/8 9:44:19</string> <string>-2℃/11℃</string> <string>3月8日 晴</string> <string>西南风小于3级</string> <string>0.gif</string> <string>0.gif</string> <string>今日天气实况:气温:5.5℃;风向/风力:南风 2级;湿度:24%;紫外线强度:强。</string> <string>感冒指数:极易发,天气寒冷,昼夜温差极大。 运动指数:较不宜,天气寒冷,推荐您进行室内运动。 过敏指数:较易发,外出需远离过敏源,适当采取防护措施。 穿衣指数:寒冷,建议着厚羽绒服等隆冬服装。 洗车指数:适宜,天气较好,适合擦洗汽车。 紫外线指数:强,涂擦SPF大于15、PA+防晒护肤品。 </string> <string>-2℃/13℃</string> <string>3月9日 晴</string> <string>西风转北风小于3级</string> <string>0.gif</string> <string>0.gif</string> <string>0℃/13℃</string> <string>3月10日 晴转多云</string> <string>西北风转北风小于3级</string> <string>0.gif</string> <string>1.gif</string> <string>北京位于华北平原西北边缘,市中心位于北纬39度,东经116度,四周被河北省围着,东南和天津市相接。全市面积一万六千多平方公里,辖12区6县,人口1100余万。北京为暖温带半湿润大陆性季风气候,夏季炎热多雨,冬季寒冷干燥,春、秋短促,年平均气温10-12摄氏度。北京是世界历史文化名城和古都之一。早在七十万年前,北京周口店地区就出现了原始人群部落“北京人”。而北京建城也已有两千多年的历史,最初见于记载的名字为“蓟”。公元前1045年北京成为蓟、燕等诸侯国的都城;公元前221年秦始皇统一中国以来,北京一直是中国北方重镇和地方中心;自公元938年以来,北京又先后成为辽陪都、金上都、元大都、明清国都。1949年10月1日正式定为中华人民共和国首都。北京具有丰富的旅游资源,对外开放的旅游景点达200多处,有世界上最大的皇宫紫禁城、祭天神庙天坛、皇家花园北海、皇家园林颐和园,还有八达岭、慕田峪、司马台长城以及世界上最大的四合院恭王府等各胜古迹。全市共有文物古迹7309项,其中国家文物保护单位42个,市级文物保护单位222个。北京的市树为国槐和侧柏,市花为月季和菊花。另外,北京出产的象牙雕刻、玉器雕刻、景泰蓝、地毯等传统手工艺品驰誉世界。 </string> </ArrayOfString> ''' print(res.text) root = ET.XML(res.text) for node in root: data_list.append(node.text) return data_list result = xml_to_list("北京") print(result)
-
返回值可以是任意类型,如果函数中没写return,则默认返回None
# 返回值可以是任意类型 def func(): return [1, True, (11, 22, 33,)] result = func() print(result) # [1, True, (11, 22, 33)]
# 未写返回值 或 return 或 return None,执行函数获取的返回值都是None def func2(): value = 1 +1 ret = func2() print(ret) # None
-
return后面的值如果有逗号,则默认会将返回值转换元组再返回
# 后面的值有逗号,默认返回值转成元组返回 def func3(): return 1, 2, 3 value = func3() print(value) # (1, 2, 3)
-
函数一旦遇到return就会立即退出函数(终止函数中的所有代码)
# 遇到return就立即推出函数 def func4(): print(1) return "结束吧" print(2) ret = func4() # 1 print(ret) # 结束吧
2.函数进阶
1.1参数的补充
'''
Python参数的特性有两个好处:
1.节省内存
2.对于可变类型且函数中修改元素的内容,所有的地方都会修改。可变类型: 列表、字典、集合
'''
name = "Tom"
print(id(name)) # 2957232352080
func5(name) # Tom 2957232352080
# 可变类型 & 修改内部元素
def func6(data):
data.append(666)
list_num = [11, 22, 33]
# id()查看列表的地址
print(id(list_num)) # 1207590744832
func6(list_num)
print(id(list_num)) # 1207590744832
print(list_num) # [11, 22, 33, 666]
# 可变类型 & 重新赋值
def func7(data):
data = ["Python", "JAVA"]
list_v1 = [11, 22, 33]
# id()获取地址,地址一样
print(id(list_v1)) # 2448412623744
func7(list_v1)
print(id(list_v1)) # 2448412623744
print(list_v1) # [11, 22, 33]
1.函数的返回值是内存地址
def func8():
data = [11, 22, 33]
print(id(data))
return data
num_list_1 = func8() # 2345095810048
print(num_list_1, id(num_list_1)) # [11, 22, 33] 2345095810048
num_list_3 = func8() # 2345095381376
print(num_list_3, id(num_list_3)) # [11, 22, 33] 2345095381376
2.参数的默认值
def func9(a1, a2=18):
print(id(a1), id(a2))
print(a1, a2)
# 执行函数未传值时,a2指向函数维护的内存地址
func9("root") # 140734791238752 140734792256472 root 18
# 执行函数传值时,a2指向新传入的值,内存地址指向新地址
func9("root", 20) # 140734791238752 140734792256536 root 20
-
注意事项
-
默认参数的值时可变类型列表、字典、集合,函数内部修改这个默认值,地址发生改变
a2 = [11, 22] print(id(a2)) # 2692011379456 def func10(a1, a2): a2.append(a1) print(id(a2)) # 2692010932096 return a2 str_list = func10("Ailke", ["Python", "JAVA"]) print(id(str_list)) # 2692010932096 print(str_list) # ['Python', 'JAVA', 'Ailke']
-
3.动态参数
-
动态参数,定义函数时在形参位置用 * 或 ** 可以接受任意个参数
def func11(*args, **kwargs): print(args, kwargs) func11("Python", "JAVA", name="Ailke", age=18) # ('Python', 'JAVA') {'name': 'Ailke', 'age': 18}
-
在定义函数时可以用 * 和 **,其实在执行函数时,也可以用
-
形参固定,实参用* 和 **
def func12(a1, a2): print(a1, a2) func12(11,12) # 11 12 func12(a1=12, a2=15) # 12 15 func12(*[11, 33]) # 11 33 func12(**{"a1": 12, "a2": 18}) # 12 18
-
形参用* 和 *,实参也用 * 和 *
def func13(*args, **kwargs): print(args, kwargs) func13(*[11, 22, 33], **{"name": "Ailke", "addr": "成都市"}) # (11, 22, 33) {'name': 'Ailke', 'addr': '成都市'}
# 字符串格式化format str = "我在{},简单地{}".format("成都市", "活着") str = "我在{addr},简单地{status}".format(addr="成都市", status="活着") str = "我在{},简单地{}".format(*["成都市", "活着"]) str = "我在{addr},简单地{status}".format(**{"addr":"成都市", "status":"活着")
-
1.2函数和函数名
-
函数名其实就是一个变量,这个变量只不过代指的函数而已
-
函数必须先定义才能被调用执行
def add(num1, num2): return num1 + num2 result = add(*[22, 44]) print(result) # 66
1.函数做元素
-
函数同时也可被哈希,所以函数名通常也可以做 集合的元素、字典的键
def send_message(phone, content): pass def send_image(img_path, content): pass def send_emoji(emoji): pass def send_file(path): pass function_dict = { "a": [send_message, ['132***56985', '您好!']], "b": [send_image, ['**/**/**.jpeg', '消息内容']], "c": [send_emoji, ["😁"]], "d": [send_file, ['**.Zz']] } print("a.发消息 b.发图片 c.发表情 d.发送文件".center(30, "*")) choice = input("请选择: ") item = function_dict.get(choice) if not item: print("输入错误") else: func = item[0] param_list = item[1] func(*param_list)
2函数名赋值
-
函数名赋值给其他变量,函数名其实就个变量,代指某函数;如果将函数名赋值给另一个变量,则此变量也会代指该函数
def func(a1, a2): print(a1, a2) newFunc = func func(1, 2) newFunc(2, 3)
-
对函数名重新赋值,如果将函数名修改为其他值,函数名便不再代指函数
def func(a1, a2): print(a1, a2) #执行func函数 func(11, 12) # func重新赋值成一个字符串 func = "ailke" print(func) # ailke
-
注意点: 由于函数名被重新定义之后,就会变成被定义的值,在实际的项目开发中,自定义函数时,不要与python内置的函数同名,否则会覆盖内置函数
id(), bin(), hex(), oct(), len(), ...
# len()内置函数用于计算长度 strNum = len("Python") print(strNum) # 5 # 下面的错误示范,len()重新定义成另一个函数 def len(a1, a2): return a1 + a2 # 以后执行len()函数,只能按照重新定义来使用 print(len(11, 22)) # 33
3.函数名做参数和返回值
-
函数名其实就一个变量,代指某个函数;和其他的数据类型一样,也可以当作函数的参数和返回值
-
参数
# 参数 def plus(num): return num + 100 def handler(func): result = func(10) msg = "执行func,并获取到的结果为:{}".format(result) print(msg) # 执行func,并获取到的结果为:110 handler(plus)
-
返回值
# 返回值 def diff(num): return num - 10 def handler2(): print("执行handler函数") # 执行handler函数 return diff result = handler2() print(result(20)) # 10
-
1.3返回值和print
-
在函数中使用print,只是用于在某个位置输出内容
-
在函数中使用return,是为了将函数得执行结果返回给调用者,以便于后续其他操作
def add(num1, num2): print(num1 + num2) # 30 result = add(10, 20) print(result) # None def add(num1, num2): return num1 + num2 result = add(22, 33) print(result) # 55
1.4作用域
- 作用域,可以理解为一块空间,空间的数据是可以共享的
1.函数为作用域
-
Python以函数为作用域,在函数内创建的所有数据,可以在函数中被使用,无法在其他函数中被使用
def func(): name = "Ailke" data_list = [11, 22, 33] print(name, data_list) # Ailke [11, 22, 33] age = 20 print(age) # 20 def handler(): age = 18 print(age) # 18 func() handler()
2.全局和局部
-
Python中以函数为作用域,函数的作用域其实是一个局部作用域
goods = [ {"name": "笔记本", "price": 6999}, {"name": "手机", "price": 5999}, {"name": "游艇", "price": 8660000}, {"name": "显示器", "price": 2299} ] for index in range(len(goods)): item = goods[index] print(index + 1, item['name'], item['price']) while True: num = input("请输入要选择的商品序号(Q/q): ") if num.upper() == "Q": break if not num.isdecimal(): print("用输入的格式错误!") break num = int(num) if num > 4 or num < 0: print("范围选择错误!") break target_index = num - 1 choice_item = goods[target_index] print(choice_item['name'], choice_item['price'])
-
全局变量
COUNTRY
和CITY_LIST
是在全局作用域,全局作用域中创建的变量称为全局变量,可以在全局作用域中被使用,也可以在局部作用域被使用- 全局变量一般都是大写
# 全局变量 COUNTRY = "中国" CITY_LIST = ["北京", "上海", "深圳", "成都"] def download(): # 局部变量 url = "https://www.12306.cn" print(url) print(COUNTRY) print(CITY_LIST) def upload(): # 局部变量 file_name = "rose.zip" print(file_name) print(COUNTRY) print(CITY_LIST) print(COUNTRY) print(CITY_LIST) download() upload() # print(file_name) # 报错 # print(url) # 报错
3.global关键词
-
默认情况下,在局部作用域对全局变量只能进行: 读取 和 修改内部元素 (可变类型),无法对全局变量进行重新赋值
-
读取
# 全局变量 COUNTRY = "中国" CITY_LIST = ["北京", "上海", "深圳", "成都"] def download(): # 局部变量 url = "https://www.12306.cn" print(url) print(COUNTRY) print(CITY_LIST) download()
-
修改内部元素(可变类型)
# 全局变量 COUNTRY = "中国" CITY_LIST = ["北京", "上海", "深圳", "成都"] def download(): # 局部变量 url = "https://www.12306.cn" print(url) print(COUNTRY) CITY_LIST.append("重庆") CITY_LIST[0] = "西安" print(CITY_LIST) download()
-
无法对全局变量重新赋值
COUNTRY = "中国" CITY_LIST = ["北京", "成都", "上海", "深圳"] def download(): url = "https://www.12306.cn" CITY_LIST = ["四川省", "陕西", "重庆"] print(CITY_LIST) # ['四川省', '陕西', '重庆'] download() print(CITY_LIST) # ['北京', '成都', '上海', '深圳']
-
-
局部作用域中对全局变量重新赋值,则可以基于 global关键字 实现
COUNTRY = "中国" CITY_LIST = ["北京", "成都", "上海", "深圳"] def download(): url = "https://www.12306.cn" global CITY_LIST CITY_LIST = ["河北省", "山西省", "山东省"] print(CITY_LIST) # ['河北省', '山西省', '山东省'] global COUNTRY COUNTRY = "中华人民共和国" print(COUNTRY) # 中华人民共和国 download() print(CITY_LIST) # ['河北省', '山西省', '山东省']
4.nonlocal关键字
def outer_function():
x = 12
def inner_function():
nonlocal x
# 此处添加nonlocal关键字,不是创建新的变量x,是修改变量x
x = 20
print("inner_function:", x) # inner_function: 20
inner_function()
print("outer_function: ", x) # outer_function: 20
outer_function()
3.函数高级
1.函数嵌套
-
Python中以函数为作用域,在作用域中定义的相关数据只能被 当前作用域 或 子作用域使用
userName = "Ailke" print(userName) # Ailke def func(): print(userName) func() # Ailke
1.1函数的作用域中
-
函数也是定义在作用域中的数据,在执行函数时候,也同样遵循: 优先在自己作用域中寻找,没有则向上一级作用域寻找
# 1.在全局作用域定义了函数func def func(): print("上一级作用域") # 2.在全局作用域找到func函数并执行 func() # 上一级作用域 # 3.在全局作用域定义了execute函数 def execute(): print("局部作用域开始") # 局部作用域开始 # 优先在当前函数作用域func函数,没有则向上级作用域中寻找 func() # 上一级作用域 print("局部作用域结束") # 局部作用域结束 # 4.在全局作用域执行execute函数 execute()
1.2函数定义的位置
-
函数均定义在全局作用域,其实函数也可以定义在局部作用域,函数被局部作用域和其子作用域中调用(函数的嵌套)
def func(): print("全局作用域") def handler(): print("全局作用域2") def inner(): print("局部作用域") inner() func() print("全局作用域3") ''' 全局作用域2 局部作用域 全局作用域 全局作用域3 ''' handler()
1.3嵌套引发的作用域问题
- 优先在自己的作用域找变量,自己没有就去上级作用域
- 在作用域中寻找值时,确保此时此刻的值是什么
- 分析函数的执行,并确定函数 作用域链 (函数嵌套)
userName = "李四"
def run():
userName = "ailke"
def inner():
print(userName)
return inner
'''
ailke
None
'''
userNAME = run()
print(userNAME())
'''
ailke
None
'''
userNAME = run()
print(userNAME())
2.闭包
- 闭包,简而言之就是将数据封装在一个包(区域)中,使用时再去里面取
- 闭包是基于函数嵌套弄出来的一个特殊嵌套
1.封装数据防止污染全局
def func(age):
userName = "赵六"
def f1():
print(userName, age)
def f2():
print(userName, age)
def f3():
print(userName, age)
def f4():
print(userName, age)
f1()
f2()
f3()
f4()
func(18)
2.封装数据封到一个包里,使用时再取
def task(arg):
def inner():
print(arg)
return inner
inner_func_list = []
for val in [11, 22, 33]:
inner_func_list.append(task(val))
inner_func_list[0]() # 11
inner_func_list[1]() # 22
inner_func_list[2]() # 33
3.装饰器
-
装饰器,在不修改原函数内容的前提下,通过 @ 函数可以实现在函数前后自定义执行一些功能
-
实现效果
- 可以在不改变原函数内部代码 和 调用方式的前提下,实现函数执行和执行扩展功能
-
实现原理
- 基于 @语法 和函数闭包,将原函数封装在闭包中,然后将函数赋值为一个新的函数(内层函数),执行函数时再在内层函数中执行闭包中的原函数
def func(): print("我是func函数") value = [11, 22, 33] return value def outer(origin): def inner(): print('before') res = origin() print('after') return res return inner func = outer(func) print(func) # <function outer.<locals>.inner at 0x00000274D6164220> # 等效输出 inner() result = func() def outers(origin): def inner(): print('before') res = origin() print('after') return res return inner @outers def func(): print('我是func函数') value = [11, 22, 33] return value func()
-
优化
-
优化以支持多个参数
def outer(origin): def inner(*args, **kwargs): print('before') res = origin(*args, **kwargs) print('after') return res return inner @outer def func1(a1): print("我是func1()函数") value = [11, 22, 33] return value @outer def func2(a1, a2): print("我是func2()函数") value = [11, 22, 33] return value @outer def func3(a3): print("我是func3()函数") value = [11, 22, 33] return value func1(12) func2(12, a2=18) func3({"name": "Ailke", "addr": "成都市"})
-
1.functools
-
装饰器实际上就是将原函数更改为其他函数,然后再此函数中再去调用原函数
-
不用functools也可以实现装饰器的基本功能,但是后期实际项目开发时,不加functools会出错(内部会读取___name_原函数,name重名的话就报错)
import functools def handler(): pass handler() # 读取当前函数名称 print(handler.__name__) # handler def auth(func): def inner(*args, **kwargs): return func(*args, **kwargs) return inner @auth def handler(): pass handler() # 读取当前函数名称 print(handler.__name__) # inner def auth_update(func): @functools.wraps(func) def inner(*args, **kwargs): return func(*args, **kwargs) return inner @auth_update def handler(): pass handler() # 读取当前函数名称 print(handler.__name__) # handler
4.内置函数和推导式
1.匿名函数
-
传统的函数的定义包括了: 函数名 + 函数体
def send_email(): pass # 执行 send_email() # 当作列表元素 # data_list = [send_email, send_email, send_email] # 当作参数传递 # other_functions(send_email)
-
匿名函数,则是基于lambda表达式现实定义一个可以没有名字的函数
# 匿名函数 data_list = [lambda x: x + 100, lambda x: x + 110, lambda x: x + 120] print(data_list[0](20))
-
基于Lambda定义的函数格式为: lambda 参数: 函数体
-
参数,支持任意参数
lambda x: 函数体 lambda x1, x2: 函数体 lambda *args, **kwargs: 函数体
-
函数体,只能支持单行的代码
def send(x): return x + 100 f1 = lambda x: x + 100 # 函数体只能支持单行代码 # functions = lambda x: # x + 100 print(send(10)) # 110 print(f1(10)) # 110
-
返回值,默认将函数单行代码执行的结果返回给函数的执行
func = lambda x: x + 123 value = func(123) print(value) # 246
-
-
扩展: 三元运算
-
简单的函数,可以基于lambda表达式实现
-
简单的条件语句,可以基于三元运算实现
''' 三元运算 - 格式 结果 = 条件成立时 if 条件 else 条件不成立时 ''' # 结合lambda func = lambda x: "大了" if x > 66 else "小了" print(func(99))
-
2.生成器
-
生成器是由函数 + yield关键字创造出来的写法,在特定情况下,可以帮助我们节省内存
-
生成器函数,函数中有yield存在时,函数就是生成器函数
def func(): print(112) yield 12
-
生成器对象,执行生成器函数时,会返回一个生成器对象
def func(): print(112) yield 12 print(func()) # <generator object func at 0x0000021DC6F34940>
-
生成器的特点是,记录在函数中的执行位置,下次执行next时,会从上一次的位置基础上继续向下执行
def func(): print(112) yield 12 print(func()) # <generator object func at 0x0000021DC6F34940> print(next(func())) def funcs(): print(111) yield 1 print(222) yield 2 # StopIteration: 2 error # return 2 print(333) yield 3 # print(444) data = funcs() print(next(data)) print(next(data)) print(next(data))
-
应用场景
import random def gen_random_num(max_count): counter = 0 while counter < max_count: yield random.randint(1000, 9999) counter += 1 data_list = list(gen_random_num(30000)) print(type(data_list)) print(len(data_list)) print(data_list[8989])
-
知识拓展
def func(): print(111) v1 = yield 1 print(v1) print(222) v2 = yield 2 print(v2) print(333) v3 = yield 3 print(v3) print(444) data = func() ''' send()方法的作用: - 发送一个值到生成器中,这个值将作为上一个yield表达式的结果;第一次调用生成器的send()方法时,传入None值 - 触发生成器继续执行,直到遇到下一个yield语句,并返回该yield语句产出的值 - 发送值之后生成器执行完毕(没有更多的yield语句),则send()方法将会引发Stopiteration异常 ''' n1 = data.send(None) print(n1) n2 = data.send(666) print(n2) n3 = data.send(777) print(n3) n4 = data.send(888) print(n4)
3.内置函数
# abs 绝对值
print(abs(-10)) # 10
# pow 指数
print(pow(2, 3)) # 8
# sum 求和
print(sum([1, 2, 3, -10, 12])) # 8
# divmod 求商和余数,返回元组类型
print(divmod(9, 2)) # (4, 1)
# round,小数点后n位(四舍五入)
print(round(3.1415926, 4)) # 3.1416
# min 最小值 def min(*args, key=None):
print(min([12, 56, 8, 10])) # 8
# max 最大值
print(max([12, 56, 88], key=lambda x: x * 10))
# all 是否全部为True
print(all([11, 22, 33, " ", ""])) # False
# any 是否存在True
print(any([11, 22, 33, " ",""])) # True
# oct 十进制转八进制
print(oct(125)) # 0o175
# hex 十进制转十六进制
print(hex(125)) # 0x7d
# bin 十进制转二进制
print(bin(125)) # 0b1111101
4.推导式
# 列表
num_list = [i for i in range(10)]
print(num_list) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 集合
num_set = {(i, i, i) for i in range(10) if i > 6}
print(num_set) # {(8, 8, 8), (7, 7, 7), (9, 9, 9)}
# 字典
num_dict = {i: (i, 11) for i in range(10) if i >= 6}
print(num_dict) # {6: (6, 11), 7: (7, 11), 8: (8, 11), 9: (9, 11)}
# 元组,不同于其他类型
# 不会立即执行内部循环去生成数据,而是得到一个生成器
num_tup = (i for i in range(10))
print(num_tup) # <generator object <genexpr> at 0x0000025B35546A40>
print(next(num_tup)) # 0
print(next(num_tup)) # 1
2.模块
1.自定义模块
1.1模块和包
import hashlib
def encrypt(data):
'''数据加密'''
hash_object = hashlib.md5()
hash_object.update(data.encode('utf-8'))
return hash_object.hexdigest()
userName = input("Enter your username:")
pwd = input("Enter your password:")
md5_password = encrypt(pwd)
message = "用户名:{},密码:{}".format(userName,md5_password)
print(message)
- 简单的程序,可以通过一个py文件编写完成;对于程序比较庞大,此时就需要代码结构清晰
- 在Python中一般对文件和文件的称呼
- 一个py文件,称为模块(Module)
- 含多个py文件的文件夹,称为包(package)
- 注意: 在包(文件夹)中有一个默认内容为空的___init___.py的文件,一般用于描述当前包的信息
- py2必须有,如果没有导入包就会失败
- py3可有可无
1.2导入
-
导入,其实就是将模块或包加载的内存中,以后再去内存中去拿就行
-
在Python内部默认设置了一些路径,导入模块或包时,都会按照指定顺序逐一去特定的路径查找
-
手动设置路径,进行包的导入,**sys.path()**中添加路径
import sys sys.path.append("指定路径") # 导入指定路径下的一个***.py文件 import ***
- 写模块名称时,不能和内置和第三方的同名
- 项目执行文件一般在项目根目录,执行文件嵌套的内存目录,就需要自己手动在sys.path中添加路径
- pycharm中默认会将项目目录加入到sys.path中
-
第一类方式: **import *****(开发中,一般多用于导入sys.path目录下的一个py文件)
''' |---commons | |---- __init__.py | |---- tools | |---- __init__.py | |---- sum.py |---main.py ''' import commons.utils import commons.tools.sum userName = input("Enter your username:") pwd = input("Enter your password:") # md5_password = utils.encrypt(pwd) md5_password = commons.utils.encrypt(pwd) message = "用户名:{},密码:{}".format(userName,md5_password) print(message) print("输入数据和: ", commons.tools.sum.sum_itme([12, 13, 14])) print("输入数据和: ", commons.tools.sum.sum_itme((12, 15, 16,))) print("输入数据和: ", commons.tools.sum.sum_itme(12.45)) import hashlib def encrypt(data): '''数据加密''' hash_object = hashlib.md5() hash_object.update(data.encode('utf-8')) return hash_object.hexdigest() def sum_itme(items): if isinstance(items, (int, float)): items = [items] elif not isinstance(items, (list, tuple)): raise TypeError("The input must be a number or a list of numbers") return sum(items)
-
第二类方式: from ******* import *******(常用),一般适用于多层嵌套和导入模块中某个成员的情况
''' |---commons | |---- __init__.py | |---- tools | |---- __init__.py | |---- sum.py |---main.py ''' from commons import utils from commons.tools import sum # import commons.utils # import commons.tools.sum userName = input("Enter your username:") pwd = input("Enter your password:") # md5_password = utils.encrypt(pwd) md5_password = utils.encrypt(pwd) message = "用户名:{},密码:{}".format(userName,md5_password) print(message) print("输入数据和: ", sum.sum_itme([12, 13, 14])) print("输入数据和: ", sum.sum_itme((12, 15, 16,))) print("输入数据和: ", sum.sum_itme(12.45)) # print("输入数据和: ", commons.tools.sum.sum_itme([12, 13, 14])) # print("输入数据和: ", commons.tools.sum.sum_itme((12, 15, 16,))) # print("输入数据和: ", commons.tools.sum.sum_itme(12.45)) import hashlib def encrypt(data): '''数据加密''' hash_object = hashlib.md5() hash_object.update(data.encode('utf-8')) return hash_object.hexdigest() def sum_itme(items): if isinstance(items, (int, float)): items = [items] elif not isinstance(items, (list, tuple)): raise TypeError("The input must be a number or a list of numbers") return sum(items)
1.3相对导入
-
在导入模块时,对于from ******* import *** 这种模式,还支持相对导入
''' mypackage/ __init__.py module_a.py subpackage/ __init__.py module_x.py module_y.py ''' # 从module_a.py导入module_x.py from .subpackage import module_x # 从module_x.py导入module_a.py from .. import module_a
-
**.代表当前包,…**代表父级包,相对导入只能用在包中的py文件中
1.4导入别名
-
项目在导入 成员、模块、包 有重名,那么导入后会覆盖之前的导入,为了避免这种情况的发生,Python支持重命名
# 两种导入方式都可重命名 from ***.*** import *** as ** import ***.*** as **
1.5主文件
-
执行一个py文件时
__name__ = "__main__"
-
导入一个py文件时
__name__ = "模块名"
-
文件内部__name__变量的值为__main___,以主文件的形式允许此脚本时start函数才会被执行,被导入时则不会被执行
if __name__ == '__main__': start()
2.第三方模块
1.pip (最常用)
-
pip其实是个第三方模块包管理工具,默认安装Python解释器时自动会安装,默认目录
''' windows系统,即: Python安装路径的scripts目录下 - C:\**\Scripts\pip3.exe - C:\**\Scripts\pip.版本号.exe '''
-
pip安装模块,默认安装最新版本
# 默认安装 pip3 install 模块名称 # 指定版本安装 pip3 install 模块名称==版本
-
pip更新版本
# 查看当前版本 pip3 --version # 更新 pip3 install --upgrade pip
2.豆瓣源
-
pip默认是去https://pypi.org去下载第三方模块,国内下载可能出现问题,为了加速下载可以使用豆瓣源
-
一次性使用下载
# 如果按照一下指令显示对源不信任,在末尾加上--trusted-host pypi.douban.com pip3 install 模块名称 -i https://pypi.douban.com/simple
-
永久使用
- 配置
# 替换主机下载路径 pip3 config set global.index-url https://pypi.douban.com/simple/ ''' 国内常用的镜像 - 阿里云:http://mirrors.aliyun.com/pypi/simple/ - 中国科技大学:https://pypi.mirrors.ustc.edu.cn/simple/ - 清华大学:https://pypi.tuna.tsinghua.edu.cn/simple/ -中国科学技术大学:http://pypi.mirrors.ustc.edu.cn/simple/ '''
- 使用
pip3 install 模块名称
3.源码
-
下载源码安装模块
-
下载源码
# 1.不管是GitHub或网站下载,需要解压的首先解压 # 2.进入到目录 # 3.运行命令 # # 编译 python setup.py build # # 安装 python setup.py install
-
4.wheel
-
下载wheel文件
- 从某个源下载模块的wheel文件,wheel的文件扩展命通常是.whl
-
安装wheel包
# 需要安装wheel pip3 install wheel
-
使用pip安装wheel文件
pip3 install 模块名称.whl
3.内置模块
1.os
import os.path
# 获取当前脚本绝对路径
abs_path = os.path.abspath(__file__)
print(abs_path) # C:\Tools\devTools\Pycharm\code\内置模块\main.py
# 获取当前文件的上级目录
parent_path = os.path.dirname(abs_path)
print(parent_path) # C:\Tools\devTools\Pycharm\code\内置模块
# 路径拼接
print(os.path.join(parent_path, "test.txt")) # C:\Tools\devTools\Pycharm\code\内置模块\test.txt
# 判断路径是否存在
print(os.path.exists(os.path.join(parent_path, "test.txt"))) # False
print(os.path.exists(os.path.join(parent_path, "main.py"))) # True
# 创建路径
os.makedirs(os.path.join(parent_path, "test"), exist_ok=True)
print(os.path.exists(os.path.join(parent_path, "test"))) # True
# 是否是文件夹
print(os.path.isdir(os.path.join(parent_path, "test"))) # True
print(os.path.isdir(os.path.join(parent_path, "test.txt"))) # False
# 删除文件或文件夹
os.remove(os.path.join(parent_path, "test.txt"))
print(os.path.exists(os.path.join(parent_path, "test.txt"))) # False
os.rmdir(os.path.join(parent_path, "test"))
print(os.path.exists(os.path.join(parent_path, "test"))) # False
# 创建文件
# 'w'模式表示写入模式,如果文件不存在,则会创建该文件
with open(os.path.join(parent_path, "test.txt"), "w", encoding="utf-8") as f:
f.write("hello world")
print(os.path.exists(os.path.join(parent_path, "test.txt"))) # True
# 查看目录下所有的文件
print(os.listdir(os.path.join(parent_path, "test"))) # ['test.txt', 'txt']
# 查看目录下所有的文件(含子孙文件)
data = os.walk(os.path.join(parent_path, "test"))
for path, folder_list, file_list in data:
print(path)
print(folder_list)
print(file_list)
# for file_name in file_list:
# file_abs_path = os.path.join(path, file_name)
# print(file_abs_path)
# for folder_name in folder_list:
# folder_abs_path = os.path.join(path, folder_name)
# print(folder_abs_path)
#
# for path_name in path:
# print(path_name)
2.shutil
import shutil
import os
# 获取当前脚本的绝对位置
abs_path = os.path.abspath(__file__)
# 获取当前位置的上一级目录
base_path = os.path.dirname(abs_path)
print(base_path) # C:\Tools\devTools\Pycharm\code\内置模块
print(os.getcwd()) # C:\Tools\devTools\Pycharm\code\内置模块
# 删除文件夹
shutil.rmtree(os.path.join(os.getcwd(), 'study'))
# 拷贝文件夹 拷贝的目标地址,如果存在就会报错
shutil.copytree(os.path.join(base_path, "test"), os.path.join(os.getcwd(), 'studentInfo'))
# 拷贝文件
shutil.copy(os.path.join(abs_path), os.path.join(os.getcwd(), 'study'))
# 文件或文件夹重命名
shutil.move(os.path.join(os.getcwd(), "study/main.py"), os.path.join(base_path, "study/info.py"))
# 压缩文件
shutil.make_archive(base_name=r'dataFile', format='zip', root_dir=os.path.join(base_path, 'studentInfo'))
# 解压文件
shutil.unpack_archive(filename=r'dataFile.zip', extract_dir=os.path.join(os.getcwd(), "study"), format='zip')
3.sys
import sys
# 获取解释器版本
print(sys.version)
print(sys.version_info)
print("Python主版本号:", sys.version_info.major, ",Python此版本号:", sys.version_info.minor, ",Python微版本号:",sys.version_info.micro,
",Python发行级别:", sys.version_info.releaselevel, ",Python发行序列号:", sys.version_info.serial)
# 导入模块路径
print(sys.path)
4.random
import random
# 获取范围内的随机整数
print(random.randint(10, 20))
# 获取范围内的随机小数
print(random.uniform(10, 20))
# 随机抽取一个元素
print(random.choice([11, 22, 23, 56, 89]))
# 随机抽取多个元素
print(random.sample([11, 55, 66, 23, 56, 89], 3))
# 打乱顺序
data = [1, 2, 3, 4, 5, 6]
random.shuffle(data)
print(data)
5.hashlib
6.configparser
- 见下文
7.xml
- 见下文
3.文件操作
1.文件操作
-
字符串类型(str),在程序中用于表示文字信息,本质上是unicode编码中的二进制
str = "Python"
-
字节类型
-
可表示文字信息,本质上是utf-8/gbk等编码的二进制
strInfo = "Python" data = strInfo.encode("utf-8") # b'Python' print(data) result = data.decode("utf-8") print(result) # Python
-
可表示原始二进制(图片、文件等信息)
-
1.读文件
- 读文本文件
# 打开文件
'''
mode是一个可选字符,默认值为 r,打开文本阅读模式
- w 表示写入(截断文件)
- x 表示用于创建喝写入新文件
- a 表示追加(在某些Unix系统上,表示所有写入),追加到文件的末尾
- b 表示二进制模式
- t 表示文本模式(默认)
- + 打开磁盘文件进行更新(读写)
'''
import os.path
# 打开文件
file_object = open(os.path.join(os.getcwd(), "test") + "/test.txt", mode='rb')
# 读取文件内容,并赋值给data
data = file_object.read()
# 关闭文件
file_object.close()
# 输出文件内容(二进制)
print(data)
# 解码
text = data.decode('utf-8')
print(text)
# # 打开文件
# file_object = open(os.path.join(os.getcwd(), "test") + "/test.txt", mode='rt',encoding='utf-8')
# # 读取文件内容,并赋值给data
# data = file_object.read()
# # 关闭文件
# file_object.close()
#
# print(data)
-
读图片等非文本内容文件
# 打开文件 file_object = open(os.path.join(os.getcwd(), "test") + "/python安装检验.png", mode="rb") # 读取文件内容,并赋值给data data = file_object.read() # 关闭文件 file_object.close() # 打印二进制码 print(data)
-
读文件时,文件不存在程序会报错
file_path = os.path.join(os.getcwd(), "test/test.txt") exists = os.path.exists(file_path) if exists: # 打开文件 file_object = open(file_path, mode='rt', encoding='utf-8') # 读取文件内容,并赋值给data data = file_object.read() # 关闭文件 file_object.close() print(data) else: print("文件不存在!")
2.写文件
# 写文件文本
# 打开文件 用二进制方式输入
# file_object = open(os.path.join(os.getcwd() + "/test/txt.txt"), mode="wb")
# 用文本方式输入 w模式会新建,然后再写入内容;文件存在时,w模式会清空文件再写入内容
file_object = open(os.path.join(os.getcwd() + "/test/text.txt"), mode="wt", encoding='utf-8')
# 写入内容
# file_object.write("新公司真不错".encode("utf-8"))
file_object.write("新公司业务好")
# 文件关闭
file_object.close()
# 写图片等文件
f1 = open(os.path.join(os.getcwd() + "/test/python安装检验.png"), mode='rb')
content = f1.read()
f1.close()
f2 = open(os.path.join(os.path.dirname(os.path.abspath(__file__)) + "/test/python安装检验_copy.png"), mode='wb')
f2.write(content)
f2.close()
# 案例: 多用户注册
# 新建文件夹
os.makedirs(os.path.join(os.getcwd(), "files"), exist_ok=True)
file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="wt", encoding="utf-8")
while True:
user = input("请输入用户名:")
if user.upper() == "Q":
break
pwd = input("请输入密码:")
data = "{}----{}".format(user, pwd)
file_object.write(data + "\n")
file_object.close()
3.文件打开模式
-
基于文件操作基本实现了读、写的功能,其中涉及的文件操作模式: rt 、rb、wt、wb,其实再文件操作还有其他很多模式
Character Meaning --------- --------------------------------------------------------------- 'r' open for reading (default) 'w' open for writing, truncating the file first 'x' create a new file and open it for writing 'a' open for writing, appending to the end of the file if it exists 'b' binary mode 't' text mode (default) '+' open a disk file for updating (reading and writing) The default mode is 'rt' (open for reading text)
-
文件的打开模式常见应用有
-
只读: r 、rt 、rb
- 存在,读
- 不存在,报错
-
只写: w、wt、wb
- 存在,清空再写
- 不存在,创建再写
-
只写: x、xt、xb
- 存在,报错
- 不存在,创建再写
-
只写: a、at、ab
- 存在,尾部追加
- 不存在,创建再写
-
读写:
-
r+、rt+、rb+
-
默认光标位置,起始位置
# rt+ # 打开文件 file_object = open(os.path.join(os.getcwd() + "/files/infos.txt"), mode="rt+") # 读取文件 data = file_object.read() print(data) # 写入内容 file_object.write("你好呀") file_object.close()
-
w+、wt+、wb+,默认光标位置,为起始位置(清空文件)
# wt+ # 打开文件 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="wt+") # 读取文件 data = file_object.read() print(data) # # 写入内容 file_object.write("你好呀") # 重置光标起始位置 file_object.seek(0) # 读取文件 data = file_object.read() print(data) # 你好呀 file_object.close()
-
x+、xt+、xb+,默认光标位置: 起始位置(新文件)
-
a+、at+、ab+,默认光标位置: 末尾
# at+ # 打开文件 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="at+") # 写入内容 file_object.write("你好呀") # 重置光标起始位置 file_object.seek(0) # 读取文件 data = file_object.read() print(data) # 你好呀 file_object.close()
-
-
4.常见功能
-
read,读
-
读所有
# 读取二进制模式下,不需要设置字符编码 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="r", encoding='utf-8') data = file_object.read() file_object.close()
-
读n个字符(字节)
# 读取二进制模式下,不需要设置字符编码 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="r", encoding='utf-8') # 读一个字符 data = file_object.read(1) file_object.close() # 读取二进制模式下,不需要设置字符编码 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="rb") # 读一个字节;编码格式为utf-8,参数输入3,表示读取一个字符 data = file_object.read(1) file_object.close()
-
readline,读一行
# 读取二进制模式下,不需要设置字符编码 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="r", encoding='utf-8') data = file_object.readline() file_object.close()
-
readlines,读所有行,每行作为列表的一个元素
# 读取二进制模式下,不需要设置字符编码 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="r", encoding='utf-8') data_list = file_object.readlines() file_object.close()
-
循环,读大文件
# 读取二进制模式下,不需要设置字符编码 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="r", encoding='utf-8') for line in file_object: print(line.strip()) file_object.close()
-
-
write,写
# 打开文件 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="a", encoding="utf-8") # 写入内容 file_object.write("你好呀") file_object.close() # 打开文件 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="ab") # 写入内容 file_object.write("你好呀".encode("utf-8")) file_object.close()
-
flush,刷到硬盘
# 打开文件 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="ab") # 写入内容 file_object.write("你好呀".encode("utf-8")) # 缓冲区刷到硬盘 file_object.flush() file_object.close()
-
移动光标位置(字节)
- 在a模式下,调用write在文件中写入内容,永远只能将内容写入尾部,不会写到光标位置
# 打开文件 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="r+", encoding="utf-8") # 移动光标位置,(UTF-8)编码格式,按照每3个字节为一个单位移动 file_object.seek(3) # 写入内容 file_object.write("你好呀") # 缓冲区刷到硬盘 file_object.flush() file_object.close()
-
获取当前光标位置
# 打开文件 file_object = open(os.path.join(os.getcwd() + "/files/info.txt"), mode="r", encoding="utf-8") # 获取光标位置 0 file_object.tell() # 读取三个字符 file_object.read(3) # 获取光标位置 3 * 3 = 9 file_object.tell() file_object.close()
5.上下文管理
-
进行文件操作时,使用with上下文管理,可以自动实现关闭文件
# Python2.7之后,支持同时多个文件的上下文管理 with open(os.path.join(os.getcwd() + "/files/info.txt"), mode="r", encoding="utf-8") as f1, open(os.path.join(os.getcwd() + "/files/infos.txt"), mode="rb") as fb: pass
2.csv格式文件
-
逗号分隔值(csv,也称为字符分隔值),其文件以纯文本形式存储表格数据
-
文本
26044585,Hush,https://hbimg.huabanimg.com/51d46dc32abe7ac7f83b94c67bb88cacc46869954f478-aP4Q3V 19318369,柒十一,https://hbimg.huabanimg.com/703fdb063bdc37b11033ef794f9b3a7adfa01fd21a6d1-wTFbnO 15529690,Law344,https://hbimg.huabanimg.com/b438d8c61ed2abf50ca94e00f257ca7a223e3b364b471-xrzoQd 18311394,Jennah·,https://hbimg.huabanimg.com/4edba1ed6a71797f52355aa1de5af961b85bf824cb71-px1nZz 18009711,可洛爱画画,https://hbimg.huabanimg.com/03331ef39b5c7687f5cc47dbcbafd974403c962ae88ce-Co8AUI 30574436,花姑凉~,https://hbimg.huabanimg.com/2f5b657edb9497ff8c41132e18000edb082d158c2404-8rYHbw 17740339,小巫師,https://hbimg.huabanimg.com/dbc6fd49f1915545cc42c1a1492a418dbaebd2c21bb9-9aDqgl 18741964,桐末tonmo,https://hbimg.huabanimg.com/b60cee303f62aaa592292f45a1ed8d5be9873b2ed5c-gAJehO 30535005,TANGZHIQI,https://hbimg.huabanimg.com/bbd08ee168d54665bf9b07899a5c4a4d6bc1eb8af77a4-8Gz3K1 31078743,你的老杨,https://hbimg.huabanimg.com/c46fbc3c9a01db37b8e786cbd7174bbd475e4cda220f4-F1u7MX 25519376,尺尺寸,https://hbimg.huabanimg.com/ee29ee198efb98f970e3dc2b24c40d89bfb6f911126b6-KGvKes 21113978,C-CLong,https://hbimg.huabanimg.com/7fa6b2a0d570e67246b34840a87d57c16a875dba9100-SXsSeY 24674102,szaa,https://hbimg.huabanimg.com/0716687b0df93e8c3a8e0925b6d2e4135449cd27597c4-gWdv24 30508507,爱起床的小灰灰,https://hbimg.huabanimg.com/4eafdbfa21b2f300a7becd8863f948e5e92ef789b5a5-1ozTKq 12593664,yokozen,https://hbimg.huabanimg.com/cd07bbaf052b752ed5c287602404ea719d7dd8161321b-cJtHss 16899164,一阵疯,https://hbimg.huabanimg.com/0940b557b28892658c3bcaf52f5ba8dc8402100e130b2-G966Uz 847937,卩丬My㊊伴er彎,https://hbimg.huabanimg.com/e2d6bb5bc8498c6f607492a8f96164aa2366b104e7a-kWaH68 31010628,慢慢即漫漫,https://hbimg.huabanimg.com/c4fb6718907a22f202e8dd14d52f0c369685e59cfea7-82FdsK 13438168,海贼玩跑跑,https://hbimg.huabanimg.com/1edae3ce6fe0f6e95b67b4f8b57c4cebf19c501b397e-BXwiW6 28593155,源稚生,https://hbimg.huabanimg.com/626cfd89ca4c10e6f875f3dfe1005331e4c0fd7fd429-9SeJeQ 28201821,合伙哼哼,https://hbimg.huabanimg.com/f59d4780531aa1892b80e0ec94d4ec78dcba08ff18c416-769X6a 28255146,漫步AAA,https://hbimg.huabanimg.com/3c034c520594e38353a039d7e7a5fd5e74fb53eb1086-KnpLaL 30537613,配䦹,https://hbimg.huabanimg.com/efd81d22c1b1a2de77a0e0d8e853282b83b6bbc590fd-y3d4GJ 22665880,日后必火,https://hbimg.huabanimg.com/69f0f959979a4fada9e9e55f565989544be88164d2b-INWbaF 16748980,keer521521,https://hbimg.huabanimg.com/654953460733026a7ef6e101404055627ad51784a95c-B6OFs4 30536510,“西辞”,https://hbimg.huabanimg.com/61cfffca6b2507bf51a507e8319d68a8b8c3a96968f-6IvMSk 30986577,艺成背锅王,https://hbimg.huabanimg.com/c381ecc43d6c69758a86a30ebf72976906ae6c53291f9-9zroHF 26409800,CsysADk7,https://hbimg.huabanimg.com/bf1d22092c2070d68ade012c588f2e410caaab1f58051-ahlgLm 30469116,18啊全阿,https://hbimg.huabanimg.com/654953460733026a7ef6e101404055627ad51784a95c-B6OFs4 15514336,W/小哥,https://hbimg.huabanimg.com/a30f5967fc0acf81421dd49650397de63c105b9ead1c-nVRrNl 17473505,椿の花,https://hbimg.huabanimg.com/0e38d810e5a24f91ebb251fd3aaaed8bb37655b14844c-pgNJBP 19165177,っ思忆゜♪,https://hbimg.huabanimg.com/4815ea0e4905d0f3bb82a654b481811dadbfe5ce2673-vMVr0B 16059616,格林熊丶,https://hbimg.huabanimg.com/8760a2b08d87e6ed4b7a9715b1a668176dbf84fec5b-jx14tZ 30734152,sCWVkJDG,https://hbimg.huabanimg.com/f31a5305d1b8717bbfb897723f267d316e58e7b7dc40-GD3e22 24019677,虚无本心,https://hbimg.huabanimg.com/6fdfa9834abe362e978b517275b06e7f0d5926aa650-N1xCXE 16670283,Y-雨后天空,https://hbimg.huabanimg.com/a3bbb0045b536fc27a6d2effa64a0d43f9f5193c177f-I2vHaI 21512483,汤姆2,https://hbimg.huabanimg.com/98cc50a61a7cc9b49a8af754ffb26bd15764a82f1133-AkiU7D 16441049,笑潇啸逍小鱼,https://hbimg.huabanimg.com/ae8a70cd85aff3a8587ff6578d5cf7620f3691df13e46-lmrIi9 24795603,v,https://hbimg.huabanimg.com/a7183cc3a933aa129d7b3230bf1378fd8f5857846cc5-3tDtx3 29819152,妮玛士珍多,https://hbimg.huabanimg.com/ca4ecb573bf1ff0415c7a873d64470dedc465ea1213c6-RAkArS 19101282,陈勇敢❤,https://hbimg.huabanimg.com/ab6d04ebaff3176e3570139a65155856871241b58bc6-Qklj2E 28337572,爱意随风散,https://hbimg.huabanimg.com/117ad8b6eeda57a562ac6ab2861111a793ca3d1d5543-SjWlk2 17342758,幸运instant,https://hbimg.huabanimg.com/72b5f9042ec297ae57b83431123bc1c066cca90fa23-3MoJNj 18483372,Beau染,https://hbimg.huabanimg.com/077115cb622b1ff3907ec6932e1b575393d5aae720487-d1cdT9 22127102,栽花的小蜻蜓,https://hbimg.huabanimg.com/6c3cbf9f27e17898083186fc51985e43269018cc1e1df-QfOIBG 13802024,LoveHsu,https://hbimg.huabanimg.com/f720a15f8b49b86a7c1ee4951263a8dbecfe3e43d2d-GPEauV 22558931,白驹过隙丶梨花泪う,https://hbimg.huabanimg.com/e49e1341dfe5144da5c71bd15f1052ef07ba7a0e1296b-jfyfDJ 11762339,cojoy,https://hbimg.huabanimg.com/5b27f876d5d391e7c4889bc5e8ba214419eb72b56822-83gYmB 30711623,雪碧学长呀,https://hbimg.huabanimg.com/2c288a1535048b05537ba523b3fc9eacc1e81273212d1-nr8M4t 18906718,西霸王,https://hbimg.huabanimg.com/7b02ad5e01bd8c0a29817e362814666a7800831c154a6-AvBDaG 31037856,邵阳的小哥哥,https://hbimg.huabanimg.com/654953460733026a7ef6e101404055627ad51784a95c-B6OFs4 26830711,稳健谭,https://hbimg.huabanimg.com/51547ade3f0aef134e8d268cfd4ad61110925aefec8a-NKPEYX
-
代码
with open(os.path.join(os.getcwd() + "/test/stuInfos.csv"), mode="r", encoding="utf-8") as file_object: file_object.readline() for line in file_object: user_id, userName, url = line.strip().split(",") # 根据URL下载图片 res = requests.get( url=url, headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" } ) # 检查 images 目录是否存在? 不存在,创建images目录 if not os.path.exists(os.getcwd() + "/test/images"): # 创建 os.makedirs(os.getcwd() + "/test/images") # 将图片的内容写入文件 with open(os.path.join(os.getcwd() + "/test/images/{}.png".format(userName)), mode="wb") as img_object: img_object.write(res.content)
-
3.ini格式文件
-
ini文件时initialzation File的缩写,平时用于存储软件的配置文件
-
文件
[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock log-bin=py-mysql-bin character-set-server=utf8 collation-server=utf8_general_ci log-error=/var/log/mysqld.log # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 [mysqld_safe] log-error=/var/log/mariadb/mariadb.log pid-file=/var/run/mariadb/mariadb.pid [client] default-character-set=utf8
-
代码
# 初始化对象 config = configparser.ConfigParser() config.read(os.path.join(os.getcwd() + "/test/my.ini"), encoding="utf-8") # 获取所有节点 result = config.sections() print(result,type(result)) # ['mysqld', 'mysqld_safe', 'client'] <class 'list'> # 获取节点下的键值 result = config.items(result[1]) print(result, type(result)) # [('log-error', '/var/log/mariadb/mariadb.log'), ('pid-file', '/var/run/mariadb/mariadb.pid')] <class 'list'> for key,value in config.items("mysqld_safe"): print(key, value) # 获取某个节点下的键对应的值 result = config.get("mysqld_safe", "pid-file") print(result, type(result)) # /var/run/mariadb/mariadb.pid <class'str'> # 检查、删除、添加节点 hassection = config.has_section("client") print(hassection) # True # 删除节点,包含该节点下面的键值对 config.remove_section('client') # 删除节点下指定键的键值对 config.remove_option("mysqld", "datadir") # 操作删除之后,需要更新回配置文件中 with open(os.path.join(os.getcwd() + "/test/my.ini"), mode="w", encoding="utf-8") as configFile: config.write(configFile) # 添加节点 config.add_section('server') config.set('server', 'port', '8080') config.set('server', 'ipAddr', '176.0.5.6') config.set('mysqld', 'datadir','/var/lib/mysql') # 添加操作之后,需要更新回配置文件 效果类似于with open... config.write(open(os.path.join(os.getcwd() + "/test/my.ini"), mode='w', encoding='utf-8'))
-
4.XML格式文件
-
可扩展标记语言,是一种捡蛋的数据存储语言,XML被设计用来传输和存储数据
- 存储,可用来存放配置文件
- 传输,网络传输时以这种格式存在
1.读取文件和内容
from xml.etree import ElementTree as ET
# XML格式文件
# 打开XML文件
tree = ET.parse(open(os.path.join(os.getcwd() + "/test/data.xml")))
# 获取根标签
root = tree.getroot()
# 打印根标签
print(root.tag) # data
# 代码中的XML解析
content = """
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2023</year>
<gdppc>141100</gdppc>
<neighbor direction="E" name="Austria" />
<neighbor direction="W" name="Switzerland" />
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2026</year>
<gdppc>59900</gdppc>
<neighbor direction="N" name="Malaysia" />
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2026</year>
<gdppc>13600</gdppc>
<neighbor direction="W" name="Costa Rica" />
<neighbor direction="E" name="Colombia" />
</country>
</data>
"""
# 获取根标签
root = ET.XML(content)
print(root.tag) # data
2.读取节点数据
# 读取节点数据
country_object = root.find("country")
# attrib函数获取标签内的属性
print(country_object.tag, country_object.attrib) # country {'name': 'Liechtenstein'}
# 获取标签gdppc
gdppc_object = country_object.find("gdppc")
print(gdppc_object.tag, gdppc_object.text) # gdppc 141100
# 获取data标签的子标签
for child in root:
# 子标签的标签名和标签内部属性
print(child.tag, child.attrib)
print("单个data标签分割线".center(30, "*"))
for node in child:
# 子标签内部节点 标签命 标签内部属性 标签的值 无值用None表示
print(node.tag, node.attrib, node.text)
# 通过根标签指定内部标签,获取内部标签的相关信息
for child in root.iter('rank'):
'''
rank 2
rank 5
rank 69
'''
print(child.tag, child.text)
# 查找XML中指定的所有标签
root_son = root.findall("country")
print(root_son) # [<Element 'country' at 0x0000025D2B79FBF0>, <Element 'country' at 0x0000025D2B79FDD0>, <Element 'country' at 0x0000025D2B79FF60>]
# 通过find()函数,查找多层标签,仅限查询到的一个符合标签
root_son_str = root.find("country").find("year")
print(root_son_str.tag, root_son_str.attrib, root_son_str.text)
3.修改和删除节点
# 修改节点内容和属性
rank = root.find("country").find("rank")
print(rank.text)
rank.text = "123"
rank.set("update", "no")
print(rank.text, rank.attrib)
# 保存配置
tree = ET.ElementTree(root)
tree.write(os.path.join(os.getcwd() + "/test/data.xml"), encoding="utf-8")
# 删除节点
root.remove(root.find("country"))
print(root.findall("country"))
# 保存文件
tree = ET.ElementTree(root)
tree.write(os.path.join(os.getcwd() + "/test/data.xml"), encoding="utf-8")
# 笑死,禁忌切勿混合模块
# tree.write(open(os.path.join(os.getcwd() + "/test/data.xml"), mode="w", encoding="utf8"))
4.构建文档
-
student.csv
李四,18,四川省成都市 田六,20,四川省德阳市 王五,27,四川省南充市 Tom,38,NewYork
# 创建根标签
root = ET.Element("studentInfos")
#
# # 创建根标签的子节点
# student1 = ET.Element("student", {"desc": "学生信息"})
# name = ET.Element("name")
# name.text = "张三"
# age = ET.Element("age", {"desc": "Data legitimacy"})
# age.text = "20"
# address = ET.Element("address")
# address.text = "成都市"
# student1.append(name)
# student1.append(age)
# student1.append(address)
#
# student2 = ET.Element("student", {"desc": "学生信息"})
# name = ET.Element("name")
# name.text = "赵六"
# age = ET.Element("age", {"desc": "Data legitimacy"})
# age.text = "25"
# address = ET.Element("address")
# address.text = "上海市"
# student2.append(name)
# student2.append(age)
# student2.append(address)
#
# student3 = ET.Element("student", {"desc": "学生信息"})
# name = ET.Element("name")
# name.text = "李四"
# age = ET.Element("age", {"desc": "Data legitimacy"})
# age.text = "18"
# address = ET.Element("address")
# address.text = "重庆市"
# student3.append(name)
# student3.append(age)
# student3.append(address)
#
# root.append(student1)
# root.append(student2)
# root.append(student3)
def create_student_info(username, Age, addr):
student = ET.Element("student", {"desc": "学生信息"})
name = ET.Element("name")
name.text = username
age = ET.Element("age", {"desc": "Data legitimacy"})
age.text = Age
address = ET.Element("address")
address.text = addr
student.append(name)
student.append(age)
student.append(address)
return student
with open(os.path.join(os.getcwd() + "/test/student.csv"), mode="rt", encoding="utf-8") as stu_infos:
for stu_info in stu_infos:
name, age, addr = stu_info.strip().split(",")
root.append(create_student_info(name, age, addr))
tree = ET.ElementTree(root)
tree.write(os.path.join(os.getcwd() + "/test/studentInfos.xml"), encoding="utf-8", short_empty_elements=False)
-
studentInfos.xml
<studentInfos> <student desc="学生信息"> <name>李四</name> <age desc="Data legitimacy">18</age> <address>四川省成都市</address> </student> <student desc="学生信息"> <name>田六</name> <age desc="Data legitimacy">20</age> <address>四川省德阳市</address> </student> <student desc="学生信息"> <name>王五</name> <age desc="Data legitimacy">27</age> <address>四川省南充市</address> </student> <student desc="学生信息"> <name>Tom</name> <age desc="Data legitimacy">38</age> <address>NewYork</address> </student> </studentInfos>
5.Excel格式文件
-
Python内部未提供处理Excel文件的功能,需要按照第三方的模块来处理
pip3 install openpyxl
1.读Excel
-
读sheet
from openpyxl import load_workbook # #sheet # 获取C盘根目录的 # c_drive = os.path.join(os.environ['SystemDrive']) # 获取其他盘根目录 # try: # d_drive = os.path.join('D:\\', '') # print(d_drive) # except OSError: # print("D盘不存在!") wb = load_workbook(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试.xlsx")) # 获取excel文件中的所有sheet名称 print(wb.sheetnames) # ['学生信息', '商品价格'] # 指定sheet,基于指定的sheet获取指定位置数据 sheet = wb[wb.sheetnames[0]] # wb['学生信息'] 等效 cell = sheet.cell(2, 2) print(cell.value) # username # 指定sheet,基于索引位置 sheet = wb.worksheets[0] cell = sheet.cell(2, 2) print(cell.value) # username # 循环所有的sheet for name in wb.sheetnames: sheet = wb[name] cell = sheet.cell(2, 2) ''' username 名称 ''' print(cell.value) for sheet in wb.worksheets: cell = sheet.cell(2, 2) print(cell.value) for sheet in wb: cell = sheet.cell(2, 2) print(cell.value)
-
读sheet中单元格的数据
from openpyxl import load_workbook from openpyxl.worksheet.merge import MergedCellRange # 读取sheet中单元格的数据 # 获取第n行第n列的单元格(单元格计算是1开始) cell = wb.worksheets[0].cell(1, 1) # 单元格的值 print(cell.value) # 单元格的样式 print(cell.style) # 单元格的字体 print(cell.font) # 单元格的单元格中文本的对齐方式 print(cell.alignment) # 获取某一个单元格 value = wb.worksheets[0]['A2'].value print(value) # uid value = wb.worksheets[0]['D4'].value print(value) # 56 # 获取n行所有单元格 for cell in wb.worksheets[0][2]: print(cell.value) # 获取行的数据(获取某一列的数据) for row in wb.worksheets[0].rows: print(row[0].value, row[1].value) # 获取所有列的数据(获取某一行的数据) for col in wb.worksheets[0].columns: print(col[1].value) # 读合并单元格 for row in wb.worksheets[1].rows: print(row) for item in sorted(wb.worksheets[1].merged_cells.ranges): if wb.worksheets[1].cell(1, 2).coordinate in item: print(item.start_cell.value)
2.写Excel
-
原文件基础上写内容
# 写Excel # 修改单元格数据 sheet = wb.worksheets[1] cell = sheet.cell(2, 4) cell.value = "生产产地" wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试修改.xlsx"))
-
新创建Excel文件写内容
from openpyxl import load_workbook, workbook from openpyxl.styles import Alignment, Border, Side, Font, PatternFill, GradientFill # 创建Excel且默认会创建一个sheet(名称为Sheet) wb = workbook.Workbook() # 或 sheet = wb["Sheet"] sheet = wb.worksheets[0] # 找到单元格,并修改单元格的内容 cell = sheet.cell(1, 1) cell.value = "测试参数" # 将Excel表保存到指定位置 wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) ''' insert_rows(idx, amount=1) - idx 插入位置的行索引,新的行被插入到这个行之前 - amount 要插入的行数,默认值为1 insert_cols(idx, amount=1) - idx 插入位置的列索引,新的行被插入到这个列之前 - amount 要插入的列数,默认值为1 delete_rows(idx, amount) - idx 要删除的第一行的索引 - amount 要删除的行数,默认值为1 delete_cols(idx, amount) - idx 要删除的第一列的索引 - amount 要删除的列数,默认值为1 ''' # 添加2行 # sheet.insert_rows(2, amount=2) # 删除2行 # sheet.delete_rows(1, amount=2) # 删除2列 # sheet.delete_cols(1, amount=1) # 保存 wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 修改sheet名称 wb.worksheets[0].title = "测试表格" wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 创建sheet并设置sheet颜色 sheet = wb.create_sheet("工作计划", 0) sheet.sheet_properties.tabColor = "1072BA" wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 设置默认打开的sheet wb.active = 1 wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 拷贝sheet new_sheet = wb.copy_worksheet(wb["工作计划"]) new_sheet.title = "新的工作计划" wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 删除sheet del wb["测试表格"] wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 获取某些单元格,修改值 cell_list = wb.worksheets[0]["B2":"C3"] for row in cell_list: for cell in row: cell.value = "测试值" wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 对齐方式 ''' horizontal,水平方向对齐方式 general, left, center, fill, justify, centerContinuous, distributed vertical,垂直方向对齐方式 top, center, bottom, justify, distributed text_rotation,旋转角度 wrap_text,是否自动换行 ''' cell = wb.worksheets[0].cell(2, 2) cell.alignment = Alignment(horizontal="center", vertical="center", textRotation=45) wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 边框 ''' side的style有一下这些 - dashDot','dashDotDot', 'dashed','dotted','double','hair', 'medium', 'mediumDashDot', 'mediumDashDotDot','mediumDashed', 'slantDashDot', 'thick', 'thin' ''' cell = wb.worksheets[0].cell(2, 3) cell.border = Border( top=Side(style="thin", color="FF86C1"), bottom=Side(style="dashed", color="FFB6C1"), left=Side(style="dashed", color="FEB6C1"), right=Side(style="dashed", color="F86CC1"), # 对角线 diagonal=Side(style="thin", color="48DF51"), # 对角线的方向 # 左下 ~ 右上 diagonalUp=True, # 左上~ 右下 diagonalDown=True ) wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 字体 cell = wb.worksheets[0].cell(3, 2) cell.font = Font(name="微软雅黑", size=12, bold=True, color="EF23EE", underline="single") wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 背景色 cell = wb.worksheets[0].cell(3, 3) cell.fill = PatternFill(start_color="EE86C1", end_color="FF86E2", fill_type="solid") wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 渐变背景色 cell = wb.worksheets[0].cell(2, 2) cell.fill = GradientFill("linear", stop=("FFFFFF", "99CCFF", "000000")) wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 宽高(索引从1开始) wb.worksheets[1].row_dimensions[1].height = 30 wb.worksheets[1].column_dimensions['B'].width = 40 wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 合并单元格 wb.worksheets[1].merge_cells("B2:C5") wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 取消合并单元格 wb.worksheets[1].unmerge_cells("B2:C5") wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 写入公式 wb.worksheets[0]["D1"] = "合计" wb.worksheets[0]["D2"] = "=SUM(D3:D5)" wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 移动 wb.worksheets[1]["E3"] = "总计" wb.worksheets[1]["E4"] = "=A2*B4" wb.worksheets[1]["E5"] = "=SUM(A2,C4)" # 将A2:E5范围的数据,向右移动10个单元格,向下移动1个单元格 wb.worksheets[1].move_range("A2:E5", cols=10, rows=1, translate=True) wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 打印区域 wb.worksheets[1].print_area = "A2:E5" wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx")) # 打印时,每个页面的固定表头 wb.worksheets[1].print_title_cols = "A:D" wb.worksheets[1].print_title_rows = "1:3" wb.save(os.path.join(os.environ['SystemDrive'], "/Users/梁/Desktop/测试新表输入.xlsx"))
6.压缩文件
- 见上文shutil
7.补充知识
1.深浅拷贝
1.浅拷贝
-
不可变类型,不拷贝
-
由于python内部优化机制,内存地址是相同的;对于不可变类型而言,以后修改值,会重新创建一份数据。不会影响原数据
-
import copy
string = "Ailke"
print(id(string)) # 2674432039728
cstr = copy.copy(string)
print(id(cstr)) # 2674432039728
object_list = ["Ailke", "root", [45, 23]]
print(id(object_list)) # 2437294345408
print(id(object_list[2])) # 2437296306752
copy_object_list = copy.copy(object_list)
print(id(copy_object_list)) # 2437296306496
print(id(copy_object_list[2])) # 2437296306752
-
可变类型,只拷贝第一层
object_list = ["Ailke", "root", [45, 23]] print(id(object_list)) # 2437294345408 print(id(object_list[2])) # 2437296306752 copy_object_list = copy.copy(object_list) print(id(copy_object_list)) # 2437296306496 print(id(copy_object_list[2])) # 2437296306752
2.深拷贝
-
不可变类型,不拷贝
strs = "Ailke" print(id(strs)) # 1769370573616 copy_strs = copy.deepcopy(strs) print(id(copy_strs)) # 1769370573616
-
特殊的元组
-
元组元素中无可变类型,不拷贝
tup_list = ("Ailke", "root",) print(id(tup_list)) # 2283265800896 copy_tup_list = copy.deepcopy(tup_list) print(id(copy_tup_list)) # 2283265800896
-
元素中有可变类型,找到所有[ 可变类型 ]或[ 含有可变类型的元组 ] 均拷贝一份
tup_list = ("Ailke", "root", [11, [44, 55], (11, 22), (11, [], 22), 33]) copy_tup_list = copy.deepcopy(tup_list) print("分割线".center(30, "#")) print(id(tup_list)) # 2219888325184 print(id(copy_tup_list)) # 2219888318080 print(id(tup_list[2])) # 2219886650944 print(id(copy_tup_list[2])) # 2219887055424 print(id(tup_list[2][1])) # 2219886331968 print(id(copy_tup_list[2][1])) # 2219887012608 print(id(tup_list[2][2])) # 2219886197568 print(id(copy_tup_list[2][2])) # 2219886197568 print(id(tup_list[2][3])) # 2219888325504 print(id(copy_tup_list[2][3])) # 2219888318016
-
-
可变类型
-
找到所有层级的 [ 可变类型 ] 或[ 含有可变类型的元组 ] 均拷贝一份
tup_list = ("Ailke", "root", [11, [44, 55], (11, 22), (11, [], 22), 33]) copy_tup_list = copy.deepcopy(tup_list) print(id(tup_list[2][2])) # 2219886197568 print(id(copy_tup_list[2][2])) # 2219886197568 print(id(tup_list[2][3])) # 2219888325504 print(id(copy_tup_list[2][3])) # 2219888318016
-