python_tips

1. python版本管理

Linux发行版自带的python解释器被多个系统组件所依赖,如ubuntu20.04自带的python3.8.10。强行sudo ln -sf /usr/bin/python3.9 /usr/bin/python3会造成系统组件无法开启,比如terminal无响应,应该禁止使用这种覆盖系统python解释器的做法。推荐使用pyenv来管理python解释版本。

2. 偏函数partial

https://stackoverflow.com/questions/15331726/how-does-functools-partial-do-what-it-does

functools提供的partial高阶函数操作,用于简化原始函数的调用方式,使用args和kwargs来覆盖原函数的部分参数,使得调用更加简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from functools import partial

def add(a, b, c, d=1) -> int:
return 1000 * a + 100 * b + 10 * c + d

partial_add = partial(add, 2, d=5)

# partial函数使得第一个位置参数a始终为2,关键字参数d预设为5
print(partial_add(3, 4)) # 2345
print(partial_add(3, 4, d=6)) # 2346

# 在调用int方法时,始终将base设置为2
basetwo = partial(int, base=2)
basetwo.__doc__ = 'Convert base 2 string to an int.'
print(basetwo('10010'))
1
2
3
4
5
6
7
8
# 偏函数的实现
def partial(func, *part_args, **part_kwargs):
def wrapper(*extra_args, **extra_kwargs):
args = list(part_args)
args.extend(extra_args)
kwargs = {**part_kwargs, **extra_kwargs} #关键字参数可以在调用时覆盖
return func(*args, **kwargs)
return wrapper

3.exec的用法

https://docs.python.org/3/library/functions.html#exec

exec可以动态的执行一段存储在string中的python代码

1
2
3
4
5
6
7
8
9
10
11
code = """
def fibo(n):
a = 0
b = 1
for i in range(n-2):
b, a = a+b, b
return b
"""

exec(code)
print(fibo(5))
1
2
3
4
5
6
7
8
code = """
def add_a(n):
return a + n
"""
env = {"a": 100}
exec(code, env) #不同于上面的情况,add_a函数只存在于env globals作用域下
print(env["add_a"])
print(env["add_a"](5))

4. 函数参数中的/和*

https://www.zhihu.com/question/287097169

*后的参数必须使用关键字的方式调用,不能用位置参数的方式。

1
2
3
4
5
6
7
8
9
10
def add(a, *, b, c):
return a + b + c


print(add(1, 2, 3))
# Traceback (most recent call last):
# File "/Users/noname/Desktop/yunwei/test.py", line 4, in <module>
# print(add(1, 2, 3))
# TypeError: add() takes 1 positional argument but 3 were given
print(add(1, b=2, c=3)) # 6

/前的参数必须使用位置参数的调用形式,而不能使用关键字参数。

1
2
3
4
5
6
7
8
9
10
def add(a, b, /, c):
return a + b + c


print(add(1, b=2, c=3))
# Traceback (most recent call last):
# File "/Users/noname/Desktop/yunwei/test.py", line 4, in <module>
# print(add(1, b=2, c=3))
# TypeError: add() got some positional-only arguments passed as keyword arguments: 'b'
print(add(1, 2, c=3)) # 6

5. globals()和locals()

https://stackoverflow.com/questions/7969949/whats-the-difference-between-globals-locals-and-vars

locals() 返回是当前局部变量的深拷贝,修改locals() 中变量值的时候,实际上对于原变量本身是没有任何影响的。
而globals()返回的是全局变量的字典,修改其中的内容,值会真正的发生改变。

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
d = 1000

def add(a, b):
c = 100
local_vars = locals()
print(local_vars)
# {'a': 1, 'b': 10, 'c': 100}
local_vars['c'] = 200
print(locals())
# {'a': 1, 'b': 10, 'c': 100, 'local_vars': {...}}
global_vars = globals()
print(global_vars)
# {'__name__': '__main__', '__doc__': None, '__package__': None,
# '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x108397340>,
# '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>,
# '__file__': '/Users/noname/Desktop/yunwei/test.py',
# '__cached__': None, 'd': 1000, 'add': <function add at 0x1083890d0>}
global_vars['d'] = 2000
print(globals())
# {'__name__': '__main__', '__doc__': None, '__package__': None,
# '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x108397340>,
# '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>,
# '__file__': '/Users/noname/Desktop/yunwei/test.py', '
# __cached__': None, 'd': 2000, 'add': <function add at 0x1083890d0>}

return a + b + c + d

if __name__ == '__main__':
print(add(1, 10))
# 2111 对locals的修改不生效,对globals的修改会生效

6. functools.wraps

https://stackoverflow.com/questions/308999/what-does-functools-wraps-do

用于将装饰器装饰的原始函数的docstring,name,参数列表等复制到被装饰后的函数。

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

def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging

@logged
def f(x):
"""does some math"""
return x + x * x

print(f.__name__) # prints 'f'
print(f.__doc__) # prints 'does some math'

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!