Jestem początkującym Pythonem i właśnie nauczyłem się techniki obejmującej słowniki i funkcje. Składnia jest łatwa i wydaje się trywialna, ale moje zmysły pytona mrowią. Coś mi mówi, że jest to głęboka i bardzo pytoniczna koncepcja i nie do końca rozumiem jej znaczenie. Czy ktoś może nazwać tę technikę i wyjaśnić, w jaki sposób / dlaczego jest ona przydatna?
Technika polega na tym, że masz słownik Pythona i funkcję, której zamierzasz używać. Wstawiasz dodatkowy element do słownika, którego wartością jest nazwa funkcji. Kiedy jesteś gotowy, aby wywołać funkcję, wywołujesz połączenie pośrednio , odwołując się do elementu dict, a nie funkcji według nazwy.
Przykład, z którego pracuję, pochodzi z Learn Python the Hard Way, 2nd Ed. (Jest to wersja dostępna po rejestracji przez Udemy.com ; niestety bezpłatna wersja HTML na żywo to obecnie Ed 3 i nie zawiera już tego przykładu).
Parafrazować:
# make a dictionary of US states and major cities
cities = {'San Diego':'CA', 'New York':'NY', 'Detroit':'MI'}
# define a function to use on such a dictionary
def find_city (map, city):
# does something, returns some value
if city in map:
return map[city]
else:
return "Not found"
# then add a final dict element that refers to the function
cities['_found'] = find_city
Następnie następujące wyrażenia są równoważne. Możesz wywołać funkcję bezpośrednio lub przez odwołanie się do elementu dict, którego wartością jest funkcja.
>>> find_city (cities, 'New York')
NY
>>> cities['_found'](cities, 'New York')
NY
Czy ktoś może wyjaśnić, co to jest funkcja językowa i może gdzie jest grać w „prawdziwym” programowaniu? To ćwiczenie z zabawkami wystarczyło, by nauczyć mnie składni, ale nie zabrało mnie tam.
źródło
Odpowiedzi:
Za pomocą słownika możesz przetłumaczyć klucz na wywoływalny. Klucz nie musi być jednak zakodowany na stałe, jak w twoim przykładzie.
Zwykle jest to forma wysyłania dzwoniącego, w której wartość zmiennej jest używana do łączenia się z funkcją. Powiedzmy, że proces sieciowy wysyła Ci kody poleceń, mapowanie wysyłki pozwala łatwo przetłumaczyć kody poleceń na kod wykonywalny:
Zauważ, że funkcja, którą teraz nazywamy, zależy całkowicie od wartości
command
. Klucz nie musi się również zgadzać; nie musi to być nawet ciąg znaków, możesz użyć wszystkiego, co może być użyte jako klucz i pasuje do twojej konkretnej aplikacji.Korzystanie z metody wysyłki jest bezpieczniejsze niż inne techniki, takie jak
eval()
, ponieważ ogranicza ona polecenia dozwolone do tego, co zdefiniowałeś wcześniej. Na przykład żaden atakujący nie będzie mógł wymknąć sięls)"; DROP TABLE Students; --
zastrzyku poza tabelę wysyłki.źródło
dict
działa jako dyspozytora (menedżer poleceń Invoker, etc.).@Martijn Pieters wykonał kawał dobrej roboty wyjaśniając technikę, ale chciałem wyjaśnić coś z twojego pytania.
Ważne jest, aby wiedzieć, że NIE przechowujesz w nazwie „nazwy funkcji”. Przechowujesz odwołanie do samej funkcji. Możesz to zobaczyć za pomocą
print
funkcji a.f
jest tylko zmienną, która odwołuje się do zdefiniowanej funkcji. Korzystanie ze słownika pozwala grupować podobne rzeczy, ale nie różni się niczym od przypisania funkcji do innej zmiennej.Podobnie możesz przekazać funkcję jako argument.
źródło
Zauważ, że klasa Python jest tak naprawdę tylko cukrem składniowym dla słownika. Kiedy to zrobisz:
kiedy zadzwonisz
jest naprawdę taki sam jak:
który po rozpoznaniu nazwy jest taki sam jak:
Jedną przydatną techniką jest mapowanie danych wejściowych użytkownika na wywołania zwrotne. Na przykład:
Można to alternatywnie zapisać w klasie:
dowolna lepsza składnia wywołania zwrotnego zależy od konkretnej aplikacji i gustu programisty. Pierwszy z nich jest bardziej funkcjonalny, drugi bardziej zorientowany obiektowo. Ten pierwszy może wydawać się bardziej naturalny, jeśli trzeba dynamicznie modyfikować wpisy w słowniku funkcji (być może na podstawie danych wprowadzonych przez użytkownika); to drugie może wydawać się bardziej naturalne, jeśli masz zestaw różnych mapowań ustawień wstępnych, które można wybierać dynamicznie.
źródło
5 * x
do5x
(wybacz prostą analogię).Są w mojej głowie 2 techniki, do których możesz się odwoływać, z których żadna nie jest Pythoniczna, ponieważ są szersze niż jeden język.
1. Technika ukrywania / enkapsulacji informacji i spójności (zwykle idą w parze, więc łączę je razem).
Masz obiekt, który ma dane, i dołączasz metodę (zachowanie), która jest bardzo spójna z danymi. Jeśli musisz zmienić funkcję, rozszerzyć funkcjonalność lub dokonać innych zmian, dzwoniący nie będą musieli zmieniać (zakładając, że nie trzeba przekazywać żadnych dodatkowych danych).
2. Tabele wysyłki
Nie jest to klasyczny przypadek, ponieważ jest tylko jedna pozycja z funkcją. Jednak tabele wysyłki służą do organizowania różnych zachowań według klucza, dzięki czemu można je wyszukiwać i wywoływać dynamicznie. Nie jestem pewien, czy myślisz o tym, ponieważ nie odwołujesz się do funkcji w sposób dynamiczny, ale mimo to nadal uzyskujesz skuteczne późne wiązanie (wywołanie „pośrednie”).
Kompromisy
Jedną z rzeczy, na które należy zwrócić uwagę, jest to, co robisz, będzie działać dobrze ze znaną przestrzenią nazw kluczy. Istnieje jednak ryzyko kolizji między danymi a funkcjami z nieznaną przestrzenią nazw kluczy.
źródło
Publikuję to rozwiązanie, które moim zdaniem jest dość ogólne i może być przydatne, ponieważ jest proste i łatwe do dostosowania do konkretnych przypadków:
można także zdefiniować listę, w której każdy element jest obiektem funkcji, i użyć
__call__
wbudowanej metody. Podziękowania dla wszystkich za inspirację i współpracę.„Wielki artysta jest prostotą”, Henri Frederic Amiel
źródło