简体   繁体   English

python 如何解释字符串中的变量属性

[英]How does python interpret variable attributes in strings

Suppose I have a string like this假设我有一个这样的字符串

"Style.BRIGHT + 'BRIGHT' + '\\n' + Style.DIM + 'DIM' + '\\n' + Style.NORMAL + 'NORMAL'"

I try to print it directly我尝试直接打印

from colorama import Style

s = "Style.BRIGHT + 'BRIGHT' + '\\n' + Style.DIM + 'DIM' + '\\n' + Style.NORMAL + 'NORMAL'"
print(s)

Output: Output:

Style.BRIGHT + 'BRIGHT' + '\n' + Style.DIM + 'DIM' + '\n' + Style.NORMAL + 'NORMAL'

This is not the result I want, I want it to display the result in the terminal like this.这不是我想要的结果,我希望它像这样在终端中显示结果。

在此处输入图像描述

So I tried eval and it worked.所以我尝试了eval并且它起作用了。

from colorama import Style

s = "Style.BRIGHT + 'BRIGHT' + '\\n' + Style.DIM + 'DIM' + '\\n' + Style.NORMAL + 'NORMAL'"
print(eval(s))

Output: Output:

BRIGHT
DIM
NORMAL

Although it succeeded, it seems to be unsafe, I also tried adding the global variable {"Style": Style} , so it might be relatively safe.虽然成功了,但是好像不安全,我也试过添加全局变量{"Style": Style} ,这样可能比较安全。

But maybe I'll extract properties in other variables, like this xy , where x and y can be any value.但也许我会提取其他变量中的属性,例如xy ,其中 x 和 y 可以是任何值。 So it feels like eval doesn't apply.所以感觉 eval 不适用。

The answer of @jfs in this question seems to be what I want, and I modified the program. @jfs在这个question中的答案似乎是我想要的,我修改了程序。

from colorama import Style

import ast
import operator as op
# supported operators
operators = {ast.Add: op.add}


def eval_expr(expr):

    return eval_(ast.parse(expr, mode='eval').body)


def eval_(node):
    if isinstance(node, ast.Constant):  # <number>
        return node.n
    elif isinstance(node, ast.BinOp):  # <left> <operator> <right>
        return operators[type(node.op)](eval_(node.left), eval_(node.right))
    elif isinstance(node, ast.Attribute):
        return ast.unparse(node)
    else:
        raise TypeError(node)


s = "Style.BRIGHT + 'BRIGHT' + '\\n' + Style.DIM + 'DIM' + '\\n' + Style.NORMAL + 'NORMAL'"
print(eval_expr(s))

Output: Output:

Style.BRIGHTBRIGHT
Style.DIMDIM
Style.NORMALNORMAL

In the program the string Style.BRIGHT is converted into an ast.Attribute object, I don't know how to get its value( '\x1b[1m' ).在程序中,字符串Style.BRIGHT被转换为ast.Attribute object,我不知道如何获取它的值( '\x1b[1m' )。

In [1]: from colorama import Style

In [2]: Style.BRIGHT
Out[2]: '\x1b[1m'

If I use eval(ast.unparse(node)) it succeeds, but if so why not just use eval directly...如果我使用eval(ast.unparse(node))它会成功,但如果是这样,为什么不直接使用eval ......

So my question is:所以我的问题是:

  • How can I extract the primitive value corresponding to the ast.Attribute object?如何提取与ast.Attribute object 对应的原始值?

Or is there any other way to interpret the string.或者有没有其他方法来解释字符串。


The demo above is just one case, it can be applied to other cases.上面的demo只是一种情况,可以应用到其他情况。 For example, I want to define a macro, which is a string that adds and sums some properties of a class, which will be applied to other programs or processes.例如,我想定义一个宏,它是一个将 class 的某些属性相加和求和的字符串,它将应用于其他程序或进程。 Demo:演示:

class Base:

    a = 1
    b = 2


def get(cls):
    s = []
    for k, v in cls.__dict__.items():
        if k.startswith("_"):
            continue
        s.append(f"{cls.__name__}.{k}")
    return " + ".join(s)


s = get(Base)
print(s)

# Base.a + Base.b

Maybe my case is a bit unsatisfactory, but this problem may appear in a future scenario, maybe it's just me wanting to know how to deal with it.可能我的情况有点不尽人意,但是这个问题可能会出现在未来的场景中,也许只是我想知道如何处理。

NB.注意。 It would be hundred times better to use the correct object and not a string in the first place, starting with correct input is almost always more explicit and efficient than trying to fix a broken input.首先使用正确的 object 而不是字符串会好一百倍,从正确的输入开始几乎总是比尝试修复损坏的输入更明确和有效。

If you have a string with arbitrarily complex operations, you will need to understand its grammar, which is exactly what ast is doing, or blindly (and potentially unsafely) evaluate it with eval .如果您有一个包含任意复杂操作的字符串,您将需要了解它的语法,这正是ast正在做的事情,或者使用eval盲目地(并且可能不安全地)评估它。

That said, if you want to simplify your process in the particular case you showed , you need to do 3 things.也就是说,如果你想在你展示的特定情况下简化你的过程,你需要做 3 件事。 1- replace the Styler definitions with the string formatting codes they represent, 2- remove the quotes and +, 3- unescape the escaped newlines. 1- 将Styler定义替换为它们所代表的字符串格式代码,2- 删除引号和 +,3- 取消转义转义的换行符。

2 and 3 are quite easy to achieve, so I'll focus only on interpreting the codes here. 2 和 3 很容易实现,所以我将只专注于解释这里的代码。 You can use a regex to find the Styler definitions and re.sub to replace them safely with the actual formatting code.您可以使用正则表达式查找 Styler 定义并使用re.sub安全地将它们替换为实际的格式化代码。

from colorama import Style
import re

s = "Style.BRIGHT + 'BRIGHT' + '\\n' + Style.DIM + 'DIM' + '\\n' + Style.NORMAL + 'NORMAL'"

s2 = re.sub('Style\.[A-Z]+', lambda m: getattr(Style, m.group(0).split('.')[1]), s)

Output: Output:

"\x1b[1m + 'BRIGHT' + '\\n' + \x1b[2m + 'DIM' + '\\n' + \x1b[22m + 'NORMAL'"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM