python 杂记

记录python相关的知识或使用技巧。

LEGB规则

LEGB含义解释:
L-Local(function):函数内的名字空间
E-Enclosing function locals:外部嵌套函数的名字空间(例如closure)
G-Global(module):函数定义所在模块(文件)的名字空间
B-Builtin(Python):Python内置模块的名字空间

yield 语句

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
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK'

def produce(c):
c.send(None) # first para is None
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close()

c = consumer()
produce(c)

# result
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK

将列表中的元素,依次每 k 个分作一组

1
2
3
4
5
6
7
def group_each(a, size: int):
"""
将一个可迭代对象 a 内的元素, 每 size 个分为一组
list(group_each([1,2,3,4], 2)) -> [(1,2), (3,4)]
"""
iterators = [iter(a)] * size # 将新构造的 iterator 复制 size 次(浅复制)
return zip(*iterators) # 然后 zip

偏函数

1
2
3
4
from functools import partial

# 每两个分一组
group_each_2 = partial(group_each, size=2)

多 dict 的去重

1
2
# a = [{'a': 1}, {'a': 1}, {'b': 2}]
# a = [{'a': 1}, {'b': 2}]
1
2
3
4
5
6
7
8
9
10
import json

def unique_dicts(data_list: list):
"""unique a list of dict
dict 是 unhashable 的,不能放入 set 中,所以先转换成 str

unique_dicts([{'a': 1}, {'a': 1}, {'b': 2}]) -> [{'a': 1}, {'b': 2}]
"""
data_json_set = set(json.dumps(item) for item in data_list)
return [json.loads(item) for item in data_json_set]

str 的 startswith 和 endswith 两个函数的参数可以是元组

1
2
3
>>> file = "/opt/gts.tar.gz"
>>> file.endswith((".gz", "txt"))
True

交互环境下的”_”操作符

在 Python 控制台,不论何时我们测试一个表达式或者调用一个方法,结果都会分配给一个临时变量: _(一个下划线) 。

1
2
3
4
>>> 2 + 3
5
>>> _
5

开启文件分享

Python 允许运行一个 HTTP 服务器来从根路径共享文件,下面是开启服务器的命令:(python3环境)

1
python3 -m http.server

上面的命令会在默认端口也就是 8000 开启一个服务器,你可以将一个自定义的端口号以最后一个参数的方式传递到上面的命令中。

重置递归限制

1
2
3
4
5
6
7
>>> import sys

>>> sys.getrecursionlimit()
1000
>>> sys.setrecursionlimit(2000)
>>> sys.getrecursionlimit()
2000

检查一个对象的内存使用

1
2
3
4
>>> import sys

>>> sys.getsizeof(1)
28

使用slots来减少内存开支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> import sys

>>> class FileSystem(object):
def __init__(self, files, folders, devices):
self.files = files
self.folders = folders
self.devices = devices3

>>> sys.getsizeof(FileSystem)
1056

>>> class FileSystem1(object):
__slots__ = ['files', 'folders', 'devices']

def __init__(self, files, folders, devices):
self.files = files
self.folders = folders
self.devices = devices

>>> sys.getsizeof(FileSystem1)
888

将中文转为unicode编码

1
2
>>> "编码".encode("unicode_escape")
b'\\u7f16\\u7801'

创建多级目录

1
2
3
import os

os.makdirs("/opt/a/b/c")

打印日期序列

1
2
3
4
5
6
7
8
9
>>> import pandas as pd
>>> a = pd.date_range("2020-02-25", "2020-03-02")
>>> a
DatetimeIndex(['2020-02-25', '2020-02-26', '2020-02-27', '2020-02-28',
'2020-02-29', '2020-03-01', '2020-03-02'],
dtype='datetime64[ns]', freq='D')
>>> time_list = [x.strftime("%Y-%m-%d") for x in pd.date_range("2020-02-25", "2020-03-02")]
>>> time_list
['2020-02-25', '2020-02-26', '2020-02-27', '2020-02-28', '2020-02-29', '2020-03-01', '2020-03-02']

查看当前系统编码方式

1
2
3
>>> import locale

>>> locale.getpreferredencoding()

序列过滤

1
2
3
4
5
6
7
8
9
10
11
>>> import random

>>> lst = [random.randint(-10, 10) for range(10)]
>>> lst
[2, 10, 3, 4, 6, -4, 2, 1, -6, -7]

