Python技术

Python技术 's Blog


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于

我擦!发红包遇到了微信抖动!

发表于 2021-01-19 | 分类于 python
0

下午和老婆手牵手心连心去“好时光”照相馆拍照片,记录我们的美好时刻。

拍完一组照片,在等待摄影师修图的时候,老婆站在我身后给我捶背,说我开车辛苦了,给我揉揉肩捶捶背。这待遇真是羡煞了路人甲,作为男人,这种满足感也是无与伦比的。

这时候,作为一个男人,咱也不甘示弱:掏出手机,打开微信,点击“转账”,输入520,转账留言还不忘附一句“么么哒”。

一气呵成之后,我提醒老婆赶紧看微信,老婆打开微信,刷了几下,啥都没看到,跑来问我说,看什么呀?

我提高嗓门说:给你发了个大包,你赶紧领了,过时不候哈!

哪里有大包嘛?你看看,啥也没收到呀!

听到这句话,我愣了一下,随即冒了一丝冷汗:没收到?难道我发错人了?完了完了,赶紧检查一下,要是发到另一个女孩的微信上就跳进黄河也洗不清了!

我赶忙打开手机,确认了三遍,没发错,这才松了一口气。我说你看,我已经发过去了,你没接收到,你是不是信号不好,你连 WiFi 看看!

老婆连了 WiFi,也还是没看到。我打开手机微博,刷新内容都没问题,心理一百个为什么。。。

这时候修照片的老板娘(据说像某位明星)跟我们说,照片修好了,让我们看看。我们看了之后说很满意,把我严肃的表情修成了微笑,很棒!

接着老板娘让我加她微信,把底片发给我。我微信扫一扫二维码,添加了微信。可是老板娘等了半天,也没有收到好友请求。我又添加了一次,还是一样的结果。我不信邪,切换到了另一张联通 5G 卡,又添加了一下,结果同样没收到。

我就郁闷了,这都 4G 加 5G ,一共 9G 了,怎么还是收不到请求呢?

结果让老婆添加,一次性就成功了。

当时贼郁闷,炫耀的红包老婆没有收到,明星老板娘的微信也没加上,今天这人品是咋啦?

1

草草收场之后,我们离开了影楼,老婆路上还念叨着红包,看着她可怜兮兮的样子,我心疼啊,于是我又拿起手机转了一个 520 过去,为了区分,我特意在转账留言后面加了一个企鹅发爱心的表情。

这次发过去她就看到了,以迅雷不及掩耳之势点了红包。令人意想不到的是,她收了红包之后,马上又冒出来一个,也就是之前没收到的那个,这时候也出现了。毫无意外,以抢红包的手速马上又点了一次,欣喜若狂地对我说:谢谢老公,两个红包都收到了!

这杀千刀的微信,害人啊!微信余额总共才 1000 出头,这一下子掏空了,接下来日子怎么过啊!大家可以理解我此时内心的 OS 吗?

2

晚上,回到家刷微博,无意间发现“微信bug”上了热搜,看到微信官方的微博,才知道自己被微信坑了:

微信团队表示,今天14点左右,部分微信用户遇到了消息收取延迟情况,原因是系统抖动,目前已经修复完成。

微信团队还宽慰大家:你家网络应该没啥问题。

我内心想:我家网络是没问题,我家家庭和睦关系差点遭殃!

3

看了这个解释,作为技术人员,我的第一反应当然是去了解一下什么是“系统抖动”,我去网上搜索相关资料,解释是这样的:

如果低优先级进程所分配的帧数低于计算机体系结构所需的最小数量,那么必须暂停该进程执行。然后,应调出它的所有剩余页面,以便释放所有分配的帧。这个规定引入了中级 CPU 调度的换进换出层。

事实上,需要研究一下没有“足够”帧的进程。如果进程没有需要支持活动使用页面的帧数,那么它会很快产生缺页错误。此时,必须置换某个页面。然而,由于它的所有页面都在使用中,所以必须立即置换需要再次使用的页面。因此,它会再次快速产生缺页错误,再一次置换必须立即返回的页面,如此快速进行。

这种高度的页面调度活动称为抖动。如果一个进程的调页时间多于它的执行时间,那么这个进程就在抖动。

系统抖动的原因是什么呢?

操作系统监视 CPU 利用率。如果 CPU 利用率太低,那么通过向系统引入新的进程来增加多道程度。采用全局置换算法会置换任何页面,而不管这些页面属于哪个进程。

现在假设进程在执行中进入一个新阶段,并且需要更多的帧。它开始出现缺页错误,并从其他进程那里获取帧。然而,这些进程也需要这些页面,因此它们也会出现缺页错误,并且从其他进程中获取帧。这些缺页错误进程必须使用调页设备以将页面换进和换出。当它们为调页设备排队时,就绪队列清空。随着进程等待调页设备,CPU 利用率会降低。

CPU 调度程序看到 CPU 利用率的降低,进而会增加多道程度。新进程试图从其他运行进程中获取帧来启动,从而导致更多的缺页错误和更长的调页设备队列。因此,CPU 利用率进一步下降,并且 CPU 调度程序试图再次增加多道程度。这样就出现了抖动,系统吞吐量陡降,缺页错误率显著增加。结果,有效内存访问时间增加,没有工作可以完成,因为进程总在忙于调页。

在本次微信事件中,我们通俗的理解为:

所谓系统抖动(thrashing),是一个计算机专业名词,指的是虚拟内存方案中的一种现象,通常是因为内存或其他资源耗尽或有限,导致无法完成所要执行的操作。

当上述情况发生时,程序就会通过操作系统发出请求,操作系统则试图从其他程序中调用所需资源,导致新的请求不能得到满足。

系统抖动发生时,系统时间会消耗在低速的I/O上,更多地进行页面交换而不是指令执行,进而大大降低系统效率。

用大白话说就是:微信消息收发系统的资源不够用了。

今天虽然钱包空了,感觉损失了几个亿,并且差点好事变坏事,但是经历了一次微信的重大事件,而且学到了点新知识,也算是不小的收获了!

阅读全文 »

用 Python + Appium 的方式自动化清理微信僵尸好友

发表于 2021-01-19 | 分类于 python

随着微信的使用时间越长,微信好友也越来越多,有些好友将你删除了你也不知道。当我们发消息的时候会出现下面扎心的一幕,然后默默将他删除

阅读全文 »

比特币涨疯了,区块链是什么鬼?

发表于 2021-01-11 | 分类于 python

2020 年底,数字货币鼻祖,比特币,高歌猛进,突破了惊人的 3万美元,直逼4万美元,再一次引起世人的眼球,又是一场褒贬不一,血雨腥风……

我们作为有头脑、有理智、有技术的人,不能像大多数人那样趋之若鹜,看个热闹就完了。那么这么厉害的、建立在计算机和网络之上的比特币,它的底层技术是什么呢?又,是如何才能实现的呢?

今天,我们用不到 50 行的代码,了解和领略一下比特币底层技术 —— 区块链的魅力吧,另外还有在实际项目中的应用噢,让同事刮目相看的机会来了,开干

什么是区块链

简单来说,区块链就是一系列的记录的集合,可以理解成数据库,不同的是,这些记录直接都通过一种类型链的东西串联在一起

如果链上的一个环节出了问题,那么它后面的记录就有问题,因此必须保证链上的记录都是真实可靠的链在一起的

也就是,后面的记录加入之前,需要和前面的数据关联起来才能加入

可想而知,这样的方式可以有效地防止数据被篡改,比如前面的数据被修改后,后面的数据与前面的数据将不匹配,很快就可以发现

这就是区块链的基本概念,就在这个简单的概念上,区块链催生了新的、完全数字化的货币,这些货币并不是由中心控制系统控制的,而是分布在整个互联网上,如比特币和莱特币。

而且区块链技术还在不断地革新,例如以太坊,Mixin 等等

区块链的原理

区块链的概念看起来挺简单的,实现原理是什么呢?

这里就需要了解一个概念,那就是 数子签名,也可以叫做 不对称加密

因为信息是由一系列字符成的,对于一个区块的记录来说,也可以看出一系列的字符,比如一个表示姓名和年龄的字符串:

name:Tom;age:18

对这个字符串进行 Md5 加密(一种常用的数字签名算法),会得到类似这样的字符串:

1
2
3
4
5
6
from hashlib import md5

m = md5()
m.update(b"name:Tom;age:18")
m.hexdigest()
# 'ca8d85b134922fe48d17bf36ceb38046'  当前记录的特征码

可以理解为记录的一个特征码

如果再来一条记录:name:Jim;age:19

特征码很好计算,不过怎么和上一条记录链接起来呢?

方法就是将上一个记录的特征码,一起编织在这一条的特征码中,例如:

lastHash:ca8d85b134922fe48d17bf36ceb38046;name:Jim;age:19

然后得到特征码:

1
2
3
4
5
6
from hashlib import md5

m = md5()
m.update(b"lastHash:ca8d85b134922fe48d17bf36ceb38046;name:Jim;age:19")
m.hexdigest()
# '82391695a3760b2de1c92d512b83cc14'  当前记录的特征码

这样就完成了记录直接的链接

经验一条记录是否被修改,或者连续,只需要对这条记录和其上一记录一起重算一次特征码就好了

当然,比特币,或者由实际应用的区块链会更为复杂,比如字段、加密算法等

实现一个区块链

下面,我们来实现一个比较完整的区块链

首先定义一个区块类:

1
2
3
4
5
6
7
8
9
10
11
12
class Block:
    def __init__(self, index, timestamp, data, previous_hash):
        self.index = index
        self.timestamp = timestamp
        self.data = data
        self.previous_hash = previous_hash
        self.hash = self.hash_block()

    def hash_block(self):
        sha = hasher.sha256()
        sha.update((str(self.index) + str(self.timestamp) + str(self.data) + str(self.previous_hash)).encode("utf-8"))
        return sha.hexdigest()
  • 初始化方法中,初始化了当前区块的索引、时间戳、数据(业务相关的信息)、紧前区块(上一个区块)的特征值,和当前区块的特征值
  • hash_block 根据初始化中的一些信息,得到一个特征值,就是用它来计算当前区块的特征值

接下来,区块链中的第一个区块的特征值如何计算,它的紧前特征值是什么?

我们来定义一个产生 起始区块 的方法:

1
2
3
def create_genesis_block():
    # 手工创建第一个区块,其索引为 0,且随意取给紧前特征值 '0'
    return Block(0, date.datetime.now(), "Genesis Block", "0")

然后,我们定义一个生成新区块的方法:

1
2
3
4
5
6
def next_block(last_block):
    this_index = last_block.index + 1
    this_timestamp = date.datetime.now()
    this_data = "Hey! I'm block " + str(this_index)
    this_hash = last_block.hash
    return Block(this_index, this_timestamp, this_data, this_hash)
  • 参数是 紧前 区块对象
  • 对索引做递增处理
  • 得到当前时间戳
  • 产生区块业务数据(为了简便只做了相对固定的内容)
  • 记录上个区块的特征值
  • 最后根据以上信息,得到一个新区块

现在所有的基础工作已经完成了,我们建立一个区块数据库,即区块链,并计入第一个区块

1
blockchain = [create_genesis_block()]

最后我们模拟一个产生区块的过程:

1
2
3
4
5
6
7
8
9
10
11
# 设置产生区块的个数
num_of_blocks_to_add = 20

