模块
相对导入
当前执行文件不能进行相对导入,
只有被导入包里的文件可以进行相对导入
和被执行文件同一目录的包是顶层包,顶层包之间不能互相引用
inspect
def v2():
for frame in inspect.stack():
print(frame[3])
def v1():
v2()
def main():
v1()
if __name__ == "__main__":
main()
v2
v1
main
<module>
语法
闭包
用比较容易懂的人话说,就是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。看例子
如果想在闭包中修改外部函数变量,需要加nolocal关键字。这个和global关键字类似。
def nonlocal_test():
count = 0
def test2():
nonlocal count
count += 1
return count
return test2
val = nonlocal_test()
print(val())
print(val())
print(val())
装饰器
装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象
简单的装饰器
def debug(func):
def wrapper(*args, **kwargs): # 指定宇宙无敌参数
print "[DEBUG]: enter {}()".format(func.__name__)
print 'Prepare and say...',
return func(*args, **kwargs)
return wrapper # 返回
@debug
def say(something):
print "hello {}!".format(something)
带参数的装饰器
其中变量level闭包
def logging(level):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
print "[{level}]: enter function {func}()".format(
level=level, # ****这里是闭包****
func=func.__name__)
return func(*args, **kwargs)
return inner_wrapper
return wrapper
@logging(level='INFO')
def say(something):
print "say {}!".format(something)
类装饰器
class logging(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print "[DEBUG]: enter function {func}()".format(
func=self.func.__name__)
return self.func(*args, **kwargs)
@logging
def say(something):
print "say {}!".format(something)
上下文管理器
from contextlib import contextmanager
class MyResource:
def query(self):
print('query data')
@contextmanager
def make_myresource():
print('start to connect')
yield MyResource()
print('end connect')
pass
@contextmanager 需要配合with … as 使用, yield之前定的语句在进入with 之前调用,紧跟着yield 的函数将返回值传递该as 后的参数,yield之后的语句在退出with之前执行
带参数类装饰器
class logging(object):
def __init__(self, level='INFO'):
self.level = level
def __call__(self, func): # 接受函数
def wrapper(*args, **kwargs):
print "[{level}]: enter function {func}()".format(
level=self.level,
func=func.__name__)
func(*args, **kwargs)
return wrapper #返回函数
@logging(level='INFO')
def say(something):
print "say {}!".format(something)
@functools.wraps(func)
一般情况下wrap后函数名也会发生改变,functools.wraps的功能就是保留原函数名
import time
import functools
def log(kind):
def add_log(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
start_time = time.time()
res = func(*args,**kwargs)
end_time = time.time()
print('<%s> [%s] 函数名:%s,运行时间:%.6f,运行返回值的结果'
':%d' %(kind,time.ctime(),func.__name__,
end_time-start_time,res))
return res
return wrapper
return add_log
@log('debug')
def add():
time.sleep(1)
return 1+1
@log('debug')
def sub():
time.sleep(1)
return 2-1
print(add())
print(sub())
propoerty
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
c.x 将触发 getter,c.x = value 将触发 setter , del c.x 触发 deleter。
types.SimpleNamespace()
今天看到代码使用了SimpleNamespace, 他是和argparse模块一起出现的,很好奇这个是什么东西。经过一般摸索,大概掌握了基本的用法。 我们知道了argparse使用,他是最后返回来了个Namespace,而其实我们这个SimpleNamespace也是返回一个命名空间了。他可以接受命名关键字参数,然后我们就可以使用.运算符。
>> from types import SimpleNamespace
>>> d = {'a': 1, 'b':2}
>>> sn = SimpleNamespace(**d) # 这里的**不可以少,表示命名关键字参数
>>> sn
namespace(a=1, b=2)
>>> sn.a
1
泛型
from typing import TypeVar, Generic
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self) -> None:
# Create an empty list with items of type T
self.items: List[T] = []
def push(self, item: T) -> None:
self.items.append(item)
def pop(self) -> T:
return self.items.pop()
def empty(self) -> bool:
return not self.items
# Construct an empty Stack[int] instance
stack = Stack[int]()
stack.push(2)
stack.pop()
stack.push('x') # Type error
多态
from abc import ABCMeta, abstractmethod
class Transform(metaclass=ABCMeta):
- 多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。
- 在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)
- 也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
- 上述代码子类是约定俗称的实现这个方法,加上@abc.abstractmethod装饰器后严格控制子类必须实现这个方法
多进程
python 多进程传参时默认按值传递,如果想多个进程共享list或dict数据结构需要专门声明
进程之间共享数据(dict,list):
import multiprocessing
def func(mydict,mylist):
mydict["index1"]="aaaaaa" #子进程改变dict,主进程跟着改变
mydict["index2"]="bbbbbb"
mylist.append(11) #子进程改变List,主进程跟着改变
mylist.append(22)
mylist.append(33)
if __name__=="__main__":
with multiprocessing.Manager() as MG: #重命名
mydict=multiprocessing.Manager().dict() #主进程与子进程共享这个字典
mylist=multiprocessing.Manager().list(range(5)) #主进程与子进程共享这个List
p=multiprocessing.Process(target=func,args=(mydict,mylist))
p.start()
p.join()
print(mylist)
print(mydict)
hydra
├───conf
│ │ evaluate.yaml
│ │ preprocess.yaml
│ │ train.yaml
│ │
│ ├───data
│ │ vectornet_train.yaml
│ │ vectornet_val.yaml
│ │
│ ├───hparams
│ │ vectornet_baseline.yaml
│ │
│ ├───model
│ │ vectornet.yaml
│ │
│ └───status
│ debug.yaml
│ train.yaml
hydra主要负责读取层次化的.yaml文件。 在顶层的train.yaml中只要用
resume:
save_dir: models/
log_dir: ${name}/
defaults:
- data: vectornet_train
- model: vectornet
- hparams: vectornet_baseline
- status: train
就可以读取到data,model,hparams文件夹下的vectornet_train.yaml,vectornet.yaml以及vectornet_baseline。 data,model,hparams这三个参数并不会保存到config对象中,但是可以利用main函数的运行时参数进行修改。
如果给出多个运行时参数当做输入参数,即此脚本会自动运行多次,比如:
❯ python main.py lr=1e-3,1e-2 wd=1e-4,1e-2 -m
[2021-03-15 04:18:57,882][HYDRA] Launching 4 jobs locally
[2021-03-15 04:18:57,882][HYDRA] #0 : lr=0.001 wd=0.0001
[2021-03-15 04:18:58,016][HYDRA] #1 : lr=0.001 wd=0.01
[2021-03-15 04:18:58,149][HYDRA] #2 : lr=0.01 wd=0.0001
[2021-03-15 04:18:58,275][HYDRA] #3 : lr=0.01 wd=0.01
matplot
draw dynamic polint cloud
def show_gif(pointsList1,pointsList2):
from matplotlib import pyplot as plt
import numpy as np
import mpl_toolkits.mplot3d.axes3d as p3
from matplotlib import animation
fig = plt.figure()
ax = p3.Axes3D(fig)
ax.set_box_aspect([1,1,1])
ax.set(xlim3d=(-300, 300), xlabel='X')
ax.set(ylim3d=(-300, 300), ylabel='Y')
ax.set(zlim3d=(-300, 300), zlabel='Z')
azim=0
if azim is not None:
ax.azim = azim
# if dist is not None:
# ax.dist = dist
# if elev is not None:
# ax.elev = elev
points1, = ax.plot(pointsList1[0][:,0], pointsList1[0][:,1], pointsList1[0][:,2], '.r')
points2, = ax.plot(pointsList2[0][:,0], pointsList2[0][:,1], pointsList2[0][:,2], '.b')
def update_points(i):
# update properties
points1.set_data(pointsList1[i][:,0], pointsList1[i][:,1])
points1.set_3d_properties(pointsList1[i][:,2], 'z')
points2.set_data(pointsList2[i][:,0], pointsList2[i][:,1])
points2.set_3d_properties(pointsList2[i][:,2], 'z')
# return modified artists
return points1,points2
ani=animation.FuncAnimation(fig, update_points, frames=50)
ani.save('./interpo_gru/save3d/animation.gif', writer='imagemagick', fps=2)
plt.show()
return
plt.subplots_adjust(left=None, bottom=None, right=None, top=None,
wspace=None, hspace=None)
subplots_adjus 可以调整所有子图在归一化figure坐标系中的位置,也可以调整子图之间的距离。
add_axes可以指定子图在figure中的位置,以及宽高占figure宽高的比例
#figure的百分比,从figure 10%的位置开始绘制, 宽高是figure的80%
left, bottom, width, height = 0.1, 0.1, 0.8, 0.8
#获得绘制的句柄
ax1 = fig.add_axes([left, bottom, width, height])
ax1.plot(x, y, ‘r’)
ax1.set_title(‘area1’)
#新增区域ax2,嵌套在ax1内,看一看图中图是什么样,这就是与subplot的区别
left, bottom, width, height = 0.2, 0.6, 0.25, 0.25
#获得绘制的句柄
ax2 = fig.add_axes([left, bottom, width, height])
ax2.plot(x,y, ‘b’)
ax2.set_title(‘area2’)
plt.show()
结果如下:
#figure的百分比,从figure 10%的位置开始绘制, 宽高是figure的80%
left, bottom, width, height = 0.1, 0.1, 0.8, 0.8
#获得绘制的句柄
ax1 = fig.add_axes([left, bottom, width, height])
ax1.plot(x, y, ‘r’)
ax1.set_title(‘area1’)
#新增区域ax2,嵌套在ax1内,看一看图中图是什么样,这就是与subplot的区别
left, bottom, width, height = 0.2, 0.6, 0.25, 0.25
#获得绘制的句柄
ax2 = fig.add_axes([left, bottom, width, height])
ax2.plot(x,y, ‘b’)
ax2.set_title(‘area2’)
plt.show()
结果如下:
#figure的百分比,从figure 10%的位置开始绘制, 宽高是figure的80%
left, bottom, width, height = 0.1, 0.1, 0.8, 0.8
#获得绘制的句柄
ax1 = fig.add_axes([left, bottom, width, height])
ax1.plot(x, y, ‘r’)
ax1.set_title(‘area1’)
#新增区域ax2,嵌套在ax1内,看一看图中图是什么样,这就是与subplot的区别
left, bottom, width, height = 0.2, 0.6, 0.25, 0.25
#获得绘制的句柄
ax2 = fig.add_axes([left, bottom, width, height])
ax2.plot(x,y, ‘b’)
ax2.set_title(‘area2’)
plt.show()
plt.axis(‘off’)
可以去除边框