Use str.format() to access object attributes

Posted by Wang Zhihao on 2016-11-07

今天下午看到如下几段代码,发现这其中的str.format()和之前看到过的不太一样。

@classmethod
def get_multi_by_message(cls, message, sequence=1):
sql = ('select {columns} from {table} where message_id=:message_id and '
'sequence=:sequence').format(columns=','.join(cls.columns), table=cls.table)
params = dict(message_id=message.id_, sequence=sequence)
rs = db.execute(sql, params).fetchall()
db.commit()
return [cls(*r) for r in rs]
@classmethod
def get_max_sequence_by_message(cls, message):
sql = ('select max(sequence) from {.table} where message_id=:message_id').format(cls)
params = dict(message_id=message.id_)
r = db.execute(sql, params).fetchone()
db.commit()
return r[0] or 0

我发现第二个方法里有 '{.table}'.format(cls)这样的写法,和第一个方法中的有明显的不同。不禁有这样的疑问:

  • {.table}{table} 有什么不同
  • 在什么情况下format()的参数可以只写cls而不写object attribute

查阅了一些资料,我做了以下的尝试:

class Test(object):
def __init__(self, a, b):
self.a = a
self.b = b
obj = Test(111, 222)
print "a={a}, b={b}".format(a=obj.a, b=obj.b)

这是最常见的一种str.format()的情况,很显然这是正确的,输入结果为:

a=111, b=222

接下来尝试这一句:

print "a={a}, b={b}".format(obj)
Traceback (most recent call last):
File "test.py", line 8, in <module>
print "a={a}, b={b}".format(obj)
KeyError: 'a'

这个错误在预料之中,str.format()的参数列表里没有a这个key,于是报错了。

那接下来尝试这一句:

print "a={.a}, b={.b}".format(obj)
Traceback (most recent call last):
File "test.py", line 8, in <module>
print "a={.a}, b={.b}".format(obj)
IndexError: tuple index out of range

竟然爆出了IndexError,具体原因是tuple index out of range
这说明什么呢?说明当str中只有一个replacement fields的时候才可以在参数中直接写cls。为了验证这一点,执行下面这行:

print "a={.a}".format(obj)
a=111

的确如此。
而且当我们想通过.format(obj)直接获取obj.a的时候我们必须用{.a}而不是{a}

那么问题又来了,如果我有不止一个replacement fields,我又想直接获取(多个)object attributes,怎么操作呢?
其实是有办法的,代码如下:

print "a={0.a}, b={0.b}".format(obj)
a=111, b=222

Reference