Может ли pythonic возвращать несколько значений из функции таким образом?
def f():
f.x = 1
f.y = 2
return f
r = f()
print r.x,r.y
1 2
Может ли pythonic возвращать несколько значений из функции таким образом?
def f():
f.x = 1
f.y = 2
return f
r = f()
print r.x,r.y
1 2
Вы не возвращаете цепные значения, вы создаете функцию, которая возвращает себя после установки переменных сама по себе.
Проблема заключается в том, что если вы повторно запустите функцию (предполагая, что это не просто постоянная функция, как показано в вашем примере), то это то, что каждый вид функции (и понимаем, что r
совпадает с f
в вашем коде) изменит эти значения. У вас будет эта проблема, будет ли ваша программа использовать несколько потоков.
Обычный способ возврата нескольких значений - это просто возврат кортежа, который может быть источником назначения деструктуризации (последовательности). Кроме того, если вы хотите управлять совокупностью переменных вместе, вы должны использовать объект. Для чего они предназначены.
Нет. Вы изменяете глобальный объект, который не является потокобезопасным.
Чаще всего
return 1, 2
или, если вы хотите иметь имена,
return {'x': 1, 'y': 2}
Это не 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
Что касается цепочки методов , общий способ - вернуть 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
Все советы, приведенные до сих пор, хороши, но не показывают много кода, вот они, один за другим.
Наиболее распространенным ответом было "вернуть кортеж", который будет выглядеть следующим образом:
def f():
return 1, 2
x, y = f()
Относительным ответом был "return a 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()
Это неправильно:
>>> 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 также изменится! Поэтому не очень хорошая практика сделать это таким образом.
Вы можете вернуть кортеж:
def f():
return 1,2
x,y = f()
print x,y
...
(1,2)
Смотрите другие комментарии к вашему вопросу, если это pythonic...
В качестве простого решения вы можете использовать класс вместо этого.
class cls:
def __init__(self):
self.x, self.y = 1, 2
r = cls()
print(r.x, r.y) # 1 2
Другим вариантом, если вам нужно сохранить некоторую информацию о состоянии, является использование класса и перегрузка метода __ __.
class f:
def __call__(self):
self.x = 1
self.y = 2
return self.x, self.y
r = f()
print(r())
Это напечатает:
(1, 2)