从python工厂中导入

2024-06-07 03:02:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我想创建一个抽象工厂,以便在Python2.7中抽象计算机(比如RaspberryPi和Arduino)之间的硬件差异

我正在使用抽象工厂的以下实现:

  '''
  Provide a device-agnostic display interface
  '''
  from hardware import sysname

  class DisplayBase(object):
        def __init__(self):
           pass

        def show(self, message):
           pass

        def __str__(self):
           return "DisplayBase"

        def __repr__(self):
           return self.__str__()

   class RPIDisplay(DisplayBase):
        def __new__(cls, *args, **kwargs):
            from rpi_display import writeline
            instance = super(RPIDisplay, cls).__new__(cls, *args, **kwargs)
            return instance

        def __str__(self):
            return "RPIDisplay"

       def show(self, message):
           writeline(message)

    class ArduinoDisplay(DisplayBase):
        def __new__(cls, *args, **kwargs):
            import arduino_display
            instance = super(ArduinoDisplay, cls).__new__(cls, *args, **kwargs)
            return instance

        def __str__(self):
            return "ArduinoDisplay"

        def show(self, message):
            return arduino_display.println(message)

   class Display(DisplayBase): # Display Factory
       def __new__(cls, *args, **kwargs):
           platform = sysname()
           if platform == "RaspberryPi":
               return RPIDisplay()
           elif platform == "Arduino":
               return ArduinoDisplay()
           else:
               return MockDisplay()

    if __name__ == "__main__":
        display = Display()
        print display
        display.show("hello world")

该实例化工作正常,但当我尝试运行它时,我得到:

    ArduinoDisplay
    Traceback (most recent call last):
    File "tt.py", line 56, in <module>
      display.show("hello world")
    File "tt.py", line 41, in show
      return arduino_display.println(message)
    NameError: global name 'arduino_display' is not defined

因此arduino_display的导入确实起到了一定的作用,但我找不到在对象中使用它的方法

由于不同的平台将安装不同的模块,因此需要条件导入

知道如何使用这些条件导入吗

我试过self.arduino_displayArduinoDisplay.arduino_display但都没用

很明显,我可以捕获导入错误,如添加到顶部:

    try:
        import arduino_display
    except:
        pass

…这会在RPI上失败,这很好,但必须有更好的方法


Tags: importselfmessagenewreturndefshowdisplay
3条回答

问题是,您导入的函数没有保存在任何地方,其他方法无法看到它们,因此它们除了在本地之外,在其他任何地方都不可见。导入后尝试设置ArduinoDisplay.arduino_display = arduino_display

下面是一些示例代码,说明了我的意思:

class ADisplay:

    def __init__(self):
        from builtins import print as display_write

    def show(self, msg):
        display_write(msg)

disp = ADisplay()
disp.show("mymsg")

这在NameError: name 'display_write' is not defined时失败

现在,将导入绑定到类

class ADisplay:

    def __init__(self):
        from builtins import print as display_write
        ADisplay.display_write = display_write

    def show(self, msg):
        self.display_write(msg)

disp = ADisplay()
disp.show("mymsg")

这很有效。事实上,如果所有这些硬件打印方法都只使用字符串作为参数,并且不需要格式化或修改任何内容,那么您甚至可以通过直接分配它来省去show

class ADisplay:

    def __init__(self):
        #do other init stuff...
        pass

        #only bind show the first time.
        if getattr(ADisplay, "show", None):
            return

        from builtins import print as display_write
        ADisplay.show = display_write

disp = ADisplay()
disp.show("mymsg")

问题是由于import在其当前范围内仅绑定名称。在函数/方法中执行import不会使它在其他方法中可用

在实际需要的地方执行导入。例如,ArduinoDisplay应该在使用它的地方导入arduino_display

class ArduinoDisplay(DisplayBase):
    # no new, no import

    def __str__(self):
        return "ArduinoDisplay"

    def show(self, message):
        # import where needed
        import arduino_display
        return arduino_display.println(message)

请注意,import是幂等的,如果模块之前已经加载,import只是再次绑定名称。这使得这种嵌套的import语句在大多数情况下都足够快


如果您的类需要许多导入,或者速度是个问题,请将类隔离到单独的模块中,并有条件地导入整个模块。您可以使用公共名称直接分配正确的类,而不是使用构造另一个类的伪类型

# ## display/arduino.py ##
# other systems accordingly
from .base import DisplayBase

# import once, globally
import arduino_display

class ArduinoDisplay(DisplayBase):
    # no new, no import

    def __str__(self):
        return "ArduinoDisplay"

    def show(self, message):
        # import where needed
        return arduino_display.println(message)

# ## display/__init__.py ##
from hardware import sysname

platform = sysname()
# resolve and import appropriate type once
if platform == "RaspberryPi":
    from .rpi import RPIDisplay as Display
elif platform == "Arduino":
    from .arduino import ArduinoDisplay as Display
else:
    from .mock import MockDisplay as Display

您是否尝试过使用from arduino_display import println然后像使用RPIs一样使用println

编辑:忽略了明显的

你可以这样做:

from hardware import sysname

class Display(object):
    def __init__(self, print_function, display_name):
        self._print_function = print_function
        self._display_name = display_name

    def show(self, message):
        self.print_function(message)

    def __str__(self):
        return self._display_name

    def __repr__(self):
        return self.__str__()

def create_display():
    platform = sysname()
    if platform == "RaspberryPi":
        from rpi_display import writeline
        return Display(writeline, "RPIDisplay")
    elif platform == "Arduino":
        from arduino_display import println
        return Display(println, "ArduinoDisplay")

如果需要类和嵌套工厂,也可以应用同样的原则将函数对象存储在那里

相关问题 更多 >