Python
python 是一种脚本语言,其底层采用 C 语言实现。编写好的 python 代码,会先转为字节码,然后在 c 语言编写的虚拟机上进行运行。python 里面所有的东西都是对象,数据是对象、函数是对象、类是对象。对象可以作为参数进行传递!
def get_function(choose):
def func_add(a, b):
return a + b
def func_mult(a, b):
return a * b
return func_add if choose == 1 else func_mult
func = 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 wrapTheFunction
def 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_decorator
def 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 wraps
def 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_decorator
def 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 wraps
def 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:
# 现在将日志打到指定的logfile
opened_file.write(log_string + '\n')
return func(*args, **kwargs)
return wrapped_function
return logging_decorator
@logit()
def myfunc1():
pass
@logit(logfile='func2.log')
def myfunc2():
pass
myfunc1()
myfunc2()
装饰器类
from functools import wraps
class logit(object):
def __init__(self, logfile='out.log'):
self.logfile = logfile
def __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_function
def 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 + b
result = 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 reduce
b = [1, 2, 3, 4, 5]
a = reduce(lambda x, y: x * y, b)
代码中,reduce 首先取 b 的头两个数进行计算,计算结果和第三个数进行计算,产生结果之后和第四个数进行计算,以此类推…可以方便用于多个数求累积
常用库或函数
zip
dis
可以实现将 python 代码转为字节码
import dis
dis.dis("a = [1, 2, 3]")
内存管理
python 中的每个对象都有一个引用标签,比如可能两个变量 p1, p2 都引用的同一个对象,那么该对象的引用标签即为 2,python 在进行内存回收时,对于引用标签不为 0 的不会进行回收,对于引用标签为 0 的进行回收。
class person:
def __init__(self):
self.name = "Alice"
a = person()
b = a
del a
print(b.name)
实例化的 person 对象在上述代码中开始有两个引用,调用 del 会删除一个引用,但是由于该对象引用不为 0,所以其内存不会被释放