# 产生区块并加入区块链
for i in range(0, num_of_blocks_to_add):
    previous_block = blockchain[-1]
    block_to_add = next_block(previous_block)
    blockchain.append(block_to_add)
    # 发布当前区块的信息
    print("Block #{} has been added to the blockchain!".format(block_to_add.index))
    print("Hash: {}\n".format(block_to_add.hash))

运行后,我们可以得到如下结果:

Block #1 has been added to the blockchain!
Hash: 788ec79310315740f7df959e03c8788f102c3e02d6b6ce6488ed7b7d04cc3e01

Block #2 has been added to the blockchain!
Hash: 5b6c6e0be9659ae359356015ffe9ba9e4645f181d848bfd5127dd24d29f1747c

Block #3 has been added to the blockchain!
Hash: c40e3accb5de25728770754f24d7504cc72b8138d465f5d8f1b84ad149c9b59c

Block #4 has been added to the blockchain!
Hash: 9a118b7c8b90aaab2fe6a59dd84224adb90ba4af8aaa03bf4c9b08799cc81d9b

Block #5 has been added to the blockchain!
Hash: f8fbd5b6684d926fb96dd36b89f61db3c868...<省略>...

显示的结果就是区块链上的信息

实际当中,是在分布式环境下运行的,需要考虑更多的因素,如调度,合并,以及选举等,加密算法也需要更为安全,例如常用的是 椭圆曲线加密算法(ECC), 来加强区块链的安全性和可靠性,但最基本的实现逻辑是一样的。

应用

有句虐心的话:

明白了很多道理,却还是过不好这一生

虽然粗浅地了解了区块链的基本概念和实现,然而有什么用呢?

既不能取改比特币(再说也不需要改),也不能创建一个区块链应用(虽然不是不可能)

不过这种思想可以在很多地方得到应用

这里我列举一个我实际工作中的例子:

在一个项目上,需要实现一个审计日志功能,基本要求就是需要连续并防篡改

如果不了解区块链的算法的话,可能需要考虑半天,然后得到一个蹩脚的方式,比如用额外的记录来控制日志记录,或者记录关联关系(之前确实这么干过)

现在,只需要在记录中增加两个字段:上一个记录的特征码 和 当前特征码

再实现一个,根据指定字段,计算特征码的方法

为了便于识别,再加一个检验方法,就好了

除了这样的应用,你还能想到哪些应用呢?欢迎留言交流

总结

截至写稿(2021年1月9日),比特币的价格已经接近 27 万了,如此受热捧(也不是一直这么热,理财有风险,投资需谨慎),而其内在原理竟然如此简单

基于加密算法就可以完成可以承载巨大信息量的数据货币世界,这就是所谓 越简单的, 就越有效和稳定 的恰当解释

无论什么事物,总有其内在的基本原理和理论做支撑,只有了解和掌握了其内部原理,才能更好地认识一个事物,我们只需要多一些好奇心,多一点耐心就好,比心

参考

  • 区块链白皮书: https://bitcoin.org/bitcoin.pdf
  • https://zhuanlan.zhihu.com/p/28595570
  • https://zhuanlan.zhihu.com/p/101907402

示例代码:https://github.com/JustDoPython/python-examples/tree/master/taiyangxue/blockchain

阅读全文 »

都 2021 年了,居然还有人在手写测试数据

发表于 2021-01-10 | 分类于 python

封面

平时我们在开发程序的时候,总免不了需要造一些假数据来验证自己的程序功能是否正常。那么你是通过什么方式来造假数据的呢,不会每次都是手写「测试数据、test」吧。

阅读全文 »

Python 小项目实战了解一下?

发表于 2021-01-08 | 分类于 Python 小项目实战了解一下?

最近无论是北方还是南方都迎来了强冷空气的袭击,北风呼呼吹,我所在的城市这两天则可随处溜冰,城市道路结冰橙色预警,全省交通到处管制、小学幼儿园停课休息;上班路上的行人则是小心翼翼怕摔跤;老家韭菜坪的风景更美,给大家来带张照片感受感受:

韭菜坪雪景1

韭菜坪雪景2

言归正传,今天的文章来点有趣的小项目实战,希望给繁忙工作中的朋友们减减压,也给这个严冬增添几分暖色;详细项目请见后文。

用 Python 画彩虹线

用 Python turtle 画个转圈圈的彩虹线,实现思路如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 导入 turtle 包
import turtle
# 打开画笔
q = turtle.Pen()
# 设置背景颜色
turtle.bgcolor("white")
sides = 7

# 设置彩虹线
colors =["red","orange","yellow","green","cyan","blue","purple"]
for x in range(360):
     q.pencolor(colors[x % sides])
     q.forward(x*3 / sides+x)
     q.left(360 / sides+1)
     q.width(x * sides/200)

实现结果如下: 彩虹图

用 Python 实现有趣的图片转字符游戏

实现思路如下:

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
#用 Python 实现图片转字符
from PIL import Image
import os

#设置参数输入像素的灰度值
def g2s(gray):
    pixel_str='''$#%@&MNBEFRWYLIkbtj?*984532menocvzst{}[]1|()<>=+~-;:i^"'. '''
    length=len(pixel_str)
    # 字符之间的灰度区间
    plus=255/length
    # str_gray表示字符所代表的灰度值
    str_gray=0
    for i in range(length):
        str_gray = str_gray + plus
        if gray <=str_gray:
            return pixel_str[i]

