When you're studying Python programming with decorators, you can understand it on the spot, but you'll soon forget it. So, this time, I tried to actually operate the sample application that dynamically adds a method, and made a note of what values each parameter holds.
This is a sample program that decorates methods with arguments (func1, func2).
sample1.py
import sys
import json
import logging
logging.basicConfig()
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
def api_method(api_name):
def _api_method(fn):
log.debug("fn={}".format(fn))
log.debug("api_name={}".format(api_name))
setattr(fn, '__api_name__', api_name)
return fn
return _api_method
class Sample(object):
def __init__(self):
log.debug(json.dumps(dir(self), sort_keys=False, indent=4))
self._api_methods = {}
for method_name in dir(self):
method = getattr(self, method_name)
try:
name = getattr(method, '__api_name__')
msg = 'API method {0} registered'.format(name)
log.debug(msg)
self._api_methods[name] = method
except AttributeError:
pass
log.debug("_api_methods=[%s]"%self._api_methods)
@api_method('func1')
def _func1(self, params):
print ("*** func1 : params=[%s]"%params)
return "func1 is done!"
@api_method('func2')
def _func2(self, params):
print ("*** func2 : params=[%s]"%params)
return "func2 is done!"
if __name__ == '__main__':
args = sys.argv
if len(args) == 3:
method = args[1]
params = args[2]
m = Sample()
result = m._api_methods[method](params)
print ("*** result=[%s]"%result)
First, let's move the func1 method
$ python sample1.py func1 aaa
DEBUG:__main__:fn=<function Sample._func1 at 0x10dde60d0>
DEBUG:__main__:api_name=func1
DEBUG:__main__:fn=<function Sample._func2 at 0x10dde6158>
DEBUG:__main__:api_name=func2
DEBUG:__main__:[
"__class__",
"__delattr__",
"__dict__",
"__dir__",
"__doc__",
"__eq__",
"__format__",
"__ge__",
"__getattribute__",
"__gt__",
"__hash__",
"__init__",
"__init_subclass__",
"__le__",
"__lt__",
"__module__",
"__ne__",
"__new__",
"__reduce__",
"__reduce_ex__",
"__repr__",
"__setattr__",
"__sizeof__",
"__str__",
"__subclasshook__",
"__weakref__",
"_func1",
"_func2"
]
DEBUG:__main__:API method func1 registered
DEBUG:__main__:API method func2 registered
DEBUG:__main__:_api_methods=[{'func1': <bound method Sample._func1 of <__main__.Sample object at 0x10ddde898>>, 'func2': <bound method Sample._func2 of <__main__.Sample object at 0x10ddde898>>}]
*** func1 : params=[aaa]
*** result=[func1 is done!]
Next, try running the func2 method
$ python sample1.py func2 bbb
DEBUG:__main__:fn=<function Sample._func1 at 0x10f9790d0>
DEBUG:__main__:api_name=func1
DEBUG:__main__:fn=<function Sample._func2 at 0x10f979158>
DEBUG:__main__:api_name=func2
DEBUG:__main__:[
"__class__",
"__delattr__",
"__dict__",
"__dir__",
"__doc__",
"__eq__",
"__format__",
"__ge__",
"__getattribute__",
"__gt__",
"__hash__",
"__init__",
"__init_subclass__",
"__le__",
"__lt__",
"__module__",
"__ne__",
"__new__",
"__reduce__",
"__reduce_ex__",
"__repr__",
"__setattr__",
"__sizeof__",
"__str__",
"__subclasshook__",
"__weakref__",
"_func1",
"_func2"
]
DEBUG:__main__:API method func1 registered
DEBUG:__main__:API method func2 registered
DEBUG:__main__:_api_methods=[{'func1': <bound method Sample._func1 of <__main__.Sample object at 0x10f971908>>, 'func2': <bound method Sample._func2 of <__main__.Sample object at 0x10f971908>>}]
*** func2 : params=[bbb]
*** result=[func2 is done!]
I was able to start it properly.
This is a sample program that works in the same way without using decorations.
sample2.py
import sys
import json
import logging
logging.basicConfig()
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
class Sample(object):
def __init__(self):
log.debug(json.dumps(dir(self), sort_keys=False, indent=4))
def func1(self, params):
print ("*** func1 : params=[%s]"%params)
return "func1 is done!"
def func2(self, params):
print ("*** func2 : params=[%s]"%params)
return "func2 is done!"
if __name__ == '__main__':
args = sys.argv
if len(args) == 3:
method = args[1]
params = args[2]
m = Sample()
meth = getattr(m, method, None)
if meth:
result = meth(params)
print ("*** result=[%s]"%result)
First, let's move the func1 method
$ python sample2.py func1 aaa
DEBUG:__main__:[
"__class__",
"__delattr__",
"__dict__",
"__dir__",
"__doc__",
"__eq__",
"__format__",
"__ge__",
"__getattribute__",
"__gt__",
"__hash__",
"__init__",
"__init_subclass__",
"__le__",
"__lt__",
"__module__",
"__ne__",
"__new__",
"__reduce__",
"__reduce_ex__",
"__repr__",
"__setattr__",
"__sizeof__",
"__str__",
"__subclasshook__",
"__weakref__",
"func1",
"func2"
]
*** func1 : params=[aaa]
*** result=[func1 is done!]
Next, try running the func2 method
$ python sample2.py func2 bbb
DEBUG:__main__:[
"__class__",
"__delattr__",
"__dict__",
"__dir__",
"__doc__",
"__eq__",
"__format__",
"__ge__",
"__getattribute__",
"__gt__",
"__hash__",
"__init__",
"__init_subclass__",
"__le__",
"__lt__",
"__module__",
"__ne__",
"__new__",
"__reduce__",
"__reduce_ex__",
"__repr__",
"__setattr__",
"__sizeof__",
"__str__",
"__subclasshook__",
"__weakref__",
"func1",
"func2"
]
*** func2 : params=[bbb]
*** result=[func2 is done!]
This was also able to start correctly.
When creating an app that adds methods dynamically, I feel that it is simpler to write code without creating a decorator, but when is it desirable to use a decorator? I think it's just for the purpose of decorating the method, such as adding a DEBUG statement, so I extended it further.
sample3.py
import sys
import json
import logging
logging.basicConfig()
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
def api_method(api_name):
def _api_method(fn):
log.debug("fn={}".format(fn))
log.debug("api_name={}".format(api_name))
def _wrap(*args, **kwargs):
log.debug("--Preprocessing-- [{}]".format(api_name))
ret = fn(*args, **kwargs)
log.debug("--Post-processing-- [{}]".format(api_name))
return ret
return _wrap
return _api_method
class Sample(object):
def __init__(self):
log.debug(json.dumps(dir(self), sort_keys=False, indent=4))
@api_method('func1')
def func1(self, params):
print ("*** func1 : params=[%s]"%params)
return "func1 is done!"
@api_method('func2')
def func2(self, params):
print ("*** func2 : params=[%s]"%params)
return "func2 is done!"
if __name__ == '__main__':
args = sys.argv
if len(args) == 3:
method = args[1]
params = args[2]
m = Sample()
meth = getattr(m, method, None)
if meth:
result = meth(params)
print ("*** result=[%s]"%result)
First, let's move the func1 method
$ python sample3.py func1 aaa
DEBUG:__main__:fn=<function Sample.func1 at 0x10aba10d0>
DEBUG:__main__:api_name=func1
DEBUG:__main__:fn=<function Sample.func2 at 0x10aba11e0>
DEBUG:__main__:api_name=func2
DEBUG:__main__:[
"__class__",
"__delattr__",
"__dict__",
"__dir__",
"__doc__",
"__eq__",
"__format__",
"__ge__",
"__getattribute__",
"__gt__",
"__hash__",
"__init__",
"__init_subclass__",
"__le__",
"__lt__",
"__module__",
"__ne__",
"__new__",
"__reduce__",
"__reduce_ex__",
"__repr__",
"__setattr__",
"__sizeof__",
"__str__",
"__subclasshook__",
"__weakref__",
"func1",
"func2"
]
DEBUG:__main__:--Preprocessing-- [func1]
*** func1 : params=[aaa]
DEBUG:__main__:--Post-processing-- [func1]
*** result=[func1 is done!]
Next, try running the func2 method
$ python sample3.py func2 bbb
DEBUG:__main__:fn=<function Sample.func1 at 0x106a1d0d0>
DEBUG:__main__:api_name=func1
DEBUG:__main__:fn=<function Sample.func2 at 0x106a1d1e0>
DEBUG:__main__:api_name=func2
DEBUG:__main__:[
"__class__",
"__delattr__",
"__dict__",
"__dir__",
"__doc__",
"__eq__",
"__format__",
"__ge__",
"__getattribute__",
"__gt__",
"__hash__",
"__init__",
"__init_subclass__",
"__le__",
"__lt__",
"__module__",
"__ne__",
"__new__",
"__reduce__",
"__reduce_ex__",
"__repr__",
"__setattr__",
"__sizeof__",
"__str__",
"__subclasshook__",
"__weakref__",
"func1",
"func2"
]
DEBUG:__main__:--Preprocessing-- [func2]
*** func2 : params=[bbb]
DEBUG:__main__:--Post-processing-- [func2]
*** result=[func2 is done!]
It's working nicely now. that's all
Recommended Posts