Python
python 是一种脚本语言,其底层采用 C 语言实现。编写好的 python 代码,会先转为字节码,然后在 c 语言编写的虚拟机上进行运行。python 里面所有的东西都是对象,数据是对象、函数是对象、类是对象。对象可以作为参数进行传递!
def get_function(choose):def func_add(a, b):return a + bdef func_mult(a, b):return a * breturn func_add if choose == 1 else func_multfunc = get_function(1)print(func(3, 8))func = get_function(2)print(func(3, 8))
Python Debugger
https://docs.python.org/3/library/pdb.html
迭代器
iterable
可迭代对象是能够提供迭代器的对象,如要使得对象可以迭代,只需要实现 Python 两个内置函数 iter 或者 _getitem (pytorch 中的 DataSet 就是可迭代的),之后采用 _iter(iterableObject) 即可获取迭代器
python 中的类,一经定义是会自动被赋予这些魔法函数的(双下划线开始和结尾)
iterator
迭代器即为实现了 _next 方法的对象,可以通过 _next(object) 每次获取一个数据。
生成器
生成器和迭代器非常类似,其只需要在函数中采用关键字 yield data 即可(data为生成数据)。迭代器和生成器非常类似,都用于迭代获取数据的场景。但是生成器只有调用的时候才会产生对应的数据(节省内存),迭代器数据在一开始就被产生。
- 迭代器每次 yield 之后,从 yield 下一句开始运行
- 迭代器和生成器产生数据结束之后都会 raise StopIteration 的 exception
修饰器(神奇操作)
python 中一切皆为对象,当然函数也是对象罗,函数可以作为参数进行传递或者返回。装饰器接收一个函数作为参数,然后返回一个新的函数。
def a_new_decorator(a_func):def wrapTheFunction():print("I am doing some boring work before executing a_func()")a_func()print("I am doing some boring work after executing a_func()")return wrapTheFunctiondef a_function_requiring_decoration():print("I am the function which needs some decoration to remove my foul smell")a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)a_function_requiring_decoration()
上述代码等价于
def a_new_decorator(a_func):def wrapTheFunction():print("I am doing some boring work before executing a_func()")a_func()print("I am doing some boring work after executing a_func()")return wrapTheFunction@a_new_decoratordef a_function_requiring_decoration():print("I am the function which needs some decoration to remove my foul smell")a_function_requiring_decoration()
按照上述操作之后,被修饰的函数事实上是被 decorator 中返回的函数替换了,func.name 可以看到变了!为了解决这个问题,需要在装饰器内部进行声明(@wraps(a_func):
from functools import wrapsdef a_new_decorator(a_func):@wraps(a_func)def wrapTheFunction(*args, **kwargs):print("I am doing some boring work before executing a_func()")a_func(*args, **kwargs)print("I am doing some boring work after executing a_func()")return wrapTheFunction@a_new_decoratordef a_function_requiring_decoration():print("I am the function which needs some decoration to remove my foul smell")a_function_requiring_decoration()
为了解决参数匹配问题:在装饰器内部的函数通常采用 args, *kwargs 来接收参数
带参数装饰器
from functools import wrapsdef logit(logfile='out.log'):def logging_decorator(func):@wraps(func)def wrapped_function(*args, **kwargs):log_string = func.__name__ + " was called"print(log_string)# 打开logfile,并写入内容with open(logfile, 'a') as opened_file:# 现在将日志打到指定的logfileopened_file.write(log_string + '\n')return func(*args, **kwargs)return wrapped_functionreturn logging_decorator@logit()def myfunc1():pass@logit(logfile='func2.log')def myfunc2():passmyfunc1()myfunc2()
装饰器类
from functools import wrapsclass logit(object):def __init__(self, logfile='out.log'):self.logfile = logfiledef __call__(self, func):@wraps(func)def wrapped_function(*args, **kwargs):log_string = func.__name__ + " was called"print(log_string)# 打开logfile并写入with open(self.logfile, 'a') as opened_file:# 现在将日志打到指定的文件opened_file.write(log_string + '\n')# 现在,发送一个通知self.notify()return func(*args, **kwargs)return wrapped_functiondef notify(self):# logit只打日志,不做别的pass@logit()def myfunc1():pass
map, filter and reduce
map
_map(function, iterable, ...)_
如果定义了一个函数 func_add,我们有多组输入,可以采用 map 将所有输入映射到函数得到输出,输出为 mapObject,将其转为 list 即可查看
def func_add(a, b):return a + bresult = map(func_add, [1, 3], [5, 7])print(list(result))
- 如果是多元输入的函数,则采用多个迭代器即可
- map 更常用语匿名函数即 lambda 表达式:
a = map(lambdax, y: x * y, [1, 2], [3, 4])
filter
filter 用于数据的过滤,即保存某些符合指定要求的元素,例如 filtered = filter(lambda x: x.requires_grad==True, params)(其中 params 是可迭代的)
reduce
reduce 对可迭代对象进行元素按照传入的函数进行计算,计算过程是迭代的,直至最终计算的结果为一个常数。
from functools import reduceb = [1, 2, 3, 4, 5]a = reduce(lambda x, y: x * y, b)
代码中,reduce 首先取 b 的头两个数进行计算,计算结果和第三个数进行计算,产生结果之后和第四个数进行计算,以此类推…可以方便用于多个数求累积
常用库或函数
zip
dis
可以实现将 python 代码转为字节码
import disdis.dis("a = [1, 2, 3]")
内存管理
python 中的每个对象都有一个引用标签,比如可能两个变量 p1, p2 都引用的同一个对象,那么该对象的引用标签即为 2,python 在进行内存回收时,对于引用标签不为 0 的不会进行回收,对于引用标签为 0 的进行回收。
class person:def __init__(self):self.name = "Alice"a = person()b = adel aprint(b.name)
实例化的 person 对象在上述代码中开始有两个引用,调用 del 会删除一个引用,但是由于该对象引用不为 0,所以其内存不会被释放
