2025-09-10:仓库迁移

This commit is contained in:
2025-09-10 16:12:45 +08:00
parent e0e49b0ac9
commit 3130e336a1
146 changed files with 4066 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
# 普通的序列分解方式
def normal_func(list):
# list是可迭代对象能够直接分解成多个元素
length = list.__len__()
length= 2
x, y = list
# 如果list长度和接数据的元素数量不匹配会造成错误
x, y, z = list
# 在知道元素顺序的情况下想要丢弃list中的某些元素可以用下划线来无视变量
_ ,y = list

View File

@@ -0,0 +1,25 @@
# 如果序列中存储的元素是可哈希的,那就可以使用集合与生成器解决
def dequpe(items):
seen = set()
for item in items:
if item not in seen:
yield item
seen.add(item)
# 如果序列里的元素是不可哈希的,比如字典这种东西,就要先转化为可哈希对象;
# 这里自定义的key函数就起到了给字典解包的作用
def dequpe(items, key):
seen = set()
for item in items:
val = item if key is None else key(item)
if val not in seen:
yield item
seen.add(val)
# 如果单纯的做不改变顺序的去重,直接转集合再转列表就行了
a = [1,5,2,1,9,1,5,10]
a = list(set(a))
print(a)

View File

@@ -0,0 +1,18 @@
items = [0,1,2,3,4,5,6]
# 我们可以使用内置的slice函数对切片进行命名,参数分别为start|stop|step
a = slice(2,6,2)
print(items[a])
print(a.start, a.stop, a.step)
# indeces方法可以帮我们把start和stop自动限制在序列长度内,并返回一个限制后的切片
s = "sukahelloworld"
# 上面那个可能看着不明显,但是下面这个看着就明显多了
# s = "suka"
print(a.indices(len(s)))
# 因为返回的是元组,所以要使用得先解包
for i in range(*a.indices(len(s))):
print(s[i])

View File

@@ -0,0 +1,24 @@
words = ["look", "into", "my", "eyes", "look", "into", "my", "eyes",
"the", "eyes", "the", "eyes", "the", "eyes", "not", "around", "the",
"eyes", "don't", "look", "around", "the", "eyes", "look", "into",
"my", "eyes", "you're", "under"]
# collect里面的Counter库可以帮我们计数
from collections import Counter
word_counts = Counter(words)
top_three = word_counts.most_common(3)
print(top_three)
# Counter的底层是一个字典,是一个DefaultDict,这里处于学习目的把它实现一遍
from collections import defaultdict
def counter(word_list):
counter = defaultdict(int)
for word in word_list:
counter[word] += 1
return counter
print(counter(words))

View File

@@ -0,0 +1,25 @@
# 我们有一个字典列表,想要按照字典里的某些键对列表进行排序
# 字典列表如下:
rows = [
{"fname":"Brian", "lname": "Jones", "uid":1003},
{"fname":"David", "lname": "Beazley", "uid":1002},
{"fname":"John", "lname": "Cleese", "uid":1001},
{"fname":"Big", "lname": "Jones", "uid":1004}
]
# 这时候用到itemgetter模块
from operator import itemgetter
# itemgetter的主要功能是通过可查询的标记进行数据获取;
# 下面分别根据fname和uid进行数据获取
rows_by_fname = sorted(rows, key=itemgetter("fname"))
rows_by_uid = sorted(rows, key=itemgetter("uid"))
print(rows_by_fname)
print(rows_by_uid)
# 当然itemgetter也能被lambda函数替代替代操作如下
rows_by_fname_v2 = sorted(rows, key= lambda row: row["fname"])
print(rows_by_fname_v2)

View File

@@ -0,0 +1,32 @@
# 众所周知对class这种原生不支持比较的对象直接进行比较会造成暴毙
# 我们但如果非比不可呢?比如这个东西:
class User:
def __init__(self,user_id):
self.user_id = user_id
def __repr__(self):
return "User({})".format(self.user_id)
# 这里有一个列表user
user = [User(23), User(3), User(99)]
# 如果这时候需要按照某个属性给这个列表排序那么直接sorted会报错
try:
sorted(user)
pass
except:
print("你看吧,报错了")
# 这里的原因是对象不能直接进行比较,所以想要排序只能按照对象里的某个属性
# 有两种解决方案:
sorted_list = sorted(user, key=lambda x: x.user_id)
print(sorted_list)
# 要么就用operator库里的attrgetter
from operator import attrgetter
sorted_list = sorted(user, key=attrgetter("user_id"))
print(sorted_list)
# 用这东西的好处和针对字典的itemgetter一样可以取多个字段
# sorted_list = sorted(user, key=attrgetter("user_id", "word_2", "word_3", ...))
# 同样的max和min这种有key参数的内建函数都能用这些东西折腾

View File

@@ -0,0 +1,39 @@
# 假如我们有一个记录需要进行分组
rows = [
{"address": "5412 N CLARK", "date": "07/01/2012"},
{"address": "5148 N CLARK", "date": "07/04/2012"},
{"address": "5800 E 58TH", "date": "07/02/2012"},
{"address": "2122 N CLARK", "date": "07/03/2012"},
{"address": "5645 N RAVENSWOOD", "date": "07/02/2012"},
{"address": "1060 W ADDISON", "date": "07/02/2012"},
{"address": "4801 N BROADWAY", "date": "07/01/2012"},
{"address": "1039 W GRANVILLE", "date": "07/04/2012"},
]
# 如果我们想按日期进行分组那itertools里的groupby会很好用
from operator import itemgetter
from itertools import groupby
# 因为groupby只能检查连续的项所以我们先对列表进行排序
rows.sort(key=itemgetter("date"))
print(rows)
# 然后我们进行分组操作:
for date, items in groupby(rows, itemgetter("date")):
print(date)
for i in items:
print(' ', i)
# groupby每次返回的是一个值分组名称和一个子迭代器组内数据
# 当然如果是单纯的分组,一键多值字典是个好东西
from collections import defaultdict
data = defaultdict(list)
for item in rows:
data[item["date"]].append(item)
print(data)
# 在不考虑内存开销的情况下这东西比先排序再groupby快

View File

@@ -0,0 +1,71 @@
# 比如我有一个列表
mylist = [1,4,-5,10,-7,2,3,-1]
# 最脑瘫的方法就是用列表推导式重新生成一遍
filted_list_b0 = [x for x in mylist if x > 0]
filted_list_s0 = [x for x in mylist if x < 0]
# print(filted_list_b0)
# 当然如果列表很大这样做会裂开因为列表推导式本质上是遍历会建立一份mylist的复制
# 这个时候我们可以用生成器的方式表达解析结果以节省内存
filted_list_b0 = (x for x in mylist if x > 0)
# for i in filted_list_b0:
# print(i)
# 当然有的列表比较抽象:
mylist_suka = ['1', '2', '-3', '-', '4', 'N\A', '5']
# 这个时候我们可以先写逻辑进行过滤:
def drop_suka(val):
try:
x = int(val)
return True
except ValueError:
return False
# 然后我们用内建的filter函数进行过滤
# 第一个位置是一个值判断布尔函数,第二个参数是要过滤的列表,布尔函数里写过滤逻辑;
# filter返回一个迭代器所以可以直接用list方法转成列表
my_nonsuka_list = list(filter(drop_suka, mylist_suka))
# print(my_nonsuka_list)
# 列表推导式和生成器推导式都可以在值的位置进行:
# 1.计算 x*2
# 2.三元判断 x*2 if x < 1 else x
filted_list_b0 = [x*2 if x < 1 else x for x in mylist if x > 0]
filted_list_b0 = (x*2 if x < 1 else x for x in mylist if x > 0)
# 如果要筛选的元素在另一个列表里怎么办?比如我们有:
rows = [
"5412 N CLARK",
"5148 N CLARK",
"5800 E 58TH",
"2122 N CLARK",
"5645 N RAVENSWOOD",
"1060 W ADDISON",
"4801 N BROADWAY",
"1039 W GRANVILLE",
]
counts = [0,3,10,4,1,7,6,1]
# counts表示rows里面对应元素出现的次数如果我们想找count>5的元素咋整
# 1.搞一个布尔列表,告诉程序谁才是我们要的
wanted = [n > 5 for n in counts] # 这和[n for n in counts if n > 5]不一样,之前是在for的同时筛选,现在是for完看看是否符合n>5
# print(wanted)
# 2.用itertools的compress函数来进行对比
from itertools import compress
# itertools里的compress函数输入一个列表和一个布尔列表,返回一个迭代器,里面是列表中同样位置在布尔列表里为True的元素
result = list(compress(rows, wanted))
print(result)

View File

@@ -0,0 +1,19 @@
# 假如我们有一个字典,需要提取子集:
price = {
"ACME": 45.23,
"AAPL": 612.78,
"IBM": 205.55,
"HPQ": 37.2,
"FB": 10.75
}
# 直接用字典推导式
p1 = {key :value for key, value in price.items() if value > 200}
# 提取key也是
keys = {"AAPL", "IBM", "HPQ", "MSFT"}
p2 = {key : value for key, value in price.items() if key in keys}
# 字典推导式是最快的方法,比下面两个办法都快:
dict((key, value) for key, value in price if value > 100) # 快两倍
{key:price[key] for key in price.keys() if key in price.keys() & keys} # 快1.6倍

View File

@@ -0,0 +1,37 @@
# collection库中有一个东西叫做namedtuple,有点像结构体,可以给元组中的元素起名
from collections import namedtuple
Subscribe = namedtuple('Subscriber', ["addr", "joined"])
sub = Subscribe("suka@qq.com", "2024/07/17")
print(sub)
print(sub.addr)
print(sub.joined)
# 可以看到,这个东西和对象有点相似,但这种操作又保留了适用于元组的所有操作,比如索引和分解
print(sub[0])
print(len(sub))
addr, joined = sub
print(addr, joined)
# 如果我们获取的数据总是list类型,不是标准的json数据,那这东西就很有用
# 比如返回的数据是这种东西: data = [0,1,1,3,2,6]
# 如果是这种非标数据,普通代码处理长这样:
def compute_cost(records):
total = 0.0
for rec in records:
total += rec[1] * rec[2]
return total
# 这造成一个问题,鬼知道rec[1]和rec[2]是什么东西,代码可读性很傻逼;
# 所以我们可以在拿到数据的时候先标准化一下
Stock = namedtuple("Stock", ['name', 'share', 'price'])
def compute_cost(records):
total = 0.0
for rec in records:
stock = Stock(*rec)
total += stock.share * stock.price
return total
# 当然如果返回的已经是对象了,那就没有做namedtuple的必要了,在不想用类的时候可以用这东西替代字典

