Python 中动态调用函数或类的方法
使用 importlib
# module.py
class A:
def foo(self):
print('this is foo.')
@staticmethod
def static_method():
print('this is static.')
def bar():
print('bar……')
def baz():
print('==baz==')
这种方式其实是__import__() 方式的扩展。
Python官方文档推荐程序式地导入模块时应该使用 import_module() 而不是__import__。
这里我们继续使用上面定义好的module.py模块。
# main.py
import importlib
module_name = 'module'
module_obj = importlib.import_module(module_name)
class_of_module_obj = module_obj.A()
class_of_module_obj.foo()
class_of_module_obj.static_method()
module_obj.bar()
文档参见此处:importlib — import 的实现 — Python 3.9.0 文档
importlib 包的目的有两个。
第一个目的是在 Python 源代码中提供 import 语句的实现(并且因此而扩展 import() 函数)。 这提供了一个可移植到任何 Python 解释器的 import 实现。 相比使用 Python 以外的编程语言实现方式,这一实现更加易于理解。
第二个目的是实现 import 的部分被公开在这个包中,使得用户更容易创建他们自己的自定义对象 (通常被称为 importer) 来参与到导入过程中。
应用场景
我们在使用 redis 的时候,有时候需要添加一个代理类,示例如下:
class RedisClient:
def init_con(self, *args, **kwargs):
# do init things
# like connect redis
pass
然后希望直接通过这个 RedisClient 执行 redis 相关操作, 比如 set, get, hget…
rc = RedisClient()
rc.set(...)
rc.get(...)
...
这样调用的话, 就需要将 pyredis 中的所有函数都在 RedisClient 中写一遍, 那就有点得不偿失了。
这里实际就是希望能够做到动态调用, 将 RedisClient 中的操作, 根据操作名, 直接映射到实际的 pyredis 操作之上。
所以, 我们在 RedisClient 中:
class RedisClient:
def __getattr__(self, func_name):
def func(*args, **kwargs):
# 这里的 getattr 实际就相当于redis_con.<func_name>了
return getattr(self.redis_conn, func_name)(*args, **args)
if __name__ == '__main__':
redis_client = RedisClient()
redis_client.init_con(...)
redis_client.set('key_name', 'key_value')
这样,就实现动态调动 pyredis 的操作的目的了。
参考链接:https://masantu.com/blog/2020-10-15/python-call-method-dynamically/