使用实例变量作为命名格式替换

时间:2012-12-07 21:38:34

标签: python

我正在编写一个生成C ++程序的Python程序。有很多这样的代码实例:

class TestBlock(object):
    def __init__(self, mod, name, casetype, generator):
        self.mod = mod
        self.name = name
        self.casetype = casetype
        self.generator = generator

    def fullname(self):
        return "{mod}.{name}".format(**self.__dict__)

    def write_cases(self, outf):
        outf.write("const {casetype} {mod}_{name}[] = {{\n"
                   .format(**self.__dict__))
        for case in self.generator():
            outf.write("  { " + case + " },\n")
        outf.write("};\n\n")

"text {subst}".format(**self.__dict__)构造是我发现使self的实例变量可用作命名替换的唯一方法,而且它很难看,我不喜欢它。我希望能够写"text {subst}".format(self);这是可能的,如果是的话,怎么样?我知道"text {0.subst}".format(self)可以开箱即用,"text {subst}".format(**self)可以使用一些特殊的方法,但是这两种方法都有额外的垃圾。

4 个答案:

答案 0 :(得分:2)

您可以将功能包装在一个函数中:

def fmt(msg, obj):
    return msg.format(**obj.__dict__)

然后:

def fullname(self):
    return fmt("{mod}.{name}", self)

答案 1 :(得分:1)

不,没有一般方法可以做你想要的。您可以编写您的类,使其具有__getitem__方法,该方法将项目访问权委托给属性访问权限(即使obj['foo']obj.foo相同)。但是,你不能使用项目访问权限。对于没有以这种方式定义项目访问权限的第三方类,您不能这样做。

你也可以创建一个实用程序函数来创建一个包装你的对象的映射对象,这样你就可以"text {subst}".format(wrapper(self)),但是如果`{0.subst}'对你来说已经是“太多了”也不会让你满意。

format方法不是将任何名称空间中的名称映射到格式字符串的通用方法。它映射映射中的键,而不映射对象上的属性。如果要在对象上映射属性,则必须以某种方式将它们放入映射中。 “{0.subst}”并不是那么糟糕。

答案 2 :(得分:0)

如果由于某种原因没有使用string.format(例如,你只是使用字符串,不需要格式迷你语言),那么这样的东西可能会有用:

import re


SUB_RE = re.compile(r"{(.*?)}")

class Formattable(object):
   def format(self, s):
      def repl(matchobj):
         var = matchobj.group(1).strip()
         try:
            retval = getattr(self, var)
         except AttributeError:
            retval = "ERROR"
         return retval

      return SUB_RE.sub(repl, s)



class Test(Formattable):
   def __init__(self, foo, bar, baz):
      self.foo = foo
      self.bar = bar
      self.baz = baz

t = Test('myFoo', 'bbbbbar', 'BAZZZZ')
print t.format("foo = {foo}")
print t.format("bar = {bar} but baz is {baz}")

打印

foo = myFoo
bar = bbbbbar but baz is BAZZZZ

答案 3 :(得分:0)

使用string.Template

这样的事情怎么样?
from string import Template

class TestBlock(object):
    def __init__(self, mod, name, casetype, generator):
        self.mod = mod
        self.name = name
        self.casetype = casetype
        self.generator = generator

    def subst(self, format):  # added method
        return Template(format).substitute(self.__dict__)

    def fullname(self):
        return self.subst("$mod.$name")

    def write_cases(self, outf):
        outf.write(self.subst("const $casetype ${mod}_$name[] = {{\n"))
        for case in self.generator():
            outf.write("  { " + case + " },\n")
        outf.write("};\n\n")

import sys

def generator():
    for v in ['normal', 'extraordinary']: yield v

tb = TestBlock('somemod', 'somename', 'somecasetype', generator)

sys.stdout.write('fullname: '+tb.fullname()+'\n')
tb.write_cases(sys.stdout)

输出:

fullname: somemod.somename
const somecasetype somemod_somename[] = {{
  { normal },
  { extraordinary },
};

请注意,可以使用$name${name}以两种不同的方式触发替换。两者都在上面使用过。