View File

@@ -0,0 +1,30 @@
# 这是一种简化操作,可以将转换和换算合为一体,比如我们有一个列表
nums = [1,2,3,4,5]
# 计算平方和我们一般这样子做:
nums_square = [x*x for x in nums]
s = sum(nums_square)
# 这个时候我们就可以这样来简化一下运算:
s = sum(x*x for x in nums)
# 又或者我们要在一堆参数中间加一些分隔符:
# 注意,这里的join和os.path.join不一样,这里是用来给jion输入的列表加分隔符的
s = ("ACME", 50, 123.45)
print(','.join(str(x) for x in s))
# 这里我们将生成器表达式从()里薅出来,当作可迭代参数塞进了函数里,这样避免了列表生成器造成的内存浪费
# 对单个字典内,我们用键值反转的方法来找元素,但是如果这是一个字典列表,那情况就大大不同了
portfolio = [
{'name': 'GOOG', 'shares': 50},
{'name': 'YHOO', 'shares': 75},
{'name': 'AOL', 'shares': 20},
{'name': 'SCOX', 'shares': 65}
]
max_share = max(portfolio, key=lambda x: x["shares"])
print(max_share)
# 当然如果仅仅只要拿到最小值就用到了生成器表达式内嵌的方法
max_share_num = max(s['shares'] for s in portfolio)
print(max_share_num)

View File

@@ -0,0 +1,36 @@
# 可迭代对象分解
def iterable_breakdown(list):
# 如果可迭代对象长度大于接数据的变量数量,分解值过多报错
length = list.__len__()
length = 20
# 这样会报错因为list长度是20但分解变量只有两个
x, y = list
# 想要接住任意长度的列表,需要用*
# *x是包含list前n-1个元素的列表y是最后一个元素
# 我们可以在任意位置接入带*的参数来接住一些值,这些值会在*变量中以列表存储
*x, y = list
x, *y, z = list
# 假设有一个变长元组序列
record = [("foo",1,2),("bar","suka"),("foo",2,4)]
def do_foo(x,y):
print(x,y)
def do_bar(s):
print(s)
# 我们可以使用*来解包从而将参数薅出来
for tag, *args in record:
if tag == "foo":
do_foo(*args)
elif tag == "bar":
do_bar(*args)
# 同理,也可以用*变量来占位挖掉不要的变量,比如在特定位置用*ignore或*_来挖掉参数

View File

@@ -0,0 +1,57 @@
# 假如又两个字典:
a = {"x":1, "z":3}
b = {"y":2, "z":4}
# 怎么将这两个字典映射到一个新字典里呢?愚蠢的办法是使用字典合并
# 这个方法会把右边的b刷写到a里
c = a|b
print(c)
# 但是,你会发现,如果原字典被改了,那c不会有变化:
a["x"] = 2
print(c)
# 这个时候使用映射方案的chainmap就会很好用
from collections import ChainMap
c = ChainMap(a,b)
print(",".join(str(x) for x in [c['x'], c['y'], c['z']]))
print(len(c))
# 如果此时更改原字典的值:
a["x"] = 1
# 输出也跟着更改了
print(",".join(str(x) for x in [c['x'], c['y'], c['z']]))
print(len(c))
# 注,chainmap中如果有重复的键,则会采用左值,比如上面的例子使用a["z"]作为重复键z的取值;
# 如果修改字典值,也会作用在左值上
del c["z"]
print(",".join(str(x) for x in [c['x'], c['y'], c['z']]))
print(a, b)
# 如果尝试删除a里已经没有但b里有的键,那么会报错
try:
del c["z"]
except:
print("在a里没找到键")
# 这东西的底层其实是一个链表,演示如下:
dic = ChainMap()
dic["x"] = 1
dic = dic.new_child()
print(dic)
dic["x"] = 2
dic = dic.new_child()
print(dic)
dic["x"] = 3
print(dic)
# 从这里我们开始回溯历史
dic = dic.parents
print(dic)
dic = dic.parents
print(dic)
dic = dic.parents
print(dic)
# 可以看到我们用new_child()函数创建了一个新节点用parents属性来回溯

View File

@@ -0,0 +1,19 @@
# 队列可以对最后N个元素进行保存
from collections import deque
# 从历史记录列表history得到length条最新历史记录
def latest_history(history, length):
window = deque(maxlen=length)
for record in history:
window.append(record)
# window引用双头队列组件deque,该组件有方法如下
# 从队尾加入
window.append(1)
# 从队尾弹出
window.pop()
# 从队头加入
window.appendleft(1)
# 从队头弹出
window.popleft()

View File

@@ -0,0 +1,33 @@
import heapq
# heapq里有两个函数nlargest和nsmallest可以找最大N个和最小N个
# 参数接受一个列表和一个N
def max_n(search_list, n):
list_max_n = heapq.nlargest(n ,search_list)
return list_max_n
def min_n(search_list, n):
list_min_n = heapq.nsmallest(n, search_list)
return list_min_n
# 这两个函数都提供了一个key输入来实现在字典列表中的应用
def max_in_dictlist(search_list, n, key):
max_key_n = heapq.nlargest(n, search_list, key=lambda dic : dic[key])
return max_key_n
# 如果寻找最大N个和最小N个元素这个方法在N的规模不大的时候好用
# 当日在N=1的时候还是用max和min方法更快要是N巨大那就得排序了
# heapq事实上是一个堆方法将列表在底层序列化为一个最小堆
def heapq_func():
ori_list = [1,2,3,4,5]
heap = list(ori_list)
# 将列表进行堆排序
heapq.heapify(heap)
# 弹出堆顶元素
heapq.heappop(heap)
if __name__ == '__main__':
l = [1,2,3,4,5]
print(max_n(l, 3))

View File

@@ -0,0 +1,43 @@
import heapq
# 优先级队列(使用小根堆实现)
class PriorityQueue:
def __init__(self):
self._queue = []
# 由于优先级在比较大小时可能相同造成比较失败维护一个下标index来进行二级辨识
self._index = 0
# 由于heapq的原理是生成一个小根堆所以优先级取负这样优先级越大堆识别到的优先级越小引入index在优先级相同时比较入栈先后顺序
def push(self, item, priority):
heapq.heappush(self._queue, (-priority, self._index, item))
self._index += 1
# 弹出堆顶值
def pop(self):
return heapq.heappop(self._queue)[-1]
# 在Python中实例化对象是不可以直接进行比较的例如
class Item:
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Item {!r}'.format(self.name)
# a = Iter('foo') b = Iter('bar'), 进行a<b比较会输出报错
# 一个优先级队列的简单调用示例
if __name__ == "__main__":
q = PriorityQueue()
q.push(Item("foo"), 1)
q.push(Item("bar"), 5)
q.push(Item("spam"), 4)
q.push(Item("grok"), 1)
a = q.pop()
b = q.pop()
c = q.pop()
d = q.pop()
print(a)

View File

@@ -0,0 +1,38 @@
from collections import defaultdict
# 当你新建一个普通字典对字典中不存在的key进行调用时会报错
a = {}
try:
print(a["key"])
pass
except:
print("err")
# 如果使用defaultdict进行字典初始化建立就不存在这个问题
# 当出现不存在的key的时候会根据默认设置进行默认值创建
b = defaultdict(list)
print(b["key"])
# 但是这样就有一个问题这个key就会一直在这里等待调用如果没有用到就是垃圾
print(b)
# 这个方法可以用于记录的添加;比如一个方法如下:
pairs = [{"a":10},{"b":10},{"b":10}]
d = {}
for key, value in pairs:
if key not in d:
d[key] = []
d[key].append(value)
# 很明显这样就显得很蠢,我还要判断一下键在不在里面
# 使用defaultdict就没有这个困扰直接省略一键添加
d = defaultdict(list)
for key, value in pairs:
d["key"].append(value)
# 当然为了避免生成空键,使用这东西的时候切记在里面翻东西的时候别直接用dict[key]输入;
# 先用keys函数拿到所有键再动手

View File

@@ -0,0 +1,20 @@
from collections import OrderedDict
# 如果需要严格控制字典元素的顺序,可以使用OrderedDict
# 比如用于网络通信协议的未序列化字典对象
d = OrderedDict()
d['foo'] = 1
d['bar'] = 2
d['spam'] = 3
d['grok'] = 4
for key in d:
print(d[key])
# 这样就可以序列化得到一个有序的json编码
import json
a = json.dumps(d)
print(a)
# 尤其注意:这东西内部有一个双向链表导致它的内存开支有点恐怖,大规模情况下谨慎使用

View File

@@ -0,0 +1,28 @@
price = {
"ACME": 45.23,
"AAPL": 612.78,
"IBM": 205.55,
"HPQ": 37.2,
"FB": 10.75
}
# 对这样的数据,有时候我们想找到最大值对应的键
# 传统方法长这样
a = max(price.values())
print(a)
for key, value in price.items():
if value == a:
print(key)
# 显然,我们要对字典里的这些东西进行遍历才能根据值把键找出来
# 如果我们不想要这样的开销,可以把键值反转:
max_price = max(zip(price.values(), price.keys()))
print(max_price)
# 注意,在对键值反转的zip中使用max和min这类函数时需要注意,如果出现:
# a = {10, "AA"}, b = {10, "ZZ"}的情况
# 由于值相同,会根据键大小返回结果
# 所以如果有多个值相同的字段,还得是老办法
max_price = [key for value, key in zip(price.values(), price.keys()) if value == a]
print(max_price)

View File

