Python decorator operation memo

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.

■ Use decorators to dynamically add methods

(1) Sample program

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)

(2) Actually move it

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.

■ Try adding methods dynamically without using a decorator

(1) Sample program

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)

(2) Actually move it

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.

■ Further expansion

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.

(1) Sample program

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)

(2) Actually move it

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

Python decorator operation memo
Python memo
python memo
Python memo
Python memo
Python memo
Python memo
[Python] Operation memo of pandas DataFrame
[Python] Memo dictionary
Note: Python Decorator
python beginner memo (9.2-10)
[python] vector operation
python beginner memo (9.1)
★ Memo ★ Python Iroha
Python OS operation
[Python] EDA memo
Python 3 operator memo
[Python] Matrix operation
[My memo] python
Python3 metaclass memo
[Python] Basemap memo
Python function decorator
Python beginner memo (2)
[Python] Numpy memo
[Python beginner memo] Python character string, path operation
[Python] Operation of enumerate
Python class (Python learning memo ⑦)
My python environment memo
python openCV installation (memo)
Python module (Python learning memo ④)
Visualization memo by Python
Python test package memo
[Python] Memo about functions
python decorator to retry
python decorator usage notes
python regular expression memo
Python3 List / dictionary memo
[Memo] Python3 list sort
Python Tips (my memo)
[Python] Memo about errors
DynamoDB Script Memo (Python)
Python directory operation summary
Python basic memo --Part 2
python recipe book Memo
Python logical operation stumbling
Basic Python command memo
Python OpenCV tutorial memo
Python basic grammar memo
TensorFlow API memo (Python)
python useful memo links
I tried Python> decorator
Python basic memo --Part 1
Effective Python Memo Item 3
Divisor enumeration Python memo
[python] Array slice operation
Python memo (for myself): Array
Python execution time measurement memo
Twitter graphing memo with Python
[Line / Python] Beacon implementation memo
S3 operation with python boto3
Python and ruby slice memo