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

发布于 2024-09-29 17:21:12 字数 579 浏览 6 评论 0原文

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

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

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

我现在的代码是这样的:

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

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

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

I have a function where I need to generate different output strings for another program I invoke, depending on which type it wants.

Basically, the called program needs a command line argument telling it which type it was called with.

Happily I found this answer on SO on how to check a variable for type. But I noticed how people also raised objections, that checking for types betrays a "not object oriented" design. So, is there some other way, presumable more "more object oriented" way of handling this without explicitly checking for type?

The code I have now goes something like this:

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

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

which works just fine, but I just wanted to know if there is some technique I am unaware of.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

九歌凝 2024-10-06 17:21:12

您可以使用双重调度多种方法

You could use Double Dispatch or Multimethods.

悲歌长辞 2024-10-06 17:21:12

我不认为“双重调度”或“多重方法”特别相关,也与人们对其他 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() - 如果您对本质的抽象也就是说,“价值”是一个好的价值。

I don't think Double Dispatching or Multimethods are particularly relevant nor have much to do with the objections people had to that other SO answer.

Not surprisingly, to make what you're doing more object-oriented, you'd need introduce some objects (and corresponding classes) into it. Making each value an instance of a class would allow -- in fact, virtually force -- you to stop checking its type. The modifications to your sample code below show a very simple way this could have been done:

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)

It would be even more object-oriented if there were methods in the Value class to access its attributes indirectly, but just doing the above gets rid of the infamous type-checking. A more object-oriented design would probably have a different subclass for each kind of Value which all share a common set of methods for clients, like myfunc(), to use to create, manipulate, and extract information from them.

Another benefit of using objects is that you shouldn't have to modify myfunc() if/when you add support for a new type of 'Value` to your application -- if your abstraction of the essence of a "Value" is a good one, that is.

汐鸠 2024-10-06 17:21:12
    But I noticed how people also raised objections, 
that checking for types betrays a "not object oriented" design

实际上它被称为鸭子打字风格(“如果它看起来像鸭子并且嘎嘎叫得像鸭子,它一定是一只鸭子。”),并且Python语言推荐使用这种编程风格。

通过鸭子打字,

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

您 可以调用 EAFP (请求宽恕比请求许可更容易)意思是更Pythonic,基本上在你的情况下更Pythonic是这样的:

def myfunc(val):
    cmd_type = 'i'

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

在你的magicprogram中(我不知道这是你的脚本还是......),并且因为
在所有情况下,您的程序都会得到一个字符串,因此只需尝试将其转换为您想要的任何内容
脚本接受;

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,并记住每个规则都有其例外,所以也许你的情况是一个例外
你最好进行类型检查。

希望这能为您解决问题。

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

Actually it's called Duck typing style ("If it looks like a duck and quacks like a duck, it must be a duck."), and it's the python language that recommend using this style of programming .

and with duck typing come something call EAFP (Easier to Ask Forgiveness than Permission)

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

you mean more pythonic, basically what will be more pythonic in your case is something like this:

def myfunc(val):
    cmd_type = 'i'

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

and in your magicprogram (i don't know if it's your script or ...), and because
in all cases your program will get a string so just try to convert it to whatever your
script accept;

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

I don't know what's all your code, but you can follow the example above it's more pythonic, and remember every rule has their exception so maybe your case is an exception
and you will better be with type checking.

Hope this will clear things for you.

泅人 2024-10-06 17:21:12

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

编辑:为了解释最后一个版本,

Val = "a string"
myfunc = myfuncStringVersion

或多或少做同样的事情,您将 val 包装在类中,仅分解为值和函数,因为您可能不想将 val 包装在类中。

This is more of an engineering in the large question than how to design one small function. There are many different ways to go about it, but they more or less break down to the same general thought process. Back where the type of val is known it should specify how it should be translated into a command line arg. If it were me I would probably make val be a class that had a To Command Line function that did the right thing. You could also assign a type specific myfunc function to a variable then call that when you need to.

edit: To explain the last version something along the lines of

Val = "a string"
myfunc = myfuncStringVersion

more or less doing the same thing you would with wrapping val in a class only broken out into a value and function since you might not want to wrap val in a class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文