Python 字符串格式:% vs 串联
Python string formatting: % vs concatenation
我正在开发一个应用程序,我在其中执行一些请求以获取对象 ID。在每一个之后,我调用一个方法 (get_actor_info()
) 将此 id 作为参数传递(参见下面的代码)。
ACTOR_CACHE_KEY_PREFIX = 'actor_'
def get_actor_info(actor_id):
cache_key = ACTOR_CACHE_KEY_PREFIX + str(actor_id)
如您所见,我将 actor_id
转换为 string
并将其与前缀连接。但是,我知道我可以通过多种其他方式(例如 .format()
或 '%s%d'
)来实现,这导致了我的问题:就可读性而言,'%s%d'
会比字符串连接更好吗, 代码约定和效率?
谢谢
就性能而言,串联更好。在您的示例中,串联和替换都是可读的,但是当涉及到更复杂的模板时,替换在简单性和可读性竞赛中获胜。
例如,如果您有数据并且想在 html 中显示它,串联会让您头疼,而替换将简单易读。
这很容易成为一个 opinion-based 线程,但我发现在大多数情况下格式更易读,更易于维护。无需执行 "mental concatenation",更容易想象最终字符串的样子。例如,哪一个更具可读性?
errorString = "Exception occurred ({}) while executing '{}': {}".format(
e.__class__.__name__, task.name, str(e)
)
或:
errorString = "Exception occurred (" + e.__class__.__name__
+ ") while executing '" + task.name + "': " + str(e)
至于用%
还是.format()
,我可以比较客观的回答:用.format()
。 %
是 "old-style",根据 Python Documentation,它们可能很快就会被删除:
Since str.format()
is quite new, a lot of Python code still uses the %
operator. However, because this old style of formatting will eventually be removed from the language, str.format()
should generally be used.
更高版本的文档已不再提及这一点,但尽管如此,.format()
是未来的方式;使用它!
连接速度更快,但这不是问题。以 first-line 为目标,让你的代码具有可读性和可维护性,然后优化你需要稍后优化的部分。过早的优化是万恶之源;)
Python 3.6 将引入另一个选项:
ACTOR_CACHE_KEY_PREFIX = 'actor_'
def get_actor_info(actor_id):
cache_key = f'{ACTOR_CACHE_KEY_PREFIX}{actor_id}'
性能应该与 '{}{}'.format(ACTOR_CACHE_KEY_PREFIX, actor_id)
相当,但可以说更具可读性。
我猜想,如果要连接的所有项都是常量,则 python 可能会优化与 +
运算符的连接以提高性能。例如:
DB_PREFIX = 'prod_'
INDEX_PREFIX = 'index_'
CRM_IDX_PREFIX = DB_PREFIX + INDEX_PREFIX + 'crm_'
但大多数情况下,格式函数和运算符用于连接变量内容。例如:
crm_index_name = "{}_{}".format(CRM_IDX_PREFIX, index_id)
实际上,如果您使用 +
运算符像这样连接:
crm_index_name = CRM_IDX_PREFIX + '_' + str(index_id)
您正在以固定方式通过自定义代码定义格式。如果您使用带有命名引用的格式字符串,代码将更具可读性。例如:
crm_index_name = "{db_prefix}_{idx_prefix}_{mod_prefix}_{id}".format(
db_prefix=CRM_IDX_PREFIX,
idx_prefix=INDEX_PREFIX,
mod_prefix='crm',
id=index_id,
)
这样您就可以将格式定义为常量。例如:
IDX_FORMAT = "{db_prefix}_{idx_prefix}_{mod_prefix}_{id}"
crm_index_name = IDX_FORMAT.format(
db_prefix=CRM_IDX_PREFIX,
idx_prefix=INDEX_PREFIX,
mod_prefix='crm',
id=index_id,
)
并且这个结果更清楚,以防您将来需要更改格式。
例如,为了改变分隔符的顺序,你只需要改变
将字符串格式化为:
IDX_FORMAT = "{db_prefix}_{mod_prefix}_{idx_prefix}-{id}"
另外,为了调试,您可以将所有这些变量分配给一个字典,并将其作为关键字参数传递给格式函数:
idx_name_parts = {
'db_prefix': CRM_IDX_PREFIX,
'idx_prefix': INDEX_PREFIX,
'mod_prefix': 'crm',
'id': index_id,
}
crm_index_name = IDX_FORMAT.format(**idx_name_parts)
利用globals()函数我们还可以:
IDX_FORMAT = "{CRM_IDX_PREFIX}_{mod_prefix}_{INDEX_PREFIX}-{index_id}"
crm_index_name = IDX_FORMAT.format(mod_prefix = 'crm', **globals())
类似于 python3 的 formatted string literal:
crm_index_name = f"{CRM_IDX_PREFIX}_crm_{INDEX_PREFIX}-{index_id}"
我还看到 Internationalization 作为另一种使用上下文,其中格式化表达式比 +
运算符更有用。取以下代码:
message = "The account " + str(account_number) + " doesn't exist"
如果您将 gettext module 之类的翻译功能与 +
运算符一起使用,它将是:
message = _("The account ") + str(account_number) + _(" doesn't exist")
所以最好翻译整个格式字符串:
message = _("The account {account_number} doesn't exist").format(account_number)
以便完整的消息在西班牙语翻译文件中更有意义:
#: main.py:523
msgid "The account {account_number} doesn't exist"
msgstr "La cuenta {account_number} no existe."
这在翻译成自然语言时特别有用,这些自然语言的语法要求会改变句子的顺序,例如 德语 语言。
我正在开发一个应用程序,我在其中执行一些请求以获取对象 ID。在每一个之后,我调用一个方法 (get_actor_info()
) 将此 id 作为参数传递(参见下面的代码)。
ACTOR_CACHE_KEY_PREFIX = 'actor_'
def get_actor_info(actor_id):
cache_key = ACTOR_CACHE_KEY_PREFIX + str(actor_id)
如您所见,我将 actor_id
转换为 string
并将其与前缀连接。但是,我知道我可以通过多种其他方式(例如 .format()
或 '%s%d'
)来实现,这导致了我的问题:就可读性而言,'%s%d'
会比字符串连接更好吗, 代码约定和效率?
谢谢
就性能而言,串联更好。在您的示例中,串联和替换都是可读的,但是当涉及到更复杂的模板时,替换在简单性和可读性竞赛中获胜。
例如,如果您有数据并且想在 html 中显示它,串联会让您头疼,而替换将简单易读。
这很容易成为一个 opinion-based 线程,但我发现在大多数情况下格式更易读,更易于维护。无需执行 "mental concatenation",更容易想象最终字符串的样子。例如,哪一个更具可读性?
errorString = "Exception occurred ({}) while executing '{}': {}".format(
e.__class__.__name__, task.name, str(e)
)
或:
errorString = "Exception occurred (" + e.__class__.__name__
+ ") while executing '" + task.name + "': " + str(e)
至于用%
还是.format()
,我可以比较客观的回答:用.format()
。 %
是 "old-style",根据 Python Documentation,它们可能很快就会被删除:
Since
str.format()
is quite new, a lot of Python code still uses the%
operator. However, because this old style of formatting will eventually be removed from the language,str.format()
should generally be used.
更高版本的文档已不再提及这一点,但尽管如此,.format()
是未来的方式;使用它!
连接速度更快,但这不是问题。以 first-line 为目标,让你的代码具有可读性和可维护性,然后优化你需要稍后优化的部分。过早的优化是万恶之源;)
Python 3.6 将引入另一个选项:
ACTOR_CACHE_KEY_PREFIX = 'actor_'
def get_actor_info(actor_id):
cache_key = f'{ACTOR_CACHE_KEY_PREFIX}{actor_id}'
性能应该与 '{}{}'.format(ACTOR_CACHE_KEY_PREFIX, actor_id)
相当,但可以说更具可读性。
我猜想,如果要连接的所有项都是常量,则 python 可能会优化与 +
运算符的连接以提高性能。例如:
DB_PREFIX = 'prod_'
INDEX_PREFIX = 'index_'
CRM_IDX_PREFIX = DB_PREFIX + INDEX_PREFIX + 'crm_'
但大多数情况下,格式函数和运算符用于连接变量内容。例如:
crm_index_name = "{}_{}".format(CRM_IDX_PREFIX, index_id)
实际上,如果您使用 +
运算符像这样连接:
crm_index_name = CRM_IDX_PREFIX + '_' + str(index_id)
您正在以固定方式通过自定义代码定义格式。如果您使用带有命名引用的格式字符串,代码将更具可读性。例如:
crm_index_name = "{db_prefix}_{idx_prefix}_{mod_prefix}_{id}".format(
db_prefix=CRM_IDX_PREFIX,
idx_prefix=INDEX_PREFIX,
mod_prefix='crm',
id=index_id,
)
这样您就可以将格式定义为常量。例如:
IDX_FORMAT = "{db_prefix}_{idx_prefix}_{mod_prefix}_{id}"
crm_index_name = IDX_FORMAT.format(
db_prefix=CRM_IDX_PREFIX,
idx_prefix=INDEX_PREFIX,
mod_prefix='crm',
id=index_id,
)
并且这个结果更清楚,以防您将来需要更改格式。 例如,为了改变分隔符的顺序,你只需要改变 将字符串格式化为:
IDX_FORMAT = "{db_prefix}_{mod_prefix}_{idx_prefix}-{id}"
另外,为了调试,您可以将所有这些变量分配给一个字典,并将其作为关键字参数传递给格式函数:
idx_name_parts = {
'db_prefix': CRM_IDX_PREFIX,
'idx_prefix': INDEX_PREFIX,
'mod_prefix': 'crm',
'id': index_id,
}
crm_index_name = IDX_FORMAT.format(**idx_name_parts)
利用globals()函数我们还可以:
IDX_FORMAT = "{CRM_IDX_PREFIX}_{mod_prefix}_{INDEX_PREFIX}-{index_id}"
crm_index_name = IDX_FORMAT.format(mod_prefix = 'crm', **globals())
类似于 python3 的 formatted string literal:
crm_index_name = f"{CRM_IDX_PREFIX}_crm_{INDEX_PREFIX}-{index_id}"
我还看到 Internationalization 作为另一种使用上下文,其中格式化表达式比 +
运算符更有用。取以下代码:
message = "The account " + str(account_number) + " doesn't exist"
如果您将 gettext module 之类的翻译功能与 +
运算符一起使用,它将是:
message = _("The account ") + str(account_number) + _(" doesn't exist")
所以最好翻译整个格式字符串:
message = _("The account {account_number} doesn't exist").format(account_number)
以便完整的消息在西班牙语翻译文件中更有意义:
#: main.py:523
msgid "The account {account_number} doesn't exist"
msgstr "La cuenta {account_number} no existe."
这在翻译成自然语言时特别有用,这些自然语言的语法要求会改变句子的顺序,例如 德语 语言。