def img2str(img_path,save_path,num=0):
    txt_path=os.path.join(save_path,'img.txt')
    f=open(txt_path,'w')
    f.write('')
    # 因为此目录有可能已有内容,所以先清空
    f.close()
    # a表示在文件的末尾添加
    f=open(txt_path,'a')

    # 因为有些图片尺寸过于大,所以添加了一个修改大小的功能
    im=Image.open(img_path)
    if num==0:
        pass
    else:
        im=im.resize( ( int(im.size[0]/num),int(im.size[1]/num) ) )

    # 直接将图片转换成灰度模式
    im=im.convert('L')
    for y in range(im.size[1]):
        for x in range(im.size[0]):
            s=g2s(im.getpixel((x,y)))
            f.write(s)
        f.write('\n')
    f.close()

if __name__=='__main__':
    img2str(r'test.jpg', r'D:\Python_test', 4)

测试图片:

实现效果如下:

总结

今天的文章主要是使用 Python 实现小项目减减压,希望对大家有所帮助!

示例代码 Python 小项目实战了解一下?

阅读全文 »

做时间的朋友,必须知道收益咋算

发表于 2021-01-04 | 分类于 python

新年好,我们度过了艰难的 2020,迈进了 2021 的征程,在新年伊始,我们一起学习一个新技能,使我们能拥有看到未来的眼睛

比起对时间、精力的投资,对金钱的投资更容易理解和显现

那么面对纷繁复杂的投资种类,哪个才是对我们有利的呢?当然要看收益率高呀

那如何计算收益率呢?

年化复合回报 15% 意味着什么

如果有一个投资标的,年化复合收益率是 15%,那么 100 年后(虽然我们可能活不了这么久),能获得少倍的收入?

虽然我们可以写成计算公式,但我们的大脑并不适合计算小数的幂运算,

对于这个问题,计算公式是:

\[(1+15\%)^{100}=?\]

这样用 Python 一行代码就搞定:

1
2
(1+0.15)**100
# 1174313.4507002793

对,你没看错,是 117 万倍!,也就是投入一块钱,最终收益竟然是 117 万

这个并非假设的例子,2019 年的时候,可⼝可 乐公司上市⼀百周年。⼈们算了⼀下,在这⼀百年间,可⼝可乐公司竟然为股东创造了 15% 的年化复合回报率!

果然,收益率是很大程度上反映了投资标的的好坏

定投的收益

定投就是,定期定额,持续对某个标的的投资,可以参见《定投到底好不好 —— python 告诉你答案》

对于一个具有某个平稳收益率的标的,使用定投策略,在一段时间后,能获得多少收益呢?

通过设定收益率、定投周期、定投额度,就可以算出来,不过手工计算比较麻烦,可以直接使用 Numpy 提供的 FV 函数很方便的计算

FV 函数参数是:

  • rate, 收益率
  • nper:投资期数
  • pmt:每期定投金额
  • pv:期初已有金额,即现值
  • when:表示各期计算收益的时间点,期初为 0,期末为 1,默默为期末

假设,按月定投,每月定投 1000,月收益率为 10%,定投 12 个月,即一年的最终金额是多少:

1
2
3
import numpy_financial as npf
npf.fv(0.1, 12, -1000, 0)
# 21384.28376721003
  • 注意:numpy 将在 1.2 及以后版本,会将经济类公式去除,而专门用模块 numpy_financial 做经济类公式库,为了升级方便,建议使用 numpy_financial
  • numpy_financial 通过 pip install numpy-financial 安装
  • numpy 中 负数表示投入,正数表示获取,因此 -1000 表示投入 1000

如果在同样的条件下,想要在某个时间点,收获一定的金额,每期应该投入多少呢?比如一年后要得到 5万元,计算每月的投入

1
2
3
import numpy_financial as npf
npf.pmt(0.1, 12, 0, 50000)
# -2338.165755014362

可以得出,每月至少投入 2338.17 元

pmt 与 fv 的区别只是后面的两个参数含义不同

分别是,期初金额和终值金额

定期不定额的收益率

定投虽好,不过实际操作中难免有各种异常情况,漏投,或多投在所难免,甚至将一部分提现

这种情况下如何计算自己的收益率呢?

我们可以利用 irr 这个函数,其全称为(Internal Rate of Return),即内部报酬率,不过名称还是不太明显,我们看看如何应用吧

假设有一个定投项目,下面是每期定投的金额和支出:

期数 投入 提现 实际投入
1 -1000 0 -1000
2 0 100 100
3 -1500 200 -1300
4 -2000 0 -2000
5 -800 6000 5200

注意,金额都是相对于投资者来说的,负数为支出,正数为收入

我们做如下计算

1
2
3
4
import numpy_financial as npf
pmts = [-1000, 100, -1300, -2000, 5200]
npf.irr(pmts)
# 0.10969579295711918

pmts 为每期投入金额,因为是可变的,所有存入数组里

最终得到的结果是,不定额投资 5 期, 最终收益率为 10.96%

有了这个函数赶紧算算那些保险方案,看看承诺的收益率是否与实际相符

不定期不定额的收益率

直接在看问题,一般都会被难到,不知如何下手

但实际上这种投资操作更为实际,有钱就投,没钱不投,钱多多投,钱少少投,才是我们平常人的投资风格

如何计算收益率呢?

xirr 闪亮登场

xirr 源自于 Excel 中的计算公式

看起来问题很复杂,而 xirr 函数却很简单,即 收益率=xirr(资金流, 日期流)

不过遗憾的是 numpy-financial 模块中并未提供 xirr 函数,需要引入另外的算法

GitHub 找到了一个简单的库 https://github.com/Tacombel/XIRR.py

下载其中的 XIRR.py 放在根目录下,引用即可

假设有这样的投资记录

日期 现金
2019-02-04 -300.3
2019-06-17 -500.5
2019-11-18 741.153
2020-04-27 -600.6
2020-10-19 1420.328547

来计算看看

1
2
3
4
5
6
7
8
9
10
11
12
13
from XIRR import xirr
import datetime

