如何避免过多的参数传递?

时间:2009-10-16 22:52:16

标签: python design-patterns

我正在使用分布在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以来,我才真正体会到良好的编码实践。请帮助我成为更好的程序员!

6 个答案:

答案 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,提供信息。