2012-06-22 10 views
13

Studiuję Python i obecnie przechodzę trochę więcej nauki ze słownikami.Podzielić słownik na zmienne

Zastanawiam się;

Jeśli mam słownik taki jak: d = {'key_1': 'value_a', 'key_2': 'value_b'} i chcę go oddzielić/podzielić ten słownik na zmienne, w których każda zmienna jest kluczem ze słownika, a każda wartość zmiennej jest wartością tego klucza w słowniku.

Jaki byłby najlepszy sposób, aby to osiągnąć?

d = {'key_1': 'value_a', 'key_2': 'value_b'} 
#perform the command and get 
key_1 = 'value_a' 
key_2 = 'value_b' 

Próbowałem: key_1, key_2 = d ale to nie zadziałało.

Zasadniczo szukam wiedzy eksperta, aby dowiedzieć się, czy istnieje lepszy sposób na zredukowanie 2 linii kodu do jednego.

Uwaga: To nie jest dynamiczne tworzenie zmiennych.

+1

Słowniki nie mają porządku, co sprawia, że ​​trudno jest stworzyć ogólne rozwiązanie, ponieważ nie ma takiej potrzeby. Gdyby został wdrożony, byłby hacky. – jamylak

+4

Nie ma mowy w pythonic, ponieważ sama idea jest non-pytoniczna. W Pythonie nie chcesz tworzyć zmiennych dynamicznie. – georg

+2

Nie powinieneś tego robić. Odpowiedź brzmi: "key_1, key_2 = d.values ​​()'. ale 1) jest to podatne na wyjątki; 2) nie będziesz wiedział, która jest która, dopóki nie posortujesz 'd.values ​​()' przed przypisaniem. Jest bardzo mało prawdopodobne, że potrzebujesz tego wszystkiego. –

Odpowiedz

8

Problem polega na tym, że dyktanda są nieuporządkowane, więc nie można użyć prostego rozpakowywania z d.values(). Można oczywiście najpierw posortować dict przez klucz, następnie rozpakować wartości:

ds = sorted(d.iteritems()) 
name0, name1, name2..., namen = [v[1] for v in ds] 

Można też, przynajmniej w obrębie obiektu, zrób coś takiego:

for k, v in dict.iteritems(): 
    setattr(self, k, v) 

Dodatkowo, jak już wspomniano w komentarz powyżej, jeśli można dostać całą swoją logikę, która potrzebuje twojej rozpakowane słownika jako zmienne do funkcji, można zrobić:

def func(**kwargs): 
    # Do stuff with labeled args 

func(**d) 
+0

Dziękuję bardzo za przeczytanie mojego quesitonu i udzielenie odpowiedzi. Chyba lepiej pójdę z normalną drogą rozdzielania dyktatu na zmienne moje ja. Po prostu pomyślałem, że może istnieć rozwiązanie jednoliniowe bez iteracji lub sortowania, ale chyba nie. więc zrobię key = dict ['key'] dla każdego klawisza. Ale dziękuję Wam bardzo za to. – Phil

+0

Jeśli twój usecase pozwala, aby twój słownik źródłowy był "OrderedDict" i możesz przewidzieć kolejność wstawiania, możesz pominąć sortowanie i po prostu rozpakować 'od.values ​​()' bezpośrednio. –

+0

W tym przypadku wydaje się, że to przesada, ale dziękuję. Myślisz mi coś. wartości rzecz wygląda bardzo przydatna. – Phil

0

nie zaleca się zawsze deklarować zmienne Dynami cally, ponieważ znalezienie źródła nazwy zmiennej staje się bardzo trudne. To powiedziawszy, możliwe jest zhakowanie razem rozwiązania Dynamic variable name in python, ale nie polecam go. Prawdopodobnie lepiej skorzystać z prostego starego słownika.

+0

