我正在使用分布在5个模块中的python开发一个中等大小的程序。程序在主模块中使用OptionParser接受命令行参数,例如main.py.这些选项稍后用于确定其他模块中的方法的行为(例如a.py,b.py)。当我扩展用户自定义行为或程序的能力时,我发现我最终在a.py中的方法中需要这个用户定义的参数,而不是由main.py直接调用,而是由另一个调用a.py中的方法:
main.py:
import a
p = some_command_line_argument_value
a.meth1(p)
a.py:
meth1(p):
# some code
res = meth2(p)
# some more code w/ res
meth2(p):
# do something with p
这种过多的参数传递似乎是浪费和错误的,但是我努力尝试,我无法想到解决这个问题的设计模式。虽然我有一些正式的CS教育(在我的学士学位期间辅修CS),但自从我开始使用python以来,我才真正体会到良好的编码实践。请帮助我成为更好的程序员!
答案 0 :(得分:7)
创建与程序相关的类型的对象,并存储与其相关的命令行选项。例如:
import WidgetFrobnosticator
f = WidgetFrobnosticator()
f.allow_oncave_widgets = option_allow_concave_widgets
f.respect_weasel_pins = option_respect_weasel_pins
# Now the methods of WidgetFrobnosticator have access to your command-line parameters,
# in a way that's not dependent on the input format.
import PlatypusFactory
p = PlatypusFactory()
p.allow_parthenogenesis = option_allow_parthenogenesis
p.max_population = option_max_population
# The platypus factory knows about its own options, but not those of the WidgetFrobnosticator
# or vice versa. This makes each class easier to read and implement.
答案 1 :(得分:4)
也许您应该将代码更多地组织到类和对象中?在我写这篇文章时,Jimmy展示了一个基于类实例的答案,所以这里是一个纯粹的基于类的答案。如果你只想要一个行为,这将是最有用的;如果你有可能在某些时候想要不同的默认值,你应该在Python中使用普通的面向对象编程,即在实例中使用属性p set而不是类传递类实例。
class Aclass(object):
p = None
@classmethod
def init_p(cls, value):
p = value
@classmethod
def meth1(cls):
# some code
res = cls.meth2()
# some more code w/ res
@classmethod
def meth2(cls):
# do something with p
pass
from a import Aclass as ac
ac.init_p(some_command_line_argument_value)
ac.meth1()
ac.meth2()
答案 2 :(得分:2)
如果“a”是真实对象而不仅仅是一组独立的辅助方法,则可以在“a”中创建“p”成员变量,并在实例化“a”对象时进行设置。然后,一旦“a”被实例化,你的主类就不需要将“p”传递给meth1和meth2。
答案 3 :(得分:2)
[警告:我的答案并非特定于python。]
我记得 Code Complete 将这种参数称为“tramp参数”。然而,谷歌搜索“tramp参数”并没有返回很多结果。
tramp参数的一些替代方案可能包括:
就个人而言,我不介意一个tramp参数,只要不超过一个;即你的例子对我来说没问题,但我不喜欢......
import a
p1 = some_command_line_argument_value
p2 = another_command_line_argument_value
p3 = a_further_command_line_argument_value
a.meth1(p1, p2, p3)
...相反,我更喜欢......
import a
p = several_command_line_argument_values
a.meth1(p)
...因为如果meth2
决定它想要比以前更多的数据,我宁愿它是否可以从已经传递的原始参数中提取这些额外数据,这样我就不需要了编辑meth1
。
答案 4 :(得分:1)
对于对象,参数列表通常应该非常小,因为最合适的信息是对象本身的属性。处理此问题的标准方法是配置对象属性,然后调用该对象的相应方法。在这种情况下,请将p
设置为a
的属性。如果未设置meth2
,您的p
也应该投诉。
答案 5 :(得分:1)
您的示例让人联想到代码气味Message Chains。您可以找到相应的重构,Hide Delegate,提供信息。