https://qiita.com/ganariya/items/fb3f38c2f4a35d1ee2e8
In order to study Python, I copied a swarm intelligence library called acopy.
In acopy, many interesting Python grammars and idioms are used, and it is summarized that it is convenient among them.
This time, we will focus on dynamically specifying the execution method by the variable name.
getattr
There is a built-in function called getattr
in Python.
You can retrieve that method from an instance with getattr (instance, method name of the instance)
.
For now, let's try a simple example.
class A:
def __init__(self, msg):
self.msg = msg
def hello(self):
print("hello ", self.msg)
def add(self, x, y):
return x + y
'''
hello world
7
'''
a = A("world")
getattr(a, 'hello')()
print(getattr(a, 'add')(2, 5))
Let's write a simple source code like the one above.
Instance a is generated from class A
I'm getting the method of the hello attribute of instance a with getattr (a,'hello')
.
Then, by adding () after that, the extracted method is actually executed.
Let's take a look at the actual application of getattr.
This time you decided to create a class library called Library. (Fastball)
In the library, some unique processing is executed by a function called run, and internal information is stored in a member variable called library_information
for the time being.
At this point, you also decided to distribute a ** plugin ** that gives you access to the internal information of the Library for other users who want to use the Library.
Since it is a Library you created, only you can implement the main process, but by preparing a process to execute the plugin in the run function, users who want to use the internal information of the Library can create their own plugins It can be expanded.
Let's actually look at the code.
class Library:
def __init__(self):
self.plugins = []
self.library_information = {
'a': 10,
'b': 20,
'c': 30
}
def run(self):
# plugin start
self.call_plugins('start')
for cycle in range(3):
print("Library main process (Implementation omitted)")
# plugin iteration
self.call_plugins('iteration')
# plugin finish
self.call_plugins('finish')
def call_plugins(self, hook):
for plugin in self.plugins:
plugin(hook, **self.library_information)
def add_plugin(self, plugin):
self.plugins.append(plugin)
class Plugin:
def __init__(self):
pass
def __call__(self, hook, **kwargs):
getattr(self, f'on_{hook}')(**kwargs)
def on_start(self, **kwargs):
print(kwargs['a'])
def on_iteration(self, **kwargs):
print(kwargs['b'])
def on_finish(self, **kwargs):
print(kwargs['c'])
library = Library()
library.add_plugin(Plugin())
library.run()
'''
10
Library main process (Implementation omitted)
20
Library main process (Implementation omitted)
20
Library main process (Implementation omitted)
20
30
'''
Library is a library that you want to create and publish on PyPI etc. For example, be aware of Numpy and Matplotlib.
I wanted to prepare something called library_information
in the internal information of the Library so that it could be used and extended by third-party users.
Therefore, ** Prepare a plugin array as a member variable, inherit the Plugin class and pass it to add_plugin so that the plugin can be executed.
When the Plugin is executed from the Library, the internal information of the Library is passed, so the user can extend the function. ** **
This time it is implemented by print, but originally it is an abstract class and you create this plugin as well, and the user creates the original plugin by inheriting this plugin further.
By preparing a __call__
function, you can execute it like a function.
Use getattr when calling __call__
.
As a result, the Library side executes the Plugin instance in the run and passes the Library information at that time.
Then, the Plugin instance is getattr, which brings out the function that matches the appropriate start, finish, iteration
hook in the run and uses it.
In the function run, you can also delete getattr like call_plugins_start, call_plugins_finish and write all cases separately, but this allows you to write in a unified way.
By preparing a plugin class with the library and distributing it to users
--Pass the information in the library from the library side to the plugin --Inherit the plug-in and let the user create it to extend the library with the plug-in and wear it --Getattr can reduce the amount of description
There are benefits. However, keep in mind that the risk of run-time errors increases because you do not know if it is correct until you run it.
Recommended Posts