以这种方式从函数返回多个值是pythonic吗?
def f():
f.x = 1
f.y = 2
return f
r = f()
print r.x,r.y
1 2
答案 0 :(得分:39)
你不是“返回链式值”,你创建了一个在自身设置变量后返回自身的函数。
这个问题是,如果你重新调用函数(假设它不仅仅是你的例子中显示的常量函数)是函数的每一个外观(并且理解r
是相同的作为代码中的f
)将更改这些值。无论你的程序是否使用多个线程,你都会遇到这个问题。
返回多个值的常规方法是返回一个元组,它可以作为解构(序列)赋值的来源。或者,如果要一起管理一堆变量,则可以使用对象。这就是他们的目的。
答案 1 :(得分:33)
没有。您正在更改非线程安全的全局对象。
更常见的是
return 1, 2
或者,如果你想拥有名字,
return {'x': 1, 'y': 2}
答案 2 :(得分: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?
您可以使用namedtuple或自定义type(尽管使用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
关于method chaining,常见的方法是返回self
(如果要更改对象的状态)或相同类型的新对象(对象为immutable,是好)
>>> 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
答案 3 :(得分:18)
到目前为止给出的所有建议都很好,但是没有显示太多的代码,在这里它们是一个接一个。
最常见的答案是“返回一个元组”,看起来像这样
def f():
return 1, 2
x, y = f()
相关答案是“返回namedtuple
”:
from collections import namedtuple
Point = namedtuple('Point', 'x y')
def f():
return Point(1, 2)
r = f()
print r.x, r.y
另一个想法是使用'对象'。
class Foo(object):
def __init__(self, x, y)
self.x, self.y = x, y
r = Foo(1, 2)
print r.x, r.y
你在提问中提到'链接';好像你想反复调用f()
给出不同的结果。这对发电机来说也是可行的。
def f_gen():
for x in range(1, 10)
yield x, x + 1
f = f_gen()
print f()
print f()
答案 4 :(得分: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
预计r也不会改变!所以这样做不是好习惯。
答案 5 :(得分:4)
你可以返回一个元组:
def f():
return 1,2
x,y = f()
print x,y
...
(1,2)
答案 6 :(得分:3)
如果是pythonic,请查看您问题的其他评论......
作为一个简单的解决方案,您可以使用类来代替..
class cls:
def __init__(self):
self.x, self.y = 1, 2
r = cls()
print(r.x, r.y) # 1 2
答案 7 :(得分:1)
如果您需要保留一些状态信息,另一个选择是使用一个类并重载 __ 调用 __ 方法。
class f:
def __call__(self):
self.x = 1
self.y = 2
return self.x, self.y
r = f()
print(r())
那将打印:
(1, 2)