Witam, nie próbuję dynamicznie tworzyć zmiennych. Chcę zmniejszyć liczbę n linii (n to kluczowa liczba w dyktacie) do pojedynczej linii. Myślałem, że będzie to możliwe z Pythonem, ale teraz nie sądzę. – Phil

1

I rzeczywiście mają USECASE, gdzie I wyciągnij wszystkie argumenty metody __init__ do nazw siebie na budowie obiektu:

vars(self).update(somedict) 

Funkcja vars dostaje dict z „nazw” związanego z obiekt minął. Jednak nie będzie to działać z lokalnymi w funkcji, ze względu na szczegóły implementacji CPython. Więc nie powinno działać na wszystkich tłumaczach.

Dla globalnej przestrzeni nazw można zastąpić vars(self) z globals(), ale jest to naprawdę znak, że coś jest nie tak z twoją logiką. Jak już wspomniano, dla zmiennych lokalnych to i tak nie zadziała (będzie to NameError, nawet jeśli przypisałeś wartość do dyktanda).

+0

Dziękuję bardzo! – Phil

1

Można to zrobić, jeśli jesteś odważny:

for k, v in d.items(): 
    locals()[k] = v 

Ale bycie dzielnym może nie wystarczyć - może również być lekkomyślny etc.

Jeśli chcesz być bohaterem jak @ecatmur lekkomyślny, można to zrobić:

locals().update(d) 

Ale teraz, że OP uaktualnił swoje pytanie i odpowiedział na komentarze, jak się wydaje, nie jest to, co naprawdę chce to zrobić. Tylko dla zapisu: istnieją dobre powody do dynamicznego tworzenia zmiennych - nawet jeśli wszyscy tutaj zgadzają się, że nie jest to pyton. Wiele problemów związanych z interpretacją można rozwiązać zupełnie dynamicznie zmieniając swój zakres. Po prostu rób to w kontrolowany sposób. I ... hm, nie wdrożyć to w pewnym zakładzie produkcyjnym;)

+0

Lub nawet 'locals(). Update (d)'. – ecatmur

+0

@egatmur, jesteś bohaterem! –

+1

btw, nigdy tego nie rób - za http://docs.python.org/library/functions.html#locals * Zawartość tego słownika nie powinna być modyfikowana; zmiany mogą nie mieć wpływu na wartości lokalnych i wolnych zmiennych używanych przez tłumacza. * – ecatmur

12

rozwiązanie, które nie zostały wymienione wcześniej byłoby

dictget = lambda d, *k: [d[i] for i in k] 

a następnie użyć go:

key_1, key_2 = dictget(d, 'key_1', 'key_2') 

którego zaletą jest to, że jest całkiem czytelny nawet przy większej ilości zmiennych do pobrania.

Jeszcze bardziej czytelny, jednak byłoby to funkcja „prawdziwy”, takie jak

def dictget(d, *k): 
    """Get the values corresponding to the given keys in the provided dict.""" 
    return [d[i] for i in k] 
    # or maybe 
    return (d[i] for i in k) # if we suppose that we have bigger sets of result 
    # or, equivalent to this 
    for i in k: 
     yield d[i] 

który również obsługuje komentując z docstring i ma być korzystny.

+0

Doskonały i elegancki! – Phil

+0

@Phil Nie tak bardzo. Dlatego właśnie dodałem rozwiązanie "def". – glglgl

1

myślę, że to powinno rozwiązać problem

d = {'key_1': 'value_a', 'key_2': 'value_b'} 
for k,v in d.items(): 
    exec '%s=%s'%(k,v) 
+0

Działa to dla wartości, które niekoniecznie są łańcuchami: 'for k in my_dict.keys(): exec" {0} = my_dict [\ '{0} \'] ".format (k)' –

1
var1, var2 = (lambda key1, key2: (key1, key2))(**d) 

Jeśli chcesz dać ktoś czyta kod ból głowy można użyć funkcji anonimowej rozpakować wartości jak ten.

Powiązane problemy