格式化字符串
为什么要格式化字符串
因为很多相同操作占取空间,大量重复操作
比如:身份证号: 现居家庭住址:等等
格式化字符串的两种方式
%作占位符
%s表示字符串,%i或%d表示整数
%f表示浮点数
{}作占位符
%叫做定义的格式化字符串,%是固定符号 (name,age)是实际值 # %占位符 name = '张三' age = 20 print('我叫%s,今年%d岁'% (name,age)) # 我叫张三,今年20岁 # {}格式化操作 print('我叫{0},今年{1}岁'.format(name,age) ) # 我叫张三,今年20岁 # f-string print(f'我叫{name},今年{age}岁') # 我叫张三,今年20岁 # %10d,10表示宽度 print('%10d' % 99) # 99 # %f表示浮点数,%.3是小数点后三位小数 print('%.3f' % 3.1415926) # %10.3f同时表示宽度和精度 print('%10.3f' % 3.1415926)#3.142 总宽度是10,小数点后三位 # 用{}形式也能注册 ,.3表示的一共是三位数 print('{0:.3}'.format(3.1415926)) # .3f表示3位小数 print('{0:.3f}'.format(3.1415926)) # 同时设置宽度 # print('{:10.3f}'.format(3.1415926))
为什么需要字符串的编码转换
str在内存中以UNICODE表示,将计算机中的内容传送到你的电脑上去,这时候就需要字节进行传输,这时候就需要将str转换成二进制数据传送到你的电脑上,你的电脑再进行转换成str进行展示
编码:将字符串转换为二进制数据(bytes)
解码:将bytes类型的数据转换成字符串类型
注意:编码格式和解码格式要相同
s = '解码编码操作'
# 编码
print(s.encode(encoding='GBK')) # GBK这种编码格式中,一个中文是二个字节 print(s.encode(encoding='UTF-8')) # UFT-8这种编码格式中,一个中文是三个字节 #
# 解码
# byte代表就是一个二进制数据 (字节类型的数据) byte = s.encode(encoding='GBK') # 编码 # print(byte.decode(encoding='UTF-8 ')) # 解码 报错,用什么编码,用什么解码 byte = s.encode(encoding='UTF-8') print(byte.decode(encoding='UTF-8')) # 解码编码操作
输出
b'\xbd\xe2\xc2\xeb\xb1\xe0\xc2\xeb\xb2\xd9\xd7\xf7' b'\xe8\xa7\xa3\xe7\xa0\x81\xe7\xbc\x96\xe7\xa0\x81\xe6\x93\x8d\xe4\xbd\x9c'
解码编码操作
函数
什么是函数?
函数就是执行特定任务和以完成特定功能的一段代码
为什么需要函数
复用代码
隐藏实现细节
提高可维护性
提高可读性便于调试
函数的创建
def 函数名 ([输入参数]) :
函数体
[return xxx]
函数名需要遵循字母、数字、下划线
# 这里的a,b是形式参数-形参,形参的位置是在函数的定义处 def calc(a,b): c = a+b return c print(calc(10,50)) # 60 这里的10,50称为实际参数的值,简称实参 print(calc(b=50,a=10)) #=左侧的变量名称为关键字参数,自动找a和b
定义函数取奇偶数
def fun(num): odd = [] # 存奇数 even = [] # 存偶数 for i in num: if i%2: odd.append(i) else: even.append(i) return odd,even lst=fun([10,21,33,66,88,99]) print(lst) # ([21, 33, 99], [10, 66, 88])
如果函数没有返回值【函数执行完毕之后,不需要给调
用处提供数据】 return可以省略不写
函数的返回值,如果是1个,直接返回类型
函数的返回值,如果是多个,返回的结果为元组
函数的参数定义
函数定义默认值参数
函数定义时,给形式参数设置默认值,只有与默认值不符的时候才需要传递实参
def fun(a,b=10) print(a,b) fun(100) #只传一个参数,b采用默认值 fun(20,30) #30将默认值10替换
个数可变的位置参数
定义参数时,可能无法事先确定传递的位置实参的个数时,使用可变的位置参数
使用*定义个数可变的位置形参
只能定义一个,def fun(* args,*a):这样报错
结果为一个元组
def fun(*args): # 函数定义时的 可变的位置参数 print(args) fun(10) fun(10,30) fun(30,405,50) """
结果
(10,) 注意元组有, 逗号,否则为字符串了 (10, 30) (30, 405, 50) """
个数可变的关键字形参
定义函数时,无法事先先确定传递的关键字实参的个数时,使用可变的关键字形参
使用**定义个数可变的关键字形参
只能定义一个,def fun(** args, **a):这样报错
结果为一个字典
def fun1(**args): print(args) fun1(a=10) # {'a': 10} fun1(a=20,b=30,c=40) # {'a': 20, 'b': 30, 'c': 40}
print源码
它是一个形式可变的位置参数,所以print('这里写几个都没问题')
def print(self, *args, sep=' ', end='\n', file=None):
注意:
在一个函数定义过程中,既有个数可变的关键字形参,也有个数可变的位置形参,要求,个数可变的位置形参,放在个数可变的关键字形参之前
def fun(**args1,*arg2):
在函数调用时的参数传递,称为位置传参
def fun(a,b,c): print(a,end='\t') print(b,end='\t') print(c,end='\t') fun(10,20,30) # 10 20 30 函数调用时的参数传递,称为位置传参 lst = [11,22,33] # fun(lst) #报错 fun(*lst) # 11 22 33 在函数调用时,将列表中的每个元素都转换为位置实参传入 dic = {'a':111,'b':222,'c':333} # fun(dic) #报错 fun(**dic) # 111 222 333 在函数调用时,将字段的键值对都转换为关键字实参传入 # 个数可变的关键字传参 def fun4(**args): print(args) fun4(a=666,b=888) # {'a': 666, 'b': 888}
函数传参其它类型
def fun5(a,b,*,c,d): print(a) print(b) print(c) print(d) fun5(a=10,b=20,c=30,d=40) # 10 20 30 40 # fun5(10,20,30,d=40) # 错误 前两个参数采用的是位置实参传递,c,d只能采用关键字传递 fun5(10,20,c=30,d=40) # 10 20 30 40 # 这些也都是可以的 def fun5(a,b,*,c,d,**args): print(args) fun5(1,3,c=3,d=4,e=4) # {'e': 4} def fun(*args,**args2): pass def fun(*args,**args2): pass def fun(a,b=10,*args,**args2): pass
变量的作用域
程序代码能访问该变量的区域
根据变量的有效范围可分为
局部变量:
在函数内定义并使用的变量,只在函数内部有效,局部变量使用global声明,这个变量就会成为全局变量
全局变量
在函数体外定义的变量,可作用函数内外
def fun(): global age # 声明global在外部也可以使用了 age=20 print(age) # 20 fun() print(age+1) # 21
递归函数
什么是递归函数
在函数体内调用了函数本身
递归的组成部分
递归调用与递归终止条件
递归的调用过程
每递归调用一次函数,都会在栈内存分配的一个栈帧
每执行完一次函数,都会释放相应的空间
递归的优缺点
优点:占用内存多,效率低下
缺点:思路和代码简单
斐波那契数列
形如1 1 2 3 5 8..每一项都前两项之和
# 斐波那契数列 def fib(n): if n == 1 or n == 2: return 1 else: return fib(n-1)+fib(n-2) print(fib(3)) # 2 # 输出前四项数组 for i in range(1,5): print(fib(i)) # 1 1 2 3
Python的异常处理机制
Bug的常见类型
Python提供了异常处理机制,可以在异常出现时即时捕获,然后内部“消化”,让程序继续运行
多个except结构
捕获异常的顺序按照先子类后父类的顺序,为了避免遗漏可能出现的异常,可以在最后增加BaseException
try...except...else结构
如果try块中没有抛出异常,则执行else块,如果try中抛出异常,则执行except块
try...except...else..finally结构
finally块无论是否发生异常都会被执行,能常用来释放try块中申请的资源
案例1
try: a = int(input('请输入第一个整数:')) b = int(input('请输入第二个整数:')) result = a/b print('结果为:',result) except ZeroDivisionError: print('对不起,除数不能为0') except ValueError: print('只能输入数字串') print('程序结束')
案例2
try: a = int(input('请输入第一个整数:')) b = int(input('请输入第二个整数:')) result = a/b except BaseException as e: print('出错了',e) else: print('计算结果为:',result) finally: print('谢谢你的使用')
Python中常见的异常
ZeroDivisionError :除(或取模)零(所有数据类型)
IndexError:序列中没有此索引(index)
KeyError:映射中没有这个键
NameError:未声明/初始化对象(没有属性)
SyntaxError:Python语法错误
ValueError:传入无效的参数
traceback
使用traceback模块打印异常信息
import traceback try: a = 1/0 except: traceback.print_exc()
输出
这些日志信息放到日志文件里面还是有用的
Traceback (most recent call last): File "F:\pythonProject1\venv\test.py", line 3, in <module> a = 1/0 ZeroDivisionError: division by zero
面向对象
类和对象
一切皆对象,和java一样,各编程语言一样的思想
规范:
类名首字母大写,和java一样
创建的规范
python3创建类的时候,可以不带括号,也可以带,也可以显示继承object,如果带个()空括号,其实也是隐士的继承了object。这三种方式是相等的。
class Student: pass
类的组成
类属性:类中方法外,被该类所有对象共享
类方法:@classmethod修饰,使用类名直接访问的方法
静态方法@staticmethod,使用类名直接调用
类属性、类方法、静态方法都是用类名直接调用
实例方法
# 创建的语法 class Studnet: native_pace = '吉林' # 类属性 # 初始化方法 这个self赋值时候不用写,赋值name和age即可,self默认带 def __init__(self,name,age): # 将局部变量的值赋值给实体属性,self.name称为实例属性 self.name = name self.age = age # 实例方法 # self 为这个方法名,name,age的为实例属性 def eat(self): # 这个self这里必写,self单词可以变,但程序员习惯self print('学生在吃饭') # 在类外定义的称为函数,类之内称为方法 # 类方法 @classmethod def cm(cls): print('类方法') # 静态方法中不能写self,注意 @staticmethod def sm(): print('静态方法') # 类之外定义的称为函数,在类之内定义的称为方法 def drink(): print('喝水')
对象的创建
和java一样
对象的创建又称为类的实例化
语法:
实例名=类名()
如stu = Student()
实例对象会有个类指针指向类对象
类名.方法名(类的对象),实际上就是方法定义处的self
Stu1 = Student('张三',20) Student.eat(stu1)
动态绑定属性和方法
Python是动态语言,在创建对象之后,可以动态地绑定属性和方法
stu1 = Studnet('张三',20) stu2 = Studnet('李四',30) print(id(stu1)) # 和stu2不同 print(id(stu2)) print('--------为stu2动态绑定性别属性-----------') stu2.gender = '女' # 这点和java不一样,java没有成员变量(属性-字段),是不能指定的 # Student中没有 gender属性 能动态绑定性别 ,只属于stu2自己 print(stu2.gender) # 女 def show(): print('定义在类之外的,称函数') stu1.show = show() stu1.show # 定义在类之外的,称函数 stu2.show # 报错 没有胃stu2动态绑定show方法,在对象上之后函数就称为方法了
面向对象的三大特征
封装:提高程序的安全性
将数据(属性)和行为(方法)包装到类中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度
在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前面使用两个"-"
继承:提高代码的复用性
如果一个类没有继承任何类,默认继承object
Python支持多继承(java不支持多继承)
定义子类时,必须在其构造函数中调用父类的构造函数
多态:提高程序的可扩展性和维护性
封装 class Student: def __init__(self,name,age): self.name = name self.__age = age def show(self): print(self.name,self.__age) stu = Student('张三',20) # 在类外部使用name、age print(stu.name) # 张三 # print(stu.__age) # 报错 print(dir(stu)) # dir()可以查看类的所有属性和方法 ,里面找到一个_Student__age print(stu._Student__age) # 这样也能访问,但是不建议这种访问方式 class Student2: def __init__(self,age): self.set_age(age) def get_age(self): return self.__age # 不希望在外面使用,所以加上两个__ def set_age(self,age): if 0<=age<=120: self.__age = age else: self.__age = 18 stu1 = Student2(150) stu2 = Student2(30) print(stu1.get_age()) # 18 print(stu2.get_age()) # 30 继承 class Person(object): #object默认不写也行 def __init__(self,name,age): self.name = name self.age = age def info(self): print('姓名:{0},年龄{1}'.format(self.name,self.age)) # 定义子类 class Student(Person): def __init__(self,name,age,score): super().__init__(name,age) self.score = score def info(self): super.info()# 还想用父类的info()可以super. print(self.score)# 重写 # 测试 stu = Student('Haha',20,'1001') stu.info() # 从父类中继承的方法 ,重写后就是Student的方法了
object类
object类是所有类的父类,因此所有类都有object类的属性和方法
内置函数dir()可以查看指定对象的所有属性
Object有一个_ str_ ()方法,用于返回一个对于“对象的描述”,对于内置函数str()进程用于print()方法,帮我们查看对象的信息,所以我们经常会对__str _()进行重写,而不是输出内存地址
重写str class Student: def __init__(self,name,age): self.name=name self.age=age def __str__(self): return '我的名字是{0},今年{1}岁'.format(self.name,self.age) stu=Student('Haha',20) print(stu) # 我的名字是Haha,今年{20}岁 默认调用_str_()这样的方法
多态
指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度
Python中虽然没有数据类型,但是具备多态特征
class Animal: def eat(self): print('eating...') class Dog(Animal): def eat(self): print('dog gnawing...') def fun(obj): obj.eat() fun(Animal()) # eating... fun(Dog()) # # dong gnawing
Java是静态,强类型语言,Python是动态语言
静态语言和动态语言关于多态的区别
静态语言实现多态的三个必要特征
继承
方法重写
父类引用执行子类对象
动态语言的多态的多态崇尚“鸭子类型”,当看到一只鸟走起来像鸭子、游泳像鸭子,收起来也像鸭子,那么这鸟就可以被称为鸭子;
在鸭子类型中,不用对象是什么类型,到底是不是鸭子,只关心对象的行为
特殊方法和特殊属性
特殊属性
_ dict __ :获得类对象或实例对象所绑定的所有属性和方法 __ len __():通过重写它,让内置函数len()的参数可以是自定义类型
特殊方法
_add _():通过重写它,让内置函数len()的参数可以是自定义类型 _new _():用于创建对象 _init() _:对创建的对象进行初始化
class A: def __init__(self,name,age): self.name = name self.age = age x = A('Jack',18) print(x.__dict__) #{'name': 'Jack', 'age': 18} print(x.__class__) # <class '__main__.A'> 所属的类 class B(A): pass print(B.__base__) # <class '__main__.A'> # 类的基类,如果多继承,谁在前输出谁 print(B.__bases__) # (<class '__main__.A'>,) 输出其父类类型的元素 print(B.__mro__) # 继承层次结果 B继承A继承object (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>) print(A.__subclasses__())#子类列表 [<class '__main__.B'>] a = 20 b = 100 c = a + b d = a.__add__(b) #等同于+ print(c) print(d) class Student: def __init__(self,name): self.name = name def __add__(self, other): # 必须在这里写,stu1.__add_(stu2)这样也报错 return self.name + other.name def __len__(self): # 必须写在这里才能计算长度 return len(self.name) stu1 = Student('张三') stu2 = Student('李四') s = stu1 + stu2 # 写了__add__方法才能加,否则报错 print(s) # 张三李四 lst = [1,2,3,4,5] print(len(lst)) # 5 print(lst.__len__()) # 5 print(stu1.__len__()) # 2 new执行是优先于init的。new后的对象会给__ init __中的self
类的浅拷贝与深拷贝
变量的赋值操作
只是形成两个变量,实际上还是指向同一个对象
浅拷贝
Python拷贝如果没特殊说明的话,一般都是浅拷贝,拷贝时,对象包含的子对象的内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象
深拷贝
使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同
源对象和拷贝对象的所有子对象也要重新拷贝一份
浅拷贝
class CPU: pass class Disk: pass class Computer: def __init__(self,cpu,disk): self.cpu = cpu self.disk = disk cpu1 = CPU() cpu2 = cpu1 # 这个是赋值操作 print(cpu1,cpu2) # 内存地址一样 # <__main__.CPU object at 0x000001A54423FF40> <__main__.CPU object at 0x000001A54423FF40> print('----------------------') disk = Disk() # 创建一个硬盘 computer = Computer(cpu1,disk) # 创建一个计算机类的对象 # 浅拷贝 import copy computer2 = copy.copy(computer) print(disk) # # <__main__.Disk object at 0x000001E1026AF3D0> print(computer,computer.cpu,computer.disk) # computer2和computer内存地址不同,子对象的内存地址是相同的-Disk和CPU # <__main__.Computer object at 0x000001A543EF4850> <__main__.CPU object at 0x000001A54423FF40> <__main__.Disk object at 0x000001A54423F3D0> print(computer2,computer2.cpu,computer2.disk) # <__main__.Computer object at 0x000001A5442928F0> <__main__.CPU object at 0x000001A54423FF40> <__main__.Disk object at 0x000001A54423F3D0> print('---------------------------') # 深拷贝 computer3 = copy.deepcopy(computer) print(computer,computer.cpu,computer.disk) print(computer3,computer.cpu,computer3.disk) # 打印的内存地址各不同,computer、cpu、disk都拷贝了一份,内存地址变化了 # <__main__.Computer object at 0x00000265D67B3E80> <__main__.CPU object at 0x00000265D67B3FD0> <__main__.Disk object at 0x00000265D67B3EB0> # <__main__.C
深拷贝
多态对于:动态语言关注对象的行为
静态语言:继承、方法重写、父类引用指向子类对象
模块
英文为Modules
一个模块可以包含N多个函数
在Pyhton中一个扩展名.py的文件就是一个模块
使用模块的好处
方便其它程序和脚本的导入并使用
避免函数名和变量名冲突
提高代码的可维护性
提高代码的可重用性
自定义模块
创建模块
新建一个.py文件,名称尽量不要与Python的自带的标准名称相同
导入模块
import 模块 [as 别名]
from 模块名称 import 函数/变量/类
import math # 导入数学模块 每一个模块都有id、type以及它的值组成 print(id(math)) print(type(math)) print(math) print(math.pi) # 3.141592653589793 #2051647076960 #<class 'module'> #<module 'math' (built-in)> print(dir(math)) from math import pi print(pi) # 这是能直接输出的 print(pow(2,3)) # 如果不导入math,只导入from math import pi 是不能使用的
以主程序形式运行
在每个模块的定义中都包括一个记录模块名称的变量_ name _,程序可以检查该变量,以确定它们在哪个模块中执行,如果一个模块不是被导入到其它程序中执行,那么它可能在解释器的顶级模块中执行。顶级模块的 _ name _变量的值为 _main _
# 开发时间:2023/2/11 def add(a,b): return a+b if __name__ == '__main__': print(add(10,20)) # 只有当运行这个calc2的时候才会执行这个主程序语句,可防止其它程序调用此类运行这个
Python中的包
Python中的包
包是一个分层次的目录结构,它将一组功能相近的模块组织在一起(包中包含N多个模块)
作用:
代码规范
避免模块名称冲突
包与目录的区别
创建之后默认包含__ init __ .py文件的目录称为包
目录里通常不包含_init _ .py文件
包的导入
import 包名.模块名(import只能导入包名、模块名)
用from 能导入包、模块、函数名、变量名 pageage1.module_A import ma
比如
创建python软件包
在下面新建pageage1,下面创建2模块-module_A.py/moduleB.py
在外面创建demo.py
import pageage1.module_A as ma # 现在就可以使用pageage1.module_A的内容了(别名叫ma)
Python中常用的内置模块
模块名 描述
sys 与Python解释器及其环境操作相关的标准库
time 提供与时间相关的各种函数的标准库
os 提供了访问操作系统服务功能的标准库
calendar 提供与日期现相关的各种函数的标准库
urllib 用于读取来自网上(服务器)的数据标准库
json 用于使用序列号和反序列化对象
re 用于在字符串中执行正则表达式匹配和替换
math 提供标准算术运算函数的标准库
decimal 用于进行准确控制精度、有效位数和四舍五入的十进制运算
logging 提供灵活的记录事件、错误、警告和调试信息等日志信息的功能
简单的代码实现
import sys import time import urllib.request import math # getsizeof是获取占用字节数 print(sys.getsizeof(20)) # 28 print(sys.getsizeof(21)) # 28 print(sys.getsizeof(True)) # 28 print(sys.getsizeof(False)) # 24 print(time.time()) # 对应秒数 1676127718.0125294 print(time.localtime(time.time())) # 将秒转成本地时间time.struct_time(tm_year=2023, tm_mon=2, tm_mday=11, tm_hour=23, tm_min=1, tm_sec=58, tm_wday=5, tm_yday=42, tm_isdst=0) print(urllib.request.urlopen('http://ww.baidu.com').read()) print(math.pi)
第三方模块
Python如此强大,离不开第三方模块
第三方模块的安装
pip install 模块名(在线安装方式-cmd安装-也是使用最多的方式)
第三方模块的使用
import 模块名(安装导入之后我们就可以使用)
在cmd窗口,我们可以输入python进入python交互模式
此时import使用已经安装的模块如果能使用证明安装成功
编码格式
编码格式介绍
文件的读写原理
文件读写操作
文件对象常用的方法
with语句(上下文管理器)
目录操作
常见的字符编码格式
Python的解释器使用的是Jnicode(内存)
py文件在磁盘上使用UTF-8存储(外存)
py默认是UTF-8,它是变长编码,1-4个字节表示1个字符,英文1个字节,汉字3个字节
文件读写原理
读写俗称IO操作-先进先出,如管道一般
文件到内存称为读,内存到文件称为写
读写之后需要关闭资源
文件读写操作
内置函数open()创建文件对象
语法规则:file = open(filename,[,mode,encoding])
file 是被创建的文件对象,open是创建文件对象的函数,
filename:是要创建或打开的文件名称,
mode:打开模式为只读模式
file = open('a.txt','r') # 读,中括号是可选,写不写都行 print(file.readlines()) # readlines读取的是一个列表 file.close()
encoding:默认文本文件中字符的编写格式为gbk(所以我们在编译器中常见一打开乱码,并提示reload gbk)
常用的文件打开模式
文件的类型
按文件中数据的组织形式,文件分为以下两大类
文本文件:存储的是普通“字符"文本,默认为unicode:字符集,可以使用记本事程序打开
二进制文件:把数据内容用“字节”进行存储,无法用记事本打开,必须使用专用的软件打开,举例:mp3音频文件,jpg图片.doc文档等
打开模式 描述
r(read only) 以只读模式打开文件,文件的指针将会放在文件的开头
w(write only) 以只写模式打开文件,如果文件不存在则创建,如果文件存在,则覆盖原有内容,文件指针在文件的开头
a 以追加模式打开文件,如果文件不存在则创建,文件指针在文件开头,如果文件存在,则在文件末尾追加内容,文件指针在原文件末尾
b 以二进制方式打开文件,不能单独使用,需要与共它模式一起使用,rb,或者wb
+ 以读写方式打开文件,不能单独使用,需要与其它模式一起使用,a+
文件对象的常用方法
方法名 说明
read([size]) 从文件中读取size个字节或字符的内容返回。若省略[size],则读取到文件末尾,即一次读取文件所有内容
readline() 从文本文件中读取一行内容
readlines() 文本文件中的每一行都作为单独的字符串对象,并将这些对象返回到列表中返回
write(str) 将字符串str内容写入文件
writelines(s_list) 将字符串列表s_lst写入文本文件,不添加换行符
seek(offset[,whence]) 把文件指针移动到新的位置,offset表示相对于hencel的位置:offset:为正往结束方向移动,为负往开始方向移动whence(从何处)不同的值代表不同含义:0:从文件头开始计算(默认值)1:从当前位置开始计算2:从文件尾开始计算
tell() 返回文件指针的当前位置,第一个字母是0,也就是从0开始
flush() 把缓冲区的内容写入文件,但不关闭文件
close() 把缓冲区的内容写入文件,同时关闭文件,释放文件对象相关资源-close()之后就不能写内容了,flush之后能close
file = open('a.txt','r') file = seek(2) # a.txt有中国两字。一个字占取2字节(gbk),从国开始读(如果在pyCharm中写的txt,可能就是utf-8了,不是2字节) print(file.read()) # 国 # tell print(file.tell()) # 会把当前所有内容打印出,指向最后一个位置。如seek(2)跳过了2,如果打印hello的话只会出现llo
with语句
with语句可以自动管理上下文资源,不论什么原因跳出with块,都能确保文件正确的关闭,以此来达到释放资源的目的
写文件时建议使用with语句形式
上下文为表达式,结果为上下文管理器
实现了__ enter__ () 方法和 __ exit()__方法 称为这个类遵守上下文管理协议,这个类的实例对象称为上下文管理器
图描述如下:
# open('logo.png','rb') with之后as之前为上下文表达式,结果为上下文管理器-->同时创建一个运行时上下文-->自动调用_enter_()方法,并将返回值赋值给src_file with open('logo.png','rb') as src_file: # as src_file:可选项上下文管理器对象的引用[可选项] src_file.read() # with语句体 # 离开运行时上下文,自动调用上下文管理器的特殊方法_exit_() with open('a.txt','r') as file: print(file.read()) # 不用再手动close关闭了,因为离开with语句时会自动释放资源 # 开发时间:2023/2/12 # MyContentMgr实现了特殊方法__enter__(),__exit__()称为该类对象遵守了上下文管理器协议,该类对象的实例对象,称为上下文管理器 class MyContentMgr(object): def __enter__(self): print('enter方法被调用执行了') return self def __exit__(self, exc_type, exc_val, exc_tb): print('exit方法被调用执行了') # print('show方法被调用执行了',1/0) 即使产生异常也会调用exit方法,称为自动关闭资源 def show(self): # 实例Method print('show方法被调用执行了') # MyContentMgr这个类遵守上下文管理协议,它的对象就称为上下文管理器,把这个对象赋给file去存储 # 相当于file = MyContentMgr(),这时候就可以通过file调用它的方法 # with里面的所有缩进都称为with语句体 with MyContentMgr() as file: # 这个with语句体执行之后就会自动跳出上下文管理器,调用exit方法 file.show() # exit方法被调用执行了
目录操作
os模块是Python内置的与操作系统功能和文件系统相关的模块
该模块中的语句的执行结果通常与操作系统有关,在不同的操作系统上运行,得到的结果可能不一样。
os模块与os.path模块用于对目录或文件进行操作
既然是和os有关的,那么可以调用os有关的文件
不需要安装,它是自带的模块
os模块操作目录相关函数
函数 说明
getcwd() 返回当前的工作目录(文件目录)
listdir(path) 返回指定路径下的文件和目录信息
mkdir(path[,mode]) 创建目录
makedirs(path1/path2...[,mode]) 创建多级目录
rmdir(path) 删除目录
removedirs(path1/path2......) 删除多级目录
chidr(path) 将path设置为当前工作目录
import os # 调用记事本 # os.system('notepad.exe') # 直接调用可执行文件 # os.startfile('C:\\Users\\79382\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe')
os.path模块操作目录
import 导入os.path
函数 说明
abspath(path) 用于获取文件或目录的绝对路径
exists(path) 用于判断文件或目录是否存在,如果存在返回True,否则返回False
join(path,name) 将目录与目录或者文件名拼接起来
splitext() 分离文件名和扩展名
basename(path) 从一个目录中提取文件名
dirname(path) 从一个路径中提取文件路径,不包括文件名
isdir(path) 用于判断是否为路径
import os.path print(os.path.abspath('demo13.py')) # F:\pythonProject1\venv\Scripts\demo13.py print(os.path.exists('demo13.py')) # False print(os.path.join('E:\\Python','demo13.py')) # E:\Python\demo13.py print(os.path.split('E:\\vipython\\chap15\\demo13.py')) # ('E:\\vipython\\chap15', 'demo13.py') print(os.path.splitext('demo13.py')) # ('demo13', '.py') print(os.path.basename('E:\\vippython\\chap15\\demo13.py')) # demo13.py print(os.path.dirname('E:\\vippython\\chap15\\demo13.py')) # E:\vippython\chap15 print(os.path.isdir('E:\\vippython\\chap15\\demo13.py')) # False 因为demo13.py是文件 获取当前目录下的指定文件 import os path = os.getcwd() # 获取当前目录下的所有文件 lst = os.listdir(path) for filename in lst: # 获取所有以py结尾的文件 if filename.endswith('.py'): print(filename) 获取当前目录下的指定文件(包括子目录) import os path = os.getcwd() # os.walk()可以遍历指定目录下所有的文件 lst_files = os.walk(path) print(lst_files) # 获取的是一个对象 # 这个迭代器对象返回来的是一个元组 for dirpath,dirname,filename in lst_files: ''' print(dirpath) print(dirname) print(filename) print('------------') ''' for dir in dirname: print(os.path.join(dirpath,dir)) for file in filename: print(os.path.join(dirpath),file) print('------------------------------')