DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • python面向过程

    • Python语言介绍
    • 基本运算符和流程控制
    • 数据类型之序列
    • 数据类型之哈希
    • 函数基础
    • 函数高级
    • 函数进阶
    • 文件处理
    • 必用模块
    • 常用模块
    • 模块导入与包
    • 开胃小菜
    • 饶头训练
      • 数据构建与解析
        • 筛选数据
        • 元组元素命名
        • 字典排序
        • 元素频度
        • 字典公共键
        • 字典无序
        • 可迭代对象切片
        • 历史记录功能
      • 字符串处理
        • 拆分字符串
        • 调整文本格式
        • 拼接字符串
        • 字符串对齐
        • 去除字符
      • 迭代与反迭代
        • 抓取城市气温
        • 查找素数
        • 浮点数发生器
        • 并行与串行
    • 小项目之ATM_shopping
  • python面向对象

  • 网络并发编程

  • 不基础的py基础

  • 设计模式

  • python_Need
  • python面向过程
DC
2023-09-08
目录

饶头训练

列表、字典、集合解析
sorted的key参数
from itertools import islice
from collections import namedtuple
from collections import Counter
from collections import OrderedDict
from collections import deque
from collections import Iterable, Iterator ,Generator

from functools import reduce
re.split()
re.sub()
my_str.join()
my_str.maketrans()  my_str.translate()

反迭代协议 __reversed__
from decimal import Decimal
from itertools import chain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 数据构建与解析

# 筛选数据

列表、字典、集合生成式 
过滤列表中的负数
取出字典中的值大于90的键值对
取出集合中能被3整除的数

△方案一: 列表解析、字典解析、集合解析
△方案二: filter

from random import randint

data_list = [randint(-10, 10) for _ in range(10)]
data_dict = {f'student{i}': randint(60, 100) for i in range(1, 20)}
data_set = {randint(0, 20) for _ in range(20)}

# -- 列表
[x for x in data_list if x >= 0]
filter(lambda x: x >= 0, data_list)
# -- 字典
{k: v for k, v in data_dict.items() if v > 90}
filter(lambda x: x[1] > 90, data_dict.items())
# -- 集合
{x for x in data_set if x % 3 == 0}
filter(lambda x: x % 3 == 0, data_set)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 元组元素命名

如何 为元组中的每个元素命名 ,提高程序的可读性?
对于格式固定的数据, 我们通常可以使用元祖来存储
比如某个学生信息系统, 其中每个学生的格式都是确定的(名字、年龄、性别、邮箱)
('Jim',16,'male',[email protected])

1> 使用元祖的 优点 : 节省空间!!! 存储相同的数据, 使用元祖比使用字典开销会小很多!
2> 使用元祖的 缺点 : 访问的时候, 我们需要使用索引(index)访问, 大量索引降低程序可读性.
                                   因为它不知道元组中每个字段的含义.

使用 collections.namedtuple 替代内置tuple
(还可以定义一系列数值常量或枚举类型来解决..但不推荐 略)

使用标准库collections下的一个命名元祖namedtuple: 即为元祖的每个字段起名字 
它是一个类的工厂, 可以创建出一种元祖的子类, 它其中的每个字段是有名字的
     第一个参数: 为命名元祖起个名字
     第二个参数: 可以传入一个列表, 包含了命名元祖中每个字段的名字
     return: 返回一个类, 元祖的子类

In [27]: from collections import namedtuple
# -- namedtuple()可以看作是一个类; student0是namedtuple()()的实例化, 
In [28]: student0 = namedtuple('Stu0',['name','age','sex','email'])('xiaoming',
    ...: 16,'man','[email protected]')

In [29]: student0
Out[29]: Stu0(name='xiaoming', age=16, sex='man', email='[email protected]')

In [30]: student0[0]
Out[30]: 'xiaoming'

In [38]: student0.name
Out[38]: 'xiaoming'
1
2
3
4
5
6
7
8
9
10
11
12
13

# 字典排序

根据字典中值的大小对字典中的项进行排序,并加上排名
{'c': (1, 95), 'd': (2, 91)}

传递sorted函数的 key 参数.

from random import randint

data = {i: randint(60, 100) for i in 'abcdefg'}

