函数是pythonic返回链接值/设置变量吗?

use*_*730 22 python

以这种方式从函数返回多个值是pythonic吗?

def f():
    f.x = 1
    f.y = 2
    return f

r = f()
print r.x,r.y
1 2
Run Code Online (Sandbox Code Playgroud)

Mar*_*cin 39

你不是"返回链式值",你创建了一个在自身上设置变量后返回自身的函数.

这个问题是,如果你重新调用函数(假设它不仅仅是你的例子中显示的常量函数)是函数的每一个外观(并且理解rf代码中的相同)将具有那些价值观改变.无论您的程序是否使用多个线程,您都会遇到此问题.

返回多个值的常规方法是返回一个元组,它可以是解构(序列)赋值的源.或者,如果要一起管理一堆变量,则可以使用对象.这就是他们的目的.


JBe*_*rdo 33

不.您正在更改非线程安全的全局对象.

更常见的是

return 1, 2
Run Code Online (Sandbox Code Playgroud)

或者,如果你想拥有名字,

return {'x': 1, 'y': 2}
Run Code Online (Sandbox Code Playgroud)

  • 或者一个命名的元组. (18认同)
  • 线程安全甚至不是主要问题.它会在单个线程中产生意外结果. (16认同)

Jak*_* M. 20

它不是pythonic,对任何可能支持这种结构的语言来说都是不合理的.

您所做的是使用函数的全局状态作为输出值的载体.要从函数返回值,您应该使用返回值,而不是被调用函数.在您的示例中,您无法确定您的返回值是多少:

>> def f(x):
...   f.x=x
...   return f
...
>>> z=f(1)
>>> z.x
1
>>> f(2)    # <--- alters global state of the function
<function f at 0x10045c5f0>
>>> z.x
2           # <--- errr, five lines ago z.x was 1, no?
Run Code Online (Sandbox Code Playgroud)

您可以使用namedtuple或自定义类型(尽管使用type()可能被视为太低级别):

>>> def dict_as_tuple(**kwargs):
...     return type('CustomType', (object,), kwargs)()
...
>>> z = dict_as_tuple(x=1, y=2)
>>> z.x
1
>>> z.y
2
Run Code Online (Sandbox Code Playgroud)

关于方法链接,常见的方法是返回self(如果要更改对象的状态)或相同类型的新对象(对象是不可变的,这很好)

>>> class C(object):
...   def __init__(self, x):
...      self.x = x
...   def add(self, y):
...     return C(self.x + y)
...   def mul(self, y):
...     return C(self.x * y)
...
>>> C(0).add(1).mul(10).x
10
Run Code Online (Sandbox Code Playgroud)


Sin*_*ion 18

到目前为止给出的所有建议都很好,但是没有显示太多的代码,在这里它们是一个接一个的.

最常见的答案是"返回一个元组",看起来像这样

def f():
    return 1, 2

x, y = f()
Run Code Online (Sandbox Code Playgroud)

一个相关的答案是'返回namedtuple':

from collections import namedtuple

Point = namedtuple('Point', 'x y')

def f():
    return Point(1, 2)

r = f()
print r.x, r.y
Run Code Online (Sandbox Code Playgroud)

另一个想法是使用'对象'.

class Foo(object):
    def __init__(self, x, y)
        self.x, self.y = x, y

r = Foo(1, 2)
print r.x, r.y
Run Code Online (Sandbox Code Playgroud)

你在问题中提到'链接'; 好像你想要反复调用f()以给出不同的结果.这对发电机来说也是可行的.

def f_gen():
    for x in range(1, 10)
        yield x, x + 1

f = f_gen()
print f()
print f()
Run Code Online (Sandbox Code Playgroud)


use*_*730 7

这是错的:

>>> def f(a):
...   f.x = a
...   return f
...
>>> r = f(1)
>>> print r.x
1
>>> p = f(2)
>>> print p.x
2
>>> print r.x
2
Run Code Online (Sandbox Code Playgroud)

预计r也不会改变!所以这样做不是很好的做法.