使用exec()从文本文件创建和分配变量 [英] Using exec() to make and assign variables from a text file

查看:73
本文介绍了使用exec()从文本文件创建和分配变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题是对我在这里问的问题,总结为:

"在python中,我如何从文本文件params.txt中读取参数,创建变量并为其分配文件中的值?该文件的内容为(请忽略自动语法突出显示,params.txt实际上是纯文本文件):

"In python how do I read in parameters from the text file params.txt, creating the variables and assigning them the values that are in the file? The contents of the file are (please ignore the auto syntax highlighting, params.txt is actually a plain text file):

Lx = 512 Ly = 512
g = 400
================ Dissipation =====================
nupower = 8 nu = 0
...[etc]

,我希望我的python脚本读取文件,以便我可以将Lx,Ly,g,nupower,nu等用作变量(而不是字典中的键),并在params.txt中提供适当的值.顺便说一下,我是python新手."

and I want my python script to read the file so that I have Lx, Ly, g, nupower, nu etc available as variables (not keys in a dictionary) with the appropriate values given in params.txt. By the way I'm a python novice."

在帮助下,我想出了以下使用exec()的解决方案:

With help, I have come up with the following solution that uses exec():

with open('params.txt', 'r') as infile:
    for line in infile:
        splitline = line.strip().split(' ')
        for i, word in enumerate(splitline):
            if word == '=':
                exec(splitline[i-1] + splitline[i] + splitline[i+1])

这有效,例如print(Lx)按预期返回512.

This works, e.g. print(Lx) returns 512 as expected.

我的问题是:

(1)这种方法安全吗?提到exec()函数的大多数问题都有答案,其中包含有关其用法的严厉警告,这意味着除非您真的知道自己在做什么,否则不要使用它.如前所述,我是一个新手,所以我真的不知道自己在做什么,因此我想检查一下,使用该解决方案不会给自己带来麻烦.脚本的其余部分使用从该文件读取的变量以及其他文件的数据进行一些基本的分析和绘图.

(1) Is this approach safe? Most questions mentioning the exec() function have answers that contain dire warnings about its use, and imply that you shouldn't use it unless you really know what you're doing. As mentioned, I'm a novice so I really don't know what I'm doing, so I want to check that I won't be making problems for myself with this solution. The rest of the script does some basic analysis and plotting using the variables read in from this file, and data from other files.

(2)如果我要将以上代码包装在一个函数中,例如read_params(),仅仅是将最后一行更改为exec(splitline[i-1] + splitline[i] + splitline[i+1], globals())的问题吗?我知道这会导致exec()在全局名称空间中进行分配.我不明白的是这是否安全,如果不是,那么为什么不安全. (请参阅上文中的新手知识!)

(2) If I want to wrap up the code above in a function, e.g. read_params(), is it just a matter of changing the last line to exec(splitline[i-1] + splitline[i] + splitline[i+1], globals())? I understand that this causes exec() to make the assignments in the global namespace. What I don't understand is whether this is safe, and if not why not. (See above about being a novice!)

推荐答案

(1)这种方法安全吗?

(1) Is this approach safe?

不,这不安全.如果有人可以编辑/控制/替换params.txt,则可以以允许在运行脚本的计算机上执行任意代码的方式来制作它.

No, it is not safe. If someone can edit/control/replace params.txt, they can craft it in such a way to allow arbitrary code execution on the machine running the script.

这实际上取决于运行Python脚本的位置和人员,以及他们是否可以修改params.txt.如果这只是用户直接在普通计算机上运行的脚本,那么不必担心,因为他们已经可以访问该计算机并且可以执行他们想要的任何恶意操作,而不必使用您的Python脚本来执行.

It really depends where and who will run your Python script, and whether they can modify params.txt. If it's just a script run directly on a normal computer by a user, then there's not much to worry about, because they already have access to the machine and can do whatever malicious things they want, without having to do it using your Python script.

(2)如果我要将以上代码包装在一个函数中,例如read_params(),是否只是将最后一行更改为exec(splitline [i-1] + splitline [i] + splitline [i + 1],globals())的问题?

