Я новичок в питоне, и я только что изучил технику, включающую словари и функции. Синтаксис прост, и это кажется тривиальной вещью, но мои чувства питона покалывания. Что-то подсказывает мне, что это глубокая и очень питоническая концепция, и я не совсем понимаю ее важность. Может кто-нибудь дать название этой технике и объяснить, как / почему она полезна?
Техника заключается в том, когда у вас есть словарь Python и функция, которую вы собираетесь использовать в нем. Вы вставляете дополнительный элемент в dict, значением которого является имя функции. Когда вы готовы вызвать функцию, вы выполняете вызов косвенно , ссылаясь на элемент dict, а не на функцию по имени.
Пример, из которого я работаю, - «Изучите Python: трудный путь», 2-е изд. (Эта версия доступна, когда вы регистрируетесь через Udemy.com ; к сожалению, в настоящее время бесплатной бесплатной HTML-версией является версия Ed 3, которая больше не включает этот пример).
Перефразировать:
# 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
Тогда следующие выражения эквивалентны. Вы можете вызвать функцию напрямую или путем ссылки на элемент dict, значением которого является функция.
>>> find_city (cities, 'New York')
NY
>>> cities['_found'](cities, 'New York')
NY
Может кто-нибудь объяснить, что это за языковая функция, и, возможно, где она играет в "реальном" программировании? Этого игрушечного упражнения было достаточно, чтобы научить меня синтаксису, но оно меня не охватило.
источник
Ответы:
Используя dict, давайте переведем ключ в вызываемый. Ключ не должен быть жестко закодирован, как в вашем примере.
Обычно это форма отправки вызовов, где вы используете значение переменной для подключения к функции. Скажем, сетевой процесс отправляет вам коды команд, а диспетчеризация позволяет легко преобразовать коды команд в исполняемый код:
Обратите внимание, что функция, которую мы вызываем сейчас, полностью зависит от значения
command
. Ключ не должен совпадать; она даже не должна быть строкой, вы можете использовать все, что может быть использовано в качестве ключа, и подходит для вашего конкретного приложения.Использование метода диспетчеризации более безопасно, чем другие методы, например
eval()
, поскольку он ограничивает допустимые команды тем, что вы определили заранее.ls)"; DROP TABLE Students; --
Например, ни один злоумышленник не сможет пробраться через инъекцию мимо таблицы диспетчеризации.источник
dict
действует как диспетчер (менеджер команды, инициатор вызова, и т.д.).@Martijn Pieters хорошо объяснил методику, но я хотел кое-что прояснить из вашего вопроса.
Важно знать, что вы НЕ сохраняете «имя функции» в словаре. Вы храните ссылку на саму функцию. Вы можете увидеть это с помощью
print
функции.f
это просто переменная, которая ссылается на функцию, которую вы определили. Использование словаря позволяет группировать подобные вещи, но это ничем не отличается от назначения функции другой переменной.Точно так же вы можете передать функцию в качестве аргумента.
источник
Обратите внимание, что класс Python - это просто синтаксический сахар для словаря. Когда вы делаете:
когда ты звонишь
действительно так же, как:
который после разрешения имени точно такой же как:
Одним из полезных методов является сопоставление пользовательского ввода с обратными вызовами. Например:
Это может быть альтернативно написано в классе:
Какой синтаксис обратного вызова лучше, зависит от конкретного приложения и вкуса программиста. Первый - более функциональный стиль, последний - более объектно-ориентированный. Первый может показаться более естественным, если вам нужно динамически изменять записи в словаре функций (возможно, на основе пользовательского ввода); последний может показаться более естественным, если у вас есть набор различных предустановок, которые можно выбирать динамически.
источник
5 * x
к5x
(простите за простую аналогию).В моей голове есть две техники, о которых вы, возможно, имеете в виду, но ни одна из них не является Pythonic, поскольку они более широки, чем один язык.
1. Техника сокрытия / инкапсуляции и сплоченности информации (обычно они идут рука об руку, поэтому я их объединяю).
У вас есть объект, у которого есть данные, и вы присоединяете метод (поведение), который тесно связан с данными. Если вам нужно изменить функцию, расширить функциональность или внести другие изменения, вызывающим абонентам менять не нужно (при условии, что дополнительные данные не нужно передавать).
2. Диспетчерские таблицы
Не классический случай, потому что есть только одна запись с функцией. Однако таблицы диспетчеризации используются для организации различных поведений по ключу, так что их можно искать и вызывать динамически. Я не уверен, что вы думаете об этом, поскольку вы не ссылаетесь на функцию динамически, но тем не менее вы все равно получаете эффективное позднее связывание («косвенный» вызов).
компромиссы
Стоит отметить, что ваши действия будут хорошо работать с известным пространством имен ключей. Однако вы рискуете столкнуться между данными и функциями с неизвестным пространством имен ключей.
источник
Я публикую это решение, которое я считаю достаточно общим и может быть полезным, поскольку оно простое и легко адаптируется к конкретным случаям:
Можно также определить список, в котором каждый элемент является функциональным объектом, и использовать
__call__
встроенный метод. Кредиты всем за вдохновение и сотрудничество.«Великий художник - упрощитель», Анри Фредерик Амиэль
источник