dates = [datetime.date(2019, 2,4), 
datetime.date(2019, 6, 17), 
datetime.date(2019,11, 18),
datetime.date(2020,4, 27),
datetime.date(2020,10, 19)]

values = [-300.3,-500.5,741.153,-600.6,1420.328547]

xirr(values, dates)
# 输出为: 0.779790640991537

实际的收益率为 77.98%

有了 irr 和 xirr 两个函数,投资世界是否变得清晰多了

总结

如果有什么方法让流失的时光留住,那就对时间做定投,正如在 2020 总结篇 中说的:做时间的朋友,成为长期主义者

我们知道长期主义者与非长期主义者的最大区别在于,对待积累的方式

只有让流走的时间、精力、金钱积攒起来,发挥价值,才能使我们走的更远更宽

期望今天的分享能让你从另外的角度上看待投资,让我们以更快的速度成长,比心~

参考

  • https://github.com/Tacombel/XIRR.py
  • https://github.com/xiaolai/spreadsheets-for-investors

示例代码:https://github.com/JustDoPython/python-examples/tree/master/taiyangxue/rate-of-return

阅读全文 »

2020 年 GitHub 上十大最火 Python 项目,看完之后我裂开了

发表于 2021-01-02 | 分类于 python

封面

GitHub 作为程序员每天必逛的网站之一,上面有着太多优秀的开源项目,今天派森酱就带大家来梳理下在过去的一年里,GitHub 上最火的 Python 项目 Top10。

阅读全文 »

一文教你如何在网上选车牌

发表于 2020-12-25 | 分类于 python

年底买车的朋友很多,有朋友买了车,但却为车上牌发愁,因为卖车的告诉他,上牌选号时间只有几分钟,他要在几分钟内从50个号码中选出自己的车牌号。虽然只是个号牌,但谁都想选个好号码,毕竟可能要用一辈子,而且没准以后还增值。但这要在几分钟内决定,真是比高考还紧张。后来我跟他说为啥不先在网上预选下,他才知道还能网上选号,赶紧跟他一起操作了一把。今天就为大家简单介绍下操作,以后卖车再也不用为选号发愁了。

阅读全文 »

一起来用 Python 做个是男人就坚持100秒游戏

发表于 2020-12-22 | 分类于 python

相信大家在初中电脑课上都偷偷玩过 Flash 游戏–是男人就坚持 100 秒,在游戏中无数的小球随机运动,玩家用鼠标控制大球,当大球碰撞到小球后,游戏结束,显示坚持的时间。今天我们一起来开发这个小游戏吧。

阅读全文 »

用 Python 给微信头像加个圣诞老人(平安果)小图标

发表于 2020-12-22 | 分类于 python

圣诞老人是西方神话里圣诞节前夜给小孩子赠送礼物的人物,在国内的圣诞节中,除了圣诞老人,苹果(平安果)也是一个特色元素,本文我们看一下如何使用 Python 给自己的微信头像加一个圣诞老人或苹果小图标。

阅读全文 »

Pythoner 的花式浪漫,你会吗?

发表于 2020-12-21 | 分类于 python

一年一度的圣诞节又到了,对于这个重大的节日,今年的外国人可能比较难,还处在水深火热之中,希望他们一切都赶快好起来。在我们国内,我们还可以像往年一样正常地过节,虽然是一个外国人的节日,但是每年在这个日子里,还是成就了不少鸳鸯的,也不失是一件好事。作为 Python 程序员,你还在送花、送苹果、送口红吗?有没有想过程序猿式的浪漫?本文就抛砖引玉,为大家提供一种思路,希望大家喜欢。

阅读全文 »

十行 Python 代码就提取了韦小宝的身份证信息

发表于 2020-12-16 | 分类于 python

记得以前有个广告词叫:“学好数理化,走遍天下都不怕”,感觉应该再加一句:“带上身份证”,本文我们看一下如何使用 Python 提取身份证信息。

阅读全文 »

记一次线上问题排查与解决

发表于 2020-12-15 | 分类于 python

最近开发中遇到个小问题,因为业务上的设计存在问题,导致数据库表总是被锁,而且是不定期的锁定,导致服务器运行异常,最后经过排查原因是多线程同时更新同一表中同一条记录导致问题。今天就来跟大家说说该如何避免这种问题。

阅读全文 »

程序员奶爸必修课——用 pygame 写小游戏

发表于 2020-12-15 | 分类于 python

周末在家没事,大哥和嫂子要出去 happy,于是将他的儿子丢到我家,让我当奶爸陪玩一下。为了让这磨人的小妖精消停会,我好安静地打盘王者,我灵机一动,准备写个简单的小游戏给他玩一会。

阅读全文 »

用 Python 教你画花样图

发表于 2020-12-11 | 分类于 python

在之前的一篇文章Python可视化神器-Plotly动画展示展现了可视化神器-Plotly的动画的基本应用,本文介绍如何在Python中使用 Plotly 创建地图并在地图上标相应的线。对于 Plotly的详解请参阅之前的文章。

阅读全文 »

用了 Google 这么久,竟然不知道还有这些高级技巧

发表于 2020-12-07 | 分类于 python

封面

搜索引擎基本上是我们每个人天天都要用的东西,但大部分人使用搜索引擎的时候多半是输入关键字之后直接回车,那么你是否遇到过在试了各种关键字之后依然没找到自己想要的答案的时候呢,搜索引擎是智能的,同时也是不智能的,比如我们输入关键字苹果,它怎么知道你是想找水果苹果,还是想找苹果手机呢。

阅读全文 »

都无代码编程了,编程还香吗

发表于 2020-12-06 | 分类于 python