@@ -0,0 +1,33 @@
# 我们有两个字典如下:
a = {
"x":1,
"y":2,
"z":3
}
b = {
"w":10,
"x":11,
"y":12
}
# 如果想要得到相同处,只需要用keys和items这类可迭代方法执行集合操作就行
# 大家都有
print(a.keys() & b.keys())
# a有b没有
print(a.keys() - b.keys())
# b有a没有
print(b.keys() - a.keys())
# 想快速给a减键,可以这样:
c = {key:a[key] for key in a.keys() - {"w", "z"}}
print(c)
# python3.9更新了使用|的字典合并和与+=一样的合并运算符|=
d = a
d |= b
print(d)

View File

@@ -0,0 +1,20 @@
import time
def countdown(n):
while n > 0:
print("T-minus", n)
n -= 1
time.sleep(5)
def countdown2(n):
while n > 0:
print("T-minus", n)
n -= 1
time.sleep(6)
from threading import Thread
t = Thread(target=countdown, args=(10, ))
t.start()
t2 = Thread(target=countdown2, args=(10, ))
t2.start()

View File

@@ -0,0 +1,23 @@
# 众所周知split函数可以针对单个分隔符把字符串拆开
a = "suka,caonimade,shabi"
b = a.split(",")
print(b)
# 但是假如系统可以检测到这种粗鄙之语,那就会让🐎🐎消失
# 想要保卫自己的🐎,那就要粗鄙的隐晦一点:
a = "suka,*&&**caonimade,_&^shabi"
# 这时候关键词检测就暴毙了
b = a.split(",")
print(b)
# 但是聪明的审核会用re库来解决这个问题
import re
# re库中的split函数接受多个输入可以同时干掉多种干扰
b = re.split(r'[,*&^_]', a)
print(b)
# 如果要保留分隔符, 记得使用正则闭包
b = re.split(r'(,|&|^|_)', a)
print(b)

View File

@@ -0,0 +1,11 @@
import re
if __name__ == '__main__':
# 默认情况下re模块已经认识了某些unicode字符比如\d现在已经可以匹配unicode的数字
num = re.compile(r'\d+')
# match会从第一个字符开始匹配如果不匹配就返回None
print(num.match('123'))
print(num.match('\u0661\u0662\u0663'))
# 我的评价是别这样干在处理东西之前先将输入标准化为ascii编码是一个程序员的基本素养

View File

@@ -0,0 +1,24 @@
if __name__ == '__main__':
# 使用strip方法可以删除不要的字符串默认是删除空格
s = ' hello world \n'
print(s.strip())
# 同样的这个方法还有进阶版本lstrip和rstrip可以从左右开始检测指定符号进行删除
# 如果左边开头或右边开头没有指定符号,则不会起作用
s2 = '---hello world==='
print(s2.lstrip('-'))
print(s2.rstrip('='))
print(s2.strip('-='))
# 在这个例子中hello world中间的空格不会被strip系列函数删除因为这个方法不会管字符串中间的字符
# 如果需要删除hello world中间的空格请使用replace方法
# 在一个文件中,我们可以这样进行每一行的信息过滤:
# with open(file) as f:
# lines = (line.strip() for line in f)
# for line in lines:
# print(line)

View File

@@ -0,0 +1,26 @@
import sys
import unicodedata
if __name__ == '__main__':
# 总有脑瘫喜欢输入一些奇奇怪怪的东西,这个时候我们就需要做一些过滤操作
s = 'pyth\u0303on\fis\tawesome\r\n'
# 这个字符串看起来就非常恶心了这时候我们可以用translate方法对一些特殊符号进行迭代
remap = {
ord('\t'): ' ',
ord('\f'): ' ',
ord('\r'): None,
}
s = s.translate(remap)
print(s)
# 这个时候我们就过滤掉了各种空格符和回车符
# 我们也可以构建更大的order_dict去把unicode过滤掉
b = unicodedata.normalize("NFD", s)
# 对每一个unicode建立一个None的映射
cmb_dict = dict.fromkeys(c for c in range(sys.maxunicode) if unicodedata.combining(chr(c)))
b = b.translate(cmb_dict)
print(b)
# 如果只是简单的替换操作那么replace函数已经很好了速度也很快
# 在做字符映射操作的时候可以使用translate方法并构建一个映射字典

View File

@@ -0,0 +1,22 @@
if __name__ == "__main__":
text = 'Hello World'
# 如果想要对齐字符串可以使用ljest、rjust和center方法
print(text.ljust(20))
print(text.rjust(20))
print(text.center(20))
# 当然,这个轮椅也支持填充操作
print(text.ljust(20, '='))
print(text.rjust(20, '-'))
print(text.center(20, '='))
# 除了轮椅函数建议使用format函数这个东西更加泛用还能进行格式转换
print(format(text, '-<20')) # <表示宽度20居左
print(format(text, '=>20')) # >表示宽度20居右
print(format(text, '+^20')) # ^表示宽度20居中
# <>^前面的符号表示使用该符号填充
# format的好处主要在于它的处理对象不仅是字符串可以对任何数据形式进行格式化
num = 1.23456
print(format(num, '=^20.2f')) # 这表示宽度20保留两位小数居中使用=填充

View File

@@ -0,0 +1,15 @@
if __name__ == "__main__":
# 如果有一堆字符串, 那我想join函数是一个好选择, 但如果就几个那用+就可以了
parts = ["Is", "Chicago", "Not", "Chicago?"]
str_c = ' '.join(parts)
print(str_c)
# 如果我有密钥的两部分想把a和b连接在一起那可以这样
keyword = 'su' 'ka'
print(keyword)
# 在实际运用中,如果遇到一堆字符串拼接,千万别用+=,这样会产生大量内存垃圾
# 如果有大量的片段需要拼接,则应该考虑使用生成器函数(字段确定的情况下)

View File

@@ -0,0 +1,43 @@
import sys
if __name__ == "__main__":
# 一般来说,我们用{}和format函数对字符串进行插值
s = "{name} has {n} messages"
s1 = s.format(name="Sam", n=10)
print(s1)
# 当然如果你想偷懒,也可以这样:
name = "Sam"
n = 10
s2 = s.format_map(vars())
print(s2)
# 在上面这段代码中vars函数会从堆栈里自动寻找变量名称的值
# vars还能解析类实例
class INFO:
def __init__(self, name, n):
self.name = name
self.n = n
info = INFO(name, n)
s3 = s.format_map(vars(info))
print(s3)
# 爽吗?确实爽,但是有一个缺点,在填充值缺失的时候这玩意儿会报错
try:
s4 = s.format(name=name)
except KeyError:
print("少参数")
# 我们可以定义一个类的__missing__方法来防止出现这种情况
class Safe_Sub(dict):
def __missing__(self, key):
return '{'+ key +'}'
del n
print(s.format_map(Safe_Sub(vars())))
# 如果经常操作,那么可以把这个功能藏在函数里,同时从当前调用的堆栈里找到变量(我反正不建议这么干,不过得知道)
def sub(text):
# 不代码里tmd堆栈这是手贱行为可能导致各种bug除非有必要的理由否则不要这么做
return text.format_map(Safe_Sub(sys._getframe(1).f_locals))
name = "Suka"
print(sub(s))

View File

@@ -0,0 +1,20 @@
import textwrap
import os
if __name__ == '__main__':
words = ' '.join(["look", "into", "my", "eyes", "look", "into", "my", "eyes",
"the", "eyes", "the", "eyes", "the", "eyes", "not", "around", "the",
"eyes", "don't", "look", "around", "the", "eyes", "look", "into",
"my", "eyes", "you're", "under"])
print(words)
# 可以看到这样打印出来的字符串巨长无比如果想要控制行宽度就用textwrap模块
print(textwrap.fill(words, 70))
print(textwrap.fill(words, 40))
# 第二个参数width可以控制显示宽度如果是控制台输出你还能去找os.get_terminal_size()
# 注意由于未知原因这在pycharm中不好使2024.8.27
t_width = os.get_terminal_size().columns
print(t_width)
print(textwrap.fill(words, t_width))
# 用的应该不多在需要显示长字符串的时候去查textwrap库就行

View File

@@ -0,0 +1,4 @@
# 这本书的年代有些久远当时HTML和XML解析器还不是特别完善
# 在现在的工具中想要处理HTML和XML文件只需要寻找HTML Parser和XML解析库就行

View File

@@ -0,0 +1,37 @@
import re
from collections import namedtuple
if __name__ == "__main__":
text = 'foo = 23 + 42 * 10'
# 我们想要将这个字符串解析成这个样子:
# tokens = [('NAME', 'foo'), ('EQ', '='), ('NUMS', '23'), ('PLUS', '+'),
# ('NUMS', '42'), ('TIMES', '*'), ('NUMS', '10')]
# 首先,我们要对每种情况编写一个捕获组
NAME = r'(?P<NAME>[a-zA-Z_][a-zA-Z_0-9]*)'
NUM = r'(?P<NUM>\d+)'
PLUS = r'(?P<PLUS>\+)'
TIMES = r'(?P<TIMES>\*)'
EQ = r'(?P<EQ>=)'
WS = r'(?P<WS>\s+)'
# 把这些捕获组静态编译给re模块
master_pat = re.compile('|'.join([NAME,NUM,PLUS,TIMES,EQ,WS]))
# 定义一个数据结构来存储每个部分
Token = namedtuple('Token', ['type', 'value'])
def generate_tokens(pat, text):
# 调用re.compile的scanner模块来扫描并用iter模块将其变成可迭代对象进行迭代
scanner = pat.scanner(text)
for m in iter(scanner.match, None):
# 生成结构来存储分词
yield Token(m.lastgroup, m.group())
# 对分词类型进行过滤,去掉空格
tokens = (tok for tok in generate_tokens(master_pat, text) if tok.type != 'WS')
for tok in tokens:
print(tok)
# 看起来很简单是吧唯一的难点就在compile的时候
# 要把大词放前面先搜完再搜小词,保证较长的模式先匹配;比如<=的顺序就应该比<靠前

View File

@@ -0,0 +1,3 @@
"""
我的评价是去看编译原理的文本解析部分
"""

View File

