【Python实践】Python部分实际案例解答1

据说,看我文章时 关注、点赞、收藏帅哥美女们 心情都会不自觉的好起来。

前言:
作者简介:大家好我是 user_from_future ,意思是 “ 来自未来的用户 ” ,寓意着未来的自己一定很棒~
✨个人主页:点我直达,在这里肯定能找到你想要的~
专栏介绍:Python实践 ,一个专注于分享实际案例的专栏~

专栏文章直链:
【Python实践】关于python多任务设计基础
【Python实践】你可能没有见过的码代码小技巧1
史上最最最没用程序——自写平衡化学方程式
Python进阶——对Python“脚本”的理解与使用
十大排序算法整理(含JavaScript版本与Python版本源码)
从常用实例学习正则2
从常用实例学习正则1
自制小功能——cmd中的规则加密输入
文件目录操作实例2
文件目录操作实例1

人生苦短,我用python

Python部分实际案例解答1

  • 不同进制之间的转换
    • 其他进制转十进制
    • 十进制转其他进制
  • 获取变量内存地址、获取内存地址所指向的变量
    • 了解C语言指针
    • python“使用”指针
    • python垃圾回收
  • 二维数组生成的区别
    • 浅拷贝与深拷贝
  • 从列表中分离奇数和偶数
  • 从列表中提取公共信息转换成字典
  • 模拟有密码输入次数的登录系统
  • 计算1-100内的奇数和、代码执行时间计时
  • 二层列表转单层列表、代码执行时间计时
  • 发扑克小程序

不同进制之间的转换

首先,我们最长看见的是十进制数,所以我们用此作为“桥梁”,连接其他进制。
这里就分两种情况,一个是其他进制转十进制,一个是十进制转其他进制,这样其他进制转其他的其他进制就可以通过十进制中转。

其他进制转十进制

这个比较简单,python的内置函数 int 就能实现:

int("1010011010", base=2)  # 666
int("1232", base=8)  # 666
int("666", base=10)  # 666
int("29a", base=16)  # 666

对于“特殊”进制,二进制、八进制、十进制、十六进制,设置 base0 就会自动识别字符串中的进制,默认为 10

int("0b1010011010", base=0)  # 666
int("0o1232", base=0)  # 666
int("666", base=0)  # 666
int("666")  # 666
int("0x29a", base=0)  # 666

就如这小栗子所示,0b 是二进制的前缀, 0o 是八进制的前缀,0x 是十六进制的前缀,十进制没有前缀。

十进制转其他进制

常用辗转相除法来计算,取余的逆向数字为结果。辗转相除法本来是为了优化更相减损术,用来计算最大公约数的,为什么能用辗转相除法计算呢?慢慢来理解:

【Python实践】Python部分实际案例解答1_第1张图片
先来一段2的指数结果表

  • 20 = 1
  • 21 = 2
  • 22 = 4
  • 23 = 8
  • 24 = 16
  • 25 = 32
  • 26 = 64
  • 27 = 128
  • 28 = 256
  • 29 = 512

再来看看十进制 666 是如何由 2 的指数加起来的:
666 = 1 * 29 + 0 * 28 + 1 * 27 + 0 * 26 + 0 * 25 + 1 * 24 +1 * 23 + 0 * 22 + 1 * 21 + 0 * 20
== 29 + 27 + 24 + 23 + 21


最后看看辗转相除法能得到什么:
666 = 2 * 333 + 0 = 29 + 27 + 24 + 23 + 21
333 = 2 * 166 + 1 = 28 + 26 + 23 + 22 + 20
166 = 2 * 83 + 0  = 27 + 25 + 22 + 21
83  = 2 * 41 + 1  = 26 + 24 + 21 + 20
41  = 2 * 20 + 1  = 25 + 23 + 20
20  = 2 * 10 + 0  = 24 + 22
10  = 2 * 5 + 0   = 23 + 21
5   = 2 * 2 + 1   = 22 + 20
2   = 2 * 1 + 0   = 21
1   = 2 * 0 + 1   = 20
对右边竖线观察,会发现经过每次除以2,高位指数慢慢变成了低位,直到最高位指数变成0为止。
然后从最底下逆推上去的原因就是:
上一式子总是在下一式子的基础上,乘以指数,加上余数(也就是余数 * 底数的** 0** 次方);
也就是不断把整个下一式子最右边的指数和代入上一式子中的 2 * ? 中的 ? 部分,从而一步一步的得到指数和的相加结果。

