cookbook_ metaprogramming

1 to add a wrapper function

Question: function to add a layer of packaging, additional processing has been added, for example, logging, statistics and other timing 


solutions: You can define a decorator to wrap function

2 How to save a function of the time of writing decorator metadata

Problem: When a function is decorative decorator, a number of important metadata such as: name of the function, documentation string, the function call notes and signatures have been lost 
Solution: Whenever define a decorator should always remember as the underlying Add functools wrapper function library @wraps decorator

# Problem: When a function is decorative decorator, a number of important metadata such as: name of the function, documentation string, the function call notes and signatures were missing 

# Solution: Whenever define a decorator should always remember to underlying wrapper function added functools library @wraps decorator 

Import Time
 Import functools
 DEF timethis (FUNC): 
    @ functools.wraps (FUNC) 
    DEF warpper (* args, ** kwargs): 
        START_TIME = the time.time () 
        Result = FUNC (* args, ** kwargs) 
        END_TIME = the time.time ()
         Print (FUNC. the __name__ , end_time- START_TIME)
         return Result
     return warpper 

@timethis 
DEFmysleep (NUM: int):
     "" " 
    primitive Comments Document 
    : param NUM: 
    : return: 
    " "" 
    the time.sleep (NUM) 
    Print ( " I am the original function " ) 


mysleep ( 3 )
 Print (mysleep. __name__ )
 Print (mysleep. __doc__ )
 Print (mysleep. __annotations__ ) 


# If decorators use @ functools.wraps (func) decoration, we can use the following method to get to the original function! ! ! 
mysleep. __wrapped__ (. 3)
 

Three pairs decorator be unpacked

Question: We have added a decorator to function, but would like to withdraw it, access the original function without packaging. 

Solution: Assuming decorator has achieved @warps (func), in general we can get to the original function by accessing the property __wrapped__

4 may receive the definition of a parameter decorator

Question: We want to write a decorator function can receive parameters 
Solution: Suppose we want to write a decorator to add logging to function, but it allows the user to specify the level of logging as well as some other details of the operation as a parameter.
import logging
import functools


def logged(level,name=None,message=None):
    def decorate(func):
        logname = name if name else func.__module__
        log = logging.getLogger(logname)
        logmsg = message if message else func.__name__


        @functools.wraps(func)
        def wrapper(*args,**kwargs):
            log.log(level,message)
            return func(*args,**kwargs)
        return wrapper
    return decorate

 

 5 defines a property that can be modified by the user decorator

Question: We want to write a decorator to wrap function, but allows the user to adjust the properties decorator, so at runtime can control the behavior of the decorator
from functools import wraps,partial
import logging

def attach_wrapper(obj,func=None):
    if func is None:
        return partial(attach_wrapper,obj)
    setattr(obj,func.__name__,func)
    return func

def logged(level,name=None,message=None):
    def decorate(func):
        logname = name if name else func.__module__
        log = logging.getLogger(logname)
        logmsg = message if message else func.__name__

        @wraps(func)
        def wrapper(*args,**kwargs):
            log.log(level,logmsg)
            return func(*args,**kwargs)

        @attach_wrapper(wrapper)
        def set_level(newlevel):
            nonlocal level
            level = newlevel

        @attach_wrapper(wrapper)
        def set_message(newmsg):
            nonlocal logmsg
            logmsg = newmsg


        return wrapper
    return decorate

logging.basicConfig(level=logging.DEBUG)
@logged(logging.DEBUG)
def add(x,y):
    return x + y

add(2,5)

add.set_message("Add called")
add(3,8)

 

6 to receive a definition of optional parameters decorator

Problems: We want to write a separate decorator, so that it may be no parameter like @decorator, optional parameters may be received so as @decorator (x, y, z)
from functools import wraps,partial
import logging


def logged(func=None,*,level=logging.DEBUG,name=None,message=None):
    if func is None:
        return partial(logged,level=level,name=name,message=message)

    logname = name if name else func.__module__
    log = logging.getLogger(logname)
    logmsg = message if message else func.__name__
    @wraps(func)
    def wrapper(*args,**kwargs): 
        log.log (Level, logmsg) 
        return FUNC (* args, ** kwargs)
     return warpper 



@logged 
DEF the Add (X, Y): 
    logging.debug ( " hahahah " )
     return X + Y 

# no parameters, decorative it is equivalent to: logged (func), so the first parameter decorator is func, others are optional parameters 

@logged (Level = logging.CRITICAL, name = " Example " )
 DEF from spam ():
     Print ( " !!! from spam " ) 

# With an argument, decorator equivalent logged (Level = logging.DEBUG, name =" Example ") (from spam) 
#Clever use of the constructed functools.partial the method returns to 

the Add ( 1,2 ) 
from spam ()

 

7 enforces of Deco-type checking of function arguments