temp = sorted(data.items(), key=lambda item: item[1], reverse=True)
# -- 等同于 {items[0]: (index, items[1]) for index, items in enumerate(temp, 1)}
res = {k: (index, v) for index, (k, v) in enumerate(temp, 1)}
print(res)

# -- 在原字典上,加上排名
for index, (k, v) in enumerate(temp, 1):
    data[k] = (index, v)
    
"""
Ps: sorted(zip(data.values(), data.keys()))
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 元素频度

统计序列中元素的频度并排序
1.某随机序列[12,5,6,4,6,5,5,7]中, 找到出现次数最高的3个元素, 它们出现的次数是多少?
2.对于某英文文章的单词, 进行词频统计, 找到出现次数最高的10个单词, 它们出现次数是多少?

△方案一: 将序列转换为字典 {元素:频度} ,根据字典中的值排序
△方案二: 使用标准库 collections 中的 Counter对象
Ps: 方案一,若列表很大只找前三个,对整个列表排序很浪费, 这时候可以使用堆 import heapq

"""
★ --方案一
"""
from random import randint

data = [randint(0, 20) for _ in range(30)]
# -- 对data数据去重后作为字典的键,每个键的值都默认为0
d = dict.fromkeys(data, 0)
# -- 注意一点 字典的键是唯一的 所以要达到预定效果就不能对d进行循环.
for i in data:
    d[i] += 1

sorted(d.items(), key=lambda item: item[1], reverse=True)[:3]
# -- 改变键值顺序,通过元祖进行比较 好别扭
# sorted([(v, k) for k, v in d.items()], reverse=True)[:3]
sorted(((v, k) for k, v in d.items()), reverse=True)[:3]


"""
★ --方案二
"""
from collections import Counter
from random import randint

data = [randint(0, 20) for _ in range(30)]
# -- Counter就相当于一个频度字典
# -- 类似于这样 => Counter({7: 2,0: 1,10: 1,4: 1,16: 2,...,9: 2}
c = Counter(data)
# -- 取出频度最高的前3个数字
res = c.most_common(3)
print(res)  # -- [(0, 6), (20, 3), (4, 3)]


"""
★ --文本词频统计
"""
import re
from collections import Counter
# -- 读取文件
txt = open('example.txt').read()
# -- 使用正则将词全部切分出来,可以得到一个词的列表
word_list = re.split('\W+', txt)
c2 = Counter(word_list)
# -- 取出文本中出现频度前10的单词
c2.most_common(10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 字典公共键

快速找到多个字典中的公共键
实际案例:
     西班牙足球甲级联赛, 每轮球员进球统计:
     第一轮: {'苏亚雷斯': 1, '梅西': 2, '本泽马':1,...}
     第二轮: {'苏亚雷斯': 2, 'C罗': 2, '格里兹曼': 2,…}
     第三轮: {'苏亚雷斯': 1, '托雷斯': 2, '贝尔': 1,…}
     …… .... ....
     统计出前N轮, 每场比赛都有进球的球员

△方案一: 可以使用循环
△方案二: map(得到T or F)+all+列表推导式
△方案三: 对于大量的字典, 我们通常利用集合的 交集操作获取字典的公共键

from random import randint, sample

# -- 假设每轮有3~6人进球,每个人进球的数目1~4个
d1 = {k: randint(1, 4) for k in sample('abcdefgh', randint(3, 6))}
d2 = {k: randint(1, 4) for k in sample('abcdefgh', randint(3, 6))}
d3 = {k: randint(1, 4) for k in sample('abcdefgh', randint(3, 6))}


"""
★ --方法一:用for循环 看d1字典中的项是否在其余两个字典中
    缺点: 面对实际问题,我们并不知道一共会有多少轮
"""
[k for k in d1 if k in d2 and k in d3]


"""
★ --方法二:map+all
    直接对字典循环,循环打印出的是字典的键
    可以通过 'd' in {'d': 2, 'a': 2} 这种方式判断字典中是否有这个键
    `all([True,1]) =>  True`; `all([True,0]) => False`
