【问题标题】:Is it good code style if a Python function returns different types depending on the arguments如果 Python 函数根据参数返回不同的类型,它是一种好的代码风格吗
【发布时间】:2020-02-05 18:28:31
【问题描述】:

如果 Python 函数根据提供的参数返回不同的类型,这是一种好的代码风格吗?

def foo(bar):
  if bar is None:
    return None
  elif bar == 1:
    return 1*1
  else:
    return [b*b for b in bar]

foo 如果 bar 为 None,则返回 None

foo如果bar == 1返回1

foo 如果 bar 是元组/整数列表,则返回 int 列表

例子:

>> foo(None)
None
>> foo(1)
1
>> foo(1, 2, 3, 4)
[1, 4, 9, 16]

返回Noneint 应该没问题,但是否可以根据函数参数返回intints 列表?您可能会争辩说这没问题,因为用户知道期望哪些返回类型并且不需要类型检查(在这种情况下我会说它不正确),但有人可能会争辩说最好将函数拆分为两个函数,一个期望 int 并返回 int,另一个期望 int 列表并返回 ints 列表。

【问题讨论】:

  • 那么foo(2)foo('asd') 呢?您需要处理更多案件,这取决于您的做法。
  • 这完全取决于用例 - 例如,json.loads(x) 根据 x 的值返回不同的类型。
  • 在我看来,如果你记录它就可以了
  • @Guy:我知道这个例子并不完整,需要更多的检查来处理不同的输入。我想保持这个例子简短。
  • 简短回答:不。长答案:不。尽可能返回最受限制的类型。这样想:你将如何使用打字模块输入这个函数?类型可以是AnyUnion。这通常是麻烦的征兆。有例外,但它们非常具体。

标签: python python-3.x


【解决方案1】:

这完全取决于您的用例。这是标准库中的一个示例,其中结果的类型取决于输入的 type

>>> import operator
>>> operator.add(1, 2)
3
>>> operator.add(1.0, 2.0)
3.0

这种行为通常是可以的,可以用@typing.overload记录。


这是一个示例,其中结果的类型取决于输入的

>>> import json
>>> json.loads('1')
1
>>> json.loads('[1]')
[1]

这种类型的行为通常保留用于序列化和反序列化,或者是模糊类型/值边界的 API,例如 np.int_(3).astype(bool) 中的 astype


另一方面,这是一个明显设计不佳的函数示例:

from typing import Union  # make sure to document the mixed return type

def is_even(x: int) -> Union[bool, str]:
    if x % 2 == 0:
        return True
    else:
        return "no"

在不了解您的具体用例的情况下,很难在这里给出建议。

【讨论】:

    【解决方案2】:

    这个问题没有明确的答案,因此很难制定一个清晰全面的答案,这可以在this 非常相似的问题中看到。

    一般来说,你应该避免从一个函数返回不同的类型。例如,我曾经参与过一个项目,其中一个函数看起来像这样:

    def get_df(url):
        data = get_data(url)
        df = reformat_data(data)
    
        if df_is_empty(df):
            return 'Empty dataframe'
    
        df_interp = interpolate_df(df)
        return df_interp
    

    你可以想象当我得到错误时

    AttributeError: 'str' object has no attribute 'iloc'
    

    这让我很困惑,花了大约半天的时间才弄清楚这个错误来自哪里。一个更好的解决方案是提出ValueError

    现在,总是会出现这种经验法则可能不正确的奇怪情况。例如,在抓取网站时,有时能够检索图像也可能很有用。在这种情况下,我会在你的函数中包含一个标志:

    def scrape_website(url, get_images=False):
        data = do_stuff(url)
        ordered_data = order_data(data, get_images)
        return ordered_data
    

    但是我宁愿把它分成两个函数,一个返回非图像数据,一个只返回图像数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-04
      • 1970-01-01
      • 2016-06-09
      • 1970-01-01
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多