2015-11-30 2 views
1

Как назначить результаты вызова функции нескольким переменным, когда результаты хранятся по имени (не индексируемому) в python.Назначить результаты вызова функции в одной строке в python

Например (протестировано в Python 3),

import random 

# foo, as defined somewhere else where we can't or don't want to change it 
def foo(): 
    t = random.randint(1,100) 
    # put in a dummy class instead of just "return t,t+1" 
    # because otherwise we could subscript or just A,B = foo() 
    class Cat(object): 
     x = t 
     y = t + 1 

    return Cat() 

# METHOD 1 
# clearly wrong; A should be 1 more than B; they point to fields of different objects 
A,B = foo().x, foo().y 
print(A,B) 

# METHOD 2 
# correct, but requires two lines and an implicit variable 
t = foo() 
A,B = t.x, t.y 
del t # don't really want t lying around 
print(A,B) 

# METHOD 3 
# correct and one line, but an obfuscated mess 
A,B = [ (t.x,t.y) for t in (foo(),) ][0] 
print(A,B) 
print(t) # this will raise an exception, but unless you know your python cold it might not be obvious before running 

# METHOD 4 
# Conforms to the suggestions in the links below without modifying the initial function foo or class Cat. 
# But while all subsequent calls are pretty, but we have to use an otherwise meaningless shell function 
def get_foo(): 
    t = foo() 
    return t.x, t.y 

A,B = get_foo() 

То, что мы не хотим, чтобы сделать

Если результаты были индексируемой (Cat расширенный кортеж/список, мы имели использовали namedtuple и т. д.), мы могли бы просто написать A,B = foo(), как указано в комментарии выше класса Cat. That's what's recommended here, например.

Предположим, у нас есть веская причина не допускать этого. Возможно, нам нравится ясность присвоения имен переменных (если они более значимы, чем x и y), или, возможно, объект не является главным образом контейнером. Возможно, поля являются свойствами, поэтому доступ фактически включает вызов метода. Мы не должны принимать ни одного из них, чтобы ответить на этот вопрос; класс Cat можно взять по номинальной стоимости.

This question уже имеет дело с тем, как проектировать функции/классы наилучшим образом; , если ожидаемое возвращаемое значение функции уже хорошо определено и не связано с типероподобным доступом, каков наилучший способ принять несколько значений при возврате?

ответ

3

Я бы настоятельно рекомендовал использовать несколько операторов или просто сохранить объект результата без распаковки его атрибутов. Тем не менее, вы можете использовать operator.attrgetter для этого:

from operator import attrgetter 
a, b, c = attrgetter('a', 'b', 'c')(foo())