"""
# -- [k for k in d_list[0] if all(map(lambda item:k in item,d_list[1:]))]
d_list = [d1, d2, d3]
my_list = []
for k in d_list[0]:
    # -- all()函数用来判断可迭代参数iterable中的所有元素是否都为TRUE,如果是返回TRUE,否则返回False
    if all(map(lambda item: k in item, d_list[1:])):
        my_list.append(k)
print(my_list)  # -- ['e', 'h', 'g']


"""
★ --方法三:map+reduce
    Step1:使用字典的keys()方法,得到一个字典keys的集合
    Step2:使用map函数,得到每个字典keys的集合
    Step3:使用reduce函数,取所有字典的keys集合的交集
    Ps: `d1.keys()` 等同于 `dict.keys(d1)`

    In [16]: list(map(dict.keys,d_list))
    Out[16]:
    [dict_keys(['f', 'b', 'h', 'g', 'a', 'c']),
     dict_keys(['g', 'f', 'a']),
     dict_keys(['f', 'h', 'g', 'c', 'a', 'e'])]
"""
from functools import reduce

d_list = [d1, d2, d3]
res = reduce(lambda a, b: a & b, map(dict.keys, d_list))
print(res)  # -- {'h', 'g', 'e'}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 字典无序

解决python3.6以前字典无序的问题

使用标准库collections中的OrderedDict. 以OrderedDict替代内置字典Dict. 用法与字典一样!!

from collections import OrderedDict
from random import shuffle

players = list('abcdefgh')
shuffle(players)  # 打乱players -- ['f', 'e', 'g', 'd', 'b', 'c', 'h', 'a']

od = OrderedDict()
for i, p in enumerate(players, 1):
    od[p] = i

# -- 写一个接口,根据名字查询排名
def query_by_name(d, name):
    return d[name]

query_by_name(od, 'c')  # 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 可迭代对象切片

提一嘴, 切片的实质是重载了 __getitem__ 方法

使用标准库 itertools 中的 islice.
注意哦, 使用islice对字典切片,切的是key值.. islice返回的是一个迭代器 

from itertools import islice
from collections import Iterable, Iterator ,Generator
# -- islice(iterable,start,stop[,step]) 

"""
★ --islice返回的是一个迭代器
"""
print(list(range(10)[3:6]))  # [3, 4, 5]
train = islice(range(10), 3, 6)
# -- <class 'itertools.islice'> [3, 4, 5]
print(type(train), list(train))
# -- False True True
print(isinstance(train,Generator),isinstance(train,Iterable),isinstance(train,Iterator))


"""
★ --使用islice对字典切片,切的是key值
"""
my_dict = dict.fromkeys([i for i in 'abcde'], 0)
print(my_dict)  # -- {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0}
print(list(islice(my_dict, 3)))  # -- ['a', 'b', 'c']
print(list(islice(my_dict, 1, 3)))  # -- ['b', 'c']


"""
★ --使用islice对文件切片
"""
# -- 这个日志文件一共有70行
f = open('/var/log/wifi.log')
# -- 若通过`f.readlines()[10:20]`获取到行的列表,再对此进行切片,可行
#    但readlines()会先将文件所有内容读取到内存中,如果日志文件很大,就很不友好.
f.readlines()[10:20]
# -- islice在这里实际上读了20行 前10行扔掉
for line in islice(f, 10, 20):
    print(line)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 历史记录功能

需求: 制作一个简单的猜数字的小游戏, 添加历史记录功能, 显示用户猜过的数字..

1> 使用标准库 collections 中的 deque ,它是一个双端队列.
双端队列, 左右两端都可以进行出队和入队操作的队列;
(通常历史记录是有限度的,不能无限存储),使用容量为n的队列存储历史记录
2> 使用pickle模块将历史记录存到硬盘,以便下次启动使用
因为这个队列是在内存当中的,程序退出后,历史记录就消失了.

from collections import deque
# -- 第一个参数: 对队列进行初始化
#    第二个参数: 队列的容量,不传默认队列无限大
q = deque([], 5)
# -- 入队操作有两个方法   q.append右端入队;q.appendleft左端入队
# -- 出队操作有两个方法   q.pop右端出队;q.popleft左端出队
q.append(1)
q.append(2)
q.append(3)
q.append(4)
q.append(5)
print(q) # deque([1, 2, 3, 4, 5], maxlen=5)
q.append(6)
# -- 容量满了,会将1自动弹出去
print(q) # deque([2, 3, 4, 5, 6], maxlen=5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

猜数字实现:

from random import randint
from collections import deque


def guess(n, k):
    # n是系统随机数,k是用户猜的数字
    if n == k:
        print('猜对了,这个数字是%d.' % k)
        return True
    if n < k:
        print('猜大了,比%d小.' % k)
    elif n > k:
        print('猜小了,比%d大.' % k)
    return False


def main():
    n = randint(1, 100)
    i = 1
    hq = deque([], 5)

    while True:
        line = input('[%d] 请输入一个数字:' % i)
        # -- isdigit()判断输入的是否是数字
        if line.isdigit():
            k = int(line)
            hq.append(k)
            i += 1
            # -- 猜对了guess()返回True,程序退出;猜错了,继续猜.
            if guess(n, k):
                break
        elif line == 'quit':
            break
        # -- 添加一个查询历史记录的接口
        elif line == 'h?':
            print(list(hq))

if __name__ == '__main__':
    main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

永久存储

# -- 使用pickle模块将历史记录存到硬盘,以便下次启动使用
import pickle
# -- dump()可以将一个python对象导入到文件中去
#    第一个参数:python对象
#    第二个参数:文件对象
#    注意存取操作都必须是二进制
pickle.dump(q, open('save.pkl', 'wb'))
# -- 取出
q2 = pickle.load(open('save.pkl', 'rb'))
print(q)  # -- q: deque([2, 3, 4, 5, 6], maxlen=5)
print(q2) # -- q2: deque([2, 3, 4, 5, 6], maxlen=5)
1
2
3
4
5
6
7
8
9
10
11

# 字符串处理

# 拆分字符串

有这样一字符串, 'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz', 如何根据分隔符 ; , | \t 进行拆分?

△方案一: 连续使用str.split()方法,每次只能处理一种分隔号, 需降维处理
             map()+str.split()
             sum()+str.split()
             reduce()+map()+sum()+str.split()
△方案二: 使用正则表达式的 re.split() 方法 
PS: 处理一个分隔符的时候使用方法一(一个的时候,方法二会比一慢);多个分隔符的时候使用方法二

"""
★  --方案一
   说实话,有点复杂啦,但推导后加深了我对map、reduce、sum这些高阶函数的理解!!!这1个半小时没白花!