(2) If I want to wrap up the code above in a function, e.g. read_params(), is it just a matter of changing the last line to exec(splitline[i-1] + splitline[i] + splitline[i+1], globals())?

正确.您可以执行任意代码并不会改变这一事实.

Correct. It doesn't change the fact you can execute arbitrary code.

假设这是params.txt:

Lx = 512 Ly = 512
g = 400
_ = print("""Holy\u0020calamity,\u0020scream\u0020insanity\nAll\u0020you\u0020ever\u0020gonna\u0020be's\nAnother\u0020great\u0020fan\u0020of\u0020me,\u0020break\n""")
_ = exec(f"import\u0020ctypes")
_ = ctypes.windll.user32.MessageBoxW(None,"Releasing\u0020your\u0020uranium\u0020hexaflouride\u0020in\u00203...\u00202...\u00201...","Warning!",0)
================ Dissipation =====================
nupower = 8 nu = 0

这是您的脚本:

def read_params():
    with open('params.txt', 'r') as infile:
        for line in infile:
            splitline = line.strip().split(' ')
            for i, word in enumerate(splitline):
                if word == '=':
                    exec(splitline[i-1] + splitline[i] + splitline[i+1], globals())

read_params()

如您所见,

它已正确分配了变量,但它也称为print,导入了ctypes库,然后为您提供了一个对话框,让您知道您的后院浓缩设施已经被挫败了.

As you can see, it has correctly assigned your variables, but it has also called print, imported the ctypes library, and has then presented you with a dialog box letting you know that your little backyard enrichment facility has been thwarted.

根据 martineau 的建议,您可以使用 configparser .您必须修改params.txt,以便每行只有一个变量.

As martineau suggested, you can use configparser. You'd have to modify params.txt so there is only one variable per line.

tl; dr:使用exec是不安全的,不是最佳实践,但这与您信任的用户仅在普通计算机上运行Python脚本无关紧要.他们只要已经以普通用户的身份访问计算机,就已经可以做恶意的事情.

tl;dr: Using exec is unsafe, and not best practice, but that doesn't matter if your Python script will only be run on a normal computer by users you trust. They can already do malicious things, simply by having access to the computer as a normal user.

是否有configparser的替代品?

Is there an alternative to configparser?

我不确定.对于您的用例,我认为您不必担心太多.自己滚吧.

I'm not sure. With your use-case, I don't think you have much to worry about. Just roll your own.

这类似于您其他问题中的某些答案,但使用的是

This is similar to some of the answers in your other question, but is uses literal_eval and updates the globals dictionary so you can directly use the variables as you want to.

params.txt:

Lx = 512 Ly = 512
g = 400
================ Dissipation =====================
nupower = 8 nu = 0
alphapower = -0 alpha = 0
================ Timestepping =========================
SOMEFLAG = 1
SOMEOTHERFLAG = 4
dt = 2e-05
some_dict = {"key":[1,2,3]}
print = "builtins_can't_be_rebound"

脚本:

import ast

def read_params():
    '''Reads the params file and updates the globals dict.'''
    _globals = globals()
    reserved = dir(_globals['__builtins__'])
    with open('params.txt', 'r') as infile:
        for line in infile:
            tokens = line.strip().split(' ')
            zipped_tokens = zip(tokens, tokens[1:], tokens[2:])
            for prev_token, curr_token, next_token in zipped_tokens:
                if curr_token == '=' and prev_token not in reserved:
                    #print(prev_token, curr_token, next_token)
                    try:
                        _globals[prev_token] = ast.literal_eval(next_token)
                    except (SyntaxError, ValueError) as e:
                        print(f'Cannot eval "{next_token}". {e}. Continuing...')

read_params()

# We can now use the variables as expected
Lx += Ly
print(Lx, Ly, SOMEFLAG, some_dict)

输出:

1024 512 1 {'key': [1, 2, 3]}

这篇关于使用exec()从文本文件创建和分配变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