Использование словаря для выбора функции для выполнения

Я пытаюсь использовать функциональное программирование для создания словаря, содержащего ключ и функцию для выполнения:

myDict={}
myItems=("P1","P2","P3",...."Pn")
def myMain(key):
    def ExecP1():
        pass
    def ExecP2():
        pass
    def ExecP3():
        pass
        ...
    def ExecPn():
        pass  

Теперь я видел код, используемый для поиска определенных функций в модуле, и мне нужно сделать что-то вроде этого:

    for myitem in myItems:
        myDict[myitem] = ??? #to dynamically find the corresponding function

Итак, мой вопрос: как мне составить список всех Exec функций, а затем назначить их желаемому элементу с помощью словаря? так что в конце у меня будет myDict["P1"]() #this will call ExecP1()

Моя настоящая проблема в том, что у меня есть тонны этих элементов, и я создаю библиотеку, которая будет их обрабатывать, поэтому конечному пользователю нужно только вызвать myMain("P1")

Я думаю об использовании модуля проверки, но не знаю, как это сделать.

Моя причина избегать:

def ExecPn():
    pass
myDict["Pn"]=ExecPn

заключается в том, что я должен защищать код, поскольку я использую его для создания сценариев в моем приложении.


person JohnnyDH    schedule 06.02.2012    source источник
comment
Почему бы не использовать класс? Если я понимаю, что вы пытаетесь сделать, это может быть немного более масштабируемым и более простым в реализации.   -  person Niall Byrne    schedule 07.02.2012
comment
@NiallByrne Потому что каждая функция Exec выполняет очень разный код.   -  person JohnnyDH    schedule 07.02.2012
comment
каждая функция Exec выполняет очень разный код? Так? Это верно для большинства методов в определении класса.   -  person S.Lott    schedule 07.02.2012
comment
Да, так что помещать их в класс не имеет смысла, поскольку они не связаны друг с другом.   -  person JohnnyDH    schedule 07.02.2012
comment
вместо ExecP1 вы можете назвать функцию самой P1.   -  person ETL_Devs    schedule 30.12.2020


Ответы (9)


Не горжусь этим, но:

def myMain(key):
    def ExecP1():
        pass
    def ExecP2():
        pass
    def ExecP3():
        pass
    def ExecPn():
        pass 
    locals()['Exec' + key]()

Однако я рекомендую вам поместить их в какой-либо модуль / класс, это действительно ужасно.


Если вы хотите добавить декоратор для каждой функции, вы можете определить декоратор, который добавляет каждую функцию в словарь:

def myMain(key):
    tasks = {}
    
    def task(task_fn):
        tasks[task_fn.__name__] = task_fn
    
    @task
    def ExecP1():
        print(1)
    @task
    def ExecP2():
        print(2)
    @task
    def ExecP3():
        print(3)
    @task
    def ExecPn():
        print(4)
    
    tasks['Exec' + key]()

Другой вариант - поместить все функции в класс (или в другой модуль) и использовать getattr:

def myMain(key):
    class Tasks:
        def ExecP1():
            print(1)
        def ExecP2():
            print(2)
        def ExecP3():
            print(3)
        def ExecPn():
            print(4)
    
    task = getattr(Tasks, 'Exec' + key)
    task()
person Ohad    schedule 06.02.2012
comment
Работает, но я бы создал отфильтрованную версию локальных жителей (например, filter(lambda x: x.startswith('Exec'), locals())). Что касается безопасности, locals всегда будет содержать функции, определенные в локальной области. - person Ohad; 07.02.2012
comment
См. stackoverflow.com/a/9168387/4909087, чтобы узнать, как правильно и правильно сделать это. - person cs95; 18.05.2018

Упростите, упростите, упростите:

def p1(args):
    whatever

def p2(more args):
    whatever

myDict = {
    "P1": p1,
    "P2": p2,
    ...
    "Pn": pn
}

def myMain(name):
    myDict[name]()

Это все, что вам нужно.


Вы можете рассмотреть возможность использования dict.get с вызываемым значением по умолчанию, если name относится к недопустимой функции -

def myMain(name):
    myDict.get(name, lambda: 'Invalid')()

(Подобрал этот изящный трюк от Мартин Питерс)

