Python 2.7抽象工厂模式中条件导入模块的使用问题
搞定Python 2.7抽象工厂的条件导入与NameError问题
嘿,我明白你现在的困扰——用抽象工厂屏蔽树莓派和Arduino的硬件差异,结果调用ArduinoDisplay的show方法时碰上个NameError,找不到arduino_display。这事儿大概率是条件导入的作用域没搞对,或者抽象工厂的实例化逻辑没跟导入匹配上。咱们一步步来解决:
核心问题拆解
你遇到的错误,本质是导入的类/模块没有在正确的作用域里被访问到,或者工厂没有正确返回实例。因为不同平台只装对应模块,所以条件导入必须在合适的时机做,不能随便塞在类内部导致作用域失效。
两种靠谱的条件导入实现方式
1. 全局条件导入(Python 2.7首选)
在文件最开头就根据平台判断,导入对应的具体实现类,给它们起个统一的别名。这样后面的抽象工厂直接用这个别名就行,完全不会有作用域问题。
import sys # 先写个平台检测的工具函数,你可以根据实际情况改逻辑 def is_raspberry_pi(): # 比如读cpuinfo判断树莓派,或者检查gpio库 try: with open('/proc/cpuinfo', 'r') as f: return 'Raspberry Pi' in f.read() except IOError: return False def is_arduino(): # 比如检查pyserial库是否存在,或者串口设备 try: import serial return True except ImportError: return False # 条件导入,统一别名成DisplayImpl if is_raspberry_pi(): from raspberrypi_display import RaspberryPiDisplay as DisplayImpl elif is_arduino(): from arduino_display import ArduinoDisplay as DisplayImpl else: raise NotImplementedError("这平台咱不支持啊!") # 抽象产品类,必须继承object(Python2.7的旧式类坑多) class Display(object): def show(self, message): raise NotImplementedError("子类必须实现show方法!") # 抽象工厂类 class DisplayFactory(object): def create_display(self): # 直接返回统一别名的实例,简单粗暴不出错 return DisplayImpl()
2. 工厂内部动态导入(适合运行时判断)
如果需要在程序运行过程中才确定平台,可以把导入逻辑放在工厂的create_display方法里,这样只有创建实例时才会尝试导入对应的模块:
class Display(object): def show(self, message): raise NotImplementedError("子类得实现show啊!") class DisplayFactory(object): def create_display(self): # 先试树莓派模块 try: from raspberrypi_display import RaspberryPiDisplay return RaspberryPiDisplay() except ImportError: pass # 再试Arduino模块 try: from arduino_display import ArduinoDisplay return ArduinoDisplay() except ImportError: raise NotImplementedError("没找到适配这个平台的显示模块哦")
为啥你之前的self.arduino_display没用?
你试了self.arduino_display还是报错,可能是这几个原因:
- 你根本没通过工厂创建实例,直接去引用全局变量
arduino_display,但这个变量压根没定义; - 条件导入的代码块没被执行到——比如Arduino的检测逻辑错了,导致
ArduinoDisplay根本没被导入; - 你的
arduino_display.py不在Python的搜索路径里,比如放在子目录但没加__init__.py,或者路径没加到sys.path里。
正确使用示例
不管用哪种方式,调用的时候都要先通过工厂拿到实例,再调用方法:
# 创建工厂 factory = DisplayFactory() # 获取显示实例 display = factory.create_display() # 调用show方法,这下不会报错了 display.show("嗨,硬件世界!")
Python 2.7额外注意点
- 所有类都要继承
object,不然会变成旧式类,方法重写、实例化都容易出问题; - 平台检测逻辑要靠谱,比如树莓派可以用
gpiozero库来判断(如果装了的话),Arduino可以检测/dev/ttyACM0这类串口设备; - 如果你的模块在子文件夹里,一定要给文件夹加个空的
__init__.py,让Python把它当成包来识别。
内容的提问来源于stack exchange,提问作者sagism
相关产品推荐
相关产品推荐

