调味包

时间:2014-09-19 14:26:00

标签: python python-2.6

我使用的软件包在与硬件通信时具有与以下类似的结构:

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"时,我只有一个全局调用硬件,如上所示。

3 个答案:

答案 0 :(得分:3)

您应该尝试抽象出某种通用接口背后的硬件/风格相关功能。有许多不同的方法可以做到这一点,例如类继承,composition,传递一个对象,或者---你可能正在寻找 - 甚至作为一个全局的python模块或对象。

我个人倾向于经常赞成合成,因为类继承通常不是自然适合的,并且可能会爆发成多重继承或MixInMadness

一个全局Python模块(或一个sigleton对象)很有吸引力,但我会转向远离,除非真的,真的只需要在一个进程中只有一个。这是一个很好的设计的好例子是当它与底层平台绑定时,例如Python os模块在​​Windows和Linux上具有大致相同的接口,但在下面的工作方式却截然不同。将其与hw1hw2进行比较。另一个很好的例子是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也可以处理UnitTestNose样式测试。