RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1561467
Accepted
Alexey Trukhanov
Alexey Trukhanov
Asked:2024-01-13 22:17:48 +0000 UTC2024-01-13 22:17:48 +0000 UTC 2024-01-13 22:17:48 +0000 UTC

根据外部配置选择性启动多种功能

  • 772

同事!给出了几个采用相同参数的函数。

def func1(a):
    print('Первая функция')
    return a

def func2(a):
    print('Вторая функция')
    return a

脚本从某个地方(例如,从存储配置的文件或从标准输入,这并不重要)接收有关运行哪些函数和不运行哪些函数的设置。

dic_flag = {'fun1': True, 'fun2': False}

您可以编写一堆条件语句来运行这些函数。

if dic_flag['fun1']:
    print(func1(a))

if dic_flag['fun2']:
    print(func2(a))

但我想自动化这个过程,例如,像这样:

def func1(a):
    print('Первая функция')
    return a

def func2(a):
    print('Вторая функция')
    return a

dic_flag = {'fun1': True, 'fun2': False}
dic_func = {'fun1': func1, 'fun2': func2}

a = 10

for flag in dic_flag:
    if dic_flag[flag]:
        print(dic_func[flag](a))

问题

你能为这项任务想出什么漂亮的东西?也许是 OOP 中的一些东西?或者有没有标准库?实际上有几十个功能。

选修的:

如果主要参数相同,但一些附加参数不同怎么办?

python
  • 3 3 个回答
  • 228 Views