"""
▲ 理论验证  map()+str.split()  sum()+str.split()
>>> s = 'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz'
# -- [['ab'], ['cd', 'efg', 'hi,jkl', 'mn\topq'], ['rst,uvw\txyz']]
>>> temp = [i.split('|') for i in s.split(';')]
>>> t = []
# -- list(map(lambda x: t.extend(x),temp))
>>> list(map(t.extend,temp))
[None, None, None]  # -- 注意,t.extend的返回值为None
>>> t
['ab', 'cd', 'efg', 'hi,jkl', 'mn\topq', 'rst,uvw\txyz']
>>> sum(temp,[])  # -- 相当于 []+['ab', 'cd']+['efg'] ==> ['ab', 'cd', 'efg'] 
['ab', 'cd', 'efg', 'hi,jkl', 'mn\topq', 'rst,uvw\txyz']

# -- 说实话,效率战且不谈,挺难一眼看出逻辑的
# -- 这里注意个细节,`res = [s]`,首先将字符串放进了一个列表里
#    是为了后面map()映射函数,作用的是列表里的整个字符串,而不是字符串里的每一个字符
s = 'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz'
def my_split(s, seps):
    res = [s]
    """
    for循环可以改写为:
    for sep in seps:
        res = sum(map(lambda ss: ss.split(sep), res), [])
    """
    for sep in seps:
        t = []
				# 举个例子: res=['ab,cd;efg'] map取到里面的元素'ab,cd;efg'赋值给ss 
        #          'ab,cd;efg'.split(',')得到结果['ab','cd;efg']
        #          t.extend(['ab','cd;efg']) 并将t赋值给res
        #          同理,['ab','cd;efg']经过map加工,会依次执行
        #          t.extend('ab'.split(';')) t.extend('cd;efg'.split(';'))
        #          再将t赋值给res,以此类推
        list(map(lambda ss: t.extend(ss.split(sep)), res))
        res = t
    return res
print(my_split(s, ',;|\t'))


▲ 理论验证  reduce()+map()+sum()+str.split()
纯粹复杂化了!一点都不Effective  ╮( ̄▽ ̄"")╭ 客官,图个乐吧

# -- reduce函数, 将字符串放进列表作为其匿名func的data参数的初始值, sep参数先得到值',' 
# -- [使用map函数取元素进行分割,分割会生成列表,再使用sum函数取列表元素操作..] 
#    <保证是在对元素级别进行操作> 因为map是迭代器,所以会一边map一边sum
# -- 将得到的结果再给匿名func的参数data, sep参数获得新的值';'
from functools import reduce
# 举个例子:data的初始值为['ab,cd;efg'] 将其用map进行加工 
#         map是一个迭代器,取data中的元素'ab,cd;efg'开始分割,
#         注意此元素是不可变对象,对其加工不会对原data造成任何影响!!!!
#         split返回的是一个列表['ab','cd;efg'],sum函数对其进行操作 []+['ab','cd;efg']
#         将结果扔/赋值给reduce的data,此时data为['ab','cd;efg']
#         同样的用map对其进行加工,一边加工一边sum,即依次执行
#         []+['ab'] ['ab']+['cd','efg'] 将最后结果['ab','cd',efg']扔给reduce的data
reduce(lambda data, sep: sum(map(lambda ss: ss.split(sep), data), []), ',;|\t',[s])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
"""
★  --方案二
"""
import re
s = 'ab;cd|efg|hi,jkl|mn\topq;rst,uvw\txyz'

# + 代表一个或者多个
res = re.split('[;,|\t]+', s)
# ['ab', 'cd', 'efg', 'hi', 'jkl', 'mn', 'opq', 'rst', 'uvw', 'xyz']
print(res)
1
2
3
4
5
6
7
8
9
10

# 调整文本格式

某log日志文件. 其中的日期格式为'yyyy-mm-dd'
我们想把其中的日期改为美国日期的格式 'mm/dd/yyyy'
比如: '2016-05-23' ---> '05/23/2016', 应如何处理?

使用正则表达式re.sub() 方法做字符串替换,利用正则表达式的捕获组,捕获每个部分内容,
再替换字符串中调整各个捕获组的顺序

# -- 1.txt
2021-10-14 17:56:11 good good study 2021-09-09 day day up
2021-10-14 17:56:11 believe yourself 
    
import re
with open('1.txt') as f:
    log = f.read()

# -- 使用正则表达式的组()括起我们要提取的三个部分
#    捕获组\2 \3 \1 需要转译
print(re.sub('(\d{4})-(\d{2})-(\d{2})', r'\2/\3/\1', log))
# -- 可以给组命名
re.sub('(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})', r'\g<m>/\g<d>/\g<y>', log)

"""结果如下:
10/14/2021 17:56:11 good good study 09/09/2021 day day up
10/14/2021 17:56:11 believe yourself 
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 拼接字符串