@@ -0,0 +1,21 @@
from numpy.core.defchararray import startswith
if __name__ == '__main__':
str = "https://www.baidu.com"
str2 = "http://www.baidu.cn"
str3 = "suka"
# 如果想要在字符串首进行匹配,可以使用:
is_start_with_https = str.startswith("https")
print(is_start_with_https)
# 这会输出一个布尔值,
## 比如上面匹配成功就会输出True
# 同理可以设置endswith
is_end_with_dotcom = str.endswith(".com")
print(is_end_with_dotcom)
# 如果想要匹配多种开头和结尾,可以将函数输入改成元组()
is_url = [url for url in [str, str2, str3] if url.startswith(('http', 'https'))]
print(is_url)
# 当然,复杂的操作还请使用正则表达式进行匹配,不过简单的检查用这个方法那是又快又好

View File

@@ -0,0 +1,33 @@
import re
from pyasn1.codec.ber.decoder import decode
if __name__ == '__main__':
data = b'Hello World'
# 目前字节串已经支持大部分和字符串相同的操作
data05 = data[0:5]
print(data05)
is_startwith_hello = data.startswith(b'Hello')
print(is_startwith_hello)
data_sp = data.split()
print(data_sp)
data_suka = data.replace(b'Hello', b'Hello Suka')
print(data_suka)
# 唯一需要注意的是如果用re做了匹配那记得要用字节串的形式来匹配
data = b'foo:bar,spam'
try:
re.split('[:,]', data)
except:
print("匹配错误,换字节串匹配")
data_bsp = re.split(b'[:,]', data)
print(data_bsp)
# 字节串上的字符不能直接被识别需要先用ascii解码
print(data[0])
print(data.decode("ascii")[0])
# 我的建议是除非万不得已请不要用字节串处理文本统一使用ascii解码成字符串后再进行操作

View File

@@ -0,0 +1,26 @@
from fnmatch import fnmatch, fnmatchcase
if __name__ == '__main__':
# 如果想用shell通配符做字符串匹配可以用上面的这两个函数
is_txt = fnmatch("suka.txt", "*.txt")
print(is_txt)
is_txt = fnmatchcase("suka.txt", "??ka.txt")
print(is_txt)
# 注意fnmatchcase不会对输入的name进行大小写标准化而fnmatch会对输入标准化后再进行匹配
# 需要小心的是大小写标准化的模式与底层文件系统相同比如windows不需要区分大小写但是mac要
address = [
'5412 N CLARK ST',
'1060 W ADDISON ST',
'1039 W GRANVILLE AVE',
'2122 N CLARK ST',
'4802 N BROADWAY'
]
# 可以用正则进行筛选
ST = [addr for addr in address if fnmatchcase(addr, "* ST")]
print(ST)
NUM_S = [addr for addr in address if fnmatchcase(addr, '54[0-9][0-9] *CLARK*')]
print(NUM_S)

View File

@@ -0,0 +1,49 @@
import re
if __name__ == '__main__':
# 如果只是简单的文字匹配或者查找,下面三个方法足以解决问题:
url = "http://www.baidu.com"
url.startswith("http")
url.endswith(".com")
url.find("baidu")
# 但如果是更加复杂的匹配就要用到re库的正则了
text1 = '11/27/2012'
text2 = 'Nov 27, 2012'
if re.match(r'\d+/\d+/\d+', text1):
print("yes")
else:
print("no")
if re.match(r'\d+/\d+/\d+', text2):
print("yes")
else:
print("no")
# match可以被一次性消费但是如果想要多次匹配就要先把正则编译
datepat = re.compile(r'\d+/\d+/\d+')
if datepat.match(text1):
print("yes")
else:
print("no")
if datepat.match(text2):
print("yes")
else:
print("no")
# 这里要注意的是match方法是从头匹配如果要匹配的内容在一堆垃圾里面请使用findall
# 我们还会使用捕获组,这样可以把每个组单独提取出来
datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
m = datepat.match(text1)
print(m.group(0))
print(m.group(1))
print(m.group(2))
print(m.group(3))
# match只能匹配开头它不管结尾如果想要精确匹配需要加休止符$
datepat = re.compile(r'(\d+)/(\d+)/(\d+)$')

View File

@@ -0,0 +1,22 @@
import re
if __name__ == "__main__":
text = "yeah, but no, but yeah, but no, but yeah"
# 简单的替换可以使用replace函数来完成
text_change = text.replace('yeah', 'yep')
print(text_change)
# 对复杂的替换我们可以使用re.sub模块
text = "Today is 11/27/2012. PyCon starts 3/12/2013"
text_change = re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text)
print(text_change)
# 如果需要多次替换记得先编译再sub
datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
print(datepat.sub(r'\3-\1-\2', text))
# 想要知道完成了几次替换可以使用subn
# subn返回一个元组结构为替换后的字符串 替换次数)
print(datepat.subn(r'\3-\1-\2', text))

View File

@@ -0,0 +1,35 @@
import re
if __name__ == '__main__':
text = "UPPER PYTHON, lower python, mixed Python"
# 想要找到所有的python可以在函数里面找一下有没有flag关键字并设为re.IGNORECASE
pythons = re.findall('python', text, flags=re.IGNORECASE)
print(pythons)
# 但是这样在替换的时候就有问题发生,不能把替换文本的大小写设置成和原文本一样
python_replace = re.sub('python', 'snake', text, flags=re.IGNORECASE)
print(python_replace)
# 这个时候我们需要一个辅助函数
def matchcase(word):
def replace(m):
text = m.group()
if text.isupper():
return word.upper()
elif text.islower():
return word.lower()
elif text[0].isupper():
# 这个函数将字符串的首字母大写,其余部分转成小写
return word.capitalize()
else:
return word
return replace
python_replace_with_func = re.sub('python', matchcase('snake'), text, flags=re.IGNORECASE)
print(python_replace_with_func)
# 这个辅助函数结构陌生,这里记个笔记备注一下防止以后再看忘记:
# 1.首先sub函数检测到要调用matchcase函数进入函数体返回replace函数 sub->matchcsae
# 2.此时matchcase函数的输入word仍在堆栈中等待调用 matchcase -replace-> sub
# 3.在替换的时候sub函数将识别到的python替换成replace(被识别到的部分) text -> (a1,a2,a3,...)
# 4.replace函数返回大小写处理结果 replace(a1), replace(a2), ...
# 5.函数返回被替换字符串re.sub函数进行替换 将识别到的关键词替换成处理过的word

View File

@@ -0,0 +1,18 @@
import re
if __name__ == '__main__':
# 在进行文本匹配的时候re库使用的是贪心算法即找最长匹配字符串
text1 = 'Computer says "no".'
text2 = 'Computer says "yes" and "no".'
# 这样的算法在简单的环境中不会出现问题,但如果遇到闭包匹配(最典型的是双引号)就会出现问题
said = re.compile(r'\"(.*)\"')
print(said.findall(text1))
# 看,这里就输出了距离最长的两个引号中间的内容
print(said.findall(text2))
# 问题就出现在.匹配字符上,默认.*会匹配除了\n以外的所有字符其中也包括“”
# 解决方案是强制取消正则的贪心算法,进行最短匹配
# 技术上我们在.*后界面加一个?来强制取消贪心
said_shot = re.compile(r'\"(.*?)\"')
print(said_shot.findall(text2))

View File

@@ -0,0 +1,20 @@
import re
if __name__ == '__main__':
# 正常情况下,我们会想用.来匹配所有字符串,但这个东西不能匹配换行符
text1 = '/*This is a comment*/'
text2 = '''/*This is a
multiline comment */'''
comment = re.compile(r'/\*(.*?)\*/')
print(comment.findall(text1))
print(comment.findall(text2))
# 你会发现欸我靠咋匹配不到了,那是因为由于没办法识别\n,第二行被抛弃了
# 想要识别出\n,需要使用(?:.|\n)指定一个非捕获组,意思是在识别到/n的时候只做匹配但不触发捕获退出
comment_pro = re.compile(r'\*((?:.|\n)*?)\*/')
print(comment_pro.findall(text2))
# 对于这种简单的情况可以在compile函数中加入一个参数re.DOTALL来让.匹配包括\n在内的所有字符串
# PS复杂情况请另请高明
comment_pro_se = re.compile(r'\*(.*?)\*/', re.DOTALL)
print(comment_pro_se.findall(text2))

View File

@@ -0,0 +1,37 @@
import unicodedata
if __name__ == '__main__':
s1 = 'Spicy Jalape\u00f1o'
s2 = 'Spicy Jalapen\u0303o'
# 可以看到某些字符串的表示在unicode下有多种选项
print(s1,s2)
print(s1==s2)
# 显然这种情况在我们判断字符串的时候极其不利这时候我们就需要把unicode编码进行规范
# 有两种规范方式NFC全组成和NFD组合字符
t1 = unicodedata.normalize('NFD', s1)
t2 = unicodedata.normalize('NFD', s2)
print(t1, t2)
print(t1==t2)
print(ascii(t1))
t3 = unicodedata.normalize('NFC', s1)
t4 = unicodedata.normalize('NFC', s2)
print(ascii(t3))
# unicodedata同时还提供NFKC和NFKD编码这种编码提供了额外的兼容功能能把下面这种字符分开
s = '\ufb01'
print(s)
print(unicodedata.normalize('NFD', s))
print(unicodedata.normalize('NFKC', s))
print(unicodedata.normalize('NFKD', s))
# 如果要去除音符标记~那么我们可以先用组合字符NFD标准化再进行去除
suka = unicodedata.normalize('NFD', s1)
print(suka)
suka = ''.join(c for c in unicodedata.normalize('NFD', suka) if not unicodedata.combining(c))
print(suka)
# 在上面的例子里,我们使用了unicodedata.combining()函数来判断字符是否属于组合型字符

View File

@@ -0,0 +1,16 @@
if __name__ == '__main__':
# 很多时候我们需要对浮点数进行取整操作通常情况下使用自带的round函数就能解决问题
f = 1.23456
print(round(f, 2))
# 虽然round函数可以很方便的对数值进行取整但一般情况下如果需要规范输出还是用format(.2f)来做
ff2 = format(f, '.2f')
print(ff2)
# 因为浮点数计算因为算法的局限性可能带来一些奇妙的误差
a = 2.1
b = 4.2
print(a+b)
# 所以一般来说我们就是算完直接按照需要取小数位数规整完格式就行了
# 除非我们的程序对数据精度要求非常高那这时候就要用decimal库了

