python笔记:一些常用的小trick(二)

1. 装饰器

装饰器的概念有点类似于数学中的泛函,是函数的函数。其输入参数为一个方法,输出为另一个方法。

熟练地使用装饰器,我们可以更好地对函数进行模块化操作,减少重复代码量。

下面,我们来考察一下装饰器的使用,具体包括以下内容:

  1. 装饰器的一般用法
  2. 向装饰器中传入额外参数

1. 一般用法

给出装饰器的基础用法如下:

def decorator(func):
    def wrapper(*args, **kwargs):
        ret = func(*args, **kwargs)
        print(ret)
        return ret
    return wrapper

@decorator
def my_func(n):
    return n*(n+1) / 2

myfunc(100) 

运行得到:

5050

2. 参数传递方法

要向装饰器中传入参数,在实现上只需要在装饰器外部再包装一层函数即可实现。

def decorator(log):
    def _decorator(func):
        def wrapper(*args, **kwargs):
            print(log)
            ret = func(*args, **kwargs)
            print(ret)
            return ret
        return wrapper
    return _decorator

@decorator("=== 高斯求和 ===")
def my_func(n):
    return n*(n+1) / 2

myfunc(100) 

运行得到:

=== 高斯求和 ===
5050

2. 生成器

生成器是python中的一种常用的优化性能的方法,其核心在于其计算是lazy的,每次只有当调用时才会进行相应的计算。通过这样的方式,我们往往可以大大优化内存的使用,因为我们不需要一次性的将所有的计算内容全部计算完成并保存到内存中了。

一种最为简单的生成器实现方法为:

my_iter = (i for i in range(10))
type(my_iter) # generator

但是,在实际使用中,我们所需要的生成器内容往往会更为复杂,很难全部使用列表生成式进行写作,更多的情况下,我们会将其写在函数中,并通过yield方法进行实现。

其典型的生成器调用样例如下:

def my_iter(n):
    for i in range(n):
        yield i

for i in my_iter(10):
    print(i)

可以看到,生成器往往会与yield方法联合使用,yield方法表示在执行到当前内容时直接返回后面的结果,并且在下一次调用这个函数时从下一行开始继续执行。

如果不使用for循环,我们也可以通过下面的方式手动触发生成器:

tmp = my_iter(10)

next(tmp) # 0
next(tmp) # 1

不过需要注意的是,在使用next函数时,如果已经取完了生成器中的所有元素,那么下一次调用next函数将会报错,返回一个StopIteration报错提示。

3. 保存打印结果

python中的print方法事实上调用的是sys.stdout.write方法。

其代码原则为如下形式:

import sys

def print(message, end="\n"):
    sys.stdout.write(message + end)
    return

因此,我们如果想要同步地将所有的print打印的日志全部保存在某一个外部文件中的话,可以使用下面两种操作方法。

  1. 覆盖print函数

    这种方式的实现非常的暴力,只要重新复写一下print函数即可:

    log_file = "./log.txt"
    
    def print(message, end="\n"):
        print(message, end=end)
        with open(log_file, "a") as fout:
            fout.write(message + end)
        return
    
    print("haha")
    
  2. 覆盖stdout类

    这种方法就是将print函数调用的sys.stdout.write()方法进行重写,令其可以同时执行系统打印以及文件日志内容的打印。

    给出一种实现方式如下:

    import sys
    
    class Logger(object):
        def __init__(self, log_file_path='./log.txt'):
            self.terminal = sys.stdout
            self.log = open(log_file_path, "a", encoding='utf8')
    
        def write(self, message):
            self.terminal.write(message)
            self.log.write(message)
    
        def flush(self):
            self.terminal.flush()
    
    sys.stdout = Logger(log_file_path="./log.txt")
    
    print("haha")
    

4. 参考文献

  1. 廖雪峰python教程
  2. python3 将print打印的内容保存到日志

猜你喜欢

转载自blog.csdn.net/codename_cys/article/details/107218360