Is it pythonic to return multiple values from a function in this way?
def f():
f.x = 1
f.y = 2
return f
r = f()
print r.x,r.y
1 2
You're not "returning chained values", you're creating a function which returns itself, after setting variables on itself.
The problem with this is that if you reinvoke the function (assuming it isn't just a constant function as shown in your example) is that every single appearance of the function (and understand that r
is the same as f
in your code) will have those values change. You'll have this problem whether or not your programme uses multiple threads.
The normal way to return multiple values is simply to return a tuple, which can be the source of a destructuring (sequence) assignment. Alternatively, if you want to manage a bunch of variables together, you would use an object. That's what they're for.
No. You are changing a global object that is not thread safe.
More common is
return 1, 2
or, if you want to have names,
return {'x': 1, 'y': 2}
It's not pythonic, it is not even reasonable for any language that potentially supports such a construct.
What you do is that you use the function's global state as a carrier of your output values. To return a value from a function you should use, well, a return value, not the called function. In your example you cannot be really sure what is your return value:
>> 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?
You can use namedtuple or a custom type (although using type()
might be perceived as too low level):
>>> def dict_as_tuple(**kwargs):
... return type('CustomType', (object,), kwargs)()
...
>>> z = dict_as_tuple(x=1, y=2)
>>> z.x
1
>>> z.y
2
Regarding the method chaining, a common way is to return self
(if you want to change state of the object) or new object of the same type (objects are immutable, which is good)
>>> 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
All of the advice given so far is good, but doesn't show much code, here they are, one by one.
The most common answer was 'return a tuple', which would look like this
def f():
return 1, 2
x, y = f()
A related answer was '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
another idea was to use 'objects'.
class Foo(object):
def __init__(self, x, y)
self.x, self.y = x, y
r = Foo(1, 2)
print r.x, r.y
You mention 'chaining' in your question; as though you want repeated calls to f()
to give different results. That's doable, too, with generators.
def f_gen():
for x in range(1, 10)
yield x, x + 1
f = f_gen()
print f()
print f()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With