>>> [x for x in lst if x > 0]
[2, 10, 3, 4, 6, 2, 1]

>>> list(filter(lambda x: x > 0, lst))
[2, 10, 3, 4, 6, 2, 1]

命名元组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import collections


student = collections.namedtuple("student", ("name", "age", "grade"))

# 方式一
jack = student("Jack", 20, "A") # student(name='Jack', age=20, grade='A')

# 方式二
bob = student(**dict(name="Jack", age=20, grade="A"))

print(jack[0]) # 'Jack'
print(jack.name) #'Jack'

print(bob[-1]) # 'A'
print(bob.grade) # 'A'

实现tailhead功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# -*- coding: utf-8 -*-

from collections import deque
from itertools import islice


def head(path, n=10, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
try:
with open(path, mode, buffering, encoding, errors, newline, closefd, opener) as f:
return deque(islice(f, n - 1))
except Exception as e:
print(e)


def tail(path, n=10, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
try:
with open(path, mode, buffering, encoding, errors, newline, closefd, opener) as f:
return deque(f, maxlen=n)
except Exception as e:
print(e)


if __name__ == "__main__":
path = "NEWS.txt"

实现轮询调度器

实现下述需求

1
['ABC', 'D', 'EF'] --> ['A', 'D', 'E', 'B', 'F', 'C']

方式一:可以通过在 deque 中放入迭代器来实现。

值从当前迭代器的位置0被取出并暂存(yield)。 如果这个迭代器消耗完毕,就用 popleft() 将其从对列中移去;否则,就通过 rotate() 将它移到队列的末尾

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from collections import deque

def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
iterators = deque(map(iter, iterables))
while iterators:
try:
while True:
yield next(iterators[0])
iterators.rotate(-1)
except StopIteration:
# Remove an exhausted iterator.
iterators.popleft()

if __name__ == "__main__":
roundrobin('ABC', 'D', 'EF')

耗时测试:

1
2
3
4
>>> import timeit

>>> timeit.timeit("list(roundrobin('ABC', 'D', 'EF'))", "from __main__ import roundrobin")
8.649481091000325

方式二:通过zip_longest实现。

1
2
3
4
5
>>> import functools
>>> import itertools

>>> list(filter(lambda x: x, functools.reduce(lambda x, y: x + y, itertools.zip_longest('ABC', 'D', 'EF'))))
['A', 'D', 'E', 'B', 'F', 'C']

耗时测试:

1
2
3
4
>>> import timeit

>>> timeit.timeit("list(filter(lambda x: x, functools.reduce(lambda x, y: x + y, itertools.zip_longest('ABC', 'D', 'EF'))))", "import functools")
4.335959078000087

python 在函数内部获取函数名

方式一:sys._getframe().f_code.co_name

1
2
3
4
5
6
import sys


def my_function_1():
func_name = sys._getframe(0).f_code.co_name
print(func_name)

方式二:用inspect模块中的inspect.stack()

1
2
3
4
import inspect

def my_function_2():
print(inspect.stack()[0][3])

python获取当前进程所在的文件名

  • sys._getframe().f_code.co_filename
  • __file__

re中的\1\2\3问题

1
2
3
4
>>> import re
>>> st = "Today is 01/08/2020, yesterday is 01/08/2020."
>>> re.sub("(\d+)/(\d+)/(\d+)", r"\3-\1-\2", st)
'Today is 2020-01-08, yesterday is 2020-01-08.'

简析Python中的四种队列

参考:https://www.jianshu.com/p/55243999aa56

spark 中文文档

http://spark-cn.cn/rdd-programming-guide.html
Apache Spark 2.2.0 官方文档中文版

Python 中关于 round 函数的小坑

round的结果跟python版本有关:

1
2
3
4
Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:25:58) [MSC v.1500 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> round(2.5)
3.0
1
2
3
4
Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
>>> round(2.5)
2

阅读一下python的文档,里面是这么写的:

在python2.7的doc中,round()的最后写着,”Values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done away from 0.” 保留值将保留到离上一位更近的一端(四舍六入),如果距离两端一样远,则保留到离0远的一边。所以round(0.5)会近似到1,而round(-0.5)会近似到-1。

但是到了python3.5的doc中,文档变成了”values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done toward the even choice.” 如果距离两边一样远,会保留到偶数的一边。比如round(0.5)和round(-0.5)都会保留到0,而round(1.5)会保留到2。

python 求最小公倍数

1
2
3
4
5
6
7
8
9
10
11
# -*- coding:utf-8 -*-
import math


while True:
try:
m, n = map(int, input().strip().split())
max_fac = math.gcd(m, n) # 最大公约数
print(m * n // max_fac) # 最小公倍数
except Exception as e:
break

python求两数的最大公约数

  • 使用 math.gcd 方法
1
2
3
>>> import math
>>> math.gcd(20, 25)
5
  • 欧几里德算法

欧几里德算法又称辗转相除法, 用于计算两个整数a, b的最大公约数。其计算原理依赖于下面的定理:
定理:gcd(a, b) = gcd(b, a mod b) (a > b)

证明:
a可以表示成a = kb + r, 则r = a mod b
假设d是a, b的一个公约数, 则有 d|a, d|b, 而r = a - kb, 因此d|r。
因此,d是(b, a mod b)的公约数。
加上d是(b,a mod b)的公约数,则d|b, d|r, 但是a = kb + r,因此d也是(a, b)的公约数。
因此,(a, b) 和(a, a mod b)的公约数是一样的,其最大公约数也必然相等,得证。

1
2
3
4
5
6
7
8
9
10
11
# -*- coding:utf-8 -*-

def gcd(a, b):
a, b = a, b if a >= b else b, a
while b != 0:
remainder = a % b
a = b
b = remainder
return a

gcd(20, 25)

python中开n次方根

利用 pow(a, b) 函数即可。需要开a的r次方则 pow(a, 1/r)

‘ascii’ codec can’t encode characters in position 0-6: ordinal not in range(128)

1
'ascii' codec can't encode characters in position 0-6: ordinal not in range(128)

方式一 在文件开头添加:

1
2
3
import sys
reload(sys)
sys.setdefaultencoding('utf8')

方式二:

1
2
3
import sys
import io
sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding="utf-8")

Python2.x 和 Python3.x 中 raw_input( ) 和 input( ) 区别

Python3.x 中 input() 函数接受一个标准输入数据,返回为 string 类型。

Python2.x 中 input() 相等于 eval(raw_input(prompt)) ,用来获取控制台的输入。

raw_input() 将所有输入作为字符串看待,返回字符串类型。而 input() 在对待纯数字输入时具有自己的特性,它返回所输入的数字的类型( int, float )。

注意:input() 和 raw_input() 这两个函数均能接收 字符串 ,但 raw_input() 直接读取控制台的输入(任何类型的输入它都可以接收)。而对于 input() ,它希望能够读取一个合法的 python 表达式,即你输入字符串的时候必须使用引号将它括起来,否则它会引发一个 SyntaxError 。

除非对 input() 有特别需要,否则一般情况下我们都是推荐使用 raw_input() 来与用户交互。

注意:python3 里 input() 默认接收到的是 str 类型。

python 垃圾回收机制

https://www.cnblogs.com/pinganzi/p/6646742.html

检查一个进程是否存在

1
2
3
4
5
6
7
8
def check_pid(pid):
""" Check For the existence of a unix pid. """
try:
os.kill(pid, 0)
except (OSError, ProcessLookupError):
return False
else:
return True

删除一个文件

1
2
3
4
5
6
7
8
9
os.unlink(file_path)

>>> import os
>>> os.unlink("a")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory: 'a'

注:os.unlink() 方法用于删除文件,如果文件是一个目录则返回一个错误。

python 控制台输出中文设置

1
os.environ["PYTHONIOENCODING"] = "UTF-8"

处理 Django admin.py Unknown command: ‘collectstatic’

settings.py文件的INSTALLED_APPS中添加django.contrib.staticfiles

python 格式化输出json文件

1
2
3
4
5
6
7
8
9
[root@master01 ~]# python -m json.tool /etc/docker/key.json 
{
"crv": "P-256",
"d": "dhFxxOEzeg9Gp6VkTaxR-u1g7_B9fV5fCqRAVH9dbbU",
"kid": "6UJ7:FPOO:J6DR:MY5Q:SKVX:73MZ:2W33:ZAHS:5A4W:EWB2:TLNF:RBOY",
"kty": "EC",
"x": "znFo4I-9g1i8gAWDvtwc9JPKOewp5_iGB00Z7ZrRpRs",
"y": "BnhWJZhofXl74w9hm6uvdtOLuRf8X36Llb_hCBL2yPc"
}
-------------本文结束感谢您的阅读-------------