在程序中我们将各个参数按次序收集到列表中:
['<0112>','<32>','<1024x768>','<60>','<1>','<100.0>','<500.0>']
最终我们要把各个参数拼接成一个数据报进行发送.
"<0112><32><1024x768><60><1><100.0><500.0>"

△方案一: 迭代列表,连续使用'+'操作依次拼接每一个字符串 reduce也能办到
    缺点: 过程中创建了大量的字符串,空间时间上有很大浪费
△方案二: 使用str.join()方法, 更加快速的拼接列表中所有的字符串 ✔!!!
    它会一次性的创建内存,一次性的拷贝

"""
★  --方案一
     缺点:过程中创建了大量的字符串,空间时间上有很大浪费
"""
▲ 理论验证 
>>> s1 = 'abcdef'
>>> s2 = '12345'
>>> s1+s2
'abcdef12345'
>>> str.__add__
<slot wrapper '__add__' of 'str' objects>
>>> s1.__add__(s2)
'abcdef12345'
>>> str.__add__(s1,s2)
'abcdef12345'

my_list = ['<0112>', '<32>', '<1024x768>', '<60>', '<1>', '<100.0>', '<500.0>']
result = ""
for item in my_list:
    result += item

# <0112><32><1024x768><60><1><100.0><500.0>
print(result)

# -- 简写
from functools import reduce
# <0112><32><1024x768><60><1><100.0><500.0>
print(reduce(str.__add__, my_list))