Question: We would like to add a mandatory check function as a function parameter, as an assertion or contract between the caller
from Inspect Import Signature
 from functools Import Wraps 

DEF typeassert (ty_args *, ** ty_kwargs): 

    DEF the decorate (func):
         IF  Not  __debug__ :
             return func 
        SIG = Signature (func) # acquired func parameter signature (x, y, z) 
        = sig.bind_partial bound_types (ty_args *, ** ty_kwargs) .arguments # parameter parameter type signature do mapping [( "x", <class "int">), ( "z", <class "int">)] 
        @wraps (FUNC)
         DEF wrapper (* args, ** kwargs): 
            bound_valuesSig.bind = (* args, ** kwargs) .arguments # parameter signature function arguments do mapping 
            for name, value in bound_values.items ():
                 IF name in bound_types: # determine whether there are restrictions on the type parameter 
                    IF  not isinstance (value , bound_types [name]):
                         The raise TypeError ( " the Argument MUST BE {} {} " .format (name, bound_types [name]))
             return FUNC (* args, ** kwargs)
         return warpper
     return the decorate 



class A ():
     DEF A (Self):
         Print (" A " ) 

@typeassert (int, A, Z = int)
 DEF the Add (X, Y, Z):
     Print (X, Y, Z)
     return X 

the Add ( . 1, A (),. 3 ) 


# idea: Parameter Type limiting parameters may be used in the processing method of front end of the received inspection parameters, needs to be limited it can also be used in some parts of the incoming parameter type 


# Note: this decorator a delicate place, only check the transmission parameters, if default parameters, not passed, the parameter type is not checked 


@typeassert (int, List) 
DEF bar (X, items = None):
     IF items IS None: 
        items = [] 
    items.append (X) 
    return items 

Print (bar ( 2))

 

8 defined in the class decorator

Question: We want a decorator class definition, and the effect on other functions or methods
from functools import wraps

class A:
    def decorator1(self,func):
        @wraps(func)
        def wrapper(*args,**kwargs):
            print("decorator 1")
            return func(*args,**kwargs)
        return wrapper

    @classmethod
    def decorator2(cls,func):
        @wraps(func)
        def wrapper(*args,**kwargs):
            print("decorator 2")
            returnFUNC (* args, ** kwargs)
         return wrapper 


# ponder: @property actually have a getter (), setter (), class deleter () method, each method can be used as a decorator 
# several decorator You can manipulate the state of the instance, and therefore, if desired decorative or combining the information recorded by the back, this is a very sensible approach.

 

9 is defined as a class decorator

Question: We want to wrap the decorator function, but I hope the result is an instance of a callable. We need decorator both class work, it can also be used outside of the class 

solution: put decorator defined as a class instance, you need to ensure __call __ () and __get __ () method in the class
import types
from functools import wraps

class Profield:
    def __init__(self,func):
        wraps(func)(self)
        self.ncalls = 0

    def __call__(self, *args, **kwargs):
        self.ncalls +=1
        return self.__wrapped__(*args,**kwargs)

    def __get__(self, instance, cls):
        if instance is None:
            return self
        else:
            returntypes.MethodType (Self, instance) 


# The decorator means adding a property as a function ncalls

 

10 is applied to the decorative static methods and classes
Question: We want to apply a static method on the class or decorator 

before will be simple and direct effect on the decorators to class and static methods, but to ensure decorator when the application needs to be placed @classmethod and @staticmethod: Solutions , for example:
import time
from functools import wraps

def timethis(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        start = time.time()
        r = func(*args,**kwargs)
        end = time.time()
        print(end-start)
        return r
    return wrapper
@classmethod and @staticmethod decorator and does not return an executable object, decorators should be placed below them! ! !

11 written decorator to be added wrapper function parameters

Question: We want to write a decorator, add additional parameters as the wrapped function, but does not affect the parameters added to the existing convention call the function 

solution:
from functools import wraps

def optinoal_debug(func):
    @wraps(func)
    def wrapper(*args,debug=False,**kwargs):
        if debug:
            print("Calling",func.__name__)
        return func(*args,**kwargs)
    return wrapper
Function parameters are decorated portion used to parse the remaining arguments to the function, can be used to control the parameters of the package decoration function behavior

12 using the decorator to the function defined patch

# Question: We want to check or rewrite the definition part of a class, in order to modify the behavior of the class, but do not want to through inheritance or metaclasses way to do 


# Solution:
def log_getattribute(cls):
    orig_getattribute = cls.__getattribute__


    def new_getattribute(self,name):
        print("getting",name)
        return orig_getattribute(self,name)

    cls.__getattribute__ = new_getattribute
    return cls

@log_getattribute
class A:
    def __init__(self,x):
        self.x = x

    def spam(self):
        pass

a = A(42)
a.x
This method can be done by monitoring of the properties of the class

Guess you like

Origin www.cnblogs.com/jiaojianglong/p/11260200.html