【问题标题】:Modify function and keep code workability修改功能,保持代码可操作性
【发布时间】:2019-04-02 03:42:46
【问题描述】:

我不是专业的编码员,但我不时使用 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 来调用特定函数的最 Pythonic 方式是什么。同时,我想保持其余代码的可操作性,其中使用了旧版本的_call_dll

我看到了几种方法来做到这一点,但我不确定哪一种是最专业和最好的。

  1. 为我想使用的每个 dll_n 创建自己的 _call_dll_n 函数,但它不够紧凑和美观。

  2. 在函数名前加一些前缀来指定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
    
  3. 制作 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
    

感谢您对这个特定示例的帮助,但也非常欢迎您提供有关如何工作和修改已存在的函数/类的更一般性的想法。

【问题讨论】:

  • 原始模块版本的源代码是否受控(例如是否来自Github)?
  • 是的,它来自 github,但我更喜欢拥有自己的模块版本(老实说,我只是不确定我的修改是否以适当的方式与他人分享) .
  • “我发现需要使用不同的dll来调用自己的函数”;您能否在说明中添加另一段,解释什么条件决定了在给定场合使用哪个 DLL?

标签: python coding-style


【解决方案1】:

您无需修改​​代码;正如您介绍的那样,ATS 类已经允许您所描述的内容。而是:创建多个 ATS 实例,每个实例都指定要使用的 DLL。

您对问题的描述包含两个部分:

  • mapping,来自 DLL 文件路径的某个键。
  • API wrapper,允许您在调用 API 时为上述映射指定一个键。

在 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')

这是定义类的主要好处之一:它们封装了一类对象的共同行为,同时允许每个对象具有区分它们的单独属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    • 2017-08-02
    • 1970-01-01
    • 2019-10-11
    相关资源
    最近更新 更多