文章来自《Python cookbook》.

翻译仅仅是为了个人学习,其它商业版权纠纷与此无关!

-- 0.706 [2004-09-29 18:39:31]

Evaluating Code Inside Strings 字符串内代码的求值

Credit: Joonas Paalasmaa

问题 Problem

You have a string that contains embedded Python expressions, and you need to copy the string while evaluating those expressions.

你有一个包含嵌入Python表达式的字符串,你需要拷贝字符串,同时对表达式求值。

解决 Solution

This recipe's trick is to use the % string-formatting operator's named-values variant.That variant normally takes a dictionary as the righthand operand, but in fact it can take any mapping, so we just prepare a rather special mapping for the recipe's purpose:

这个配方的窍门是使用'%'字符串格式操作符的‘命名值’(named-values)变体。该变体正常情况下需要字典当作右边的运算元,但是事实上它可以使用任何映射类型,因此,我们就为配方的目的准备一个相当特别的映射:

   1 class Eval:
   2     """mapping that does expression evaluation when asked to fetch an item """
   3     def __getitem__(self, key):
   4         return eval(key)

Now we can perform feats such as:

现在我们能完成表演了, 像是 :

   1 >>> number = 20
   2 >>> text = "python"
   3 >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % Eval(  )
   4 Python 2.2 rules!

== 讨论 Discussion ==

This recipe can be seen as a templating task, akin to Recipe 3.22 and Recipe 3.23, but it is substantially simpler, because it needs to handle only embedded expressions, not statements.However, because the solution is so much simpler and faster than the general templating ones, it's better to think of this as a totally separate task.

这一份配方可以被视为一件模板工作,类似于食谱3.22和食谱3.23,但是因为它只需要处理嵌入的表达式而不是语句,所以它实质上还是比较简单的。然而,因为本解决方案与通常的模板相比,是如此简单和快速,把这当做一件完全独立的工作,还是比较好的。

In Python, the % operator of strings is typically used for normal formatting.The values to be interpolated in the string are the items of the righthand side, which is either a tuple, for unnamed-value formatting, or a mapping, for named-value formatting (where format items have forms such as %(name)s).The mapping is often obtained by functions such as the built-in vars, which returns a dictionary that represents the current status of local variables.

在 Python中, % 字符串操作符典型地用作正常的格式化工作。 在字符串中用来替换的值是右边的项目,这或者是tuple,为‘无名值’(unnamed-value)格式,或是一个映射,为‘命名值(named-value)’格式(这里格式项的形式是在 %(name)s)。映射经常从一个函数获得,如内建的 vars ,它返回一个表示局部变量当前状态的字典。

Named-value formatting is actually much more flexible.For each name string in the format, which is enclosed in parentheses after the % character that denotes the start of a format item in the format string, Python calls the get-item method of the righthand-side mapping (e.g., the special method _ _getitem_ _, when the righthand side is an instance object).That method can perform the necessary computation.The recipe shows off this possibility by simply delegating item-fetching to the built-in function eval, which evaluates the name as an expression.This can be very useful in practice, but as presented in the solution, it's limited to accessing global variables of the module in which the Eval class is itself defined.That makes it unwieldy for most practical purposes.

命名值(Named-value)格式实际上要灵活得多。因为对格式中的每个名字字符串格式,它被放在刮弧中,在格式串中跟在指示格式项开始的‘%’字符的后边,Python将调用右边映射的get-item方法.(举例来说,当右边是一个实例对象的时候,调用特殊方法 _ _getitem_ _ )。该方法能完成必需的计算。本配方只是展现了这种可能性,简单地把项目获取委派给内建的函数 eval,把名字作为表达式求值。这在实践中可能是非常有用的,但是如解决方案所呈现,它被限制为只存取定义了Eval类的模块的全局变量。那使它很难适合于大多数实践。

This problem is easily fixed, of course, because the sys._getframe function (in Python 2.1 and later) makes it easy to learn about your caller's local and global variables.So, you can tailor the evaluation environment:

当然这个问题容易被修正,因为 sys._getframe 函数(在Python2.1中和稍后)使得认识到调用者的局部和全局的变量成为很容易的事情。因此,你能定制求值环境:

   1 import sys
   2 class Evalx:
   3     def _ _init_ _(self, locals=None, globals=None):
   4         if locals is None: self.locals = sys._getframe(1).f_locals
   5         else: self.locals = locals
   6         if globals is None: self.globals = sys._getframe(1).f_globals
   7         else: self.globals = globals
   8     def _ _getitem_ _(self, name):
   9         return eval(name, self.globals, self.locals)

See Recipe 14.9 for a way to get the same functionality in other, older versions of Python.

参看食谱14.9,还有其它的实现相同的机制的方法,可以用在Python的旧版本中。

Any instance of the Evalx class can now be used for expression evaluation, either with explicitly specified namespaces or, by default, with the local and global namespaces of the function that instantiated it.

现在,任何Evalx类的实例,无论是明确指定了名字空间,还是缺省采用实例化它的局部和全局名字空间,都能用于表达式求值。

参考 See Also

Recipe 3.22, Recipe 3.23, and Recipe 14.9.