Подтвердить что ты не робот

Является ли это pythonic для функции, чтобы возвращать цепочки значений/задавать переменные на себе?

Может ли pythonic возвращать несколько значений из функции таким образом?

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

r = f()
print r.x,r.y
1 2
4b9b3361

Ответ 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)