猿问

从 python 抽象工厂中导入

我想创建一个抽象工厂,以便在 Python 2.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_display,ArduinoDisplay.arduino_display但无济于事。

慕田峪9158850
浏览 144回答 3
3回答

慕容3067478

问题是由于仅在其当前范围内import绑定名称。在函数/方法中执行操作不会使其在其他方法中可用。import在您实际需要的地方执行导入。例如,ArduinoDisplay应该在使用它的地方导入arduino_display:class ArduinoDisplay(DisplayBase):&nbsp; &nbsp; # no new, no import&nbsp; &nbsp; def __str__(self):&nbsp; &nbsp; &nbsp; &nbsp; return "ArduinoDisplay"&nbsp; &nbsp; def show(self, message):&nbsp; &nbsp; &nbsp; &nbsp; # import where needed&nbsp; &nbsp; &nbsp; &nbsp; import arduino_display&nbsp; &nbsp; &nbsp; &nbsp; return arduino_display.println(message)请注意,这import是幂等的——如果模块之前已经加载过,import只需再次绑定名称即可。这使得这种嵌套import语句对于大多数情况来说足够快。如果您的类需要多次导入或速度存在问题,请将类隔离到单独的模块中并有条件地导入整个模块。您可以使用通用名称直接分配正确的类,而不是使用构造另一个的虚拟类型。# ## display/arduino.py ### other systems accordinglyfrom .base import DisplayBase# import once, globallyimport arduino_displayclass ArduinoDisplay(DisplayBase):&nbsp; &nbsp; # no new, no import&nbsp; &nbsp; def __str__(self):&nbsp; &nbsp; &nbsp; &nbsp; return "ArduinoDisplay"&nbsp; &nbsp; def show(self, message):&nbsp; &nbsp; &nbsp; &nbsp; # import where needed&nbsp; &nbsp; &nbsp; &nbsp; return arduino_display.println(message)# ## display/__init__.py ##from hardware import sysnameplatform = sysname()# resolve and import appropriate type onceif platform == "RaspberryPi":&nbsp; &nbsp; from .rpi import RPIDisplay as Displayelif platform == "Arduino":&nbsp; &nbsp; from .arduino import ArduinoDisplay as Displayelse:&nbsp; &nbsp; from .mock import MockDisplay as Display

交互式爱情

错过了明显的......你可以这样做:from hardware import sysnameclass Display(object):&nbsp; &nbsp; def __init__(self, print_function, display_name):&nbsp; &nbsp; &nbsp; &nbsp; self._print_function = print_function&nbsp; &nbsp; &nbsp; &nbsp; self._display_name = display_name&nbsp; &nbsp; def show(self, message):&nbsp; &nbsp; &nbsp; &nbsp; self.print_function(message)&nbsp; &nbsp; def __str__(self):&nbsp; &nbsp; &nbsp; &nbsp; return self._display_name&nbsp; &nbsp; def __repr__(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.__str__()def create_display():&nbsp; &nbsp; platform = sysname()&nbsp; &nbsp; if platform == "RaspberryPi":&nbsp; &nbsp; &nbsp; &nbsp; from rpi_display import writeline&nbsp; &nbsp; &nbsp; &nbsp; return Display(writeline, "RPIDisplay")&nbsp; &nbsp; elif platform == "Arduino":&nbsp; &nbsp; &nbsp; &nbsp; from arduino_display import println&nbsp; &nbsp; &nbsp; &nbsp; return Display(println, "ArduinoDisplay")如果您需要类和嵌套工厂,您也可以应用相同的原则将函数对象存储在那里。

catspeake

问题是您导入的函数没有保存在任何地方以供其他方法查看,因此它们在其他任何地方都不可见,只能在本地看到。ArduinoDisplay.arduino_display = arduino_display导入后尝试设置。这是一些示例代码,可以说明我的意思:class ADisplay:&nbsp; &nbsp; def __init__(self):&nbsp; &nbsp; &nbsp; &nbsp; from builtins import print as display_write&nbsp; &nbsp; def show(self, msg):&nbsp; &nbsp; &nbsp; &nbsp; display_write(msg)disp = ADisplay()disp.show("mymsg")这失败了NameError: name 'display_write' is not defined。现在,将导入绑定到您的类。class ADisplay:&nbsp; &nbsp; def __init__(self):&nbsp; &nbsp; &nbsp; &nbsp; from builtins import print as display_write&nbsp; &nbsp; &nbsp; &nbsp; ADisplay.display_write = display_write&nbsp; &nbsp; def show(self, msg):&nbsp; &nbsp; &nbsp; &nbsp; self.display_write(msg)disp = ADisplay()disp.show("mymsg")这行得通。事实上show,如果所有这些硬件打印方法仅将字符串作为参数并且您不需要格式化或修改任何内容,您甚至可以通过直接分配来省去它。class ADisplay:&nbsp; &nbsp; def __init__(self):&nbsp; &nbsp; &nbsp; &nbsp; #do other init stuff...&nbsp; &nbsp; &nbsp; &nbsp; pass&nbsp; &nbsp; &nbsp; &nbsp; #only bind show the first time.&nbsp; &nbsp; &nbsp; &nbsp; if getattr(ADisplay, "show", None):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; &nbsp; &nbsp; from builtins import print as display_write&nbsp; &nbsp; &nbsp; &nbsp; ADisplay.show = display_writedisp = ADisplay()disp.show("mymsg")
随时随地看视频慕课网APP

相关分类

Python
我要回答