python learning day 3

6 阅读7分钟

一.文件操作

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.命名空间

  1. 内置命名空间(Built-in):Python 启动时加载,包含 print、len、range 等
  2. 全局命名空间(Global)
  3. 局部命名空间 (Local)
  4. 闭包命名空间(Enclosing)

5. 作用域

(1)作用域定义了变量的可访问性或可见性。它决定了在程序的某一部分可以访问哪些变量。

LEGB 规则(由内到外)

层级名称说明示例
LLocal函数内部函数内的变量
EEnclosed外层嵌套函数闭包中的变量
GGlobal模块全局模块顶层的量
BBuilt-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)