person S.Lott    schedule 06.02.2012
comment
Я знаю, что это был мой первый выбор, но я хочу, чтобы конечный пользователь имел ограниченный доступ, чтобы пользователь не мог изменять содержимое в словаре во время выполнения. - person JohnnyDH; 07.02.2012
comment
Пользователь всегда может изменить что угодно во время выполнения. Это Python. У них есть источник. - person S.Lott; 07.02.2012
comment
Это зависит от пользователя? Что это обозначает? Не каждый пользователь может настроить код? Если вы это имеете в виду, вам следует тратить еще меньше времени на беспокойство об ограниченном доступе. Поскольку - по сути - все пользователи могут настраивать код, вряд ли стоит пытаться добавить код для создания ограниченного доступа. Во всех случаях переходите к простому. - person S.Lott; 07.02.2012
comment
Я знаю, но, как я написал ниже: Приложение представляет собой графический интерфейс для устройства, мы предлагаем функции сценариев в нашем приложении ... ... Конечные пользователи - продавцы, люди, которым нужно только следовать руководству, чтобы писать базовые сценарии, они не принимали проприетарный язык, им нужен был язык на основе Python, так что да, пользователь может изменить словарь в одной ошибочной строке ... и они хотят видеть все, кроме простого и простого приложения ... Заказчик знает ничего о программировании, но они хотят того, что хотят, и если они хотят видеть x = x+y/y вместо x++, мы должны доставить ... - person JohnnyDH; 07.02.2012
comment
как я писал ниже? Пожалуйста, обновите вопрос, чтобы он содержал все факты. Ни сверху, ни снизу нет, так как порядок ответов меняется. пользователь может изменить словарь в единственной глючной строчке, ничего не значит. Они также могут переформатировать свой жесткий диск в единственной строке с ошибками, которая вызывает subprocess.Popen. Нет веских причин для дополнительной сложности. Это не мешает пользователю вызвать хаос с одной ошибочной строкой. Действительно, чем выше сложность, тем меньше прозрачности и тем больше загадок предстоит отладить. - person S.Lott; 07.02.2012
comment
Я должен не согласиться, как я уже сказал, мы не поддерживаем все возможности python, у нас есть фильтр, и мы предоставляем доступ только к некоторым модулям, меня не волнует, что они делают со своими жесткими дисками, если они что-то знают о python, я только заботьтесь, что парень, пишущий сценарий, не может изменять модули, просто прочитайте их, это базовая функция сценариев, к сожалению, Python не обеспечивает большой безопасности в таких случаях. Итак, мне нужно сделать модули более безопасными, и неважно, будет ли код более сложным, заказчик знает сотрудников, и поэтому они требуют таких мер безопасности. - person JohnnyDH; 07.02.2012
comment
Мне нужно сделать модули более безопасными. Как? Вы не можете. они требуют таких мер безопасности. Для них это хорошо. Ничто из того, что вы делаете, не может повлиять на ситуацию, кроме как усложнить ситуацию. Но. Вы продолжаете повторять, что важно создавать бесполезную, бесполезную сложность. Я думаю, это все. Ваше здоровье. - person S.Lott; 07.02.2012
comment
Я полагаю, вы пропустили строчку, которую я разместил. Заказчик ничего не знает о программировании, но они хотят то, что хотят, и если они хотят видеть x = x+y/y вместо x++, мы должны доставить ... Я надеюсь, что вы не работаете с программным обеспечением, как я, скажите своему костюмер Молодец, и вы найдете себя в поисках работы. Я продолжаю повторять себя, потому что если бы вы смогли понять, что я не могу использовать простой способ, тогда все было бы проще ... - person JohnnyDH; 07.02.2012
comment
@JohnnyDH Это сумасшедший аргумент. Если у вас есть реальная потребность сделать код более безопасным, вы должны использовать скомпилированный язык - python не является подходящим инструментом для работы, и вы обязаны объяснить это клиенту. Добавление строк дерьма в ваш код, чтобы попытаться исправить присущую Python открытость, не является мерой безопасности - это не может быть выполнено должным образом, и попытки сделать это только сделают ваш код более уродливым и хрупким - person wim; 07.02.2012
comment
@wim Я знаю :(, я никогда не использовал python именно потому, что он слишком гибкий и открытый, к сожалению, я не ведущий инженер, этот заказчик новый, и компания хочет их удержать, поэтому я с вами, люди, но я могу слишком поздно начинать заново, и причина, по которой мы не хотели использовать Python, по той же причине, по которой они думают, что он им нужен ... Печально, но деньги - это король ... - person JohnnyDH; 07.02.2012
comment
Мы всегда используем C (для встроенных), C #, Java и ASP. Однако бывший поставщик этого клиента использовал Python для инструментов других устройств, поэтому они считают, что им нужно продолжать использовать его. - person JohnnyDH; 07.02.2012
comment
@JohnnyDH: Я поставляю программное обеспечение всего 30 лет, поэтому раньше я видел несколько примеров бесполезной сложности. Это другое. Есть разница между сложностью и безопасностью. Строка if they want to see ... - действительно, очень плохой пример, потому что в Python нет оператора ++, как в C. И. Объяснение функций сценариев должно быть включено в ваш вопрос, чтобы ваш вопрос имел хоть какой-то смысл. Повторение требований в комментариях плохо. - person S.Lott; 07.02.2012
comment
Я уверен, что вы поняли мой пример с x ++. Что ж, плохо, если я не сказал, что мы предоставляем функцию сценариев, я не понимал, что людям нужно столько информации - person JohnnyDH; 07.02.2012
comment
Этот ответ повторяет каждое имя функции 3 раза в источнике. Существуют более лаконичные решения, см. Ниже. - person Vladimir Panteleev; 14.12.2018
comment
У меня это не работает. p1() имеет аргументы. В словаре "P1": p1, вызывается без аргументов. Когда я указываю аргументы типа "P1": p1(arg1, arg2),, словарь автоматически вызывает функцию p1. - person alex; 07.05.2021

Упростить, упростить, упростить + СУХОЙ:

tasks = {}
task = lambda f: tasks.setdefault(f.__name__, f)

@task
def p1():
    whatever

@task
def p2():
    whatever

def my_main(key):
    tasks[key]()
person Joe    schedule 09.09.2016
comment
Это не СУХОЙ, это запутано. - person Aran-Fey; 09.06.2018
comment
Я думаю, что упоминание расширенных языковых функций, таких как лямбды и пользовательские декораторы, как обфускации, по меньшей мере, вводит в заблуждение. - person Vladimir Panteleev; 14.12.2018
comment
Конечно. Лямбда здесь только для краткости. Независимо от того, придерживаетесь ли вы этого или переписываете на def task(f):\n tasks[f.__name__] = f, принцип остается тем же. Быть СУХИМ снимает с вас ответственность за синхронизацию клавиш словаря с именами функций. Это также упрощает обнаружение ошибок, таких как отсутствующий @task (по сравнению с отсутствующим элементом словаря). - person Joe; 15.12.2018
comment
Это элегантно и СУХОЕ, но определенно не упрощенное. - person John Lunzer; 05.02.2020

Это вызовет методы из словаря

Это оператор переключения Python с вызовом функции

Создайте несколько модулей в соответствии с вашими требованиями. Если вы хотите передать аргументы, пройдите.

Создайте словарь, который будет вызывать эти модули в соответствии с требованиями.

    def function_1(arg):
        print("In function_1")

    def function_2(arg):
        print("In function_2")

    def function_3(fileName):
        print("In function_3")
        f_title,f_course1,f_course2 = fileName.split('_')
        return(f_title,f_course1,f_course2)


    def createDictionary():

        dict = {

            1 : function_1,
            2 : function_2,
            3 : function_3,

        }    
        return dict

    dictionary = createDictionary()
    dictionary[3](Argument)#pass any key value to call the method
person akD    schedule 27.04.2018
comment
Если в качестве ключей используются целые числа, то можно использовать и список. - person Alex Povel; 23.02.2021

Вы можете просто использовать

myDict = {
    "P1": (lambda x: function1()),
    "P2": (lambda x: function2()),
    ...,
    "Pn": (lambda x: functionn())}
myItems = ["P1", "P2", ..., "Pn"]

for item in myItems:
    myDict[item]()
person Jonas De Schouwer    schedule 19.04.2018

Часто классы используются для включения методов, и ниже приводится расширение ответов выше с методом по умолчанию в случае, если метод не найден.

class P:

     def p1(self):
         print('Start')

     def p2(self):
         print('Help')

     def ps(self):
         print('Settings')

     def d(self):
         print('Default function')

     myDict = {
         "start": p1,
         "help": p2,
         "settings": ps
     }

     def call_it(self):
         name = 'start'
         f = lambda self, x : self.myDict.get(x, lambda x : self.d())(self)
         f(self, name)


 p = P()
 p.call_it()
person Milind Deore    schedule 09.02.2020

def p1( ):
    print("in p1")

def p2():
    print("in p2")

myDict={
    "P1": p1,
    "P2": p2

}

name=input("enter P1 or P2")

myDictname

person Gokhale    schedule 20.02.2017
comment
Что, если p1() и p2() имеют параметры? - person alex; 07.05.2021

Вы зря теряете время:

  1. Вы собираетесь написать много бесполезного кода и внести новые ошибки.
  2. Для выполнения функции вашему пользователю в любом случае необходимо знать имя P1.
  3. И т. Д. И т. Д. И т. Д.

Просто поместите все свои функции в .py файл:

# my_module.py

def f1():
    pass

def f2():
    pass

def f3():
    pass

И используйте их так:

import my_module

my_module.f1()
my_module.f2()
my_module.f3()

or:

from my_module import f1
from my_module import f2
from my_module import f3

f1()
f2()
f3()

Этого должно хватить для начала.

person Misha Akovantsev    schedule 06.02.2012
comment
Вы правы, конечный пользователь будет знать имя, и я очень ценю ваш совет, я начинающий, но только в python, я очень хорошо осведомлен о некоторых принципах программирования, но я не реализую это в личном проекте, это связано с работой и клиент просит надежное приложение, и правда в том, что это программное обеспечение будет использоваться кучкой обезьян, и они хотят видеть все, кроме простого и простого приложения ... - person JohnnyDH; 07.02.2012
comment
@JohnnyDH, опишите хотя бы несколько разных сценариев, когда эти обезьяны захватят ваше приложение. Это может дать вам ответы, более подходящие для вашей ситуации. - person Misha Akovantsev; 07.02.2012
comment
Приложение представляет собой графический интерфейс для устройства, мы предлагаем функции сценариев в нашем приложении, но мы не предлагаем полную поддержку Python, поскольку это наша основная цель - ограничить доступ. Конечные пользователи - это продавцы, люди, которым нужно только следовать руководству для написания базовых сценариев, они не принимали проприетарный язык, им нужен был язык на основе Python, так что да, пользователь может изменить словарь в одной строке с ошибками и продукт не будет работать, так что да, им просто нужно перезапустить, но заказчик будет жаловаться. - person JohnnyDH; 07.02.2012
comment
@JonnyDH Твои аргументы не имеют смысла. Одной ошибочной строкой они могут уничтожить вашу основную функцию так же легко, как они могут изменить словарь. По правде говоря, маловероятно, что и то, и другое произойдет, потому что ни то, ни другое не похоже на законную нормальную работу. Но этот ответ предполагает, что вы даже не используете словарь, вы просто даете им один общедоступный модуль, который только содержит то, что конечный пользователь должен вызывать. Вы ничего не можете сделать, если беспокоитесь о том, что они импортируют другие модули и возятся со своими внутренними компонентами. - person Ben; 07.02.2012
comment
@Ben Поверьте, я прекрасно это понимаю, я уже 8 лет предоставляю программные решения, это первый раз, когда я использую Python, и я хотел бы использовать многие функции безопасности с других языков, но я не могу это контролировать, мне нужно чтобы сделать модуль в некотором роде доступным только для чтения, заказчик просит нас предоставить им доказательства того, что функция создания сценариев максимально безопасна, мы предложили собственный язык, поэтому у нас был полный контроль над процессом создания сценариев, но они отказались, и мы не можем контролировать все без ущерба для гибкости функции. - person JohnnyDH; 07.02.2012

person    schedule
comment
Я знаю, что это легко сделать таким образом, я действительно это делаю, но тогда мой словарь не имеет защиты, мне действительно нужно предотвратить изменение этого словаря конечным пользователем. - person JohnnyDH; 07.02.2012
comment
Затем сделайте его классом, охраняемым (и я использую этот термин свободно) декораторами принудительного исполнения только для записи, и используйте переменные с префиксом __ в (давайте будем честными, тщетными попытками), чтобы скрыть детали реализации от пользователя. Взгляните на fightquaker.com/pyanno для вдохновения .. - person synthesizerpatel; 07.02.2012