11月29日(2020年),腾讯举行了一场主题为 “重新定义开发” 的小程序开发技术峰会,发布的了新一代的云开发平台,用少量代码,甚至不用代码,就可以快速创建一个云应用,大幅降低应用开发门槛,让人人都能做开发,那么对于程序员以及打算学习编程的人来说,何去何从呢?

云开发厉害在哪里

零运维

相比于传统的系统开发,云开发省去了服务器搭建、系统部署、域名申请、服务器运维等工作

同时提供了弹性的计算能力:当请求量达到一定值,服务器会自动扩容,提高性能,如果请求量减少到一定量,服务器会自动缩容,甚至降低到零,以节省计算资源的使用成本

如果传统开发模式,要到的这样的效果,需要一个技术力量强大的团队才能行,而所作的这些工作,与业务本身关系不大

简单易用

鉴权

之前做个公众号或者小程序开发的童鞋,一定对微信复杂而繁琐的鉴权方式印象深刻,获取 accessToken 不但麻烦,而且还得在过期之前重新获取

使用云开发,会极大地简化了这个过程,并且弱化了相关概念,节省了工作量,降低了学习成本

在云开发平台上,原来各种复杂的事情,利用 微信 SDK(封装了各种接口的开发工具集),像调用普通本地方法一样简单

数据库

数据库是应用重要的组成部分,不过在开发中,搭建数据库、设计库表、调试、运维,需要投入大量的精力和时间

云开发平台,提供了高可用的 NOSql 数据库,不仅无需搭建,还会自动扩容,将复杂的权限管理,简化为适应不同场景的简单配置

数据以 JSON 格式存储,便于理解,而且省去了数据格式来回转换的麻烦

配合数据库实例组件,可以实现业务上的各种操作方式

文件存储

一般来说上传文件、照片等,需要文件存储的支持,传统做法是在服务器上指定存储位置,设置读写权限,如需要加速访问,还需要另购和调试 CDN 服务,极富挑战性

在云开发平台上,使用上传组件,可以轻松地将文件上传至云存储,并且自动支持 CDN 加速

和数据库权限类似,也将访问权限简化为适应不同应用场景的简单配置

免费

对个人开发者来说,应用上面提到的各种特性的云服务资源,是免费的!

免费资源配置

5G 存储空间,5G CDN 月流量、2G 数据库容量、以及 1G 的出网流量,对普通的小程序应用来说,足够了

如果开发的小程序应用得到了市场认可,用户量上来了,可以方便地切换到按量付费模式,实现更强大的弹性计算能力,以支撑业务的增长

腾讯的野心

腾讯为什么要提供这么强大的平台和机会呢?难不成是在做慈善?

链接每个人

微信从 2011 年 1 月 21 日正式发布以来,到现在月活用户已超 12 亿,几乎链接了 “所有人”,已然形成了微信互联网

微信不再只是一个熟人间免费发消息的应用了。甚至,连互联网圈、投资圈里的人经常用来描述微信的那个词 —— 操作系统 —— 也彻底不够用了 微信干脆是个完整的互联网 —— 所有人都在上面的移动互联网 —— 也就是说,先是互联网吞噬了整个世界,而后,微信吞噬了互联网……

——《微信互联网平民创业》李笑来

链接每个系统

如果说微信完成了将人链接起来的使命,那么小程序云开发,就是要将所有应用链接起来,哪怕这个应用只是在你的想象当中

  • 微信构筑了一个巨大的用户网,解决了传统系统构建中的注册、管理、单点登录等问题

  • 云平台提供各种接口,同时提供多种数据导出备份机制,可以轻松的和其他系统关联

  • 统一规格的 UI 组件,应有尽有,满足各种场景的展现和交互

  • 降低开发门槛,提供免费开发资源

这些特性,是为了让更多的人参与到应用开发中来,特别是对那些有想法而没有能力付诸实践的人,利用云开发平台,即可轻松实现

何去何从

微信云开发的出现,只是一个开始,未来程序开发会变得更简单,功能更强大

原本用来安身立命的技术本领用不上了;

学习的个各种新技能知识过时了;

想作为资深程序员宣扬下编码技巧,开发无代码化了……

什么才是重要的?又该如何应对呢?

基础知识更重要

微信云开发,虽然简化了开发过程,让后台(指服务器端)变得不太重要,但所有的技术都是以互联网为基础,依赖于最基本的 Http 协议和基本的编程规范

也就是说,云开发会尽可能多地替代了纯技术,以及可以被自动化的部分,并且这个趋势会不大增大增快,会有更多的云厂商提供更好的自动化技术

而需要程序员做使用基础的编程技能做更多实现更多的业务逻辑

也就是,集中精力学习基础的编程逻辑,了解基本的计算机、网络知识更重要

例如,前端框架工具层出不穷,但都基于基本的 Html、CSS、和 JS 构建

例如,前端模块打包工具 Webpack,很好用,但学习成本高,很快被更为简单易用的 Taro 框架融合,屏蔽了 Webpack 在使用层面的复杂性

强化探索性学习

互联网的快速发展,促生了无数的技术,涉及到互联网技术的方方面面

面对爆炸式的技术增长,不可能面面俱到,学习所有的知识,哪怕是一个方向,不断地迭代也会使我们应接不暇

不禁有人喊出 “老子学不动了” 的呐喊:

老子学不动了

那么应该如何去学呢?大概有几点建议

  • 加强基础知识的学习
  • 广泛地了解技术动态,了解当前的热门和当下正在解决的问题
  • 将新的技术与基础知识相关联,或者用基础知识对技术进行分类
  • 探索性的学习,不用从头到尾看,而是带着问题去了解,比如新框架的鉴权如何实现等

业务和想法更重要

机械化的编程,会越来越多地被机器替代,细节的基础架构,会快速地被简单易用的工具、框架完成

而具体的业务以及我们的想象力,不会被替代

