【问题标题】:Python adjust the return type to consider the input typesPython调整返回类型以考虑输入类型
【发布时间】:2017-06-18 06:43:14
【问题描述】:

在 C++ 和 C# 等中,您可以重载或调整返回类型以匹配输入类型。使用 Python,我发现返回类型无论如何都应该是一致的引用。 Like in this question

现在我的代码想要将返回类型与参数类型匹配

def myUpper(what_is_this_thing):
    try:
        return what_is_this_thing.upper()  
    except AttributeError:  
        try:
            return {k:what_is_this_thing[k].upper() for k in what_is_this_thing} 
        except TypeError:
        return [x.upper() for x in what_is_this_thing] 

print myUpper('test') 
print myUpper(['test', 'and more'])
print myUpper({'one':'test', 'two': 'and more'})
print myUpper(['test', 1000])

输出

TEST
['TEST', 'AND MORE']
{'two': 'AND MORE', 'one': 'TEST'}
An exception is rased because the payload does not have a upper method

那么这个蟒蛇罪有多严重?我主要还是在 2.7 中工作,我知道 3.3 有类型提示,学习需要等到夏天晚些时候。

有没有人有一种不那么罪恶的方式来获得大部分的好处?或一个连贯的论点为什么不应该这样做?

附录:
除了我喜欢的 Python3 Moses 之外。我觉得有必要找出这个问题是否最好用 python 2.7 之类的东西来回答

def myUpper(s): 
    return s.upper() 
print myUpper('test') 
print [s.myUpper() for s in 'test', 'and more'] d = { 'one':'test', 'two': 'and more'} 
print {k:d[k].myUpper() for k in d}

总而言之,即使很常见,也可以在代码中传播理解内容。选择扩展理解而不是晦涩的返回数据类型?

我怀疑如果我通过调整返回类型来删除最终代码中的 400 多行理解行。但如果这太奇怪了,那就这样吧。

这归结为违反关于 1 个函数 1 个返回类型的不成文规则的可读性。

【问题讨论】:

  • 如果您对参数了解不够,无法知道是否将其传递给strUpper、listUpper 或dictUpper,那么您不知道您从@ 得到什么987654328@反正。
  • 这是真的。为了集中注意力,我知道我可以测试输入类型的所有方法。我选择得到宽恕而不是许可。我可以猜测字符串更常见,而字典和列表是最不期望的。我的问题是针对常见的图书馆内部功能。我什至可以使用一个类来隐藏对我来说无关紧要的特定类型版本。问题是函数应该只有一种返回类型的论点有多强。在这种情况下,您会取回与您传入的内容相关的内容。
  • 有 Python 函数可以返回多种类型的值,但它们往往分为两类。 1) f 将返回 t 类型的值,或者将返回 None。 2) 函数将返回t 类型的值,但任何此类类型都将支持迭代/映射/等。返回一个唯一识别特征是匹配输入类型的值只是推迟了最终需要弄清楚你得到了什么类型的值....
  • ...也就是说,您的示例可以解释为遵循我的第二点;由于您使用每个值作为print 的参数,您可能会假设myUpper 返回一个支持__str__(或至少__repr__)的值。但为了清楚起见,我强烈主张一个函数应该有一个独立于其输入类型的单一、明确定义的返回类型。
  • 你不认为知道调用类型就足以知道返回类型吗?这就是重点。你认为这还不够清楚。或者它太不同而无法使用?

标签: python return-type


【解决方案1】:

如果您希望返回类型与参数(准确地说,第一个参数)保持某种一致性,您可以使用 functools.singledispatch 创建函数的重载实现;我会说你开始转向 Python 3 的原因之一:

from functools import singledispatch

@singledispatch
def my_upper(what_is_this_thing):
    return what_is_this_thing.upper()  

@my_upper.register(list)
def _(this_is_a_list):
    ...
    return this_is_also_a_list

@my_upper.register(dict)
def _(this_is_a_dict):
    ...
    return this_is_also_a_dict

【讨论】:

  • 这会向后移植吗?我一直在检查,还没有看到方法。
  • 我想我找到了一个我会尝试的来源backport
  • 通过后端端口工作。谢谢大家!
【解决方案2】:

把我的五美分放在那里:

hanlders = {
    str: (lambda what_is_this_thing: what_is_this_thing.upper()),
    dict: (lambda what_is_this_thing: {k:what_is_this_thing[k].upper() for k in what_is_this_thing}),
    list: (lambda what_is_this_thing: [x.upper() for x in what_is_this_thing]), 
}
print handlers[type(what_is_this_thing)](what_is_this_thing)

【讨论】:

  • 不需要__name__;您可以使用类型对象作为handlers 的键。
  • 这根本不处理子类。
  • 我将处理程序模式用于 case 语句并喜欢它。在这种情况下,我同意子类问题使其过于局限+这不是主要问题。
【解决方案3】:

您实际上可以检查类型而不是依赖异常。

v = 'one'
if type(v) == str:
    # Treat it as a string
elif type(v) == list:
    # Treat it as a list
elif type(v) == dict:
    # Treat is as a dict

【讨论】:

  • 可以,但这在 python 中不是首选。我的问题是关于返回类型。
  • 您应该使用isinstance 进行类型嗅探,而不是比较类型对象。 if isinstance(v, str)等
  • 再次...不是我的问题。如果我以这种方式调整我的返回类型,考虑到返回类型通常是一致的类型,那么它有多大的 Python 罪过。
  • @user2315423 那么这在很大程度上取决于您将如何使用它。与其说是“罪孽深重”的问题,不如说是“以后会不会惹麻烦?”事物。如果您只是将它用于另一个函数的内部函数,那么没问题。如果它要被很多人广泛使用,那么你应该争取清楚;在这种情况下,值得质疑导致您将不同类型传递给同一函数的情况。
  • 好的,因此考虑到该函数旨在普遍使用许多源数据类型,将其放在公司内部的通用库中似乎是合理的。所以你很清楚吗?我本可以编写 3 个名称不同的函数。谁能提供支持这种重载的更多命名空间的论据?
【解决方案4】:

您可以使用isinstance - 并将字典的键/值以及列表项递归地传递给函数将处理更多类型:

def myUpper(o):
    if(isinstance(o, str)):
        return o.upper()
    elif(isinstance(o, list)):
        return [myUpper(x) for x in o]
    elif(isinstance(o, dict)):
        return {myUpper(k):myUpper(v) for k,v in o.items()}
    else:
        return o

【讨论】:

    猜你喜欢
    • 2021-10-21
    • 2020-06-02
    • 2018-02-23
    • 2019-10-29
    • 2018-01-21
    • 1970-01-01
    • 2021-09-30
    • 2020-02-29
    • 2020-05-02
    相关资源
    最近更新 更多