3 个回答

  • Voted
  1. Best Answer
    Amgarak
    2024-01-13T22:48:42Z2024-01-13T22:48:42Z

    您可以创建一个类来根据设置管理函数调用:

    class FunctionManager:
        def __init__(self, functions, flags):
            self.functions = functions
            self.flags = flags
    
        def run_functions(self, argument):
            for func_name, flag in self.flags.items():
                if flag and func_name in self.functions:
                    print(self.functions[func_name](argument))
    
    def func1(a):
        print('Первая функция')
        return a
    
    def func2(a):
        print('Вторая функция')
        return a
    
    dic_flag = {'func1': True, 'func2': False}
    dic_func = {key: globals()[key] for key, value in dic_flag.items() if value and key in globals() and callable(globals()[key])}
    
    
    manager = FunctionManager(dic_func, dic_flag)
    a = 10
    manager.run_functions(a)
    

    作为奖励,我补充说 dic_func 字典是使用 dic_flag 中指定的键自行组装的。键必须与函数名称匹配。禁用功能不包含在词典中。


    如果字典包含 fun1,并且函数应该有不同的名称,您也可以发挥创意:

    def func1(a):
        print('Первая функция')
        return a
    
    def func2(a):
        print('Вторая функция')
        return a
    
    dic_flag = {'fun1': True, 'fun2': True}
    a = 10
    
    for flag, value in dic_flag.items():
        if value:
            func_name = globals().get(f'func{flag[3:]}')  # Извлечение функции по имени
            if func_name:
                func_name(a)
    

    经过更多思考后,我可以提出这样的思路:

    def func1(a, **kwargs):
        print('Первая функция')
        for k, v in kwargs.items(): print(f'Key={k} and Value={v}')
        return a
    
    def func2(a, **kwargs):
        print('Вторая функция')
        for k, v in kwargs.items(): print(f'Key={k} and Value={v}')
        return a
    
    def func3(a, **kwargs):
        print('Третья функция')
        for k, v in kwargs.items(): print(f'Key={k} and Value={v}')
        return a
    
    dic_flag = {'fun1': [True, {'name': 'Pankaj', 'age': 34}], 'fun2': [False, {'name': 'J', 'age': 14}], 'fun3': [True, {'name': 'Pank', 'age': 54}]}
    dic_func = {'fun1': func1, 'fun2': func2, 'fun3': func3}
    
    a = 10
    
    # Фильтруем функции по флагам
    funcs_to_run = filter(lambda f: dic_flag[f][0], dic_func)
    for value in funcs_to_run:
        print(dic_func[value](a,**dic_flag[value][1]))
    

    请允许我再曲解一下,现在转储一下函数本身:

    import dill # pip install dill ,можно обойтись и стандартным import pickle
    
    def save_locals_to_pkl(file_path):
        def func1(a, **kwargs):
            print('Первая функция')
            for k, v in kwargs.items(): print(f'Key={k} and Value={v}')
            return a
    
        def func2(a, **kwargs):
            print('Вторая функция')
            for k, v in kwargs.items(): print(f'Key={k} and Value={v}')
            return a
    
        def func3(a, **kwargs):
            print('Третья функция')
            for k, v in kwargs.items(): print(f'Key={k} and Value={v}')
            return a
    
        local_funcs = {'func1': func1, 'func2': func2, 'func3': func3}
    
        # Сохраняем словарь функций в файл с использованием dill
        with open(file_path, 'wb') as file:
            dill.dump(local_funcs, file)
    
    def load_locals_from_pkl(file_path):
        with open(file_path, 'rb') as file:
            local_funcs = dill.load(file)
        # Так как мы возвращаем словарь, можем добавить функции в глобальную область видимости
        globals().update(local_funcs)
        # Пример вывода информации о функциях
        for func in local_funcs:
            print(f"Загруженная функция: {func}")
    
    # Пример сохранения функций в дамп
    save_locals_to_pkl('local_funcs.pkl')
    
    # Загружаем и восстанавливаем локальные функции из дампа
    load_locals_from_pkl('local_funcs.pkl')
    
    a = 10
    
    # Теперь функции доступны в глобальной области видимости
    dic_flag = {'fun1': [True, {'name': 'Pankaj', 'age': 34}], 'fun2': [False, {'name': 'J', 'age': 14}], 'fun3': [True, {'name': 'Pank', 'age': 54}]}
    func1(a,**dic_flag['fun1'][1])
    func2(a,**dic_flag['fun2'][1])
    func3(a,**dic_flag['fun3'][1])
    

    或者像这样:

    def load_locals_from_pkl(file_path):
        with open(file_path, 'rb') as file:
            local_funcs = dill.load(file)
    
        # Пример вывода информации о функциях
        for func_name, func in local_funcs.items():
            print(f"Загруженная функция {func_name}: {func}")
    
        return local_funcs
    
    # Пример сохранения
    save_locals_to_pkl('local_funcs.pkl')
    
    # Загружаем и восстанавливаем локальные функции
    local_funcs = load_locals_from_pkl('local_funcs.pkl')
    
    # Теперь функции доступны в глобальной области видимости
    a = 10
    dic_flag = {'fun1': [True, {'name': 'Pankaj', 'age': 34}], 'fun2': [False, {'name': 'J', 'age': 14}], 'fun3': [True, {'name': 'Pank', 'age': 54}]}
    local_funcs['func1'](a, **dic_flag['fun1'][1])
    local_funcs['func2'](a, **dic_flag['fun2'][1])
    local_funcs['func3'](a, **dic_flag['fun3'][1])
    

    您还可以不保存函数字典,而是保存函数列表:

    # local_funcs = {'func1': func1, 'func2': func2, 'func3': func3}
    # Создаем список с локальными функциями
    local_funcs = [func1, func2, func3]
    

    并通过索引调用必要的函数:

    def load_locals_from_pkl(file_path):
        with open(file_path, 'rb') as file:
            local_funcs = dill.load(file)
    
        return local_funcs
    
    local_funcs = load_locals_from_pkl('local_funcs.pkl')
    local_funcs[0](a, **dic_flag['fun1'][1])
    local_funcs[1](a, **dic_flag['fun2'][1])
    local_funcs[2](a, **dic_flag['fun3'][1])
    

    因此,您可以将函数拆分为单独的转储并仅加载必要的函数。

    import glob
    import os
    
    def load_locals_from_folder(folder_path):
        # Получаем список файлов в заданной папке с расширением .pkl
        pkl_files = glob.glob(os.path.join(folder_path, '*.pkl'))
    
        for pkl_file in pkl_files:
            with open(pkl_file, 'rb') as file:
                local_funcs = dill.load(file)
                globals().update(local_funcs)
    
    

    您甚至可以深入研究并使用字符串表示形式来创建函数。您可以使用 exec() 或 eval() 来执行此操作:

    def add_exec_function(func_name):
        # Создаем строковое представление функции
        function_code = f'''
    def {func_name}(a, *args):
        print('{func_name.capitalize()}')
        for v in args: print(f'Value={{v}}')
        return a
    '''
        # Выполняем строковое представление кода
        exec(function_code, globals(), locals())
    
        # Возвращаем созданную функцию
        return locals()[func_name]
    
    # Пример добавления новой функции
    func4 = add_exec_function('func4')
    
    # Теперь можно вызывать новую функцию
    result = func4(42, 'value3', 56, 72)
    print(result)
    

    因此,您可以从文件中以字符串的形式加载必要的函数并执行它们。

    def add_evil_function(func_name):
        # Создаем строковое представление функции
        function_code = f'''
    def {func_name}(a, **kwargs):
        print('{func_name.capitalize()}')
        for k, v in kwargs.items(): print(f'Key={{k}} and Value={{v}}')
        return a
    '''
        # Выполняем строковое представление кода с использованием eval()
        eval(compile(function_code, '<string>', 'exec'))
        # Возвращаем созданную функцию
        return locals()[func_name]
    
    
    # Пример добавления новой функции
    func4 = add_evil_function('func4')
    
    # Теперь можно вызывать новую функцию
    result = func4(42, param1='value1', param2='value2')
    print(result)
    

    您可以按照您喜欢的任何方式运行函数:

    def func1(a):
        print('Первая функция')
        return a
    
    def func2(a):
        print('Вторая функция')
        return a
    
    # Cловарь функций
    functions = {'fun1': func1, 'fun2': func2}
    
    # Настройки из словаря
    dic_flag = {'fun1':[True, {'name': 'Pankaj', 'age': 34}], 'fun2': [False, {'name': 'kaj', 'age': 24}]}
    
    # Запускаем функции хехе
    results = [func(dic_flag[func_name][1]) if dic_flag[func_name][0] else None for func_name, func in functions.items()]
    print(results)
    
    • 3
  2. Oopss
    2024-01-13T23:08:56Z2024-01-13T23:08:56Z

    一切都已经适合你了,你懒得检查。

    def get_function_name(func):
        return str(func.__name__)
    
    def func1(a):
        print('Первая функция')
        return a
    
    def func2(a):
        print('Вторая функция')
        return a
    s=[func1, func2]
    dic_flag = {'func1': True, 'func2': False}
    x=10
    for f in s:
       if dic_flag[get_function_name(f)]:
           f(x)
    

    Первая функция
    
    • 1
  3. DeNRuDi
    2024-01-18T07:31:37Z2024-01-18T07:31:37Z

    作为python程序员,我们希望让代码更加简洁、美观。但最重要的规则是它易于理解且有效。我采用了一种更通用的方法,尽管乍一看代码可能看起来很复杂。一般来说,要理解这段代码,了解 OOP 的基础知识很重要。我还稍微修改了您的配置 - 您通常有机会向函数添加不同的参数,或者根本不添加它们。该代码还提供了使用文件中所描述的类中的方法的方法,当然,如果它们在那里,那么它们也将被正确识别,即使它是一个包装的@staticmethod,@classmethod或者什么都没有 - 在这种情况下,我通过类作为值self,即我自己,在我的上下文中它会是func(class_ref)。

    代码本身:

    from itertools import chain
    import inspect
    
    
    class FunctionRunner:
    
        def __init__(self, module, configuration: dict):
            self.module = module
            self.configuration = configuration
    
            module_name = self.module.__name__
    
            dev_functions = list(
                chain(
                    inspect.getmembers(self.module, inspect.isfunction),
                    inspect.getmembers(self.module, inspect.ismethod),
                    inspect.getmembers(self.module, inspect.isclass),
                )
            )
    
            functions = {}
            for func in dev_functions:
                if func[1].__module__ == module_name:
                    if inspect.isclass(func[1]):
                        dev_methods = list(
                            chain(
                                inspect.getmembers(func[1], inspect.isfunction),
                                inspect.getmembers(func[1], inspect.ismethod)
                            )
                        )
                        methods = {
                            method[0]: {'class': func[1], 'method': method[1]} for method in dev_methods
                            if func[1].__module__ == module_name
                        }
                        functions.update(**methods)
                    else:
                        functions.update({func[0]: func[1]})
    
            self.func_for_run = functions
    
        def run(self):
            filtered_dict = {
                name: func for name, func in self.func_for_run.items()
                if name in self.configuration and self.configuration[name]['run']
            }
    
            for name, func in filtered_dict.items():
    
                class_ref = func
                if isinstance(func, dict):
                    class_ref = func['class']
                    func = func['method']
    
                args = self.configuration[name].get('args')
                func_args = inspect.getfullargspec(func).args
                if args is None:
                    if 'self' in func_args:
                        func(class_ref)
                    else:
                        func()
                elif isinstance(args, (list, tuple)):
                    if 'self' in func_args:
                        args.insert(0, class_ref)
                    func(*args)
                else:
                    if 'self' in func_args:
                        args = [class_ref, args]
                        func(*args)
                    else:
                        func(args)
    

    Ваш файл с функциями function_module.py

    def func1():
        print('Первая функция')
        return ''
    
    
    def func2(a):
        print('Вторая функция')
        return a
    
    
    def func3(a, b):
        print('Третья функция')
        return a, b
    
    
    class Test:
    
        @staticmethod
        def method1(a):
            print('Первый метод')
            return a
    
        def method2(self, a, b):
            print('Второй метод')
            return a, b
    
        @classmethod
        def method3(cls):
            print('Третий метод')
            return ''
    
    

    Ваш файл вызова логики app.py

    import function_module # ваше имя файла, где находятся функции
    from func_runner import FunctionRunner
    
    
    dict_flag = {
        'func1': {'run': True, 'args': None},
        'func2': {'run': False, 'args': 10},
        'func3': {'run': True, 'args': [10, '']},
        'method1': {'run': True, 'args': [1]},
        'method2': {'run': False, 'args': [1, 2]},
        'method3': {'run': True, 'args': None},
    }
    fr = FunctionRunner(function_module, configuration=dict_flag)
    fr.run()
    

    Вывод:

    Первая функция
    Третья функция
    Первый метод
    Третий метод
    

    Преимущества:

    1. Подключить мой класс для вас будет очень просто, так как все что вы делаете, так это в конструктор передаете сам импорт вашего модуля, и конфигурацию.

    2. Вам не нужно заморачиваться с логикой, которая написана внутри моего класса в отличие от других приведенных ответов где логику придется применять каждый раз для разных вызовов. Плюс там много ненужных вариантов, которые может быть написал вообще chatgpt (извините, если кого-то обидел :) ).

    3. Мой класс вызывает только те функции, которые вы сами явно прописали в модуле, исключая импорты. Это означает, что вам не нужно руками прописывать все функции и методы, получать ссылки на них в словарь - класс сделает все сам.

    Важно понимать, что параметры нужно внимательно передать в функции/методы, если все же требуется такая логика, иначе будет ошибка (как и при обычном запуске).

    В целом я вообще не рекомендую использовать такой подход в программировании, так как логика выглядит достаточно запутанной и другим программистам будет сложно разобраться, где и какая функция вызывается. Не рекомендую и вашу идею с получением с внешнего источника и запуск таким образом функций. Лучше всего сделать какой-нибудь главный метод, который принимает аргументы, и уже на основе них запускать ваши функции. В качестве альтернативы посмотрите на match-case, который добавили в python 3.10 он может показаться вам полезным.

    UPDATE:

    Подумал, что вдруг вам не нужна такая навороченная логика, а нужно что-то максимально приближено к той задаче, которую вы привели, то упростил логику и подогнал под ваш вариант с функциями.

    class FunctionRunner:
    
        def __init__(self, module, configuration: dict):
            self.module = module
            self.configuration = configuration
    
            module_name = self.module.__name__
    
            dev_functions = list(
                chain(
                    inspect.getmembers(self.module, inspect.isfunction),
                    inspect.getmembers(self.module, inspect.ismethod),
                )
            )
            functions = {}
            for func in dev_functions:
                if func[1].__module__ == module_name:
                    functions.update({func[0]: func[1]})
    
            self.func_for_run = functions
    
        def run(self, arguments: dict):
            filtered_dict = {
                name: func for name, func in self.func_for_run.items()
                if name in self.configuration and self.configuration[name]
            }
    
            for name, func in filtered_dict.items():
                func_args = arguments.get(name)
                if func_args is None:
                    func()
                elif isinstance(func_args, (list, tuple)):
                    func(*func_args)
                else:
                    func(func_args)
    
    
    dict_flag = {'func1': True, 'func2': True, 'func3': True}
    func_arguments = {'func1': None, 'func2': 10, 'func3': [5, 10]}
    # если аргументов нет для функций, просто отправьте пустой словарь
    
    fr = FunctionRunner(function_module, configuration=dict_flag)
    fr.run(arguments=func_arguments)
    

    В целом задача оказалось интересной, был рад решить ее и помочь вам. Желаю успехов

    • 1

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5