还有一种拼凑法的意思就是:
666 < 210
666 > 29
666 < 29 + 28
666 > 29 + 27
666 < 29 + 27 + 26
666 < 29 + 27 + 25
666 > 29 + 27 + 24
666 > 29 + 27 + 24 + 23
666 < 29 + 27 + 24 + 23 + 22
666 = 29 + 27 + 24 + 23 + 21
从最大位开始凑;
凑到后面大了,就让最后一个2的指数调小一级;
凑到后面小了,就让最后再增加一个更小2的指数;
不断反复直到相等。


【Python实践】Python部分实际案例解答1_第2张图片
先来一段8的指数结果表

  • 80 = 1
  • 81 = 8
  • 82 = 64
  • 83 = 512

再来看看十进制 666 是如何由 8 的指数加起来的:
666 = 1 * 83 + 2 * 82 + 3 * 81 + 2 * 80


和二进制一样,看看辗转相除法能得到什么:
666 = 8 * 83 + 2 = 1 * 83 + 2 * 82 + 3 * 81 + 2 * 80
83  = 8 * 10 + 3 = 1 * 82 + 2 * 81 + 3 * 80
10  = 8 * 1 + 2  = 1 * 81 + 2 * 80
1   = 8 * 0 + 1  = 1 * 80
代入后同样能得到指数和的加法式子。

同样拼凑法的意思就是:
666 < 2 * 83
666 > 1 * 83
666 < 1 * 83 + 3 * 82
666 > 1 * 83 + 2 * 82
666 < 1 * 83 + 2 * 82 + 4 * 81
666 > 1 * 83 + 2 * 82 + 3 * 81
666 = 1 * 83 + 2 * 82 + 3 * 81 + 2 * 81


原理理解了,就能上代码了:

def dfs(x, d=2):
    if x:
        dfs(x // d, d)
        print({n: n for n in range(10)}.get(x % d, chr(x % d + 55 + 32)), end='')


print('十进制转任意进制小程序')
jz = int(input('请输入进制:') or 2)
assert 1 < jz < 37, '只能从十进制转换成二进制到三十六进制'
num = input('请输入十进制数:')
dfs(int(num), d=jz)

这可以用于十进制转任意进制,dfs 函数中的三行分别代表的如下三个步骤:

  1. 判断地板除是否为0(判断递归结束的重要标志,否则会导致无限递归最终溢出)。
  2. 将地板除的结果进行再次运算。
  3. 打印除法取余后对应的字符(小于10的时候是0-9,大于10的时候是a-z,所以进制数不能超过36

也可以改写为设置固定进制的,看着就很方便~
当然特殊的二进制、八进制和十六进制都有相应的函数,且会自带字符前缀特征:

bin(666)  # 0b1010011010
oct(666)  # 0o1232
hex(666)  # 0x29a

获取变量内存地址、获取内存地址所指向的变量

了解C语言指针

学过C语言的都知道,有个叫做 指针 的让人头疼的玩意,老是学起来问题,这边先简单讲解一下C语言的变量指针作为了解铺垫:
指针的作用:用来保存内存地址;
& 的作用:用来获取内存地址(可以在输出中用 %u 打印成无符号整数);
定义整型变量 int value = 0
定义指针变量 int *address; address = &valueint *address = &value
这里可以看出,指针变量并不是 int 类型,而是 int * 类型,虽然他存的是一个地址整数,并且这当中加了一个空格,但其是一个整体,定义完了就可以丢一边去了~
指针与变量的等价关系:*address = valueaddress = &value 。( address 是指针变量,是指针的地址;value 是变量值)
用一幅图来明白:
【Python实践】Python部分实际案例解答1_第3张图片
sizeof() 用于获取变量字节长度,这里是4是因为字符串有个终止字符**\0**,sizeof() 会将终止字符 \0 一并计算在内。
好了,对C语言指针有个初始的印象了吧?接下来就来说说,python中对指针的使用。

python“使用”指针

其实上面说一堆,下面实现起来很简单,几行代码,使用了万能的 ctypes 库【C:我有指针你没有! Python:拿来吧你!】:

import ctypes
value = 666
value_id = id(value)
print(value_id)
value_get = ctypes.cast(value_id, ctypes.py_object).value
print(value_get)

输出结果:

2022050320228
666

第一行是获取到的变量内存地址;
第二行是从该内存地址读取变量;
python和其他语言对变量和内存地址的处理不同,先举个小栗子:

value = 666
print(id(value))
del value
value = 888
value2 = 666
print(id(value2))

你们觉得两个id值输出是不是一样的?
我想大部分正常的人应该和很久之前的我一样,认为他是不一样的吧?
那就想错了,答案是它俩的 id 值是一样的,不管 del 多少次,每次指向同一变量所在的内存地址是相同的!
del 只会销毁变量名所指向的内存地址,但不会关闭该内存地址,
简单来说,python中定义的变量实际上是一个指针地址,表面上在修改变量值,实际上是在新的内存地址上创建了变量值,然后用变量名指向该内存地址。
所以与其说python中的 = 是赋值语句,倒不如说这是引用语句,就换了个内存地址的引用。

python垃圾回收

既然怎么 del ,内存空间都没有被释放,那变量太多内存满了怎么办?
这个不用担心,虽然内存空间没有被释放,但它是根据其他特征决定是否释放内存空间的,就是——引用计数器,它会动态跟踪你代码中的引用次数并判断是否可以回收内存空间。
当你有多个变量等于一个值的时候,引用计数器就会累加;
当你其中一个变量重新赋值为其他值的时候,原来的值的引用计数器就会减一,同时新的值的引用计数器会加一。
当你操作 del 解除变量的引用、或者删除可变对象(列表、字典、集合等)中的变量时,变量值的引用计数器也会相应减一,当你 del 等操作后下文没有变量名引用这个变量值了,python就会自动销毁它以释放内存空间。
所以python的垃圾回收完全是自动检测的,不会受到人为 del 的干预,完全是取决于你代码下文是否用到这个变量。

二维数组生成的区别

我之前做过的跟棋盘有关的的游戏中需要生成一个12*12且全是0的二维数组,所以我很自然是使用了符合我气质的超短生产法:[[0] * 12] * 12 ,结果不出意外的时候,出了意外,有个bug怎么看代码怎么正确,但bug依旧存在。这让我很抓狂,后来费劲千辛万苦,才找到了罪恶的源头——创建二维数组创建方法用错了。
先来简单输出对比一下,更改某一二维度值后列表的变化:

l1 = [[0 for _ in range(12)] for _ in range(12)]
l2 = [[0] * 12] * 12
print(l1)
print(l2)
l1[3][5] = 6
l2[3][5] = 6
print(l1)
print(l2)

结果:

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
[[0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0]]

可以发现,l1 的改变是我们想要的结果,只更改了一个值;
l2 的结果令人意外,每个二维表的相同位置都变了…随后我进行了大胆的尝试:打印列表中每个值的 id ,看看每个 0id 地址是否一致:

l1 = [[0 for _ in range(12)] for _ in range(12)]
l2 = [[0] * 12] * 12
for l in l1:
    print(id(l))
print('----------------')
for l in l2:
    print(id(l))

结果是意外的:

2426444079752
2426451175624
2426451175560
2426451193160
2426451090760
2426448839880
2426448839240
2426451176008
2426451385736
2426451170824
2426451385800
2426451385864
----------------
2426451385992
2426451385992
2426451385992
2426451385992
2426451385992
2426451385992
2426451385992
2426451385992
2426451385992
2426451385992
2426451385992
2426451385992

可以发现第一种生成的列表的每一项,id值都不一样,但第二种生成的列表的每一项 id 值都一样,代表只要改变其中一个第二维数组,所有第二维数组都会跟着一起变!想想就可怕,以后在这种不能偷懒的地方还是不偷懒了…

浅拷贝与深拷贝

上一个例子为什么会这样,原因很简单,因为python中有两种拷贝方式:

浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。
深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。

然后上文又说到直接赋值,就其实是对对象的引用(别名)。

了解了这个,再来看上面例子的两种二维表创建方式:
[0] * n 是浅拷贝,也就是把一个列表重复了n次,每一行的改变都会改变其他行;
[[0] * n] * m 这种方式是直接将[0] * n 复制了m遍;
[0 for _ in range(n)] 才是创建,是深拷贝。

所以其实上面还能这样创建二维数组,这样也能正确创建二维数组:

l = [[0] * 12 for _ in range(12)]

因为创建全0数组,所以最深元素0肯定是一个 id ,要想多维数组正确创建,最多只能最里层数组是采用乘法复制的操作,来看个小栗子:

l1 = [[[0 for _ in range(6)] for _ in range(6)] for _ in range(6)]
l2 = [[[0] * 6 for _ in range(6)] for _ in range(6)]
l3 = [[[0] * 6] * 6 for _ in range(6)]
l4 = [[[0] * 6] * 6] * 6
print(l1, l2, l3, l4, sep='\n')
print('*******************************************')
l1[1][2][3] = 4
l2[1][2][3] = 4
l3[1][2][3] = 4
l4[1][2][3] = 4
print(l1, l2, l3, l4, sep='\n')

举了四个小栗子,然后看看结果:

[[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]]
[[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]]
[[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]]
[[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]]
*******************************************
[[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]]
[[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]]
[[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]]
[[[0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0]], [[0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0]], [[0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0]], [[0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0]], [[0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0]], [[0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0], [0, 0, 0, 4, 0, 0]]]

看着可能有点密密麻麻,但可以 Ctrl + F 查找一下数字 4 ,会发现只有第一、第二种创建方式是我们想要的,其他都出现了问题,所以偷懒最多偷一点,偷懒多了就得不偿失了~

从列表中分离奇数和偶数

首先,随便整一堆数字:

numbers = [12, 23, 34, 45, 56, 67, 78, 89]

一般人的做法:

jishu, oushu = [], []
for num in numbers:
    if num % 2:
        jishu.append(num)
    else:
        oushu.append(num)
print(jishu)
print(oushu)

结果:

[23, 45, 67, 89]
[12, 34, 56, 78]

这是别人问过的问题,所以这里放上别人看的PPT上的解答:

【Python实践】Python部分实际案例解答1_第4张图片

奇数偶数都分离出来了不错,但用了8行,这不是我想要的 (手动滑稽) ~
我作为一个有知识的博主,肯定要挑战一行代码实现他!
上代码:

print(*(lambda jishu, oushu, numbers: [jishu.append(num) if num % 2 else oushu.append(num) for num in numbers] and (jishu, oushu))([], [], [12, 23, 34, 45, 56, 67, 78, 89]), sep='\n')

别看他长,代码是真的只有一行,奇数偶数的分类以及输出全都一行搞定,当中lambda主体的两个列表是假的,主要用来列表推导循环获取一下(他执行完后应该会自动当垃圾清理掉的吧),然后靠 and 后输出两个列表,然后在 pint 中解包,并设置 sep 参数换行输出,结果和上面一模一样。

什么?你嫌弃这太长了?没关系!我还有一个简短版本的,使用了内置函数 filter ,非常好用!

print(list(filter(lambda _: _ % 2, [12, 23, 34, 45, 56, 67, 78, 89])), list(filter(lambda _: not _ % 2, [12, 23, 34, 45, 56, 67, 78, 89])), sep='\n')

比上面的至少少了十几个字符呢 (此处应有掌声!) ~
filter 这个函数可以理解为一个功能 “条件格式” ,用于过滤序列。当满足条件(第一个参数为 True )时,他会返回遍历到的元素,否则不返回。(关于高阶函数,以后有机会更新【比如下一篇?】)
因为这个遍历返回的是可迭代对象,要强迫它立刻完成,那就用 list(filter()) ,让它直接出结果。

从列表中提取公共信息转换成字典

这仍然是解答别人问题时候的一个小栗子:

var = [
    ['王*龙', '北京市海淀区苏州街大恒科技大厦南座4层'],
    ['庞*飞', '北京市昌平区汇德商厦四楼403'],
    ['顾*锐', '江苏省扬州市三垛镇工业集中区扬州市立华畜禽有限公司'],
    ['王*飞', '上海市徐汇区上海市徐汇区H88越虹广场B座5E'],
    ['华*升', '北京市海淀区杰睿大厦'],
    ['朱*锴', '上海市浦东新区川沙新镇华川家园33号楼503'],
    ['陈*盼', '浙江省杭州市闲林街道,西溪华东园,十幢一单元401。'],
    ['司*鹏', '河南省鹤壁市淇滨大道310号  鹤壁京立医院'],
    ['聂*睿', '河北省石家庄市中山路勒泰中心写字楼b座11层'],
    ['张*', '辽宁省本溪市明兴丽城九号楼四单元'],
    ['冉*晗', '河北省石家庄市体育南大街385号'],
    ['高*杰', '北京市朝阳区广渠路42号院3号楼,408'],
    ['李*国', '安徽省合肥市新站区淮合花园'],
    ['常*源', '江苏省南京市白下路242号,南京市红十字医院,放射科'],
    ['张*玉', '河北省沧州市新居然家居广场'],
    ['王*川', '上海市奉贤区南桥镇 贝港七区'],
    ['冀*庆', '河北省保定市河北大学坤兴园生活区'],
    ['胡*晨', '浙江省宁波市浙江省宁波市江东区中山首府A座2004室'],
    ['尹*婷', '湖北省武汉市武汉大学信息学部'],
    ['李*东', '辽宁省大连市大关一街3号3-3-1'],
    ['张*', '天津市河西区隆昌路94号(天津科技馆)'],
    ['刘*', '湖北省黄冈市城关镇'],
    ['阿*亚', '内蒙古呼和浩特市包头东接民望家园1区3号楼2单元1501'],
    ['孙*云', '山东省济南市山东省济南市历下区祥泰汇东国际,一号楼3005室'],
    ['曹*亮', '黑龙江省大庆市服务外包产业园D1'],
    ['侯*琦', '上海市长宁区金钟路凌空soho16号楼3楼'],
    ['郭*峰', '河南省商丘市高新技术开发区恒宇食品厂'],
    ['赵*生', '河北省唐山市朝阳道与学院路路口融通大厦2408室'],
    ['张*', '陕西省咸阳市文汇东路6号西藏民族大学'],
    ['刘*民', '北京市大兴区南海家园四里7号楼1单元902'],
    ['郭*兰', '湖北省武汉市湖北省'],
    ['张*强', '河北省张家口市经开区钻石南路11号'],
    ['鞠*龙', '山东省潍坊市玉清街江山帝景B区12号楼一单元14楼'],
    ['李*', '北京市海淀区西二旗智学苑5号楼超市'],
    ['许*康', '北京市西城区西单北大街甲133号'],
    ['叶*生', '江苏省扬州市扬子江中路756号'],
    ['赵*兴', '北京市海淀区西二旗上地信息路1号金远见大楼华纬讯301'],
    ['徐*革', '北京市海淀区闵庄路3号102栋二层206'],
    ['徐*', '安徽省淮南市金荷小区(金格商场旁)'],
    ['雷*', '北京市朝阳区望京街道望京sohoT1C座1201'],
    ['庄*', '浙江省杭州市恒生电子大厦'],
    ['蔡*恩', '湖北省武汉市仁和路沙湖港湾B区1103'],
    ['陈*', '江苏省苏州市巴城镇湖滨北路193号牛吃蟹庄'],
    ['黄*', '北京市朝阳区霄云路26号鹏润大厦A座33层'],
    ['魏*飞', '河北省石家庄市新石北路与红旗大街交口开元大厦502室'],
    ['张*', '山东省济南市兴港路三庆城市主人'],
    ['段*琪', '山西省临汾市福利路尧乡小区'],
    ['刘*', '北京市昌平区龙禧三街骊龙园601'],
    ['王*生', '上海市杨浦区邯郸路复旦大学遗传学楼319室'],
    ['王*君', '江苏省扬州市叶挺路318号建行营业部'],
    ['王*义', '北京市东城区环球贸易中心D座'],
    ['李*', '陕西省汉中市同沟寺镇晨光村二组'],
    ['裴*宇', '吉林省四平市岭西新耀豪庭7栋'],
    ['丁*', '山东省烟台市大季家镇芦洋村'],
    ['刘*铎', '黑龙江省佳木斯市火电小区桥头浴池附近惠惠干洗店'],
    ['樊*', '浙江省宁波市文苑风荷201-301'],
    ['陈*瑞', '安徽省宣城市安徽省宣城市宣州区薰化路301合肥工业大学宣城校区'],
    ['崔*峰', '浙江省台州市福溪街道始丰西路43号501室'],
    ['徐*', '湖北省武汉市三金雄楚天地1号楼1210'],
    ['王*', '浙江省宁波市浙江工商职业技术学院信息中心'],
    ['闫*', '上海市浦东新区蓝天路368弄1号301室'],
    ['于*泉', '吉林省四平市金星书苑小区8号楼5单元102室'],
    ['刘*萌', '河北省秦皇岛市抚宁镇交通局家属院3-2-201'],
    ['石*', '安徽省宣城市薰化路301'],
    ['王*雯', '甘肃省兰州市天水南路222号兰州大学'],
    ['王*朝', '河南省郑州市嵩山南路政通路升龙城六号院'],
    ['金*晶', '吉林省延边州延吉市新兴街民安委11'],
    ['蒋*彬', '辽宁省本溪市新城北岸,恒大绿洲'],
    ['牛*鑫', '黑龙江省鸡西市南山路康光二号楼中雅发廊'],
    ['陈*宏', '山西省太原市太原理工大学'],
    ['刘*', '山西省运城市卿头镇'],
    ['陈*杰', '浙江省宁波市高新区研发园A5幢7楼多维时空科技有限公司'],
    ['郝**', '山东省德州市焦庙镇'],
    ['焦*', '山西省长治市太行西街金威超市太西店金威快购办公室'],
    ['李*旗', '北京市昌平区沙河镇汇德商厦4楼403老男孩教育'],
    ['通*大都', '北京市丰台区万泉寺东路9号院1栋1单1704'],
    ['孙*川', '浙江省金华市佛堂镇雅西村双溪口便民超市'],
    ['宋*', '安徽省合肥市上派镇滨河家园9栋2102'],
    ['李*', '陕西省安康市汉滨区新城街道南环东路口桃园小区大门口'],
    ['李*连', '北京市昌平区立汤路北七家威尼斯花园2区2-3'],
    ['籍*旭', '北京市房山区良乡鸿顺园西区20号楼3单元601'],
    ['韩*嵩', '北京市昌平区立汤路威尼斯花园2区2-3'],
    ['曹*', '北京市朝阳区东三环北路28号博瑞大厦B座'],
    ['贺*', '上海市徐汇区古美路1515号19号楼1101室'],
    ['关*轩', '山西省长治市石哲镇'],
    ['罗*', '河北省廊坊市书香苑小区四号楼'],
    ['段**', '北京市朝阳区酒仙桥东路M5世纪互联'],
    ['杜*伟', '北京市昌平区汇德商厦老男孩教育'],
    ['王*', '北京市昌平区汇德商厦四楼'],
    ['赵*波', '上海市闵行区上海市闵行区莘庄镇庙泾路水清三村52号32弄402室'],
    ['许*', '北京市海淀区西北旺镇中海枫涟山庄北门对面中心'],
    ['李*成', '北京市昌平区沙河镇于辛庄村天利合家园'],
    ['刘*', '江苏省南京市兴智路6号兴智科技园A栋7层'],
    ['张*涛', '安徽省合肥市安徽省合肥市庐阳区寿春路156号古井百花大厦大厦A座2603'],
    ['高*', '上海市虹口区欧阳路351弄10号楼104室'],
    ['谷*成', '浙江省杭州市城厢街道 下湘湖路1号'],
    ['王*玉', '上海市嘉定区南翔镇'],
    ['刘*海', '北京市海淀区玉渊潭南路3号水科院万方城科技楼'],
    ['杨*娟', '安徽省合肥市清源路中铁国际城和畅园'],
    ['谢*桥', '北京市海淀区丰秀中路3号院9号楼北京数码大方科技股份有限公司'],
    ['张*', '陕西省咸阳市北上召秦楚汽车城别克雪佛兰4s店'],
    ['邵*龙', '北京市海淀区西北旺镇大牛坊社区四期4号楼1单元301'],
    ['耿*涛', '北京市朝阳区三间房东柳巷甲一号意菲克大厦A座'],
    ['孙*周', '北京市东城区东花市街道便宜坊写字楼10层,恒信通大厦。就在崇文门地铁站口旁边'],
    ['于*涵', '山东省济南市舜耕路舜耕山庄宿舍'],
    ['陈*', '上海市普陀区近铁城市广场北座15楼'],
    ['马*', '北京市昌平区沙河镇松兰堡村西口兴业家园6号楼'],
    ['齐*', '江苏省南京市天元东路228号莱茵量子国际'],
    ['高*', '山西省太原市经济技术开发区龙盛街2号国药控股'],
    ['刘*', '北京市海淀区中关村丹棱街中国电子大厦B座1608'],
    ['陈*山', '安徽省六安市南港镇'],
    ['赵*', '黑龙江省哈尔滨市锦山路5号,黑龙江省地质科学研究所'],
    ['伍*', '安徽省芜湖市泉塘镇'],
    ['白*潮', '上海市浦东新区康桥镇环桥路2585弄文怡苑一期27号楼301'],
    ['黄*曦', '北京市朝阳区西坝河南路3号2层201室 同创双子信息技术股份有限公司'],
    ['牟*强', '山东省日照市山东东路619号 广电网络公司'],
    ['李*运', '上海市松江区沪亭南路208弄109号801室'],
    ['杨*', '北京市朝阳区安苑路20号世纪兴源大厦304'],
    ['宋*伟', '河北省石家庄市高头乡西高村'],
    ['任*鹏', '陕西省西安市锦业一路29号 龙旗科技园 6层 西安和利时系统工程有限公司'],
    ['孙*洲', '北京市东城区东花市街道便宜坊写字楼10层,恒信通公司。就在崇文门地铁站旁边'],
    ['张*义', '上海市浦东新区三舒路181弄2号904'],
    ['门*意', '黑龙江省哈尔滨市文昌街238号联通系统集成有限公司'],
    ['杨*康', '北京市丰台区丰台科技园汉威广场12栋']
]

这么一大段数据,最后要根据省份变成字典,如图:

【Python实践】Python部分实际案例解答1_第5张图片

忽略掉对方是编程小白这个因素,这个是很简单的对吧~

import json

var_dict = {}
for v in var:
    var_dict[v[1][:3]] = var_dict.get(v[1][:3], [])
    var_dict[v[1][:3]].append(v)
print(json.dumps({k: [str(i) for i in v] for k, v in var_dict.items()}, indent=4, ensure_ascii=False).replace('"[', '[').replace(']"', ']'))

这里的 var_dict[v[1][:3]] = var_dict.get(v[1][:3], []) 我感觉用的很巧,如果键值不存在就自动创建,存在就赋值为原来的值,省去了 if 的两行(但好像牺牲了些许性能),然后下面就可以放心肯定是列表而不会是 None 了。
你看 print 那里好像有点长,其实就是在转字符串,为什么要将列表转成字符串呢?因为不转换成字符串的话,列表元素会自动换行,就像这样:

【Python实践】Python部分实际案例解答1_第6张图片

为了贴合它给的示例,所以就要让列表变成一个个的字符串,这样就能在一行内显示了,最后记得把列表外面的引号去掉。
这叫什么,这就叫细节!
如果接下来不再使用这个字典,只是为了打印,那可以从上面入手转换:

import json

var_dict = {}
for v in var:
    var_dict[v[1][:3]] = var_dict.get(v[1][:3], [])
    var_dict[v[1][:3]].append(str(v))
print(json.dumps(var_dict, indent=4, ensure_ascii=False).replace('"[', '[').replace(']"', ']'))

这就少了不少代码了,完成!

模拟有密码输入次数的登录系统

这还是别人请教我的一个问题,让我看看他的代码有没有问题,我忘了他原来发的代码是什么了,不过我记得他是 账号或密码为空 的时候仍然扣除次数,这样肯定是不对, 于是我改后的代码如下:

ctrl = 3
while 1 <= ctrl <= 3:
    x, y = input("请输入账号:"), input("请输入密码:")
    if x == '' or x == ' ' or y == '' or y == ' ':
        print("警告,账号或密码不能为空")
    elif x != 'admin' or y != '123':
        ctrl -= 1
        print(f'输入错误请重新输入,你还有{ctrl}次机会')
    else:
        print(x, '欢迎登录')
        break

仅在输入不为空且账号或密码不对的时候次数减少,这样的逻辑就是对的。
现在满足他了,缺不满足我了。为啥?这代码这么长,11行的代码!这看着太多了,对于缩减王的我来说,这要能压缩到5行以内才有挑战性:

ctrl = 3
while ctrl:
    string = (lambda x, y: f'{x},欢迎登录' if x == 'admin' and y == '123' else (f'输入错误请重新输入,你还有{ctrl - 1}次机会' if ((x.strip() + y.strip()) and ctrl) else '警告,账号或密码不能为空'))(input("请输入账号:"), input("请输入密码:"))
    ctrl = int(string[-4]) if string[-4].isdigit() else (0 if string[-1] == '录' else ctrl)
    print(string)

可惜了我最大只能缩减到5行,如果是python3.10以上的话,我还能凭借海象运算符( := ,先赋值后判断)又减少至少一行代码~

计算1-100内的奇数和、代码执行时间计时

这又又又是别人请教我的一个问题,应该已经麻木了,不然我也不会想到要出此一期合集。
正常人写代码:

num = 0
for n in range(1, 100):
    if n % 2:
        num += n
print(num)

像我一样的非正常博主写代码:

from functools import reduce
print(sum([_ for _ in range(1, 100, 2)]))
print(sum([_ for _ in range(1, 100) if _ % 2]))
print(sum([_ * (_ % 2) for _ in range(1, 100)]))
print(sum([_ if _ % 2 else 0 for _ in range(1, 100)]))
print(reduce(lambda _, __: _ + __, [_ for _ in range(1, 100, 2)]))
print(reduce(lambda _, __: _ + __, [_ for _ in range(1, 100) if _ % 2]))
print(reduce(lambda _, __: _ + __ * (__ % 2), [_ for _ in range(1, 100)]))
print(reduce(lambda _, __: _ + __, [_ if _ % 2 else 0 for _ in range(1, 100)]))

分分钟给他写一堆一行就能完成的不同方案的代码(如果细小改变也能称之为新方法的话),一会 sum ,一会 range 里分奇偶,一会列表推导式分奇偶,一会遍历元素处分奇偶,一会 reduce 配合上面几种分奇偶。(实际感觉也就四种小方法和两种大方法混合使用,但我就觉得他们不一样!)

但别人跟我说,你代码短没用,说不定执行速度没我快,我心一沉,还真没考虑,现在就来测一下他们的执行速度:

import timeit

tests = """
sum([_ for _ in range(1, 100, 2)])
sum([_ for _ in range(1, 100) if _ % 2])
sum([_ * (_ % 2) for _ in range(1, 100)])
sum([_ if _ % 2 else 0 for _ in range(1, 100)])
__import__('functools').reduce(lambda _, __: _ + __, [_ for _ in range(1, 100, 2)])
__import__('functools').reduce(lambda _, __: _ + __, [_ for _ in range(1, 100) if _ % 2])
__import__('functools').reduce(lambda _, __: _ + __ * (__ % 2), [_ for _ in range(1, 100)])
__import__('functools').reduce(lambda _, __: _ + __, [_ if _ % 2 else 0 for _ in range(1, 100)])
""".strip('\n')

for test in tests.split('\n'):
    print(timeit.timeit(stmt=test, number=100000))

接下来运行多次测试,结果如下:

【Python实践】Python部分实际案例解答1_第7张图片
【Python实践】Python部分实际案例解答1_第8张图片
【Python实践】Python部分实际案例解答1_第9张图片

这里就贴了随机三次的测试,发现不仅代码长度越来越长了,执行速度还越来越慢了。
几次测试下来,第一种方法不仅稳,而且速度快,难怪能成为内置函数。那么问题来了,sum 函数和正常写多行代码来比呢?

import timeit

print(timeit.timeit(stmt="""sum([_ for _ in range(1, 100, 2)])""", number=100000))

print(timeit.timeit(stmt="""
s = 0
for i in range(1, 100, 2):
    s += i
""", number=100000))

同样取三次结果:
【Python实践】Python部分实际案例解答1_第10张图片
【Python实践】Python部分实际案例解答1_第11张图片
【Python实践】Python部分实际案例解答1_第12张图片

发现还是 sum 稳如老狗,而且速度很快。
以后就不要说代码写一行速度会变慢了,内置函数还是很好用的!

二层列表转单层列表、代码执行时间计时

这实际上是我很久以前的需求了,我肯定会要求一行代码实现,不然就不会有这个话题了。

import timeit

poke = [[f'{_ + 1}_{__ + 1}' for __ in range(4)] if _ < 13 else [str(_ + 1)] for _ in range(15)]
tests = f"""
poke_list = [];list(map(poke_list.extend, {poke}))
poke_list = sum({poke}, [])
poke_list = __import__('functools').reduce(list.__add__, {poke})
poke_list = list(__import__('itertools').chain(*{poke}))
poke_list = (lambda _, __ = eval("[]"): __.clear() or [[__.append(____) for ____ in ___ if ____] for ___ in _] and __)({poke})
""".strip('\n')

for test in tests.split('\n'):
    print(timeit.timeit(stmt=test, number=100000))

还是老样子,测试三次数据:

【Python实践】Python部分实际案例解答1_第13张图片
【Python实践】Python部分实际案例解答1_第14张图片
【Python实践】Python部分实际案例解答1_第15张图片

所有方法实际使用代码如下:

poke = [[f'{_ + 1}_{__ + 1}' for __ in range(4)] if _ < 13 else [str(_ + 1)] for _ in range(15)]
print(poke)
poke_list = [];list(map(poke_list.extend, poke))
print(poke_list)
poke_list = sum(poke, [])
print(poke_list)
poke_list = __import__('functools').reduce(list.__add__, poke)
print(poke_list)
poke_list = [_ for __ in poke for _ in __]
print(poke_list)
poke_list = list(__import__('itertools').chain(*poke))
print(poke_list)
poke_list = (lambda _, __=eval("[]"): __.clear() or [[__.append(____) for ____ in ___ if ____] for ___ in _] and __)(poke)
print(poke_list)

发现第一种测试起来不仅稳,还比其他快一截,虽然他写的不优雅…
然而最后的 lambda 函数是我之前用的,现在一看用时这么长…果然长的代码可能用的时间长…
我现在就感觉我的生命白白浪费了那么多秒!

发扑克小程序

我看到代码的下面,才发现原来上面都是铺垫,下面这个功能才是正题,依然是别人问我的,上面只是为了生成一副扑克牌而已…
不多说,上代码,这里采用已经转换成一位数组的列表直接赋值:

import random
poke_list = ['1_1', '1_2', '1_3', '1_4', '2_1', '2_2', '2_3', '2_4', '3_1', '3_2', '3_3', '3_4', '4_1', '4_2', '4_3', '4_4', '5_1', '5_2', '5_3', '5_4', '6_1', '6_2', '6_3', '6_4', '7_1', '7_2', '7_3', '7_4', '8_1', '8_2', '8_3', '8_4', '9_1', '9_2', '9_3', '9_4', '10_1', '10_2', '10_3', '10_4', '11_1', '11_2', '11_3', '11_4', '12_1', '12_2', '12_3', '12_4', '13_1', '13_2', '13_3', '13_4', '14', '15']
random.shuffle(poke_list)
players = ["alex", "武沛齐", "李路飞"]


def issue_cards(player, poke_lis):
    player_dic = {}
    for p_name in player:
        p_cards = random.sample(poke_lis, 1)
        for card in p_cards:
            poke_lis.remove(card)
        player_dic[p_name] = p_cards
        print(f"为玩家{p_name}生成了牌")
        jx = input("是否继续要牌:")
        if jx.lower() in ["是", "y", "yes"]:
            p_cards.extend(random.sample(poke_lis, 1))
        else:
            continue
    return player_dic


player_dict = issue_cards(players, poke_list)
print(player_dict)

这个程序呢,我就没什么好解释的了,这我感觉没错的话,只是个半成品,要么就是我没搞懂别人搞这程序想干啥,不过这都不重要

你可能感兴趣的