python 进阶

Python

python 是一种脚本语言,其底层采用 C 语言实现。编写好的 python 代码,会先转为字节码,然后在 c 语言编写的虚拟机上进行运行。python 里面所有的东西都是对象,数据是对象、函数是对象、类是对象。对象可以作为参数进行传递!

  1. def get_function(choose):
  2. def func_add(a, b):
  3. return a + b
  4. def func_mult(a, b):
  5. return a * b
  6. return func_add if choose == 1 else func_mult
  7. func = get_function(1)
  8. print(func(3, 8))
  9. func = get_function(2)
  10. 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 中一切皆为对象,当然函数也是对象罗,函数可以作为参数进行传递或者返回。装饰器接收一个函数作为参数,然后返回一个新的函数。

  1. def a_new_decorator(a_func):
  2. def wrapTheFunction():
  3. print("I am doing some boring work before executing a_func()")
  4. a_func()
  5. print("I am doing some boring work after executing a_func()")
  6. return wrapTheFunction
  7. def a_function_requiring_decoration():
  8. print("I am the function which needs some decoration to remove my foul smell")
  9. a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
  10. a_function_requiring_decoration()

上述代码等价于

  1. def a_new_decorator(a_func):
  2. def wrapTheFunction():
  3. print("I am doing some boring work before executing a_func()")
  4. a_func()
  5. print("I am doing some boring work after executing a_func()")
  6. return wrapTheFunction
  7. @a_new_decorator
  8. def a_function_requiring_decoration():
  9. print("I am the function which needs some decoration to remove my foul smell")
  10. a_function_requiring_decoration()

按照上述操作之后,被修饰的函数事实上是被 decorator 中返回的函数替换了,func.name 可以看到变了!为了解决这个问题,需要在装饰器内部进行声明(@wraps(a_func):

  1. from functools import wraps
  2. def a_new_decorator(a_func):
  3. @wraps(a_func)
  4. def wrapTheFunction(*args, **kwargs):
  5. print("I am doing some boring work before executing a_func()")
  6. a_func(*args, **kwargs)
  7. print("I am doing some boring work after executing a_func()")
  8. return wrapTheFunction
  9. @a_new_decorator
  10. def a_function_requiring_decoration():
  11. print("I am the function which needs some decoration to remove my foul smell")
  12. a_function_requiring_decoration()

为了解决参数匹配问题:在装饰器内部的函数通常采用 args, *kwargs 来接收参数

带参数装饰器

  1. from functools import wraps
  2. def logit(logfile='out.log'):
  3. def logging_decorator(func):
  4. @wraps(func)
  5. def wrapped_function(*args, **kwargs):
  6. log_string = func.__name__ + " was called"
  7. print(log_string)
  8. # 打开logfile,并写入内容
  9. with open(logfile, 'a') as opened_file:
  10. # 现在将日志打到指定的logfile
  11. opened_file.write(log_string + '\n')
  12. return func(*args, **kwargs)
  13. return wrapped_function
  14. return logging_decorator
  15. @logit()
  16. def myfunc1():
  17. pass
  18. @logit(logfile='func2.log')
  19. def myfunc2():
  20. pass
  21. myfunc1()
  22. myfunc2()

上述代码中,logit 返回的是包裹函数的函数

装饰器类

  1. from functools import wraps
  2. class logit(object):
  3. def __init__(self, logfile='out.log'):
  4. self.logfile = logfile
  5. def __call__(self, func):
  6. @wraps(func)
  7. def wrapped_function(*args, **kwargs):
  8. log_string = func.__name__ + " was called"
  9. print(log_string)
  10. # 打开logfile并写入
  11. with open(self.logfile, 'a') as opened_file:
  12. # 现在将日志打到指定的文件
  13. opened_file.write(log_string + '\n')
  14. # 现在,发送一个通知
  15. self.notify()
  16. return func(*args, **kwargs)
  17. return wrapped_function
  18. def notify(self):
  19. # logit只打日志,不做别的
  20. pass
  21. @logit()
  22. def myfunc1():
  23. pass

map, filter and reduce

map

_map(function, iterable, ...)_
如果定义了一个函数 func_add,我们有多组输入,可以采用 map 将所有输入映射到函数得到输出,输出为 mapObject,将其转为 list 即可查看

  1. def func_add(a, b):
  2. return a + b
  3. result = map(func_add, [1, 3], [5, 7])
  4. 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 对可迭代对象进行元素按照传入的函数进行计算,计算过程是迭代的,直至最终计算的结果为一个常数。

  1. from functools import reduce
  2. b = [1, 2, 3, 4, 5]
  3. a = reduce(lambda x, y: x * y, b)

代码中,reduce 首先取 b 的头两个数进行计算,计算结果和第三个数进行计算,产生结果之后和第四个数进行计算,以此类推…可以方便用于多个数求累积

常用库或函数

zip

将可迭代对象进行组成形成元组,之后将所有元组组成形成列表

dis

可以实现将 python 代码转为字节码

  1. import dis
  2. dis.dis("a = [1, 2, 3]")

内存管理

python 中的每个对象都有一个引用标签,比如可能两个变量 p1, p2 都引用的同一个对象,那么该对象的引用标签即为 2,python 在进行内存回收时,对于引用标签不为 0 的不会进行回收,对于引用标签为 0 的进行回收。

  1. class person:
  2. def __init__(self):
  3. self.name = "Alice"
  4. a = person()
  5. b = a
  6. del a
  7. print(b.name)

实例化的 person 对象在上述代码中开始有两个引用,调用 del 会删除一个引用,但是由于该对象引用不为 0,所以其内存不会被释放