我不是专业的编码人员,但是我会不时地使用Python来满足我的科学需求。因此,我想学习最Pythonic的方法来执行以下操作:
我正在使用一个已经存在的模块,那里的某个类看起来像这样
class ATS(Instrument):
def __init__(self, ..., dll_path: str):
...
self._dll = ctypes.cdll.LoadLibrary(dll_path)
...
def _call_dll(self, func_name: str, *args) -> None:
func = getattr(self._dll, func_name)
output = func(*args)
...
我发现我需要使用不同的DLL来调用其自己的函数(不幸的是,不同DLL中的函数名称可以相同)。
问题是:修改_call_dll
函数以显式指定我要使用哪个DLL来调用特定函数的最Python方式是什么。同时,我希望保留使用旧版本_call_dll
的其余代码的可操作性。
我看到了几种方法可以做到这一点,但是我不确定哪一种是最专业,最时尚的。
为我要使用的每个_call_dll_n
创建自己的dll_n
函数,但是它并不紧凑且美观。
在函数名称上添加一些前缀以指定DLL,例如
class ATS(Instrument):
def __init__(self, ..., dll_path, dll_path_1, ...):
...
self._dll = ctypes.cdll.LoadLibrary(dll_path)
self._dll_1 = ctypes.cdll.LoadLibrary(dll_path_1)
...
def _call_dll(self, pre_func_name: str, *args) -> None:
if prefix_func_name[:5] == 'dll_1':
dll = self._dll_1
func_name = pre_func_name[5:]
func = getattr(dll, func_name)
...
else:
dll = self._dll # Default DLL.
func_name = pre_func_name
创建my_call_dll:
def _my_call_dll(self, func_name: str, dll = None, *args))
if dll is None:
self._call_dll(self, func_name, *args)
else:
dll_bckp = self._dll
self._dll = dll
self._call_dll(self, func_name, *args)
self._dll = dll_bckp
感谢您在此特定示例上的帮助,但也非常欢迎您提供有关如何工作和修改现有功能/类的更一般的想法。
答案 0 :(得分:0)
您无需修改代码;正如您介绍的那样,ATS类已经可以满足您的描述。而是:创建多个ATS实例,每个实例指定要使用的DLL。
您对问题的描述包括两个部分:
在Python中,built-in ‘dict’ type是实现映射的自然方法。您可以使用纯字符串作为密钥。
import os.path
# You might get the path to your DLL files some other way,
# for example by reading a process environment variable.
# In this example I just hard-code the path root.
dll_file_path_root = os.path.join('/usr/lib', 'ats')
dll_file_paths = {
'foo': os.path.join(dll_file_path_root, 'foo.dll'),
'bar': os.path.join(dll_file_path_root, 'bar_v5.dll'),
'baz': os.path.join(dll_file_path_root, 'super_baz.dll'),
}
如上所示,现有的ATS类已经实现了API包装器。每个实例都将包含一个引用(其内部使用_dll
属性),ATS实例将与其对话的DLL。该类将使用您指定的任何DLL初始化ATS的每个实例。所以:
# Create an ATS instance that holds a reference to the ‘foo.dll’ library.
foo_ats = ATS(dll_path=dll_file_paths['foo'])
# Create an ATS instance that holds a reference to the ‘bar_v5.dll’ library.
bar_ats = ATS(dll_path=dll_file_paths['bar'])
# Call the ‘lorem’ function in the ‘foo.dll’ library.
foo_ats._call_dll(func_name='lorem')
# Call the ‘lorem’ function in the ‘bar_v5.dll’ library.
bar_ats._call_dll(func_name='lorem')
这是定义类的主要好处之一:它们封装了一类对象的常见行为,同时允许每个对象具有区分它们的单独属性。