首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何将Python表达式转换为字符串

如何将Python表达式转换为字符串
EN

Stack Overflow用户
提问于 2015-06-17 21:19:02
回答 2查看 3.2K关注 0票数 1

我想将用户输入表达式输出到一个字符串。

原因是输入表达式是用户定义的。我想输出表达式的结果,打印导致这个结果的语句。

代码语言:javascript
复制
import sys
import shutil  

expression1 = sys.path
expression2 = shutil.which

def get_expression_str(expression):
    if callable(expression):
        return expression.__module__ +'.'+ expression.__name__
    else:
        raise TypeError('Could not convert expression to string')

#print(get_expression_str(expression1))
# returns : builtins.TypeError: Could not convert expression to string
#print(get_expression_str(expression2))
# returns : shutil.which

#print(str(expression1))
#results in a list like ['/home/bernard/clones/it-should-work/unit_test', ...  ,'/usr/lib/python3/dist-packages']

#print(repr(expression1))
#results in a list like ['/home/bernard/clones/it-should-work/unit_test', ...  ,'/usr/lib/python3/dist-packages']

我研究了Python inspect模块,但即使

代码语言:javascript
复制
inspect.iscode(sys.path)

返回False

如果有人想知道为什么它与使用functools.partial解析成表达式的字符串相反,请参阅parse statement string

背景。

程序应该是有效的。应该是这样,但并不总是这样。因为程序需要特定的资源、操作系统、操作系统版本、其他包、文件等,所以每个程序需要不同的要求(资源)才能正常运行。无法预测需要哪些特定需求。系统最清楚哪些资源是可用的,哪些是不可用的。因此,与其手动检查所有设置和配置,不如让帮助程序为您完成此操作。

因此,程序的用户或开发人员需要指定他的需求,以及如何检索这些信息的语句:表达式。它可以使用eval来执行。有可能。就像StackOverflow上提到的,eval是邪恶的。使用黑名单很难保证eval的使用安全,参见:http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html使用多个提示,因此我使用了一个命名元组、一个字符串和一个函数来与用户输入的字符串进行比较。

白名单比黑名单更好。只有当解析的表达式字符串与"bare_expression“匹配时,才会返回一个表达式。此白名单包含如何处理f.e.的详细信息。"unit_of_measurement“。它很难解释什么和为什么,但这是必要的。命名元组的列表不仅仅是一个白名单,而且是这样定义的:

代码语言:javascript
复制
Expr_UOfM = collections.namedtuple('Expr_UOfM', ['bare_expression', 'keylist', 'function', 'unit_of_measurement', 'attrlist'])

与(非常有限的)列表匹配的命名元组:

代码语言:javascript
复制
Exp_list = [Expr_UOfM('sys.path', '' , sys.path, un.STR, []),
            Expr_UOfM('shutil.which', '', shutil.which, None, [])] 

这个列表可能很长,其内容对于进一步的正确处理至关重要。请注意,第一个和第三个字段非常相似。应该有一个单一的参考点,但对我来说,这是在这个时刻不可能的。注意:字符串:' sys.path‘等于用户输入(一部分),表达式:sys.path是命名元组列表的一部分。良好的分离,限制可能的滥用。如果字符串和表达式不是100%相同,可能会发生奇怪的行为,这很难调试。因此,它希望使用get_expression_str函数检查第一个和第三个字段是否相同。只是为了程序的总体健壮性。

我使用Python 3.4

EN

回答 2

Stack Overflow用户

发布于 2015-06-17 21:30:48

为什么不使用eval

代码语言:javascript
复制
>>> exp1 = "sys.path"
>>> exp2 = "[x*x for x in [1,2,3]]"
>>> eval(exp1)
['', 'C:\\Python27\\lib\\site-packages\\setuptools-0.6c11-py2.7.egg', 'C:\\Pytho
n27\\lib\\site-packages\\pip-1.1-py2.7.egg', 'C:\\Python27\\lib\\site-packages\\
django_celery-3.1.1-py2.7.egg', 'C:\\Python27\\lib\\site-packages\\south-0.8.4-p
y2.7.egg', 'C:\\Windows\\system32\\python27.zip', 'C:\\Python27\\DLLs', 'C:\\Pyt
hon27\\lib', 'C:\\Python27\\lib\\plat-win', 'C:\\Python27\\lib\\lib-tk', 'C:\\Py
thon27', 'C:\\Python27\\lib\\site-packages', 'C:\\Python27\\lib\\site-packages\\
PIL']
>>> eval(exp2)
[1, 4, 9]
票数 0
EN

Stack Overflow用户

发布于 2018-10-03 03:48:42

您可以使用inspect.getsource()并将您的表达式包装在一个lambda中。然后,您可以使用此函数获得一个表达式:

代码语言:javascript
复制
def lambda_to_expr_str(lambda_fn):
    """c.f. https://stackoverflow.com/a/52615415/134077"""
    if not lambda_fn.__name__ == "<lambda>":
        raise ValueError('Tried to convert non-lambda expression to string')
    else:
        lambda_str = inspect.getsource(lambda_fn).strip()
        expression_start = lambda_str.index(':') + 1
        expression_str = lambda_str[expression_start:].strip()
        if expression_str.endswith(')') and '(' not in expression_str:
            # i.e. l = lambda_to_expr_str(lambda x: x + 1) => x + 1)
            expression_str = expression_str[:-1]
        return expression_str

用法:

代码语言:javascript
复制
$ lambda_to_expr_str(lambda: sys.executable)
> 'sys.executable'

代码语言:javascript
复制
$ f = lambda: sys.executable
$ lambda_to_expr_str(f)
> 'sys.executable'

然后使用eval

代码语言:javascript
复制
$ eval(lambda_to_expr_str(lambda: sys.executable))
> '/usr/bin/python3.5'

请注意,您可以使用此方法获取参数,并将它们与eval的本地参数一起传递。

代码语言:javascript
复制
$ l = lambda_to_expr_str(lambda x: x + 1)  #  now l == 'x + 1'
$ eval(l, None, {'x': 1})
> 2

这里的是龙。这种方法有很多病理情况:

代码语言:javascript
复制
$ l, z = lambda_to_expr_str(lambda x: x + 1), 1234
$ l
> 'x + 1), 1234'

这是因为inspect.getsource获得了声明了lambda的整个代码行。获取使用def声明的函数的源代码可以避免这个问题,但是将函数体传递给eval是不可能的,因为这可能会有副作用,例如设置变量等。Lambda的在Python 2中也会产生副作用,所以更多的龙躺在Python-3之前的地方。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30892844

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档