View File

@@ -0,0 +1,16 @@
import numpy as np
if __name__ == '__main__':
# np在线性代数处理上有一个子包叫matrix专门使用线性代数规则来处理数据比如矩阵乘法、求行列式和解线性方程
m = np.matrix([[1,-2,3],[0,4,5],[7,8,-9]])
print(m)
# 做一个矩阵转置
print(m.T)
# 求可逆矩阵
print(m.I)
v = np.matrix([[2], [3], [4]])
print(m * v)
# 更多线代操作在np.linalg模块下可以找到随用随查就行

View File

@@ -0,0 +1,34 @@
import random
from gevent.subprocess import value
if __name__ == '__main__':
# 如果想要进行随机数操作那么random库是我们最好的选择
values = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 使用random.choice进行抽卡
random_num = random.choice(values)
print(random_num)
# 使用random.choices进行多次抽卡(k次),每次抽一张
random_nums = random.choices(values, k=2)
print(random_nums)
# 使用random.sample进行抽卡并剔除,这个函数只抽取一次每次抽k张所以k不能大于数组长度
random_num = random.sample(values, k=3)
print(random_num)
# 如果只是想洗牌那用shuffle就行了
random.shuffle(values) # 注意,这个函数不返回任何东西,它直接在原数组上进行操作
print(values)
# 生成随机数可以使用random.randint, 它接受两个参数生成a和b之间的随机数
print(random.randint(0, 10))
# 如果要0-1之间的float可以用random.random
print(random.random())
# 在配密钥的时候我们有的时候会想要得到N比特位的随机整数这时候可以用random.getrandbits(n)
print(random.getrandbits(12))
# 切记random虽然可以产生随机数但其使用的梅森旋转算法是确定算法只要破解seed就能计算出固定值
# 如果需要在密钥中搞到随机数请使用ssl模块产生随机加密字节

View File

@@ -0,0 +1,38 @@
from datetime import timedelta, datetime
if __name__ == '__main__':
# 使用timedelta表示时间间隔
a = timedelta(days=2, hours=6)
b = timedelta(hours=4.5)
c = a + b
print(c.days)
# 这是计算小时的秒数
print(c.seconds)
# 这是计算天+小时的秒数
print(c.total_seconds())
# 如果要创建特定的日期和时间可以用datetime来表示
time1 = datetime(2024, 8, 28)
birthday = datetime(2001, 4, 29)
life_time = time1 - birthday
print(life_time.days)
now = datetime.now()
print(now)
# 值得注意的是datetime模块可以正确处理闰年的二月并计算出正确的天数我的评价是我直接不管
# 对绝大部分的问题datetime模块已经足够使用但是如果需要处理复杂时间问题比如时区、模糊时间范围、计算节日日期等
# 请他娘的使用dateutil模块
a = datetime(2012, 9, 23)
# 很明显因为timedelta没有month这个key所以我们不能直接加一个月它的精度最大只到days
# 这时候dateutil下的relativedelta就派上用场
from dateutil.relativedelta import relativedelta
b = a + relativedelta(years=10, months=2)
print(b)
# 包括计算日期差
d = relativedelta(b, a)
print(d.years, d.months, d.days)

View File

@@ -0,0 +1,31 @@
from datetime import datetime, timedelta
if __name__ == '__main__':
weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
def get_previous_by_day(day_name, start_date=None):
if start_date is None:
start_date = datetime.today()
day_num = start_date.weekday()
day_num_target = weekdays.index(day_name)
days_ago = (7 + day_num - day_num_target) % 7
if days_ago == 0:
days_ago = 7
target_date = start_date - timedelta(days=days_ago)
return target_date
get_previous_by_day("Friday")
# 但是如果要经常这么干请使用dateutil包
d = datetime.now()
from dateutil.relativedelta import relativedelta
from dateutil.rrule import *
# 找最近的周五FR是rrule里的函数
print(d + relativedelta(weekday=FR))
# 找上一个周五
print(d + relativedelta(weekday=FR(-1)))

View File

@@ -0,0 +1,33 @@
from datetime import datetime, date, timedelta
import calendar
from fontTools.misc.plistlib import end_date
if __name__ == "__main__":
def get_month_range(start_date=None):
if start_date is None:
start_date = date.today().replace(day=1)
_, days_in_month = calendar.monthrange(start_date.year, start_date.month)
end_date = start_date + timedelta(days = days_in_month)
return start_date, end_date
a_day = timedelta(days=1)
first_day, last_day = get_month_range()
while first_day < last_day:
print(first_day)
first_day = first_day + a_day
# 在获取一个月天数的时候calendar库会非常好用monthrange会返回第一个工作日的日期和当月的天数
# 如果想要实现和Python内建的range一样的遍历效果可以写一个生成器
def date_range(start_date, end_date, step=timedelta(days=1)):
while start_date < end_date:
yield start_date
start_date += step
for d in date_range(first_day, last_day):
print(d)

View File

@@ -0,0 +1,22 @@
from datetime import datetime, date
if __name__ == '__main__':
text = "2012-09-20"
# str -> time
y = datetime.strptime(text, "%Y-%m-%d")
z = datetime.now()
diff = z - y
print(diff)
# 如果你觉得不够美观,那就格式化一下
# time -> str
struct_time_str = datetime.strftime(y, "%A %B %d, %Y")
print(struct_time_str)
# 当然strptime这个函数的性能相当糟糕大量使用时如果考虑到效率问题还请自己动手
def parse_date(date_str):
y, m, d = date_str.split("-")
return datetime(int(y), int(m), int(d))
print(parse_date(text))

View File

@@ -0,0 +1,14 @@
from datetime import datetime
from pytz import timezone
if __name__ == "__main__":
d = datetime(2012, 12, 21, 9, 30, 0)
print(d)
central = timezone('US/Central')
loc_d = central.localize(d)
print(loc_d)
bang_d = loc_d.astimezone(timezone("Asia/Kolkata"))
print(bang_d)

View File

@@ -0,0 +1,12 @@
from decimal import Decimal
if __name__ == '__main__':
# 可以看到使用float的ieee754浮点标准进行计算会产生误差
a = 4.2
b = 2.1
print(a+b)
# 如果需要高精度小数我们的处理方法是将数字字符串转成decimal类型
a = Decimal(str(4.2))
b = Decimal(str(2.1))
print(a+b)

View File

@@ -0,0 +1,14 @@
if __name__ == '__main__':
x = 1234.56789
# 对数值格式化输出我们使用经典format函数
print(format(x, '.2f'))
print(format(x, '+<10.2f'))
print(format(x, '=>10.2f'))
print(format(x, '-^10.2f'))
# 有一些特殊的比如数值特有的千位逗号1000
print(format(x, ',.2f'))
# 如果想用科学计数法把f改成e就行
print(format(x, '.2e'))
print(format(x, 'e'))

View File

@@ -0,0 +1,25 @@
if __name__ == '__main__':
# 想要将十进制数字转换成二进制、八进制和十六进制,可以使用内建函数
a = 1234
a_bin = bin(a)
print(a_bin)
a_oct = oct(a)
print(a_oct)
a_hex = hex(a)
print(a_hex)
# 如果不想要出现0b、0o、0x这样的前缀可以使用format函数格式化做转换
print(format(a, 'b'))
print(format(a, 'o'))
print(format(a, 'x'))
# 如果我们需要一个32位无符号整数可以这样干
x = 1234
x = format(2**32 + x, 'b')
print(x)
# 要转回10进制的时候用int函数+字符串进制就可以了
x = int(a_bin, 2)
print(x)

View File

@@ -0,0 +1,35 @@
import struct
import math
if __name__ == '__main__':
# 假如我们有一个用字节串存储的大整数
data = b'\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004'
# 要将其还原成整数,我们需要:
print(int.from_bytes(data, byteorder="little"))
print(int.from_bytes(data, byteorder="big"))
# 而要将整数转成字节串,我们可以做一个逆向操作
int_to_b = int.from_bytes(data, byteorder="little")
print(int.to_bytes(int_to_b, byteorder="little", length=16))
# 在IPV6中网络地址以一个128位的整数表示这时候我们可以使用struct模块来完成解包
hi, lo = struct.unpack('>QQ', data)
print((hi << 64) + lo)
# 通过byteorder我们可以指定在编成字节码的时候使用大端排序还是小端排序
byte_num = 0x01020304
print(byte_num.to_bytes(4, 'big'))
print(byte_num.to_bytes(4, 'little'))
# 但是请务必使用合适的字节串大小来保存字节串否则python会因为防止信息丢失报错
x = 523**23
try:
x.to_bytes(4, 'little')
except OverflowError:
print("数据溢出")
# 这时候就要先算一下字节长度再行转换
bit_length = x.bit_length()
# 为了让内存结构更加严整我们要将字节串补全成8的整数倍长度
bytes_num = math.ceil(bit_length / 8)
print(x.to_bytes(bytes_num, 'little'))

View File

@@ -0,0 +1,34 @@
if __name__ == '__main__':
# 在python中我们使用complex函数或者在浮点数后面加j的方式来定义一个复数
a = complex(2,4)
b = 2 + 4j
print(a, b)
# 我们可以提取复数的实部、虚部和共轭复数
print(a.real)
print(a.imag)
print(a.conjugate())
# 同样的,复数可以进行所有常见的算术操作
print(a + b)
print(a - b)
print(a * b)
print(a / b)
print(abs(a))
# 但如果需要对复数求正弦余弦或平方根这种操作,请:
import cmath
cmath.sin(a)
cmath.cos(a)
cmath.sqrt(a)
# 使用numpy可以生成复数数组并对它进行操作
import numpy as np
complex_array = np.array([1+2j, 2+3j, 3+4j])
print(complex_array + 2)
print(np.sin(complex_array))
# 在标准的math库中所有的操作都不会产生复数结果如果想要产出复数结果请使用支持复数感知的库比如cmath

