6

我有一个函数,我需要为我调用的另一个程序生成不同的输出字符串,具体取决于它想要的类型。

基本上,被调用的程序需要一个命令行参数来告诉它调用的类型。

很高兴我在 SO 上找到了关于如何检查变量类型的答案。但我注意到人们也提出了反对意见,即检查类型背叛了“非面向对象”的设计。那么,是否有其他方式,可以推测为更“面向对象”的方式来处理此问题而无需显式检查类型?

我现在的代码是这样的:

def myfunc(val):
    cmd_type = 'i'
    if instance(val, str):
        cmd_type = 's'

    cmdline = 'magicprogram ' + cmd_type + ' ' + val
    Popen(cmdline, ... blah blah)
    ...

效果很好,但我只是想知道是否有一些我不知道的技术。

4

4 回答 4

5

您可以使用Double DispatchMultimethods

于 2010-10-29T13:10:04.477 回答
3
    But I noticed how people also raised objections, 
that checking for types betrays a "not object oriented" design

其实它叫鸭子打字风格(“如果它看起来像鸭子,叫起来像鸭子,那一定是鸭子。”),是python语言推荐使用这种编程风格。

随着鸭子打字的出现,称为EAFP(请求宽恕比许可更容易)

    presumable more "more object oriented" way of handling this without 
   explicitly checking for type?

你的意思是更多的pythonic,基本上在你的情况下更多的pythonic是这样的:

def myfunc(val):
    cmd_type = 'i'

    # forget about passing type to your magicprogram
    cmdline = 'magicprogram  %s ' % val 
    Popen(cmdline, ... blah blah)

在你的魔法程序中(我不知道它是你的脚本还是......),因为在所有情况下你的程序都会得到一个字符串,所以只需尝试将它转换为你的脚本接受的任何内容;

from optparse import OptionParser

# ....

if __name__ == '__main__':

    parser = OptionParser(usage="blah blah")

    # ...
    (options, args) = parser.parse_args()

    # Here you apply the EAFP with all type accepted.
    try:
        # call the function that will deal with if arg is string
        # remember duck typing.
    except ... :
        # You can continue here

我不知道你所有的代码是什么,但你可以按照上面的例子,它更 Pythonic,并记住每条规则都有它们的例外,所以也许你的情况是一个例外,你最好进行类型检查。

希望这会为您解决问题。

于 2010-10-29T13:35:31.227 回答
3

我不认为Double DispatchingMultimethods特别相关,也与人们对其他 SO 答案的反对意见没有太大关系。

毫不奇怪,要使您所做的工作更加面向对象,您需要在其中引入一些对象(和相应的类)。使每个值成为类的实例将允许(实际上,实际上是强制)您停止检查其类型。下面对示例代码的修改显示了一种非常简单的方法:

class Value(object):
    """ Generic container of values. """
    def __init__(self, type_, val):
        self.type = type_   # using 'type_' to avoid hiding built-in
        self.val = val

def myfunc(val):
    # Look ma, no type-checking!
    cmdline = 'magicprogram {obj.type} {obj.val}'.format(obj=val)
    print 'Popen({!r}, ... blah blah)'.format(cmdline)
    # ...

val1 = Value('i', 42)
val2 = Value('s', 'foobar')

myfunc(val1)  # Popen('magicprogram i 42', ... blah blah)
myfunc(val2)  # Popen('magicprogram s foobar', ... blah blah)

如果类中有方法可以间接访问其属性,那将更加面向对象Value,但只需执行上述操作即可摆脱臭名昭著的类型检查。更面向对象的设计可能会为每种类型提供不同的子类,Value它们都为客户共享一组公共方法,例如myfunc()用于创建、操作和从中提取信息的方法。

myfunc()使用对象的另一个好处是,如果/当您向应用程序添加对新类型“值”的支持时,您不必修改——如果您对“值”本质的抽象是好的,那是。

于 2010-10-29T20:46:01.517 回答
1

这更像是一个大问题的工程,而不是如何设计一个小功能。有许多不同的方法来解决它,但它们或多或少地分解为相同的一般思维过程。回到已知 val 类型的地方,它应该指定如何将其转换为命令行 arg。如果是我,我可能会让 val 成为一个具有 To Command Line 功能的类,它做了正确的事情。您还可以将特定类型的 myfunc 函数分配给变量,然后在需要时调用它。

编辑:解释最后一个版本的东西

Val = "a string"
myfunc = myfuncStringVersion

或多或少地做与将 val 包装在一个类中相同的事情,只是分解为一个值和函数,因为您可能不想将 val 包装在一个类中。

于 2010-10-29T13:31:56.990 回答