我使用的软件包在与硬件通信时具有与以下类似的结构:
channel
__init__.py
transport
__init__.py
flow.py
multiplex.py
network
__init__.py
header.py
addressing.py
我现在希望能够配置我的包,以便我可以使用它与两个非常相似的硬件进行通信。例如,在与hw1进行通信时,我想在adressing.py中使用以下内容:
from collections import namedtuple
PacketSize = namedtuple('PacketSize', ('header', 'body'))
packet_size = PacketSize(16,256)
在测试hw2时,我想要相当于:
from collections import namedtuple
PacketSize = namedtuple('PacketSize', ('header', 'body'))
packet_size = PacketSize(8,256)
包中的几乎所有模块对于hw1和hw2都是相同的。但是,对于包中的某些功能和类,我的口味可能略有不同。
我想我可以通过这种结构来解决这个问题:
channel
__init__.py
transport
__init__.py
flow.py
multiplex.py
network
__init__.py
header.py
addressing.py
hw1
__init__.py
addressing.py
hw2
__init__.py
addressing.py
因此每个子包都将包含一个hw1和hw2子包,其中放置了特定于硬件的代码。我编写了channel / network / addressing.py,如下所示:
from collections import namedtuple
PacketSize = namedtuple('PacketSize', ('header', 'body'))
if hardware == "hw1":
from hw1.targetprops import *
elif hardware == "hw2":
from hw2.targetprops import *
和channel / network / hw1 / addressing.py这样:
from ..addressing import PacketSize
packet_size = PacketSize(16,256)
这有意义吗?我认为channel / network / addressing.py是丑陋的,因为我正在进行导入,然后我定义了一个namedtuple,然后继续条件导入。我可以做得更好吗?
一般方法是否是调整包装的最佳方法?
是否有一种标准方法来配置包,以便它知道它是否与hw1或hw2有关?目前,当我执行if harware == "hw1"
时,我只有一个全局调用硬件,如上所示。
答案 0 :(得分:3)
您应该尝试抽象出某种通用接口背后的硬件/风格相关功能。有许多不同的方法可以做到这一点,例如类继承,composition,传递一个对象,或者---你可能正在寻找 - 甚至作为一个全局的python模块或对象。
我个人倾向于经常赞成合成,因为类继承通常不是自然适合的,并且可能会爆发成多重继承或MixInMadness
。
一个全局Python模块(或一个sigleton对象)很有吸引力,但我会转向远离,除非真的,真的只需要在一个进程中只有一个。这是一个很好的设计的好例子是当它与底层平台绑定时,例如Python os
模块在Windows和Linux上具有大致相同的接口,但在下面的工作方式却截然不同。将其与hw1
和hw2
进行比较。另一个很好的例子是Twisted反应堆,其中一次只能运行一个反应堆。即使这样,Twisted代码的很大一部分也会绕过reactor
个对象,例如合成。这部分是为了使单元测试成为可能。
对于您的示例,如果hw1或hw2指的是运行程序的硬件,那么全局python模块确实有意义。如果它是指您的程序正在与之通信的硬件,例如通过串行端口或网络,则全局模块是错误的方法。您可能有两个串口,并希望在同一过程中与hw1和hw2通信。
有关如何使用全局模块或实际上是全局对象的示例,我建议您查看how Twisted does it。然后你的模块会做类似
的事情from mypackage import hardware # hw1/hw2 automatically detected
print hardware.packet_size # different for different hardware
或
# main.py
from mypackage import hw1
hw1.init()
# other.py
from mypackage import hardware # initialized to hw1 in main.py
另一方面,合成或传递一个对象看起来像是:
hw = mypackage.hw1.hw1factory()
send_data(hw, 'foo') # uses hw.packet_size
hw = mypackage.hw2.hw2factory()
frob = Frobnicator(hw)
frob.frobnicate('foo') # uses hw.packet_size internally
答案 1 :(得分:0)
你的做法是错误的。您不应该有多个模块来区分案例。在您描述的情况下,模块color.py可能包含一个函数,您可以向其传递要测试的项目列表以及用于测试项目的颜色。如何组织这取决于数据源和目标以及您正在测试的项目的性质。
答案 2 :(得分:0)
你应该考虑使用py.test和灯具(它们不像Django灯具)。这些完全符合您的要求,py.test
也可以处理UnitTest
和Nose
样式测试。