一.文件操作
1.基础知识
(1)分类:二进制文件和文本文件:
二进制文件和文本文件在磁盘上的存储没有本质区别,区别在于:前者存原始 01 机器码,可以保存任意数据(图片、视频、程序、压缩包、Excel、exe),用记事本打开全是乱码;后者只存可阅读字符(字母、数字、汉字、标点),按字符编码(UTF-8、GBK)存储,人能直接看懂
(2). 文件路径:分为绝对路径和相对路径
绝对路径在不同的操作系统下不同,windows 以根目录开始(盘符号),mac 目录第一级就是/ (绝对路径兼容性差)
windows_absolutePath = 'C:/Users/moonbit/Desktop/projects/pythonbase/test/hello.txt'
mac_absolutePath = '/projects/pythonbase/test/hello.txt'
I.路径拼接:
from pathlib import Path
import os
filePath = Path("test") / "hello.txt" #多变量拼接方法1
filePath = os.path.join('test', 'hello.txt) #多变量拼接方法2
II.几个操作
1.一个程序的文件路径运行时拿到的都是绝对路径
2.cd..可切换成上一级目录
3._ file _可以拿到当前文件的绝对路径(如果split一下,再pop一下当前文件,再join一下,就可以得到工作目录),或者用
Path(__file__).parent
relativePath = 'test/hello.txt'
absolutePath = Path(__file__).parent / relativePath
4.写文件路径的时候用斜杆就行,python会自动转,
5. .代表当前目录 ..代表上一层目录,../../代表上上层
6.os.getcwd()可以打印出程序的启动目录
2.文本文件
from pathlib import Path
dataDirAbsolutePath = Path(__file__).parent / 'data'
readTxtFilePath = dataDirAbsolutePath / 'read.txt'
文本读取格式:
file = open(readTxtFilePath, 'r',encoding = 'utf8')
content1 = file.read() #第一种方式:一次性把所有内容都读到内存里面,一般不使用,占取内存过大
[while True:
content = file.readline()
print(content)
if content == "":
break ] #可以这样读取每一行
content2 = file.readline() #第二种方式:只读一行
content3 = file.readlines() #第三种方式:读取每一行并返回一个List
for line in content3:
print(line)
print(content)
['r'是文本方式,'r+b'是二进制方式]
[一个字节为8个二进制数,最大表示255]
2.二进制文件
from pathlib import Path
dataDirAbsolutePath = Path(__file__).parent / 'data'
readTxtFilePath = dataDirAbsolutePath / 'read.txt'
格式:
file = open(readTxtFilePath, 'r+b')
content = file.read()
print(content) #会打印出字节流(可以转成List)
print(list(content)) #会打印出一个list,为十进制数(bytes转成list 可以直接list(bytes) )
[关于base64:不是加密,且体积会变大]
b = b'hello' #byte变字符串
s = b.decode('utf-8') # 'hello'
s = 'hello'
b = s.encode('utf-8') # b'hello' #字符串变byte
b = b'hello' #byte变list
lst = list(b) # [104, 101, 108, 108, 111]
lst = [104, 101, 108, 108, 111] #list变byte
b = bytes(lst) # b'hello'
file = open(filepath, 'a',encoding='utf-8')
content = input("请输入今天的日记:") # 获取用户输入的日记内容
file.write(content) # 将日记内容写入文件
file.close() # 关闭文件
with open(filepath, 'r+b') as src: #等价src = open(filepath,'r+b')
content = src.read() #会自动close文件,建议以后都是用with打开
dstFile = dataDirAbsolutePath / 'data' / 'hello.txt'
srcFile = dataDirAbsolutePath / 'test' / 'hello.txt'
with open(srcFile, 'r+b') as src, open(dstFile, 'w+b') as dst:
dst.write(src.read()) #固定路径复制
import sys
dataDirAbsolutePath = Path(__file__).parent # 获取当前脚本所在目录
dstFile = dataDirAbsolutePath / sys.argv[2]
srcFile = dataDirAbsolutePath / sys.argv[1] #从命令行参数获取源文件、目标文件路径
with open(srcFile, 'r+b') as src, open(dstFile, 'w+b') as dst:
dst.write(src.read()) # 二进制方式复制文件
from pathlib import Path
import sys dataDir = Path(__file__).parent
srcFile = dataDir / sys.argv[1]
dstFile = dataDir / sys.argv[2]
size = 4096 # 分块复制大文件
with open(srcFile, "rb") as src, open(dstFile, "wb") as dst:
while True:
chunk = src.read(size)
if not chunk:
break
dst.write(chunk)
json表现形式就是字符串
方法 方向 输入 → 输出
json.dump() Python → 文件 对象 + 文件 → 写入文件(返回 None)
json.dumps() Python → 字符串 对象 → JSON 字符串
json.load() 文件 → Python 文件 → 对象
json.loads() 字符串 → Python JSON 字符串 → 对象
jsonDictStr = '{'name':'zjw','age':18}'
jsonStr1Str = ' "hello world"'
jsonbool ='true'
dict2 = '{"name": "{\\"first\\": \\"pjw\\", \\"last\\": \\"li\\"}", "age": 10}'它不是字典,是一长串 json 格式的字符串。
python转yaml
import yaml
data = { "name": "张三", "age": 18, "hobby": ["读书", "跑步"], "student": True, "info": None }
yaml_str = yaml.dump(data, allow_unicode=True) #allow_unicode 支持中文 print(yaml_str)
yaml转python
yaml_str = """ name: 张三 age: 18 hobby: - 读书 - 跑步 student: true info: null """
data = yaml.safe_load(yaml_str)
print(data)
from pathlib import Path
baseDir = Path(__file__).parent
goodInfoFile = baseDir / "data/goodinfo.txt"
price = 0
with open(goodInfoFile, "r", encoding="utf-8") as f:
for line in f.readlines():
listInfo = line.strip('\n').split(' ')
price += int(listInfo[2])
print(price)
goodList = []
with open(goodInfoFile, "r", encoding="utf-8") as f:
for line in f.readlines():
listInfo = line.strip('\n').split(' ')
goodList.append(
{'商品名称':listInfo[0],
'单价':int(listInfo[1]),
'数量':int(listInfo[2]),}
)
prinf(goodList)
[默认用,分割]
import csv
baseDir = Path(__file__).parent
goodInfoFile = baseDir / "data/goodinfo.txt"
price = 0
with open('data.csv', 'r', encoding='utf-8') as f:
reader = csv.reader(f)
for row in reader:
price += int(row["价格"]) #以字典读出来
print(price)
with open('data.csv', 'r', encoding='utf-8') as f:
reader = csv.reader(f)
for row in reader:
print(row) #把每一行以List读出来
with open('data.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
+print(row) #读出字典
二.函数
1.函数定义
def demo_function(pos1, pos2, default_arg="默认值", *args, named_default="命名默认值", **kwargs):
Args:
pos1: 位置参数1
pos2: 位置参数2
default_arg: 带缺省值的参数(可选)
*args: 动态位置参数(可变长度,以元组形式接收)
named_default: 带默认值的命名参数(必须使用关键字传递)
**kwargs: 动态关键字参数(可变长度,以字典形式接收)
"""
写函数的时候在args之后的形参一般为命名参数,这样在写实参的时候就不会被args干扰
2.函数名的本质(理解为变量名,变量能干什么,它就能干什么)
def greet():
return "Hello, World!"
greeting = greet
print(greeting()) #output:Hello,World!
def greet(pos):
return f"Hello, {pos}!"
list1 = [greet, greet, greet]
print(list1[0]("moonbit")) #output:Hello,moonbit!
def greet(pos):
return f"Hello, {pos}!"
list1 = [greet, greet, greet]
def execFn(fn):
return fn("World")
str1 = execFn(greet)
print(str1) #output: Hello,world!
def execFn(dictFn):
dictFn['success']({"name": "john"}) #取出字典里 key 为 success 对应的那个函数,再传了一个字典当参数
dictFn['error']({"error": "网络错误"})
def printSuccess(data):
print(data)
dictRealParam = {
'success': printSuccess,
'error': printSuccess,
}
execFn(dictRealParam) #output:{"name": "john"}
{"error": "网络错误"}
#这样也能做到和上面相同的效果
def execFn(dictFn):
dictFn['success']({"name": "john"})
dictFn['error']({"error": "网络错误"})
dictRealParam = {
'success': print
'error': print
}
execFn(dictRealParam)
def execFn():
def innerFn(a):
print(a)
return innerFn
execFn()('hellworld') #output: helloworld
3.闭包
(1)闭包定义
内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数
def func():
name = "john"
def inner():
print(name)
return inner
f = func()
f() #output:john
[易错点]
funcs = []
for i in range(3):
def func():
return i
funcs.append(func)
for f in funcs:
print(f()) #output:2 2 2
第一步:循环创建 3 个函数(注意:这 3 个函数里的return i 都没执行,它们只是记住了 “我要返回 i 这个变量”)。第二步:循环结束后,i 最终变成了 2。第三步:调用函数,现在跑 3 个函数,每个函数都去拿当前的 i
[这样就可以打印出012了]
funcs = []
for i in range(3):
def func(a=i):
return a
funcs.append(func)
for f in funcs:
print(f()) #ouotput: 0 1 2
(2)闭包函数的判断
def func():
name = 'EaglesLab'
def inner():
print(name)
return inner
f = func()
print(f.__closure__) # 如果打印出的内容非空,说明该函数是闭包函数
4.命名空间
- 内置命名空间(Built-in):Python 启动时加载,包含 print、len、range 等
- 全局命名空间(Global)
- 局部命名空间 (Local)
- 闭包命名空间(Enclosing)
5. 作用域
(1)作用域定义了变量的可访问性或可见性。它决定了在程序的某一部分可以访问哪些变量。
LEGB 规则(由内到外)
| 层级 | 名称 | 说明 | 示例 |
|---|---|---|---|
| L | Local | 函数内部 | 函数内的变量 |
| E | Enclosed | 外层嵌套函数 | 闭包中的变量 |
| G | Global | 模块全局 | 模块顶层的量 |
| B | Built-in | 内置作用域 | print/len |
(2)示例
x = "global" # G: 全局作用域
def outer():
y = "enclosing" # E: 闭包作用域
def inner():
z = "local" # L: 局部作用域
print(z) # 先找 L
print(y) # L 没有,找 E
print(x) # L/E 没有,找 G
print(len) # L/E/G 没有,找 B
return inner
func = outer()
func()
6. 装饰器
示例1
def func1():
print("in func1")
def func2(func):
def inner():
print("hello world")
func()
print("hello python")
return inner
func1 = func2(func1)
func1() #output:hello world
in func1
hello python
示例2
from socket import IP_PKTINFO
import time
def timer(func):
def inner(a):
start = time.time()
func(a)
print(time.time() - start)
return inner
@timer
def func1(info):
time.sleep(1)
print(info)
func1(1232323) #output:1232323
1.000779628753662
#这个装饰器的作用:给函数加一个“计时功能”,不修改原函数代码;
@timer等价于func1 = timer(func1) func1(1232323)