既然有更多的技术支持,更低的开发门槛,我们就更容易地实现原本不容易,甚至不可能实现的的想法

现在不用担心实现问题,不用为搭建平台消耗精力,就会有更多的时间用于思考业务,和解决真正的问题

而业务知识和想象力是机器不具备的,也是无法被代替的,面对技术的发展,如何设计一个产品,去解决一个实际问题,变得更加重要了

想象以下,如果没有计算机技术的发展,我们每个人都离用计算机解决问题很远,那些只能是前沿科学家们才能做的事情

而如今,三两天就可以做出一个使用量超过 600 万的 群登记助手 小程序

总结

腾讯云开发其实不是程序员的克星,更像是一个称职的管家,是一个贴身的保镖,为我们节省了大量的非业务相关时间,为我们加强了系统平台的稳定性,提高了系统的计算性能,让我们可以全心全意学习核心知识、研究业务实质、构建优秀产品

因此,祝愿如虎添翼的你,早日构筑出自己的应用帝国,比心!

参考

  • https://mp.weixin.qq.com/s/Og9POTn4TDPoDOJNNkBxOA
  • https://baike.baidu.com/item/JSON/2462549
  • https://item.jd.com/10024550705540.html
阅读全文 »

Python可视化神器-Plotly动画展示

发表于 2020-12-04 | 分类于 python

在之前的一篇文章Python可视化神器-Plotly展现了可视化神器-Plotly的基本使用,接下来继续本着学习的姿态继续探索可视化神器-Plotly的神奇之旅。本文介绍如何在Python中使用Plotly创建动画。

阅读全文 »

如何优雅的设计一套高性能短网址服务

发表于 2020-12-01 | 分类于 python

得益于移动互联网的蓬勃发展,自媒体日益火爆的同时其门槛也越来越低,可以说是全民自媒体。其中内容创作平台尤为火爆,比如微信公众号、微博、知乎、头条等。随之而来的就是各种「奇葩」需求,比如将长链接转换为短链接务。

阅读全文 »

不懂性能优化,再强的计算机也白玩

发表于 2020-11-29 | 分类于 python

Python 的优秀有目共睹,不过说的性能,还真比不了 Java、C、Go,有没有提升性能的技巧或方法呢?今天我们一起学习下提升 Python 性能的方式方法,那还等啥,来吧

局部变量更好

记得刚开始学习 C 语言时,对先定义再使用,感到很痛苦,经常因为声明问题编译不通

现在用 Python,变量随用随定义,爽到不行

不过我却养成了先定义在使用的习惯,例如:

1
2
3
4
5
a = None  # 可以不写
if some_condition:
    a = 10
else:
    a = 0

虽然 a = None 可以不写,但是还是习惯性的写处理做变量声明,类似 C 中的 int a;

这样的习惯,促使我在写代码之前,会先考虑如何将会用到的变量,从而,对变量的使用范围做出了严格的限定,能是局部的,绝不全局

而这个习惯提高程序的性能同时,还有其他好处

  • 局部变量查找的速度更快,因为 Python 是从代码块里,向外查找变量的,里面找不到,才会去外面找,最后才是全局变量,其他语言也一样
  • 局部变量更节省内存,当代码快被执行,代码块中声明的局部变量所占用的内存就会被释放
  • 让代码更简洁,更易懂,比如可以用局部变量为冗长的命名空间中的变量起别名,如 ls = os.linesp,后面就在可以用 ls 简洁表示 os.linesp 了

函数虽好 尽量少调

函数是个伟大的发明,将可以被重复使用的过程集中起来,方便反复调用,而且函数的出现,使递归得以实现

不过,调用函数的时间成本比一般语句高的多,这是因为,函数的调用需要计算机做更多的调度协调工作

因此,应该尽量减少调用函数,特别是在大的循环中,更要注意

下面,列出几个典型例子,在这些情况下,可以不用调用函数

  • 使用 isinstance 代替 type,因为 Python 是面向对象语言,支持对象的继承,isinstance 可以直接检测对象的基类,不会像 type 一样对对象做全面的检测,会比 isinstance 做更多的函数调用
  • 避免在循环判断中,调用函数

    1
    2
    3
    4
    5
    6
    7
    8
      # 每次循环都需要计算 a 的长度
      while i < len(a):
          statement
    
      # 先计算出 a 的程度,避免每次循环计算
      length = len(a)
      while i < length:
          statement
    
  • 如果模块 X 中有个 Y 对象或函数,那么最后这样引入 from X import Y,而不是 import X,后者每次使用 Y 时,需要通过 X.Y 的方式,比直接使用 Y 多了一次函数调用

映射优于判断

在《编程珠玑 第二版》 第一章开篇中,描述了一个需求,需要对记录了一千多万行 7 位数据的文件中的数据排序,而且需要在很短时间内,在只使用 1M 内存的条件下完成

对于使用着现代计算机的我们来说,简直不可思议

一方面,现在的计算机动辄好几 G,几核,性能超强

另一方面,随便一个编程语言都有内置的高效排序算法

但在当时,计算机最大内存才不过几兆(M)!

你可能不会相信,就在当时的条件下,能在数十秒内完成吧

核心原理就是借用索引,来表示数值,比如 1000 是否存在,就看数组中索引为 1000 的值是否为 1,不存在则为 0,最后只需要便利一遍数组(书上实际应该的是字符串,一个字节索引表示一个数字),就能得到数据排序了

显而易见,相比判断,索引效率更高

例如,应该尽量避免第一种写法,而用第二种:

1
2
3
4
5
6
7
8
9
10
# 判断并赋值
if a == 1:
    b = 10
elif a == 2:
    b = 20
...

# 利用索引,直接存值,性能更好
d = {1:10,2:20,...}
b = d[a]

迭代器的性能更优

Python 中有很多迭代器,方便我们做各种循环

