精华内容
下载资源
问答
  • Python函数返回结果的技巧

    千次阅读 2020-05-19 10:21:28
    文章目录1. 单个函数不要返回多种类型2. 使用 partial 构造新函数3....Python函数返回方式 Python 函数通过调用 return 语句来返回结果。使用 return value 可以返回单个值,用 return value1,v...


    Python 的函数返回方式

    Python 函数通过调用 return 语句来返回结果。使用 return value 可以返回单个值,用
    return value1,value2 则能让函数同时返回多个值。

    如果一个函数体内没有任何 return 语句,那么这个函数的返回值默认为 None。除了通过 return 语句返回内容,在函数内还可以使用抛出异常(raise Exception)的方式来“返回结果”。

    接下来,我将列举一些与函数返回相关的常用编程建议。

    1. 单个函数不要返回多种类型

    Python 语言非常灵活,我们能用它轻松完成一些在其他语言里很难做到的事情。比如:让一个函数同时返回不同类型的结果。从而实现一种看起来非常实用的“多功能函数”。

    就像下面这样:

    def get_users(user_id=None):
        if user_id is None:
            return User.get(user_id)
        else:
            return User.filter(is_active=True)
    
    # 返回单个用户
    get_users(user_id=1)
    
    # 返回多个用户
    get_users()
    

    当我们需要获取单个用户时,就传递 user_id 参数,否则就不传参数拿到所有活跃用户列表。一切都由一个函数 get_users 来搞定。这样的设计似乎很合理。

    然而在函数的世界里,以编写具备“多功能”的瑞士军刀型函数为荣不是一件好事。这是因为好的函数一定是 “单一职责(Single responsibility)” 的。单一职责意味着一个函数只做好一件事,目的明确。这样的函数也更不容易在未来因为需求变更而被修改。

    而返回多种类型的函数一定是违反“单一职责”原则的,好的函数应该总是提供稳定的返回值,把调用方的处理成本降到最低。像上面的例子,我们应该编写两个独立的函数 get_user_by_id(user_id)、 get_active_users()来替代。

    2. 使用 partial 构造新函数

    假设这么一个场景,在你的代码里有一个参数很多的函数 A,适用性很强。而另一个函数 B 则是完全通过调用 A 来完成工作,是一种类似快捷方式的存在。

    比方在这个例子里, double 函数就是完全通过 multiply 来完成计算的:

    def multiply(x, y):
        return x * y
    
    def double(value):
        # 返回另一个函数调用结果
        return multiply(2, value)
    

    对于上面这种场景,我们可以使用 functools 模块里的 partial() 函数来简化它。

    partial(func,*args,**kwargs) 基于传入的函数与可变(位置/关键字)参数来构造一个新函数。
    所有对新函数的调用,都会在合并了当前调用参数与构造参数后,代理给原始函数处理

    利用 partial 函数,上面的 double 函数定义可以被修改为单行表达式,更简洁也更直接。

    import functools
    
    double = functools.partial(multiply, 2)
    

    建议阅读:partial 函数官方文档

    3. 抛出异常,而不是返回结果与错误

    我在前面提过,Python 里的函数可以返回多个值。基于这个能力,我们可以编写一类特殊的函数:同时返回结果与错误信息的函数。

    在这里插入图片描述
    在示例中, create_item 函数的作用是创建新的 Item 对象。同时,为了在出错时给调用方提供错误详情,它利用了多返回值特性,把错误信息作为第二个结果返回。

    乍看上去,这样的做法很自然。尤其是对那些有 Go 语言编程经验的人来说更是如此。但是在 Python 世界里,这并非解决此类问题的最佳办法。因为这种做法会增加调用方进行错误处理的成本,尤其是当很多函数都遵循这个规范而且存在多层调用时。

    Python 具备完善的异常(Exception)机制,并且在某种程度上鼓励我们使用异常(官方文档关于 EAFP 的说明)。所以,使用异常来进行错误流程处理才是更地道的做法。

    引入自定义异常后,上面的代码可以被改写成这样:

    在这里插入图片描述
    使用“抛出异常”替代“返回 (结果, 错误信息)”后,整个错误流程处理乍看上去变化不大,但实际上有着非常多不同,一些细节:

    • 新版本函数拥有更稳定的返回值类型,它永远只会返回 Item 类型或是抛出异常
    • 虽然我在这里鼓励使用异常,但“异常”总是会无法避免的让人感到惊讶,所以,最好在函数文档里说明可能抛出的异常类型
    • 异常不同于返回值,它在被捕获前会不断往调用栈上层汇报。所以 create_item的一级调用方完全可以省略异常处理,交由上层处理。这个特点给了我们更多的灵活性,但同时也带来了更大的风险。
      Hint:如何在编程语言里处理错误,是一个至今仍然存在争议的主题。比如像上面不推荐的多返回值方式,正是缺
      乏异常的 Go语言中最核心的错误处理机制。另外,即使是异常机制本身,不同编程语言之间也存在着差别。
      异常,或是不异常,都是由语言设计者进行多方取舍后的结果,更多时候不存在绝对性的优劣之分。但是,单就 
      Python 语言而言,使用异常来表达错误无疑是更符合 Python 哲学,更应该受到推崇的.
    

    4. 谨慎使用 None 返回值

    None 值通常被用来表示“某个应该存在但是缺失的东西”,它在 Python 里是独一无二的存在。很多编程语言里都有与 None 类似的设计,比如 JavaScript 里的 null、Go 里的 nil 等。因为 None 所拥有的独特 虚无 气质,它经常被作为函数返回值使用。

    当我们使用 None 作为函数返回值时,通常是下面 3 种情况。

    1. 作为操作类函数的默认返回值

    当某个操作类函数不需要任何返回值时,通常就会返回 None。同时,None 也是不带任何 return 语句函数的默认返回值。

    对于这种函数,使用 None 是没有任何问题的,标准库里的 list.append()、 os.chdir() 均属此类。

    1. 作为某些“意料之中”的可能没有的值

    有一些函数,它们的目的通常是去尝试性的做某件事情。视情况不同,最终可能有结果,也可能没有结果。而对调用方来说,“没有结果”完全是意料之中的事情。对这类函数来说,使用 None 作为“没结果”时的返回值也是合理的。

    在 Python 标准库里,正则表达式模块 re 下的 re.search、 re.match 函数均属于此类,这两个函数在可以找到匹配结果时返回 re.Match 对象,找不到时则返回 None。

    1. 作为调用失败时代表“错误结果”的值

    有时, None 也会经常被我们用来作为函数调用失败时的默认返回值,比如下面这个函数:

    在这里插入图片描述
    当 username 不合法时,函数 create_user_from_name 将会返回 None。但在这个场景下,这样做其实并不好。

    不过你也许会觉得这个函数完全合情合理,甚至你会觉得它和我们提到的上一个“没有结果”时的用法非常相似。那么如何区分这两种不同情形呢?关键在于:函数签名(名称与参数)与 None 返回值之间是否存在一种“意料之中”的暗示。

    让我解释一下,每当你让函数返回 None 值时,请仔细阅读函数名,然后问自己一个问题:假如我是该函数的使用者,从这个名字来看,“拿不到任何结果”是否是该函数名称含义里的一部分?

    分别用这两个函数来举例:

    • re.search():从函数名来看,search,代表着从目标字符串里去搜索匹配结果,而搜索行为,一向是可能有也可能没有结果的,所以该函数适合返回 None
    • create_user_from_name():从函数名来看,代表基于一个名字来构建用户,并不能读出一种
      可能返回、可能不返回的含义。所以不适合返回 None

    对于那些不能从函数名里读出 None值暗示的函数来说,有两种修改方式。第一种,如果你坚持使用 None 返回值,那么请修改函数的名称。比如可以将函数create_user_from_name() 改名为 create_user_or_none()。

    第二种方式则更常见的多:用抛出异常(raise Exception)来代替 None 返回值。因为,如果返回不了正常结果并非函数意义里的一部分,这就代表着函数出现了“意料以外的状况”,而这正是 Exceptions 异常 所掌管的领域。

    使用异常改写后的例子:

    在这里插入图片描述
    与 None 返回值相比,抛出异常除了拥有我们在上个场景提到的那些特点外,还有一个额外的优势:可以在异常信息里提供出现意料之外结果的原因,这是只返回一个 None 值做不到的。

    5. 合理使用“空对象模式”

    我在前面提到函数可以用 None 值或异常来返回错误结果,但这两种方式都有一个共同的缺点。那就是所有需要使用函数返回值的地方,都必须加上一个 if 或 try/except 防御语句,来判断结果是否正常。

    让我们看一个可运行的完整示例:

    在这里插入图片描述
    在这个例子里,每当我们调用 Account.from_string 时,都必须使用 try/except 来捕获可能发生的异常。如果项目里需要调用很多次该函数,这部分工作就变得非常繁琐了。针对这种情况,可以使用“空对象模式(Null object pattern)”来改善这个控制流。

    Martin Fowler 在他的经典著作《重构》 中用一个章节详细说明过这个模式。简单来说,就是使用一个符合正常结果接口的“空类型”来替代空值返回/抛出异常,以此来降低调用方处理结果的成本。

    引入“空对象模式”后,上面的示例可以被修改成这样:

    在这里插入图片描述
    在新版代码里,我定义了 NullAccount 这个新类型,用来作为 from_string 失败时的错误结果返回。这样修改后的最大变化体现在 caculate_total_balance 部分:

    在这里插入图片描述
    调整之后,调用方不必再显式使用 try 语句来处理错误,而是可以假设 Account.from_string 函数总是会返回一个合法的 Account 对象,从而大大简化整个计算逻辑。

    Hint:在 Python 世界里,“空对象模式”并不少见,比如大名鼎鼎的 Django 框架里的 AnonymousUser 就是一个
    典型的 null object。
    

    6. 使用生成器函数代替返回列表

    在函数里返回列表特别常见,通常,我们会先初始化一个列表 results=[],然后在循环体内使用 results.append(item) 函数填充它,最后在函数的末尾返回。

    对于这类模式,我们可以用生成器函数来简化它。粗暴点说,就是用 yielditem 替代 append 语句。使用生成器的函数通常更简洁、也更具通用性。

    在这里插入图片描述

    7. 限制递归的使用

    当函数返回自身调用时,也就是 递归 发生时。递归是一种在特定场景下非常有用的编程技巧,但坏消息是:Python 语言对递归支持的非常有限。

    这份“有限的支持”体现在很多方面。首先,Python 语言不支持“尾递归优化”。另外 Python 对最大递归层级数也有着严格的限制。

    所以我建议:尽量少写递归。如果你想用递归解决问题,先想想它是不是能方便的用循环来替代。如果答案是肯定的,那么就用循环来改写吧。如果迫不得已,一定需要使用递归时,请考虑下面几个点:

    • 函数输入数据规模是否稳定,是否一定不会超过 sys.getrecursionlimit() 规定的最大层数限制
    • 是否可以通过使用类似functools.lru_cache 的缓存工具函数来降低递归层数

    总结

    最后再总结一下要点:

    • 让函数拥有稳定的返回值,一个函数只做好一件事
    • 使用 functools.partial 定义快捷函数
    • 抛出异常也是返回结果的一种方式,使用它来替代返回错误信息
    • 函数是否适合返回 None,由函数签名的“含义”所决定
    • 使用“空对象模式”可以简化调用方的错误处理逻辑
    • 多使用生成器函数,尽量用循环替代递归
    展开全文
  • python函数返回多个值的示例方法

    千次阅读 2018-01-24 21:13:01
    python函数返回多个值的示例方法 python可以返回多个值,确实挺方便 函数里的return只能返回一个值,但是返回类型是没是限制的 因此,我们可以“返回一个 tuple类型,来间接达到返回多个值”。 例子是我在...

    python函数返回多个值的示例方法

    python可以返回多个值,确实挺方便
    函数里的return只能返回一个值,但是返回类型是没是限制的
    因此,我们可以“返回一个 tuple类型,来间接达到返回多个值”。
    例子是我在robot framework source code 时的例子:

    复制代码代码如下:

        def __init__(self, cells):
            self.cells, self.comments = self._parse(cells)

        def _parse(self, row):
            data = []
            comments = []
            for cell in row:
                cell = self._collapse_whitespace(cell)
                if cell.startswith('#') and not comments:
                    comments.append(cell[1:])
                elif comments:
                    comments.append(cell)
                else:
                    data.append(cell)
            return self._purge_empty_cells(data), self._purge_empty_cells(comments)

    当时__init__是类的构造函数,他将得到有_parse解析回来的多个返回值,self._purge_empty_cells(data) 赋给self.cells, self._purge_empty_cells(comments)赋给self.comments
    就这么简单 :)


    展开全文
  • python 函数返回多个值

    万次阅读 2017-08-01 16:48:53
    (廖雪峰Python教程学习笔记)函数体内部的语句在执行时,一旦执行到return,函数就执行完毕,并将结果返回。 如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。 return None可以简写为return。...

    (廖雪峰Python教程学习笔记)

    函数体内部的语句在执行时,一旦执行到return,函数就执行完毕,并将结果返回。
    如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。
    return None可以简写为return。

    Python中的函数是可以返回多个值的。


    比如在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度,就可以计算出新的新的坐标:

    import math
    def move(x, y, step, angle=0):
        nx = x + step * math.cos(angle)
        ny = y - step * math.sin(angle)
        return nx, ny

    然后,我们就可以同时获得返回值:

    >>> x, y = move(100, 100, 60, math.pi / 6)
    >>> print(x, y)
    151.96152422706632 70.0

    但其实这只是一种假象,Python函数返回的仍然是单一值:

    >>> r = move(100, 100, 60, math.pi / 6)
    >>> print(r)
    (151.96152422706632, 70.0)

    原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。

    展开全文
  • Python函数返回多个值的方法

    万次阅读 2019-08-19 20:20:05
    如果 Python函数直接返回多个值,Python 会自动将多个返回值封装成元组。 如下程序示范了函数直接返回多个值的情形: def sun_adn_avg(list): sum = 0 count = 0 for e in list: if isinstance(e, i...

    如果程序需要有多个返回值,则既可将多个值包装成列表之后返回,也可直接返回多个值。如果 Python 函数直接返回多个值,Python 会自动将多个返回值封装成元组。

    如下程序示范了函数直接返回多个值的情形:

    def sun_adn_avg(list):
        sum = 0
        count = 0
        for e in list:
            if isinstance(e, int) or isinstance(e, float):
                count += 1
                sum += e
    
        return sum, sum / count
    
    
    my_list = [20, 15, 2.8, 'a', 35, 5.9, -1.8]
    tp = sun_adn_avg(my_list)
    print(tp)

    上面程序中的第 9 行代码返回了多个值,当 ① 号代码调用该函数时,该函数返回的多个值将会被自动封装成元组,因此程序看到 tp 是一个包含两个元素(由于被调用函数返回了两个值)的元组。

    此外,也可使用 Python 提供的序列解包功能,直接使用多个变量接收函数返回的多个值。例如如下代码:

    # 使用序列解包来获取多个返回值
    s, avg = sum_and_avg(my_list) #②
    print(s)
    print(avg)

    上面程序中的 ② 号代码直接使用两个变量来接收 sum_and_avg() 函数返回的两个值,这就是利用了 Python 提供的序列解包功能。

    展开全文
  • python 函数返回列表、字典 return

    万次阅读 2019-04-01 20:58:27
    特点: 所有函数都有返回值,如果没有 return 语句,会隐式地调用 return None ...函数的返回值可以是一个数、列表、字典,返回列表、字典时该怎么办呢? 返回值是字典,而我们要取字典中的某个值时: def func1...
  • python函数返回多个值

    千次阅读 2018-04-16 21:46:46
    python函数可以返回多个值:>>> def f(x, y, z): return x, y, z >>> x, y, z = f(1, 2, 3) >>> print(x, y, z) 1 2 3但实际上返回的是一个...
  • 如果 Python 函数直接返回多个值,Python 会自动将多个返回值封装成元组。 如下程序示范了函数直接返回多个值的情形: def sum_and_avg(list): sum = 0 count = 0 for e in list: # 如果元素e是...
  • Python函数

    万次阅读 多人点赞 2020-10-10 20:25:56
    初识Python中的函数1.1 函数的结构1.2 函数返回1.3 函数的参数1.4 参数传递的处理1.5 变量作用域(L->E->G->B)2. 各种函数2.1 匿名函数lambda2.2 偏函数2.3 高阶函数3. 闭包4. 装饰器 1. 初识Python中的...
  • python函数多个返回值You can return many values from a function in Python. 您可以从Python中的函数返回许多值。 To achieve this, return a data structure with several values, such as a list of the total ...
  • 【编程语言】Python 函数多值返回

    千次阅读 2016-07-07 17:09:47
    在Python中返回多个值其实是可以的,但其实这只是一种假象,Python函数返回的仍然是单一值,返回的是一个tuple。但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值...
  • Python函数如何返回多个值,如何在调用函数时分别接收返回的多值,返回值为空或无返回值情况如何解决
  • Qt调用Python函数

    千次阅读 2017-11-13 12:02:03
    最近实验室的项目需要做一个GUI进行展示,考虑到算法已经在python下写好,决定使用Qt调用Python函数的方式实现。前期在numpy数组解析成PyArrayObject...最后选择绕开numpy数组,在python函数返回前将ndarray通过toList
  • Python函数返回多值

    千次阅读 2018-01-24 14:29:49
    Python函数返回多值 函数可以返回多个值吗?答案是肯定的。 比如在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度,就可以计算出新的坐标: math包提供了sin()和 cos()函数,我们先用import引用...
  • Python——返回函数

    千次阅读 2018-08-16 12:03:33
    一....高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。 >>> def lazy_sum(*args): ... def sum(): ... z = 0 ... for i in args: ... z += i ... ret...
  • Python 函数

    千次阅读 2017-05-31 18:47:59
    Python 中,函数是一组执行特定任务的相关语句。 函数有助于将程序分解成更小的块和模块化。随着我们的程序越来越大,函数使其更加有条理和可管理。 此外,还可以避免重复并使代码可重用。
  • python返回函数

    千次阅读 2016-11-13 00:31:30
    python返回函数 Python函数不但可以返回int、str、list、dict等数据类型,还可以返回函数! 例如,定义一个函数 f(),我们让它返回一个函数 g,可以这样写: def f(): print 'call f()...' # 定义...
  • 1.7 Python函数详解

    万次阅读 2019-05-24 10:30:35
    1.7 Python函数详解1.7 Python函数详解1.7.1 认识Python函数:1.7.2 函数的定义格式:1.7.3 函数文档:1.7.4 局部变量与全局变量:1.7.5 函数其他使用: 1.7 Python函数详解 1.7.1 认识Python函数: 函数的本质就是...
  • Python 函数注释

    万次阅读 多人点赞 2017-07-03 19:30:18
    Python 3.x 中,增加了一个新特性 - 函数注释(Function Annotations),顾名思义,可做为函数额外的注释来用。 函数注释是一个可选功能,它允许在函数参数和返回值中添加任意的元数据。无论是 Python 本身还是...
  • python-返回函数的理解

    万次阅读 2017-04-27 22:25:46
    最近接触python,看到了python返回函数的概念,以前只接触过函数返回值,比如python就可以返回int,str,list,dict等等类型数据,这里要说的是python还支持返回函数。首先看看python支持返回函数的基本语法def f(): ...
  • python函数

    万次阅读 2020-02-27 14:59:33
    关于函数 def 直接定义函数 def function(): pass 传参 def function(x,y): pass ...返回值可以返回多个(解包) def function(x,y): return x+y,x-y a,b = function(y=2,x=1) # a的值是x+y...
  • 版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。...我们使用python开发时,自定义的函数 有时候需要返回多个值,可能是多个数值、字符串也有可能是多个列表,那么如何返回返回之后 在调...
  • #循环第一次 append(f(1)) 返回函数如下 def g(): return 1*1 return g #循环第二次 append(f(2)) 返回函数如下 def g(): return 2*2 return g #循环第三次 append(f(3)) 返回函数如下 def g(): return 3*3 ...
  • 一文了解Python函数

    千次阅读 多人点赞 2020-04-02 19:13:31
    本文主要介绍 Python 函数,包括...Python入门之Python函数全文框架前言函数的定义和调用函数的参数位置参数默认参数关键字参数特殊参数小结函数的返回值返回 None返回一个值返回多个值多个 return 语句函数的文档...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 599,087
精华内容 239,634
关键字:

python函数返回

python 订阅