def meta(func):
def wrapper(*args, **kwiargs):
print(func.__name__)
return func(*args, **kwiargs)
return wrapper
@meta
def somefunc(x ,y):
print("Parameters: " + str(x) + ',' + str(y))
somefunc(1,2)
somefunc
help(somefunc)
from functools import wraps
def meta(func):
@wraps(func)
def wrapper(*args, **kwiargs):
print(func.__name__)
return func(*args, **kwiargs)
return wrapper
@meta
def somefunc(x ,y):
print("Parameters: " + str(x) + ',' + str(y))
somefunc
help(somefunc)
def debug(func):
funcname = func.__qualname__
@wraps(func)
def wrapper(*args, **kwiargs):
print(funcname)
return func(*args, **kwiargs)
return wrapper
def somefunc(x ,y):
print("Parameters: " + str(x) + ',' + str(y))
## diffrent kind of usage
somefunc = debug(somefunc)
somefunc("y","z")
somefunc
help(somefunc)
def debug(func):
if DEBUG not in os.environ:
return func(*args, **kwiargs)
funcname = func.__qualname__
@wraps(func)
def wrapper(*args, **kwiargs):
print(funcname)
return func(*args, **kwiargs)
return wrapper
def debug(somearg=""):
def decorator(func):
funcname = somearg + func.__qualname__
@wraps(func)
def wrapper(*args, **kwiargs):
print(funcname)
return func(*args, **kwiargs)
return wrapper
return decorator
@debug(somearg="The function name is ")
def somefunc(x ,y):
print("Parameters: " + str(x) + ',' + str(y))
somefunc
somefunc("x","y")
from functools import wraps, partial
def debug(func=None, *, somearg=""):
if func is None:
return partial(debug, somearg=somearg)
funcname = somearg + func.__qualname__
@wraps(func)
def wrapper(*args, **kwiargs):
print(funcname)
return func(*args, **kwiargs)
return wrapper
@debug
def somefunc(x ,y):
print("Parameters: " + str(x) + ',' + str(y))
somefunc
somefunc("This is test", " and works")
@debug(somearg="The function name is ")
def somefunc(x ,y):
print("Parameters: " + str(x) + ',' + str(y))
somefunc("This is test", " and works")
class sample:
@debug
def somefunc(self):
pass
@debug
def otherfunc(self):
pass
@debug
def onemore(self):
pass
def debugmethods(cls):
for key, val in vars(cls).items():
if callable(val):
setattr(cls, key, debug(val))
return cls
class sample:
def somefunc(self):
pass
def otherfunc(self):
pass
def onemore(self):
pass
sample = debugmethods(sample) # class sample's metadata is modificed here.
s = sample()
s
s.somefunc()
s.otherfunc()
s.onemore()
def debugattr(cls):
originalgetattribute = cls.__getattribute__
def __getattribute__(self, name):
print("Attribute: ",name)
return originalgetattribute(self, name)
cls.__getattribute__ = __getattribute__
return cls
@debugattr
class sampleattr:
def __init__(self,x,y):
self.x = x
self.y = y
attr = sampleattr(5,6)
attr.x
attr.y
Redefine new or init methods in the inherited class.
class custype(type):
def __new__(cls, name, bases, clsdict):
clsobj = super().__new__(cls, name, bases, clsdict)
return clsobj
When we use this new type class:
class myclass(metaclass=custype) # this step creates a new class based on the metaclass or type "custype".
class debugmeta(type): # type is top in the hierarchy.
def __new__(cls, clsname, bases, clsdict):
clsobj = super().__new__(cls, clsname, bases, clsdict) # a normal class is created.
clsobj = debugmethods(clsobj) # all the methods in the class are wrapped by debug wrapper.
return clsobj
To use it, set it in the base class which will get inherited to all the classes.
class Base(metaclass=debugmeta):
pass
class myclass1(Base):
def somefunc(self):
pass
def otherfunc(self):
pass
def onemore(self):
pass
cls1 = myclass1()
cls1
cls1.somefunc()
class myclass2(Base):
def cls2somefunc(self):
pass
def cls2otherfunc(self):
pass
def cls2more(self):
pass
cls2 = myclass2()
cls2
cls2.cls2somefunc()
Let us continue in Part 2 with more advanced techniques.
Reference: David Beazley - Python 3 Metaprogramming https://www.youtube.com/watch?v=sPiWg5jSoZI