我想将用户输入表达式输出到字符串。
原因是输入表达式是用户定义的。我想输出表达式的结果,和打印导致此结果的语句。
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.iscode(sys.path)
返回False
对于那些想知道为什么它是使用functools.partial解析为表达式的字符串的反向的人,请参阅parse statement string
程序应该有效。应该,但并非总是如此。因为程序需要特定的资源,操作系统,操作系统版本,其他包,文件等。每个程序都需要不同的要求(资源)才能正常运行。 无法预测需要哪种具体要求。系统最清楚哪些资源是可用的,哪些资源不可用。因此,不是手动检查所有设置和配置,而是让帮助程序为您执行此操作。
因此,程序的用户或开发人员将语句与语句一起指定如何检索此信息:表达式。哪个可以使用eval执行。可以。就像在StackOverflow上提到的那样,eval是邪恶的。 使用黑名单很难确保使用eval,请参阅:http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html 使用SO的多个提示我使用带有字符串的namedtuple来比较用户输入字符串和函数。
白名单比黑名单更好。仅当解析的表达式字符串与“bare_expression”匹配时,才返回表达式。 此白名单包含有关如何处理f.e的更多信息。 “unit_of_measurement”。它解释了什么和为什么,但这是必要的。 namedtuples的列表不仅仅是一个白名单,而是定义的:
Expr_UOfM = collections.namedtuple('Expr_UOfM', ['bare_expression', 'keylist', 'function', 'unit_of_measurement', 'attrlist'])
匹配(非常有限)列表的namedtuple:
Exp_list = [Expr_UOfM('sys.path', '' , sys.path, un.STR, []),
Expr_UOfM('shutil.which', '', shutil.which, None, [])]
此列表可能很长,内容对于进一步正确处理至关重要。注意第一和第三个字段非常相似。应该有一个参考点,但对我来说,这是不可能的。请注意字符串:'sys.path'等于用户输入的(一部分),表达式:sys.path是namedtuple列表的一部分。良好的分离,限制可能的滥用。 如果字符串和表达式不是100%相同,则可能会发生奇怪的行为,这很难调试。 所以它想要使用get_expression_str函数检查第一个和第三个字段是否相同。只是为了完全的稳健性 该程序。
我使用Python 3.4
答案 0 :(得分:0)
为什么不使用eval
?
>>> 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]
答案 1 :(得分:0)
您可以使用inspect.getsource()
并将表达式包装在lambda中。然后,您可以使用此函数获取表达式:
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
用法:
$ lambda_to_expr_str(lambda: sys.executable)
> 'sys.executable'
OR
$ f = lambda: sys.executable
$ lambda_to_expr_str(f)
> 'sys.executable'
然后与
进行评估$ eval(lambda_to_expr_str(lambda: sys.executable))
> '/usr/bin/python3.5'
请注意,您可以使用这种方法获取参数,并将其传递给eval的locals参数。
$ l = lambda_to_expr_str(lambda x: x + 1) # now l == 'x + 1'
$ eval(l, None, {'x': 1})
> 2
这里是龙。这种方法有很多病理情况:
$ 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之前的土地上还有更多的龙。