2017-09-08 26 views
9

Mam słownik, który ma wartości czasami jako łańcuchy, a czasem jako funkcje. Dla wartości, które są funkcjami, czy istnieje sposób na wykonanie tej funkcji bez jawnego wpisania () po uzyskaniu dostępu do klucza?Wartość słownika jako funkcja, która będzie wywoływana, gdy klucz jest dostępny, bez użycia "()"

Przykład:

d = {1: "A", 2: "B", 3: fn_1} 
d[3]() # To run function 

chcę:

d = {1: "A", 2: "B", 3: magic(fn_1)} 
d[3] # To run function 
+5

Dlaczego bez '()'? Nie dziergaj swetra wokół guzika ... – Alexander

+2

Nie rób tego. 'Jawny jest lepszy niż niejawny. Znaczenie w twoim kodzie polega na sprawdzeniu funkcji i wywołaniu jej; więc kod * powinien wyglądać jak * właśnie to robisz. Poza tym mieszanie takich typów jest złym pomysłem; musisz sprawdzić, czy najpierw masz ciąg (ponieważ nie możesz wywołać ciągu), a to sprawia, że ​​twoje życie jest trudniejsze. –

+1

... Ale po odbiciu brzmi to tak, jakbyś miał pytanie * projektu *, i powinno zadawać pytanie, które będzie bardziej odzwierciedlało to, co naprawdę chcesz zrobić. Np. Dlaczego masz ten słownik w pierwszej kolejności? –

Odpowiedz

6

Nie sądzę, że to (łatwo) możliwe z biblioteki standardowej, ale można użyć lazy_object_proxy.Proxy z modułu lazy_object_proxy (jest to strona trzecia więc musisz go zainstalować):

>>> import lazy_object_proxy 
>>> def fn_1(): 
...  print('calculation') 
...  return 1000 
... 
>>> d = {1: "A", 2: "B", 3: lazy_object_proxy.Proxy(fn_1)} 
>>> print(d[3]) 
calculation 
1000 
+0

Ah, bardzo interesujące rozwiązanie. Ta biblioteka wygląda na bardzo użyteczną dla czasochłonnych obliczeń. +1 –

0

Użyj callable() aby sprawdzić, czy zmienna jest, dobrze, wymagalne:

d = {1: "A", 2: "B", 3: fn_1} 
if callable(d[3]): 
    d[3]() 
else: 
    d[3] 
+2

Zapytanie zostało powiedziane bez użycia '()', gdy funkcja nazywa się –

11

Innym możliwym rozwiązaniem jest stworzenie obiektu niestandardowego słownika, który implementuje to zachowanie:

>>> class CallableDict(dict): 
...  def __getitem__(self, key): 
...   val = super().__getitem__(key) 
...   if callable(val): 
...    return val() 
...   return val 
... 
>>> 
>>> d = CallableDict({1: "A", 2: "B", 3: lambda: print('run')}) 
>>> d[1] 
'A' 
>>> d[3] 
run 

perhaps more idiomatic solution byłoby użyć try/except:

def __getitem__(self, key): 
    val = super().__getitem__(key) 
    try: 
     return val() 
    except TypeError: 
     return val 

Należy jednak zauważyć, że powyższa metoda jest naprawdę kompletna. Nie polecałbym go używać. As pointed out in the comments, to maskowałoby TypeError podniesione przez funkcję. Możesz przetestować dokładną treść TypeError, ale w tym momencie lepiej będzie użyć stylu LBYL.

+0

EAFP - 'try: return val(); z wyjątkiem TypeError: return val'? – AChampion

+0

@AChampion Eh, zamiast tego mógłbym użyć EAFP. W niektórych przypadkach naprawdę nie wydaje mi się, żeby miało to duże znaczenie :) Naprawdę nie myślałem o tym, kiedy opublikowałem swoją odpowiedź. –

+0

EAFP ukrywa TypeErrors, które występują w wywołanej funkcji w tym przypadku. Nie użyłbym tego. –

-2

Innym rozwiązaniem: można również przekazać niektóre metody klasy urządzone przy użyciu @property:

class Test: 
    @property 
    def method(self): 
     return 'X' 

d = {'a': 1, 'b': Test().method} 
print(d) 
print(d['a']) 
print(d['b']) 
+1

To nie jest funkcja, która jest wywoływana, gdy klucz jest dostępny. Po prostu ustawia wartość słownika, gdy jest zdefiniowana: '{'a': 1, 'b': 'X'}' –

+0

Argh ... masz rację. Wstyd mi: / – msztolcman

Powiązane problemy