View File

@@ -0,0 +1,20 @@
import math
if __name__ == '__main__':
# python没有原生的东西来表示这些值但他们可以被创建
a = float('inf')
b = float('-inf')
c = float('nan')
print(a, b, c)
# 如果想要感知这些值请使用isnan或isinf函数
print(math.isnan(c))
print(math.isinf(a))
# 要尤其注意inf在计算中会被传播
print(a+45)
# 但是一些神奇操作会产生nan比如
print(a + b)
print(a / a)
# 尤其注意nan会在所有的操作中传播且不会引起任何报错请务必在计算前进行使用isnan函数进行安全检测

View File

@@ -0,0 +1,24 @@
from fractions import Fraction
from unicodedata import decimal
from xlrd.formula import oMSNG
if __name__ == '__main__':
# 如果遇到分数问题那么我们就需要使用fractions模块
a = Fraction(1, 2)
print("这是二分之一:{}".format(a))
# 同样的,分数可以进行所有的算术运算
print(a * a)
# 我们可以通过一些方法得到分子和分母
print("分子是:{}".format(a.numerator))
print("分母是:{}".format(a.denominator))
# 或者我们可以把分数转成浮点数
print(float(a))
# 下面展示如何正确计算高精度的pi/8
import numpy as np
from decimal import Decimal
print(np.pi * Fraction(1, 8))

View File

@@ -0,0 +1,39 @@
import numpy as np
if __name__ == '__main__':
# 终于到了最喜欢的环节没有np我真的会原地爆炸np万岁
# 如果是普通的python list 想要处理是很麻烦的
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# print(li * 2)
# 但如果转成nparray,事情就变得简单了起来
np_arr = np.array(li)
# print(np_arr * 2)
# np对一维矩阵的运算也做了加强:
li2 = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
np_arr2 = np.array(li2)
# print(np_arr * np_arr2)
# 你甚至可以计算多项式的值
# print(3 * np_arr**2 + 2 * np_arr + 1)
# numpy提供了很多通用函数来对nparray进行操作比如
np.sin(np_arr)
np.sqrt(np_arr)
# 这些操作的效率很高,平时要多用
# 在底层numpy使用和C一样的连续内存空间所以只要内存够大你可以为所欲为
grid = np.zeros(shape=(10000, 10000), dtype=float)
# print(np.sin(np.sqrt(grid + 10)))
# numpy对多维数组也提供了很好的支持
nd_array = np.array([[1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15]])
print(nd_array)
print(nd_array[1])
print(nd_array[:, 1])
print(nd_array[1:3, 1:3])
print(nd_array + [1,2,3,4,5])
# np.where,没见过第一个参数是条件满足就输出第二个参数x不满足就输出第三个参数y
print(np.where(nd_array < 10, nd_array, np.nan))

View File

@@ -0,0 +1,24 @@
from scipy.stats import trim1
if __name__ == "__main__":
items = [1, 2, 3]
items = iter(items)
# 如果需要访问可迭代对象中的元素可以使用next函数
while True:
item = next(items, None)
if item is not None:
print(item)
else:
break
# next函数的第一个参数是一个可迭代对象第二个参数是None是没有元素的时候的返回值
# 如果不限制迭代器在没有元素后的返回值迭代器在迭代结束后会抛出一个StopIteration的错误
while True:
try:
item = next(items)
except StopIteration:
print("没东西了")
break

View File

