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