从从lis读取文件名和函数名的不同文件调用函数

2024-10-01 02:28:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我有多个函数存储在不同的文件中,文件名和函数名都存储在列表中。在没有条件语句的情况下,是否有调用所需函数的选项? 例如,file1有函数function11function12

def function11():
    pass
def function12():
    pass

file2具有函数function21function22

def function21():
    pass
def function22():
    pass

我有名单

file_name = ["file1", "file2", "file1"]
function_name = ["function12", "function22", "funciton12"]

我将从不同的函数中获取列表索引,在此基础上我需要调用函数并获取输出。你知道吗


Tags: 文件函数name列表文件名defpass语句
3条回答

如果另一个函数将直接给您一个列表索引,那么您不需要将函数名作为字符串处理。相反,直接存储(不调用)列表中的函数:

import file1, file2

functions = [file1.function12, file2.function22, file1.function12]

一旦找到索引,就给他们打电话:

function[index]()

方法可以在Python中执行所谓的“反射”,并从字符串获取匹配的命名函数。但它们解决的问题比您所描述的更高级,而且更困难(特别是如果您还必须使用模块名称)。你知道吗


如果您有一个允许从配置文件调用的函数和模块的“白名单”,但仍然需要按字符串查找它们,则可以使用dict显式创建映射:

allowed_functions = {
    'file1': {
        'function11': file1.function11,
        'function12': file1.function12
    },
    'file2': {
        'function21': file2.function21,
        'function22': file2.function22
    }
}

然后调用函数:

try:
    func = allowed_functions[module_name][function_name]
except KeyError:
    raise ValueError("this function/module name is not allowed")
else:
    func()

最先进的方法是,如果您需要从作者创建的“插件”模块加载代码。您可以使用import模块使用字符串名称来查找要作为模块导入的文件,并动态导入它。它看起来像:

from importlib.util import spec_from_file_location, module_from_spec

# Look for the file at the specified path, figure out the module name
# from the base file name, import it and make a module object.
def load_module(path):
    folder, filename = os.path.split(path)
    basename, extension = os.path.splitext(filename)
    spec = spec_from_file_location(basename, path)
    module = module_from_spec(spec)
    spec.loader.exec_module(module)
    assert module.__name__ == basename
    return module

这仍然是不安全的,因为它可以在文件系统的任何地方查找模块。如果您自己指定文件夹,并且只允许在配置文件中使用一个文件名,那就更好了;但是您仍然必须通过在“文件名”中使用“.”和“/”之类的内容来防止黑客攻击路径。你知道吗

(我有一个这样的项目。它从用户控制的白名单中选择路径,因此我必须警告我的用户不要相互信任路径白名单文件。我也会在目录中搜索模块,然后列出可能会用到的插件的白名单,只基于目录中的插件-所以没有带“.”的有趣游戏。我仍然担心我忘了什么。)

一旦你有了一个模块名,你就可以从中得到一个函数名,比如:

dynamic_module = load_module(some_path)
try:
    func = getattr(dynamic_module, function_name)
except AttributeError:
    raise ValueError("function not in module")

无论如何,没有理由eval任何东西,或者根据用户输入生成和导入代码。这是最不安全的。你知道吗

我不能百分之百肯定我理解这个需要。也许问题会更详细。你知道吗

你在找这样的东西吗?你知道吗

m = ["os"]
f = ["getcwd"]
command = ''.join([m[0], ".", f[0], "()"])
# Put in some minimum sanity checking and sanitization!!!
if ";" in command or <other dangerous string> in command:
        print("The line '{}' is suspicious. Will not run".format(command))
        sys.exit(1)
print("This will error if the method isnt imported...")
print(eval(''.join([m[0], ".", f[0], "()"])) )

输出:

This will error if the method isnt imported...
/home/rightmire/eclipse-workspace/junkcode

正如@KarlKnechtel所指出的,从外部文件输入命令是一个巨大的安全风险!你知道吗

另一种选择。然而,这并不是比cd1安全得多。你知道吗

有权访问您从配置文件读取的列表的人可能会在您导入的列表中注入恶意代码。你知道吗

'from subprocess import call; subprocess.call(["rm", "-rf", "./*" stdout=/dev/null, stderr=/dev/null, shell=True)'

代码:

import re
# You must first create a directory named "test_module"
# You can do this with code if needed. 
# Python recognizes a "module" as a module by the existence of an __init__.py
# It will load that __init__.py at the "import" command, and you can access the methods it imports
m = ["os", "sys", "subprocess"] # Modules to import from
f = ["getcwd", "exit", "call; call('do', ' -terrible-things')"] # Methods to import

# Create an __init__.py
with open("./test_module/__init__.py", "w") as FH:
    for count in range(0, len(m), 1):
        # Writes "from module import method" to __init.py 
        line = "from {} import {}\n".format(m[count], f[count])
        # !!!! SANITIZE THE LINE !!!!!
        if not re.match("^from [a-zA-Z0-9._]+ import [a-zA-Z0-9._]+$", line):
            print("The line '{}' is suspicious. Will not be entered into __init__.py!!".format(line))
            continue
        FH.write(line)

import test_module
print(test_module.getcwd())

输出:

The line 'from subprocess import call; call('do', ' -terrible-things')' is suspicious. Will not be entered into __init__.py!!
/home/rightmire/eclipse-workspace/junkcode

相关问题 更多 >