"""
★  --方案二
"""
>>> ''.join(['<0112>','<32>','<1024x768>','<60>','<1>','<100.0>','<500.0>'])
'<0112><32><1024x768><60><1><100.0><500.0>'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 字符串对齐

某个字典存储了一系列属性值
{
     "lodDist":100.0,
     "SmallCull":0.04,
     "DistCull":500.0,
     "trilinear":40,
     "farclip":477,
}
在程序中,我们想以工整的格式将其内容输出, 如何处理?
SmallCull:0.04,
farclip :477,
lodDist :100.0,
DistCull :500.0,
trilinear:40,

首先max + map算出len(key)的最大值 便于对齐.
△方案一: 使用字符串的str.ljust(), str.rjust(), str.center()进行左,右,居中对齐
△方案二: 使用format()方法,传递类似'<20','>20','^20'参数完成同样任务

d = {
    "lodDist": 100.0,
    "SmallCull": 0.04,
    "DistCull": 500.0,
    "trilinear": 40,
    "farclip": 477,
}

w = max(map(len, d.keys()))
for k, v in d.items():
    print(k.ljust(w), ':', v)

'''
lodDist   : 100.0
SmallCull : 0.04
DistCull  : 500.0
trilinear : 40
farclip   : 477
'''
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 去除字符

1.过滤掉用户输入中前后多余的空白字符 2.过滤某windows下编辑文本中的'\r'(window下的换行符是\r\n;linux下只需要一个\n) 'hello world\r\n'

△方法一: 字符串strip(), lstrip(), rstrip()方法去掉字符串两端多种字符
△方法二: 删除单个固定位置的字符,可以使用切片然后拼接的方式
△方法三: 字符串中的替换方法replace()方法或正则表达式的re.sub()替换方法,替换成空字符串
△方法四: 字符串的 translate() 方法-它可以将一种字符映射到另外一种字符上,达到同时删除多种不同字符

>>> s3 = '    abc  xyz    '
>>> s3.replace(' ','')
'abcxyz'
>>> s3 = '  \t  abc  \t  xyz  \n  '
>>> s3.replace(' ','').replace('\t','').replace('\n','')
'abcxyz'
>>> import re
>>> re.sub('[ \t\n]+','',s3)
'abcxyz'
>>> re.sub('\s+','',s3)
'abcxyz'

"""
★  --
translate() 允许传入一个映射表,根据映射表做替换
映射表的形式可以是一个字典 {unicode值:unicode值或字符串}

maketrans() 方便我们做映射表
"""
>>> s = 'abc1234xyz'
>>> s.translate({ord('a'):'X'})
'Xbc1234xyz'
>>> s.translate({ord('a'):'X',ord('b'):'Y'})
'XYc1234xyz'
>>> s.maketrans('abcxyz','XYZABC')
{97: 88, 98: 89, 99: 90, 120: 65, 121: 66, 122: 67}
>>> s.translate(s.maketrans('abcxyz','XYZABC'))
'XYZ1234ABC'
# -- 只要键值对的值为none就可以删除掉它!!!
>>> s.translate({ord('a'):None})
'bc1234xyz'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 迭代与反迭代

# 抓取城市气温

某软件要求, 从网络抓取各个城市气温信息, 并依次显示:
北京: 15~20
天津: 17~22
长春: 12~18
... ... ...
如果依次抓取所有城市气温再显示, 显示第一个城市气温时, 有很高的延时, 并且浪费存储空间.
我们期望以"用时访问"的策略, 能把所有城市气温封装到一个对象里, 可用for语句进行迭代.

△方案一: 实现一个迭代器对象 , __next__ 方法每次返回一个城市的信息
△方案二: 实现一个可迭代对象 , __iter__ 方法返回一个生成器对象

# -- 可迭代对象和迭代器对象的基类. 我们可以不用继承它们.自己用魔法方法构建.
from collections import Iterable, Iterator 
"""
★  --方案一
"""
import requests

class WeaterIterator():
    def __init__(self, citys):
        self.citys = citys
        # 用于手工维护整个迭代器的状态
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == len(self.citys):
            raise StopIteration
        city = self.citys[self.index]
        self.index += 1
        return self.get_weather(city)

    def get_weather(self, city):
        url = "http://www.jcznedu.com:5000/weather/now/?city=" + city
        r = requests.get(url)
        # -- r.json()返回结果的json对象
        data = r.json()["data"]["now"]
        # -- 城市、温度、湿度
        return city, data['temperature'], data['humidity']

