在Python中处理不同类型的规范方法是什么?

时间:2010-10-29 12:30:23

标签: python oop paradigms

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

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

我很高兴在SO上发现this answer如何检查变量的类型。但我注意到人们也提出异议,检查类型背叛了“非面向对象”的设计。那么,还有其他一些方法,在不明确检查类型的情况下,可以采用更“面向对象”的方式处理这个问题吗?

我现在的代码是这样的:

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

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

工作得很好,但我只是想知道是否有一些我不知道的技术。

4 个答案:

答案 0 :(得分:5)

您可以使用Double DispatchMultimethods

答案 1 :(得分:3)

    But I noticed how people also raised objections, 
that checking for types betrays a "not object oriented" design

实际上它被称为Duck typing style(“如果它看起来像鸭子,像鸭子一样嘎嘎叫,它一定是鸭子。”),这是建议使用这种编程风格的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,并记住每个规则都有他们的异常,所以也许你的情况是例外 你最好进行类型检查。

希望这能为你解决问题。

答案 2 :(得分:3)

我不认为 Double Dispatching Multimethods 特别相关,也不会与人们对其他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(),用于创建,操作和提取信息。它们。

使用对象的另一个好处是,如果/当您向应用程序添加对新类型“Value”的支持时,您不必修改myfunc() - 如果您对“精华”的抽象概括价值“是一个很好的,就是。

答案 3 :(得分:1)

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

编辑:按照

的方式解释最新版本
Val = "a string"
myfunc = myfuncStringVersion

或多或少地做同样的事情,你在一个类中包装val只会分解成一个值和函数,因为你可能不想在一个类中包装val。