跳转至
本文阅读量

1. Python 高阶特性

1.1 注解

def log_in_out(logger=logging.getLogger(), is_print_input=True, is_print_output=True, is_method=True, log_level=logging.INFO):
    """
    @param logger-
    @param is_print_input- toggle printing input arguments
    @param is_print_output- toggle printing output values
    @param is_method- True for methods, False for functions. Makes "self" not printed in case of is_print_input==True
    @param log_level-

    @returns- a decorator that logs to logger when entering or exiting the decorated function.
    Don't uglify your code!
    """

    def decor(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            if is_print_input:
                logger.log(
                    msg=f"Entered {fn.__name__} with args={args[1:] if is_method else args}, kwargs={kwargs}",
                    level=log_level
                )
            else:
                logger.log(
                    msg=f"Entered {fn.__name__}",
                    level=log_level
                )

            result = fn(*args, **kwargs)

            if is_print_output and result is not None:
                logger.log(
                    msg=f"Exited {fn.__name__} with result {result}",
                    level=log_level,
                )
            else:
                logger.log(
                    msg=f"Exited {fn.__name__}",
                    level=log_level
                )
            return result
        return wrapper
    return decor

@log_in_out()
def target_foo(*args, **kwargs):
    print('target_foo, args=%s, kwargs=%s' % (args, kwargs))

target_foo('ttt-1', msg='ttt-kv')
def real_decorator(any_number_of_arguments):
   def pseudo_decorator(function_to_be_decorated):

       def real_wrapper(function_arguments):
           print(function_arguments)
           result = function_to_be_decorated(any_number_of_arguments)
           return result

       return real_wrapper
   return pseudo_decorator
def decorator_function(original_function):
    def wrapper_function(*args, **kwargs):
        print('Executed Before', original_function.__name__)
        result = original_function(*args, **kwargs)
        print('Executed After', original_function.__name__, '\n')
        return result
    return wrapper_function


@decorator_function
def display_info(name, age):
    print('display_info ran with arguments ({}, {})'.format(name, age))


display_info('Mr Bean', 66)
display_info('MC Jordan', 57)

Output:
Executed Before display_info
display_info ran with arguments (Mr Bean, 66)
Executed After display_info

Executed Before display_info
display_info ran with arguments (MC Jordan, 57)
Executed After display_info
def prefix_decorator(prefix):
    def decorator_function(original_function):
        def wrapper_function(*args, **kwargs):
            print(prefix, 'Executed Before', original_function.__name__)
            result = original_function(*args, **kwargs)
            print(prefix, 'Executed After', original_function.__name__, '\n')
            return result
        return wrapper_function
    return decorator_function


@prefix_decorator('LOG:')
def display_info(name, age):
    print('display_info ran with arguments ({}, {})'.format(name, age))


display_info('Mr Bean', 66)
display_info('MC Jordan', 57)

Output:
LOG: Executed Before display_info
display_info ran with arguments (Mr Bean, 66)
LOG: Executed After display_info

LOG: Executed Before display_info
display_info ran with arguments (MC Jordan, 57)
LOG: Executed After display_info

1.1.1 基于 Class 的带参注解

class MyDec(object):
    def __init__(self,flag):
        self.flag = flag
    def __call__(self, original_func):
        decorator_self = self
        def wrappee( *args, **kwargs):
            print 'in decorator before wrapee with flag ',decorator_self.flag
            original_func(*args,**kwargs)
            print 'in decorator after wrapee with flag ',decorator_self.flag
        return wrappee

@MyDec('foo de fa fa')
def bar(a,b,c):
    print 'in bar',a,b,c

bar('x','y','z')

Output:
in decorator before wrapee with flag  foo de fa fa
in bar x y z
in decorator after wrapee with flag  foo de fa fa
import time

class TimerDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        start_time = time.time()
        result = self.func(*args, **kwargs)
        end_time = time.time()
        print(f"Function {self.func.__name__} executed in {end_time - start_time} seconds")
        return result

@TimerDecorator
def example_function(n):
    total = 0
    for i in range(n):
        total += i
    return total

# Usage
print(example_function(1000000))
class LoggerDecorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f"Arguments: {args}, Keyword Arguments: {kwargs}")
        result = self.func(*args, **kwargs)
        return result

@LoggerDecorator
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

# Usage
print(greet("Alice"))
print(greet("Bob", greeting="Hi"))

1.1.2 注解作用到类上

此时注解传入的参数就不是 func 了,而是被注解的类 cls

def add_method(cls):
    def square(self, x):
        return x * x
    cls.square = square
    return cls

@add_method
class MyClass:
    pass

obj = MyClass()
print(obj.square(5))
def class_method_decorator(cls):
    def new_method(self):
        print("Class method has been decorated")
        return cls.original_method(self)
    cls.original_method = cls.class_method
    cls.class_method = new_method
    return cls

@class_method_decorator
class MyClass:
    @classmethod
    def class_method(cls):
        print("Class method has been called")
        return None

obj = MyClass()
obj.class_method() 

1.1.3 三方库

from decopatch import function_decorator, DECORATED
from makefun import wraps

@function_decorator
def makestyle(st='b', fn=DECORATED):
    open_tag = "<%s>" % st
    close_tag = "</%s>" % st

    @wraps(fn)
    def wrapped(*args, **kwargs):
        return open_tag + fn(*args, **kwargs) + close_tag

    return wrapped

https://www.artima.com/weblogs/viewpost.jsp?thread=240808#function-decorators ⧉

1.1.4 使用场景整理

总体上有两种使用方式: 带参数不带参数

  • 如果完成要 wrapper handler 需要自己的参数,则选用带参模式;否则可以选择不带参模式
1.1.4.1 不带参数(两层)

两层 def xxx

def my_decorator(func):
    def wrapper(*arg, **kwargs):

        # before handler

        result = func(*args, **kwargs)

        # after handler

        return result
    return wrapper

@my_decorator
def targec_foo(111, 222, msg='success'):
    ...
1.1.4.2 带参数(三层)

三层 def xxx

def my_decorator(d1, d2):
    def dummy_decorator(func):
        def wrapper(*args, **kwargs):

            # before handler

            result = func(*args, **kwargs)

            # after handler

            return result
        return wrapper
    return dummy_decorator


@my_decorator('d1111', 'd2222')
def targec_foo(111, 222, msg='success'):
    ...
场景 使用方式(非必须遵循)
增加日志 两层
测量目标函数执行时间 两层
改变目标函数返回值类型 三层
缓存目标函数结果 两层,也可以三层,控制缓存时间等参数
验证目标函数参数的规则 三层
重试 三层
限流 三层
统一异常处理 三层
模板函数参数类型检查 两层
测量目标函数内存使用 两层
1.1.4.3 多个 decorator
  • 多个 decorator 是相同的,还是不同的

注意执行顺序

def one(func):
    def inner(*args, **kwargs):
        print('1')
        return func(*args, **kwargs)
    return inner

def two(func):
    def inner(*args, **kwargs):
        print('2')
        return func(*args, **kwargs)
    return inner

@one
@two
def speak(text):
    print(text)

speak('Hello')

# Returns:
# 1
# 2
# Hello

1.1.5 示例

1.1.6 参考

Note

The key to understand the difference between @some_decorator and @some_decorator() is that the former is a decorator, while the latter is a function (or callable) that returns a decorator.

def some_decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@some_decorator
def some_method():
    pass

等效于

some_method = some_decorator(some_method)
def some_decorator():
    def decorator(func):
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper
    return decorator

@some_decorator()
def some_method():
    pass

等效于

some_method = some_decorator()(some_method)

1.2 关于 MetaClasses