def show(w):
    for x in w:
        print(x)

if __name__ == "__main__":
    w = WeaterIterator(['北京', '上海', '广州'])
    print(w.__next__())
    print(w.__iter__())
    show(w)

# ('北京', 28.3, 39.0)
# <__main__.WeaterIterator object at 0x7f9e9ce8eaf0>
# ('上海', 20.2, 99.0)
# ('广州', 33.0, 53.0)


"""
★  --方案二
"""
import requests

class Weater():
    def __init__(self, citys):
        self.citys = citys

    def __iter__(self):
        for city in self.citys:
            yield self.get_weather(city)

    def get_weather(self, city):
        url = "http://www.jcznedu.com:5000/weather/now/?city=" + city
        r = requests.get(url)
        data = r.json()["data"]["now"]
        return city, data['temperature'], data['humidity']

if __name__ == "__main__":
    w = Weater(['北京', '上海', '广州'])
    # -- for循环的时候,会调用w对象重写的__iter__方法,里面有yield关键字
    #    w.__iter__()得到一个迭代器 for循环再不断__next__取值
    #    print(w.__iter__().__next__())
    # print(type(w.__iter__()))  # <class 'generator'>
    for x in w:
        print(x)
# ('北京', 28.5, 39.0)
# ('上海', 20.2, 100.0)
# ('广州', 33.1, 51.0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

# 查找素数

实现一个可迭代对象的类,它能迭代出给定范围内所有素数:
     质数即素数.指在大于1的自然数中,只能被1和自身整除的自然数

pn = PrimeNumbers(1,30)
print([k for k in pn])
输出结果:
[2,3,5,7,11,13,17,19,23,29]

△方案一: for循环得到迭代器对象
△方案二: for循环得到生成器对象

"""
★  --方案一
"""
class PrimeNumbers:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __iter__(self):
        return self

    def __next__(self):
        if self.a < self.b + 1:
            if self.is_prime(self.a):
                index = self.a
                self.a += 1
                return index
            self.a += 1
        else:
            raise StopIteration

    def is_prime(self, k):
        # -- 5%2 5%3 5%4 都有余数,证明5就是质数
        return False if k < 2 else all(map(lambda x: k % x, range(2, k - 1)))

pn = PrimeNumbers(1, 30)
for n in pn:
    if n != None:
        print(n, end=' ')

        
"""
★  --方案二
"""
from inspect import isgenerator

class PrimeNumbers:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __iter__(self):
        for k in range(self.a, self.b + 1):
            if self.is_prime(k):
                yield k

    def is_prime(self, k):
        # -- 不会有浪费, all碰到一个假就会返回False
        return False if k < 2 else all(map(lambda x: k % x, range(2, k - 1)))

pn = PrimeNumbers(1, 30)
# -- 这里它变成了生成器 `yield k` k是next()函数的返回值.
print(isgenerator(iter(pn)))  # True

for n in pn:
    print(n, end=' ')  # -- 2 3 5 7 11 13 17 19 23 29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

# 浮点数发生器

实现一个连续浮点数发生器FloatRange(和range类似),
根据给定的范围(start,end)和步进值(step)产生一系列连续浮点数,
如迭代FloatRange(3.0,4.0,0.2) 可产生序列:

正向: 3.0 -> 3.2 -> 3.4 -> 3.6 -> 3.8 -> 4.0
反向: 4.0 -> 3.8 -> 3.6 -> 3.4 -> 3.2 -> 3.0

解决方案: 实现反向迭代协议的 __reversed__ 方法,它返回一个反向迭代器.

reversed()方法的本质是序列的底层实现了__reversed__ 方法

>>> a = [1,2,3]
>>> reversed(a)
<list_reverseiterator object at 0x7ff5b973f2b0>  # -- 得到一个反向迭代器
>>> reversed(a).__next__()
3

>>> iter(a)
<list_iterator object at 0x7ff5b97a4700>  # -- 得到一个正向迭代器
1
2
3
4
5
6
7
8

浮点数的误差