@@ -0,0 +1,13 @@
if __name__ == "__main__":
my_list = [1,2,3,4,5,6,7,8,9]
# 有时候,我们想要在迭代的时候知道元素的下标,有些傻子(比如我)就很傻逼的做了个计数器
# 但是其实直接使用enumerate就行
for index, number in enumerate(my_list, start=0):
print(index, number)
# 但是如果可迭代对象的子元素是元组,那请务必别把元组的标识拆开
my_list = [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
for index, (x, y) in enumerate(my_list, start=1):
print(index, x, y)

View File

@@ -0,0 +1,30 @@
if __name__ == '__main__':
# 如果想要同时迭代多个序列那么可以使用zip函数
list1 = [1, 2, 3, 4, 5]
list2 = ['a', 'b', 'c', 'd', 'e']
for i, j in zip(list1, list2):
print(i, j)
# zip遵循最短木板原则迭代长度等于最短的可迭代对象长度如果想要打破这种限制请使用itertools.zip_longest()
from itertools import zip_longest
short_list = [1, 2, 3]
# fillvalue字段用来填充短列表的缺失值默认为None
for i, j in zip_longest(short_list, list1, fillvalue=0):
print(i, j)
# zip函数会构建一个元组它的长度与输入的可迭代对象数量有关
for i in zip(short_list, list2, list1):
print(i)
# 双对象元组可以直接视作键值对转成字典
dic = dict(zip(list1, list2))
print(dic)
# 重点zip函数返回的是一个一次性迭代器如果需要长久保存请转成列表在内存里持久化
storage_list = list(zip(list1, list2))

View File

@@ -0,0 +1,12 @@
from itertools import chain
if __name__ == '__main__':
a = [1,2,3,4,5]
b = ['a','b','c','d','e']
# 正常来说我们想要迭代这两个东西需要写两个循环构建两个迭代器但这样很操蛋不如直接用chain把他俩作链表连起来
for i in chain(a, b):
print(i)
# 使用chain可以避开 a + b 要求a和b类型相同的限制同时这种操作更加快速因为其底层是用指针完成而不会创建一个新的东西

View File

@@ -0,0 +1,41 @@
import os
from fnmatch import fnmatchcase
if __name__ == "__main__":
base_path = "D:\Code\Learn\practice"
# 想要建立一个处理管道需要将几个生成器函数堆叠比如我现在要输出所有practice文件夹下的注释行内容
# 1.首先生成文件夹路径
def gen_dir_path(fpath):
for path, dir, files in os.walk(fpath):
for file in files:
if (not fnmatchcase(path, "*.[git][idea]*")) and (not fnmatchcase(file, "*.md")):
yield os.path.join(path, file)
# 2.打开文件
def gen_file(paths):
for path in paths:
f = open(path, 'rt', encoding='utf-8')
yield f
f.close()
# 3.读取文件内容
def gen_file_txt(opened_files):
for file in opened_files:
yield from file
print("done")
# 4.匹配符合条件的文件行
def read_file_lines(file_lines):
for line in file_lines:
if "#" in line:
print(line)
# 将这些函数堆在一起就组成了一条管道,每次生成一个对象进行流水线处理,
# 这样避免了for循环的嵌套
paths = gen_dir_path(base_path)
files = gen_file(paths)
lines = gen_file_txt(files)
read_file_lines(lines)

View File

@@ -0,0 +1,18 @@
from collections import Iterable
if __name__ == '__main__':
# 将复杂的序列扁平化,使用递归来脱壳
def flatten(items, ignore=(str, bytes)):
for item in items:
# 要进行递归,首先这个元素要是可迭代的,其次它不能是字符串或二进制串
if isinstance(item, Iterable) and not isinstance(item, ignore):
# yield from 将请求转发到flatten函数返回的迭代器进行嵌套避免再写for循环
# yield from 在后面的协程和基于生成器的并发程序里有重要作用
yield from flatten(item, ignore)
else:
yield item
a = [1, 2, [3, 4, [5, 6], 7], 8]
for item in flatten(a):
print(item)

View File

@@ -0,0 +1,17 @@
import heapq
from itertools import chain
if __name__ == '__main__':
a = [1, 4, 7, 10]
b = [2, 5, 6, 11]
# 首先复习一下前面的知识如果不考虑合并后也是有序的用chain
for item in chain(a, b):
print(item)
# 但如果我们想要得到有序合并序列那就要用堆自带的merge功能了利用小根堆的特殊性来排序
new_arr = heapq.merge(a, b)
for item in new_arr:
print(item)
# 记住heapq的merge事先不会对输入可迭代对象的有序性进行检查而是每次从可迭代对象序列里取出最小的第一个进堆

View File

@@ -0,0 +1 @@
Hello PythonCookBook

View File

@@ -0,0 +1,33 @@
if __name__ == "__main__":
CHUNKSIZE = 10
def render(s):
# 军火展示
print(s.read())
s.seek(0)
# 在处理文件的时候我们习惯用while循环来迭代数据
print("一般while处理")
while True:
data = s.read(CHUNKSIZE)
if data == b'':
break
print(data)
s.seek(0)
# 但是可以使用迭代器来升级一下
print("进化成迭代器:")
for chunk in iter(lambda: s.read(CHUNKSIZE), b''):
print(chunk)
path = "4.迭代器与生成器/16.test.txt"
# 二进制打开文件记得用rb下一章进化一下文件读取方面的知识
f = open(path, 'rb')
render(f)
print("Done")

View File

@@ -0,0 +1,28 @@
if __name__ == "__main__":
class Node:
def __init__(self, value):
self._value = value
self._children = []
def __repr__(self):
return 'Node({!r})'.format(self._value)
def add_child(self, node):
self._children.append(node)
# 对象的内置iter方法在迭代对象的时候将迭代请求转发返回children的迭代器对象
# iter函数和len函数一样底层原理都是返回对象的底层方法iter返回对象的__iter__()
def __iter__(self):
return iter(self._children)
root = Node(0)
child1 = Node(1)
child2 = Node(2)
root.add_child(child1)
root.add_child(child2)
for ch in root:
print(ch)

View File

@@ -0,0 +1,52 @@
if __name__ == '__main__':
def fbb(start, stop, step):
x = start
while x <= stop:
yield x
x += step
# 上面是一个生成器函数,它只会在相应迭代时运行
# 在调用生成器函数的时候,因为直接生成了数字,所以有返回值
for i in fbb(0, 10, 1):
print(i)
# 尝试使用fbb生成金字塔
# 先用生成器整一个斐波那契数列生成函数
def fbb_arr(n):
index = 0
a0 = 1
a1 = 1
while index < n:
yield a0
a0, a1 = a1, a0 + a1
index += 1
# 按照n行打印出来
def print_num_delta(n):
# 计算需要生成多少个数字
fbb_number_num = sum(range(1, n + 1))
# 生成数字并保存
fbb_list = list(fbb_arr(fbb_number_num))
# 数字下标,用于遍历中保存位置
start_index = 0
# 每一行的数字数量
for number_num in range(1, n + 1):
# 切片用空格分隔后转成字符串
nums = ' '.join(str(item) for item in fbb_list[start_index: start_index + number_num])
# 格式化打印
print(format(nums, r' ^{}'.format(len(str(fbb_list[-1])) * n)))
# 更新下一行的数字下标
start_index = start_index + number_num
print_num_delta(5)
# 生成器里为什么没有return: 如果一个函数里包含yield语句那就会被识别为生成器函数
# 函数里的return此时自动失效被替换成生成器
# 生成器函数在识别到return时意识到生成结束返回的StopIteration交给for识别

View File

@@ -0,0 +1,31 @@
# 这是标准的
class Node:
def __init__(self, value):
self.value = value
self._children = []
def __repr__(self):
return "Node({})".format(self.value)
def add_child(self, node):
self._children.append(node)
def __iter__(self):
return iter(self._children)
def depth_first(self):
yield self
for child in self:
yield from child.depth_first()
if __name__ == '__main__':
root = Node(0)
child1 = Node(1)
child2 = Node(2)
root.add_child(child1)
root.add_child(child2)
child1.add_child(Node(3))
child2.add_child(Node(4))
for ch in root.depth_first():
print(ch)

View File

@@ -0,0 +1,31 @@
if __name__ == "__main__":
a = [1, 2, 3, 4]
# python自带的reversed函数搞定了反向迭代其本质时调用了__reversed__方法
for i in reversed(a):
print(i)
for i in a.__reversed__():
print(i)
# 如果想要实现类的反向迭代可以在实现__iter__()方法的同时搞一个__reversed__()方法
class Countdown:
def __init__(self, start):
self.start = start
def __iter__(self):
n = self.start
while n > 1:
yield n
n -= 1
def __reversed__(self):
n = 1
while n <= self.start:
yield n
n += 1
a = Countdown(10)
for i in reversed(a):
print(i)

View File

@@ -0,0 +1,38 @@
from collections import deque
if __name__ == "__main__":
# 在学到了生成器函数以后,有一个巨大陷阱那就是尝试用生成器函数解决一切问题
# 当生成器函数需要与外界交互的时候,就会让它非常复杂
# 所以生成器我们就让它安心生成,在需要记录或者与外界交互的时候,写一个生成器类
class FbbIterClass:
def __init__(self,nums, history_len=3):
self.nums = nums
self.history = deque(maxlen=history_len)
def __iter__(self):
a0, a1 = 1, 1
index = 0
while index < self.nums:
self.history.append(a0)
yield a0
a0, a1 = a1, a0 + a1
index += 1
fbbs = FbbIterClass(5)
# 先用生成器生成,结果在生成的过程中会存入历史队列
for i in fbbs:
print(i)
# 当然在使用for之外的方法进行迭代时需要额外套一层iter来转发请求到__iter__()
fbb_iter = iter(fbbs)
print(fbb_iter.__next__())
print(fbb_iter.__next__())
print(fbb_iter.__next__())
print(fbb_iter.__next__())
print(fbb_iter.__next__())
# 这种方法的好处是,可以在迭代时随时暴露一些东西给外部程序,比如属性和状态
for line in fbbs.history:
print("history{}".format(line))

View File

@@ -0,0 +1,26 @@
from itertools import islice
if __name__ == '__main__':
# 在程序生成过程中,我们有时候需要做一些无限生成器,这些生成器往往需要切片使用
def infinity_iterator(start):
while True:
yield start
start += 1
# 无限生成器
for i in infinity_iterator(0):
print(i)
break
# 想要对无限生成器进行切片我们就需要使用itertools里的islice函数,记得这个函数也是左闭右开
iterator= infinity_iterator(0)
iter_10_20 = islice(infinity_iterator(0), 10, 21)
for i in iter_10_20:
print(i)
# 注意islice操作是通过丢弃索引序列前的元素实现的返回的是一个一次性迭代器被迭代过后元素就被消耗掉无了
print("再次使用迭代")
for i in iter_10_20:
print(i)

View File

@@ -0,0 +1,22 @@
from itertools import dropwhile, islice
if __name__ == '__main__':
words = ["#look", "#into", "#my", "eyes", "look", "into", "my", "eyes",
"the", "eyes", "the", "eyes", "the", "eyes", "not", "around", "the",
"eyes", "don't", "look", "around", "the", "eyes", "look", "into",
"my", "eyes", "you're", "under"]
# 想要对可迭代对象进行过滤也可以使用dropwhile函数,比如这里我想过滤掉前几行有#的东西
for i in dropwhile(lambda x : x.startswith('#'), words):
print(i)
# dropwhile会在迭代时对函数进行匹配将符合条件的值丢弃直到出现第一个符合条件的值后停止工作返回所有剩余内容
# 如果你知道需要跳过几个元素那可以直接用islice进行切片操作来过滤
items = ['a', 'b', 'c', 1, 2, 3]
# None表示[3:]
for i in islice(items, 3, None):
print(i)
# 当然,使用列表的过滤方法也可以删除一些不要的东西,但是这样的删除是全局的,而不是仅在开头生效

View File

@@ -0,0 +1,23 @@
from itertools import permutations, combinations
if __name__ == '__main__':
# 有时候我们想对可迭代对象中的元素进行排列组合这个时候我们就不得不靠for循环写出很不python的代码
# itertools库帮助我们解决了这个困扰
items= ['a', 'b', 'c', 'd', 'e']
# permutations会列出所有的排列如果指定排列长度那就会输出该长度下所有的排列
for p in permutations(items):
print(p)
for p in permutations(items, 3):
print(p)
# 如果想要得到特定长度的组合那就可以使用combination函数
for c in combinations(items, 3):
print(c)
# 上面这种组合是不放回的组合如果想产生放回元素的组合可以使用combinations_with_replacement函数
from itertools import combinations_with_replacement as cwr
for c in cwr(items, 3):
print(c)

View File

@@ -0,0 +1 @@
Hello Python File

View File

@@ -0,0 +1,47 @@
if __name__ == "__main__":
path = "5.文件与IO/1.somefile.txt"
# 如果想要读取文件那open函数是唯一的选择它有很多模式
# # 只读组, 一般用于配置信息
# open(path, 'rb')
# open(path, 'rt')
#
# # 只写覆盖模式,将指针指向文件头,一般用于文件输出或覆盖旧内容
# open(path, 'wb')
# open(path, 'wt')
#
# # 只写追加模式,将指针从默认的文件头指向文件尾
# open(path, 'ab')
# open(path, 'at')
# 如果上面的任何一种模式后面有+,那么将会变成读写模式
# 在打开文件时可以指定文件的编码格式默认编码模式可以使用sys库进行查询
import sys
print(sys.getdefaultencoding())
# 当我们想打开文件的时候不建议直接使用上面的open函数因为这样需要每次记住手动关闭打开的文件像这样
# 当然二进制写入不需要指定encoding 正常来说需要指定encoding='utf-8'
a = open(path, 'wb')
a.write(b'Hello Python File\n')
a.close()
# 我们可以使用with语句来为文件创建一个上下文环境在程序离开with的程序段以后会自动关闭文件
with open(path, 'rb') as f:
# 记住如果是二进制写入解出来的时候要用utf-8解码一下
print(f.read())
# 可以看到文件已经被关闭了
print(f.closed)
# 在UNIX和Windows上换行符不太相同UNIX是\n而windows是\r\n
# Python在读取文件时做了内置的转换统一换行符为\n,如果不需要这种转换可以设置newline=''
open(path, 'rb', newline='')
# 如果遇见解码错误只需要更换encoding就行, 也可以设置错误解决方案字段errors
open(path, 'rb', encoding='utf-8', errors='replace')

BIN
5.文件与IO/10.data Normal file

Binary file not shown.

View File

@@ -0,0 +1,44 @@
import os
import mmap
if __name__ == '__main__':
def memory_map(file_path, access=mmap.ACCESS_WRITE):
size = os.path.getsize(file_path)
fild_data = os.open(file_path, os.O_RDWR)
return mmap.mmap(fild_data, size, access=access)
SIZE = 1000000
# with open(r'5.文件与IO/10.data', 'wb') as f:
# f.seek(SIZE - 1)
# f.write(b'\x00')
m = memory_map('5.文件与IO/10.data')
print(len(m))
m[0:11] = b'Hello World'
m.close()
with open(r'5.文件与IO/10.data', 'rb') as f:
print(f.read(11))
# 当然这个函数得益于他的open内嵌也能在with的上下文中打开并自动关闭
with memory_map('5.文件与IO/10.data') as m:
print(len(m))
print(m.closed)
# 当然如果你想只读可以在access里设置成mmp.ACCESS_READ,
# 如果只想把文件拷贝到内存而不是直接在文件里修改mmp.ACCESS_COPY非常有用
# mmap和memoryview又有所不同
m = memory_map('5.文件与IO/10.data')
v = memoryview(m).cast('I')
v[0] = 7
m[0:4] = b'\x07\x01\x00\x00'
print(m[0:4])
print(v[0])
# 可以看出来memoryview在做转换的时候用的是小端存储
print(int.from_bytes(m[0:4], byteorder='little'))
print(int.from_bytes(m[0:4], byteorder='big'))
v.release()
m.close()

View File

@@ -0,0 +1,20 @@
import os
if __name__ == '__main__':
path = '/Users/beazley/Data/data.csv'
# 如果我们想要得到地址的最后一部分可以使用basename字段
print(os.path.basename(path))
# 前面的部分作为文件夹可以使用dirname读出来
print(os.path.dirname(path))
# 如果想要拼接多个路径则可以使用join
print(os.path.join('suka', 'blyet', os.path.basename(path)))
# 想要提取出文件名可以使用splitext
print(os.path.splitext(os.path.basename(path)))
# 也可以使用expanduser展开上级目录,默认接控制台下的路径
path = "~\practice"
print(os.path.expanduser(path))

View File

@@ -0,0 +1,22 @@
import os
if __name__ == '__main__':
# 如果想知道文件是否存在可以使用os.path.exists
# 这个函数返回一个布尔值如果存在就返回T否则返回F
print(os.path.exists("file_not_exists.txt"))
print(os.path.exists("5.文件与IO/1.somefile.txt"))
# 判断是不是一个文件可以使用isfile方法
print(os.path.isfile("5.文件与IO/1.somefile.txt"))
# 判断是不是一个文件夹可以使用isdir方法
print(os.path.isdir("5.文件与IO"))
# 判断是不是一个软连接可以使用islink方法
print(os.path.isdir("5.文件与IO"))
# 想要知道islink的快捷方式指向的地址可以使用realpath方法
print(os.path.realpath("5.文件与IO"))
# os.path模块可以解决大部分路径问题包括切片、判断、拼接等唯一注意的就是记得给python程序访问路径的权限
# 如果要得到大小和修改日期,也有如下解决方案:
os.path.getsize("5.文件与IO/1.somefile.txt")
os.path.getmtime("5.文件与IO/1.somefile.txt")

View File

@@ -0,0 +1,9 @@
from os import listdir
if __name__ == '__main__':
# 如果想要得到路径下所有文件的列表那么我们可以使用listdir方法
print(listdir("5.文件与IO"))
# listdir函数返回一个文件列表
print(type(listdir()))

View File

@@ -0,0 +1,9 @@
import sys
if __name__ == "__main__":
# 默认情况下,文件名是根据系统编码来进行编码的
print(sys.getdefaultencoding())
# 如果你想要无视这种编码规则,可以使用字节串来指定文件名
with open(b'test.txt', 'w') as f:
print(f.read())

View File

@@ -0,0 +1,14 @@
if __name__ == "__main__":
# 有时候,可能会出现一些标准情况下打印会出现问题的文件名,他们不遵循系统的默认编码方式
# 这时候如果print这些文件名那么py会因为无法解码而将字符映射到一个代理编码表显然print无法处理这些代理为空的新建编码
# 解决的方案是建一个转换函数
def bad_filename(filename):
return repr(filename)[1: -1]
name = ''
try:
print(name)
except UnicodeEncodeError:
print(bad_filename(name))

View File

@@ -0,0 +1,40 @@
import urllib.request
import io
import gzip
import requests
if __name__ == "__main__":
req = urllib.request.Request('http://www.python.org/')
# 网页返回有时候会被压缩,用这句话让服务器帮我们解压完发过来,别给.gz
req.add_header('Accept-Encoding', 'gzip,deflate')
req.AutomaticDecompression='DecompressionMethods.GZip'
u = urllib.request.urlopen(req)
# 如果想将u以utf-8的方式添加编码可以使用io.TextIOWrapper对它进行封装
text = io.TextIOWrapper(u, encoding='utf-8')
print(text.read(10))
# 如果文件已经以文本形式打开,想要更换编码层,可以先将原有的编码层移除并替换
text = io.TextIOWrapper(text.detach(), encoding='latin-1')
print(text.read(10))
# Python打开文件时将文件分为三层源文件、源文件的二进制缓存buffer和解码器
f = open("5.文件与IO/1.somefile.txt", 'rt')
# 解码器层
print(f)
# 二进制缓存
print(f.buffer)
# 源文件
print(f.buffer.raw)
f.close()
# 如果想要改变decoder最好的办法就是使用detach()函数返回上一层的buffer然后再用io.TextIOWraper封装
f = open("5.文件与IO/1.somefile.txt", 'rt')
print(f)
b = f.detach()
print(b)
# 返回buffer层后再对buffer重编码
new = io.TextIOWrapper(b, encoding='latin-1', errors='xmlcharrefreplace')
print(new)

1
5.文件与IO/17.try.txt Normal file
View File

@@ -0,0 +1 @@
cakae

View File

@@ -0,0 +1,12 @@
import io
if __name__ == "__main__":
file = "5.文件与IO/17.try.txt"
# 上一章我们知道了文件打开后都长什么样子想要往文件里写字节数据怎么办直接往buffer里怼就完了、
# 这样可以绕过文件的编码层
f = open(file, "w")
f.buffer.write(b"write")
f.close()

View File

@@ -0,0 +1,10 @@
import os
if __name__ == "__main__":
# open函数除了可以对文件对象进行操作以外也可以打开一些由系统创建的文件描述符
fd = os.open("5.文件与IO/17.try.txt", os.O_WRONLY | os.O_CREAT)
# 当文件被关闭时,这些由系统创建的IO管道也会随之关闭
f = open(fd, 'wt')
f.write("ca")
f.close()

View File

@@ -0,0 +1,27 @@
from tempfile import TemporaryFile, NamedTemporaryFile, TemporaryDirectory
from bottle import delete
if __name__ == '__main__':
with TemporaryFile('w+t') as f:
f.write("hello")
f.write("temp_file")
f.seek(0)
data = f.read()
print(data)
print(f.closed)
# 如果想要对临时文件命名,使用NamedTemporaryFile,如果不想文件或文件夹在关闭后自动删除,请使用delete=False
# 跑完记得手动干掉它
with NamedTemporaryFile('w+t', delete=False) as f:
print("file name is : " + f.name)
# 你甚至可以创建一个临时文件夹
with TemporaryDirectory() as d:
print(d)
# 对临时文件,可以指定前缀后缀和文件夹,记住,文件夹一定要真的存在
with NamedTemporaryFile(prefix="PPP", suffix=".txt", dir=d) as f:
print("file name is : " + f.name)

View File

@@ -0,0 +1 @@
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

View File

@@ -0,0 +1,10 @@
if __name__ == "__main__":
# 如果想要将东西输出到文件中可以在print函数中指定file字段
# print函数的默认结尾是\n如果想要替换这个默认结尾可以在end字段设置
path = r"5.文件与IO/2.somefile.txt"
with open(path, "at") as f:
for i in range(10):
print(i, file=f, end=' ')
print("Done")

View File

@@ -0,0 +1 @@
# 这部分是硬件通信相关内容,先不学

BIN
5.文件与IO/21.test.bin Normal file

Binary file not shown.

View File

@@ -0,0 +1,23 @@
import pickle
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
if __name__ == '__main__':
# 对于一般的程序来说,可以使用pickle作为对象的序列化器
a = Person('a', 20)
file = open("5.文件与IO/21.test.bin", 'wb')
# 将序列化对象a写入file
pickle.dump(a, file)
file.close()
file = open("5.文件与IO/21.test.bin", 'rb')
# 从file读出序列化对象进行反序列化
a = pickle.load(file)
print(a.name, a.age)
# 值得一提的是,正在运行的线程被pickle打断后,会保存当前的状态,
# 当线程再次从文件中被读取,会继续之前的进度

View File

@@ -0,0 +1,8 @@
if __name__ == "__main__":
# 这是普通的打印
print(1,2,3)
# 想要使用分隔符来隔开数字可以在sep字段设置分隔符
print(1,2,3, sep="..")

Binary file not shown.

View File

@@ -0,0 +1,43 @@
from base64 import decode
def write_bin_file(bin_path):
with open(bin_path, 'wb') as f:
f.write(b'Hello BinFile')
if __name__ == "__main__":
path = "5.文件与IO/4.bin_file.bin"
write_bin_file(path)
# 如果想要打开二进制文件,那就需要做'rb'模式
with open(path, 'rb') as f:
print(f.read())
# 在打印的时候也有差异要记得先utf-8转码不然出来的是ascii
a = b'Hello BinFile'
for i in a:
print(i, end=' ')
print()
for i in a.decode('utf-8'):
print(i, end='')
print()
# C语言结构体和数组这种自带缓冲区接口的东西可以直接读写文件而不用先用encoder编码
import array
a = array.array('i', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 往文件里写array
with open(path, 'wb') as f:
f.write(a)
# 直接把bin array从文件里薅出来塞到b的缓冲区
b = array.array('i', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
with open(path, 'rb') as f:
f.readinto(b)
print(b)
# 但是这么干有风险,要谨慎应对

View File

@@ -0,0 +1 @@
missing file

View File

@@ -0,0 +1,17 @@
if __name__ == "__main__":
# 如果想要将数据写入一个已经不在文件系统中的文件可以使用open函数的x模式
try:
path = "5.文件与IO/4.bin_file.bin"
with open(path, 'xt') as f:
f.write("missing file")
# 可以看到,这个写入报了一个文件已存在的错误,如果我们用一个不存在的文件,那就会创建一个新文件成功写入
except FileExistsError:
path = "5.文件与IO/5.missing_file.bin"
with open(path, 'xt') as f:
f.write("missing file")
# 如果需要写入二进制文件同理使用xb就行

View File

@@ -0,0 +1,26 @@
import io
if __name__ == '__main__':
# io库里的StringIO和BytesIO提供了两个模拟文件的方法本质应该是在内存里整了块缓冲区
# StringIO提供了对字符串的虚拟IOBytesIO则对应字节串
# 这两个东西的操作和文件操作别无二致,就是不需要打开
s = io.StringIO()
b = io.BytesIO()
s.write("Hello_String_IO\n")
b.write(b'Hello BytesIO')
print("This is POWER!!!!!", file=s, end='')
print(s.getvalue())
s.seek(0)
print(s.read(4))
s.seek(0)
print(s.read())
print(b.getvalue())
b.seek(0)
print(b.read(4))
print(b.read())

View File

@@ -0,0 +1,18 @@
import gzip, bz2
if __name__ == "__main__":
# 如果想要读写.gz和.bz2后缀的压缩文件请使用上述两个包
with gzip.open("file.gz", 'rt') as f:
text = f.read()
with bz2.open("file.bz2", 'rt') as f:
text2 = f.read()
# 同样的如果写入可以使用wt和wb来进行这些包里的open函数支持和open函数相同的操作
# 如果想要增加压缩比那就需要调整compresslevel参数最高是默认9调低它以获取更高的性能
# 这些函数还支持对二进制打开的压缩文件做类似的管道操作
f = open("somefile.gz", 'rb')
with gzip.open(f, 'rt') as g:
text3 = g.read()

Some files were not shown because too many files have changed in this diff Show More