对于可以支持迭代器的对象,使用迭代器获取元素,比用索引获取元素的效率更高

例如:

1
2
3
4
5
6
7
a = [1, 2, 3]

for i in range(len(a)):  # 使用索引获取元素
    print(a[i])

for item in a:  # 使用迭代器获取元素
    print(item)

上面代码中,直接使用迭代器的效率更高

如果最开始接触的语言是 Python,应该比较习惯直接使用迭代器,如果从其他语言转过来,可能更习惯使用索引

另外,如果需要在循环中得到每个元素的索引,可以通过一个索引计数器来实现:

1
2
3
4
5
a = ['a', 'b', 'c']
index = 0  # 初始化索引
for item in a:
    print(index, item)
    index += 1  # 递增索引值

延迟享受是美德

曾经有个著名的心理学实验 —— 棉花糖实验,测试一群小孩子的延迟满足能力,最终的结论是:延迟满足能力强的孩子,未来成功的机率更高

这虽然是对人的测试,但对计算机也适用,不过,背后的逻辑有些不同

对计算机而言,没必要将还用不到的内容加载到内存里,内存就好比我们的工作太,如果放了太的的东西,查找就比较困难,从而影响工作效率

Python 中提供多种延迟加载的功能,其中生成器是个典型的应用

以 list 容器为例,在使用该容器迭代一组数据时,必须事先将所有数据存储到容器中,才能开始迭代

而 生成器 却不同,它可以实现在迭代的同时生成元素,也就是不是一次性生成所元素,只有在使用时才会生成

下面是个数字 生成器 的例子

1
2
3
4
5
6
7
8
9
def initNum():
    for i in range(10):
        yield i

gen = initNum()  # 得到生成器

for item in gen: # 遍历生成器
    print(item)

调用 initNum 会返回一个生成器,在 for 循环中,或者调用 next(等同于 gen.__next__()) 时才会生成下一个数字,在调用之前,不会生成所有的数据

生成器 占用的资源更少,意味着效率更高

先编译再调用

网络上有很多描述产品经理和研发直接矛盾的段子,让人啼笑皆非

最主要的原因是,需求的不确定性和研发需要的确定性是相互矛盾的

面对不到变动的需求,研发需要不断调整,因此效率不会高

相同的道理,计算机执行已经编译好的程序,比执行边解析边执行的程序效率高很多

例如,C 的程序运行效率会更高,因为需要对 C 代码,编译后才能运行

我们在享受 Python 这类动态语言带来的便利性同时,尽量让程序执行已经编译好的代码,以便提升性能

例如:

1
2
3
4
5
6
code = "for i in range(3):\n\tprint(i)"

exec(code)  # 直接执行

c = compile(code, "", "exec")
exec(c)  # 编译后再执行

更常见的是正则表达式

1
2
3
4
line = "name\t\tage\tschool"

reObj = re.compile("\t+")  # 编译
reObj.split(line)  # 使用编译后的性能更好

编译后不仅性能更好,而且在可以反复使用时,进一步提供效率

模块化

我们人类在不断理解这个世界的同时,产生了大量的信息和知识,一直无论哪个人,究其一生也无法掌握所有的知识

于是科学发展为分科之学,将知识分门别类,以便不同的人掌握了解他所关注的一点

知识是这样,我们的合作也是如此,没有一个可以做所有的事情,需要多人相互配合,各负其责

计算机是我们大脑的延伸,是用我们的思考方式、思维习惯制造的

面对大规模代码时,需要对代码进行分门别类,着不仅方便我们人类查看,还能提升程序执行效率,可以在需要时,才去加载和执行模块和方法

例如:

1
2
3
4
5
6
7
8
# module1.py

def fun(alist):
    for item in alist:
        do some thing
# 测试用
a = [1, 2, 3]
fun(a)

定义了函数 fun,之后测试了下,如果其他代码引用了 fun: from module1 import fun

这测试用的代码就会被执行

好的方式是,将测试用代码封装起来:

1
2
3
4
5
6
7
8
9
10
# module1.py

def fun(alist):
    for item in alist:
        do some thing

if __name__ == "__main__":
    # 测试用
    a = [1, 2, 3]
    fun(a)

这样就可以避免测试用代码的无意义执行,从而提升运行效率

总结

虽然现在的计算机性能很强,编程语言提高的功能很多,为我们提高了极大的便利,但是良好的编程习惯和编码规范仍然是很重要的,首先代码更多的时候是写给人看的,另外在强的计算机性能,也解决不了思维懒惰者的低效代码,就好比 你永远叫不醒一个装睡的人 一样。

业精于勤,在日常的工作和编程中,多学多练多思考,会使编程水平的提升事半功倍,看似不起眼的小技巧,处处做好了,将带来巨大的差异,这就是与高手直接的差距

期望今天分享的一点小技巧能给您一丝启发,让您在通往高手的道路上更加顺畅,比心!

参考

  • https://www.tutorialdocs.com/article/7-habits-to-improve-python-programs.html
  • https://stackoverflow.com/questions/1549801/what-are-the-differences-between-type-and-isinstance
  • http://c.biancheng.net/view/2393.html
  • https://www.cnblogs.com/nomorewzx/p/4203829.html
  • https://book.douban.com/subject/3227098/
  • https://baike.baidu.com/item/%E6%A3%89%E8%8A%B1%E7%B3%96%E5%AE%9E%E9%AA%8C/15659236
阅读全文 »
1 2 … 17
Python Geek Tech

Python Geek Tech

一群热爱 Python 的技术人

322 日志
52 分类
38 标签
RSS
GitHub 知乎
Links
  • 纯洁的微笑
© 2019 - 2021 Python Geek Tech
由 Jekyll 强力驱动
主题 - NexT.Mist