>>> from decimal import Decimal
>>> Decimal('0.1')*3
Decimal('0.3')
>>> 0.1*3
0.30000000000000004
>>> Decimal('0.2')+Decimal('0.3')  # -- 有些浮点数存在误差,为了避免,先把浮点数转换为字符串
Decimal('0.5')
>>> float(Decimal('0.2')+Decimal('0.3'))
0.5
# -- 2.675保留两位小数四舍五入结果是2.67而不是2.68,因为2.675在内部的存储值是2.647999999..
>>> round(2.675,2)
2.67
1
2
3
4
5
6
7
8
9
10
11
12

连续浮点数发生器代码如下:

from decimal import Decimal  # -- py标准库中专门处理十进制浮点数的库

class FloatRange:
    def __init__(self, a, b, step):
        # -- 使用实例属性维护传入的这几个参数
        self.a = Decimal(str(a))
        self.b = Decimal(str(b))
        self.step = Decimal(str(step))

    def __iter__(self):
        t = self.a
        while t <= self.b:
            yield float(t)
            t += self.step

    def __reversed__(self):
        t = self.b
        while t >= self.a:
            yield float(t)
            t -= self.step

fr = FloatRange(3.0, 4.0, 0.2)
for x in fr:
    print(x)

print('-' * 10)

for x in reversed(fr):
    print(x)
    
"""
3.0
3.2
3.4
3.6
3.8
4.0
----------
4.0
3.8
3.6
3.4
3.2
3.0
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 并行与串行

在for语句中迭代多个可迭代对象

(并行) 某班学生期末考试成绩,语文、数学、英语分别存储在三个列表中
     同时迭代三个列表,计算每个学生的总分.
(串行) 某年级有4个班,某次考试每班英语成绩分别存储在4个列表中
     依次迭代每个列表统计全学年成绩高于90分人数.

并行: 使用内置函数zip,它能将多个迭代对象合并,每次迭代返回一个元祖.
串行: 使用标准库中的itertools.chain ,它能将多个可迭代对象连接.

"""
★  --并行
"""
▲ 数据准备
from random import randint

chinese = [randint(60, 100) for _ in range(20)]
math = [randint(60, 100) for _ in range(20)]
english = [randint(60, 100) for _ in range(20)]

▲ 四种方式皆可
t1 = []
for s1, s2, s3 in zip(chinese, math, english):
    t1.append(s1 + s2 + s3)
    
t2 = [sum(s) for s in zip(chinese, math, english)]
t3 = list(map(sum, zip(chinese, math, english)))
t4 = list(map(lambda s1, s2, s3: s1 + s2 + s3, chinese, math, english))
# -- Ps: map实现zip函数的效果
#    list(map(lambda *args: args, chinese, math, english))
#    list(zip(chinese, math, english))


"""
★  --串行
"""
from itertools import chain
from random import randint

for x in chain([1, 2, 3], [4, 5], [6, 7]):
    print(x,end=" ")  # -- 1 2 3 4 5 6 7

c1 = [randint(60, 100) for _ in range(20)]
c2 = [randint(60, 100) for _ in range(22)]
c3 = [randint(60, 100) for _ in range(25)]

len([x for x in chain(c1, c2, c3) if x > 90])


"""
★  --体验下*拆包与chain的作用
     OS:说实话,这种技巧.. -_- 无语子.
"""
>>> from itertools import chain
>>> from functools import reduce
>>> s = 'abc;123|xyz;678|fweuow\tjzka'
>>> s.split(';')
['abc', '123|xyz', '678|fweuow\tjzka']
>>> list(map(lambda ss:ss.split('|'),s.split(';')))
[['abc'], ['123', 'xyz'], ['678', 'fweuow\tjzka']]
>>> list(chain(*[['abc'], ['123', 'xyz'], ['678', 'fweuow\tjzka']]))
['abc', '123', 'xyz', '678', 'fweuow\tjzka']
# -- reduce(lambda data, sep: sum(map(lambda ss: ss.split(sep), data), []), ',;|\t',[s])
>>> list(reduce(lambda it_s,sep:chain(*map(lambda ss:ss.split(sep),it_s)),';|\t',[s]))
['abc', '123', 'xyz', '678', 'fweuow', 'jzka']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

开胃小菜
小项目之ATM_shopping

← 开胃小菜 小项目之ATM_shopping→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式