微信号:pythonbuluo

介绍:最专业的Python社区,有每日推送,免费电子书,真人辅导,资源下载,各类工具.我已委托“维权骑士”(rightknights.com)为我的文章进行维权行动

剧透:Python3.6中的f字符串

2016-02-22 09:35 Python程序员


Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发


对于一个声称关注于以一个正确的方式去处理大部分情形的语言而言,python里面的字符串格式化正在受着猛烈的冲击,而且每一年都变得更加多种多样。以python 3.6开始,我们有3种方式格式化字符串,(简单的外部连接或者使用string.Template):

  • 使用%操作符

  • str.format

  • 内插替换字符串


(如果你没有耐心去阅读这些,我也会在2016年2月份的下一个PyGraz meetup中以一些例子简要的延伸谈论一下)

%-格式化


%-格式化至少从版本1.0开始就是python的一部分了,如果你做了用python 3以前的python版本做了一些事后,你就应该知道这些。

    "%s %s" % ('Hello', 'World',)



这或多或少等同于C中的sprintf。这虽然完成了工作,但是你还必须要围绕着它做相当多的工作。


因为这只支持有限的类型集,所以在将其传递给字符串格式器之前你必须在将你的自定义对象转化至这些类型集中的一种。


许多年以后,原始的字符串数据类型以一种格式方式而延伸了:

str.format()


这同一些像上下文管理器的东西一并载入了2008年8月发布的python 2.6中。就像在PEP-3101中详细讲的一样,它尝试着去处理一些老式%二进制操作符中的短板,比如%只支持有限的类型集或者实际上处理整个表达式的右侧组成部分,而这会在一些特殊的条件下会导致错误。

    >>> "%s" % ("lala",)
    'lala'
    >>> "%s" % "lala"
    'lala'


因为.format是一种方法而不是一种操作符(对应到一种二进制方法),处理的参数更加明确。如果你遇到一个字符串,让它就会被解释成为字符串。如果你遇到一个只包含一个字符串的元组,它就会被解释成一个包含一个字符串的元组:

    >>> "{}".format("lala")
    'lala'
    >>> "{}".format(("lala",))
    "('lala',)"


相比于%,它也支持提供给你参数名而不需要使用字典:

   "{firstname} {lastname}".format(firstname="Horst", lastname="Gutmann")


最开始,这原本打算是作为%操作符的完全代替(计划打击python 3.1中的老式格式化函数),但是这永远都不可能发生了,因为这个字符串格式器的核心特点都与老式的%操作符大部分都是相似的,但就语法稍微有点不一样以及就我看而言更加直观而已。事实上,正是因为如此,Ulrich于是就和我创造了pyformat.info来帮助人们过渡到新的系统。


但是很显然的是,PEP-3101并不会在只消除老式的特点集上就停止脚步,它依旧引入了一个协议来允许与自定义类之间更加通用的交互。

    class Country:
        def __init__(self, name, iso):
            self.name, self.iso = name, iso

        def __format__(self, spec):
            if spec == 'short':
                return self.iso
            return self.name

    country = Country("Austria", "AUT")

    print("{}".format(country))
    print("{:short}".format(country))


你能将__format__方法想象成为一个__str__来进行字符串格式化,这样你就能通过各种选项。一旦在你的对象中有__format__方法,它就会被用来替代__str__当你使用format-method时(除非你做了一些像"{!s}".format(country)"事情的时候)


实际上你能在python 3.4的datatime.date类中找到一个很好地例子去解释怎么使用它。

    class date:
        ...
        def __format__(self, fmt):
            if len(fmt) != 0:
                return self.strftime(fmt)
            return str(self)


这让你在“parent”字符串格式中直接格式化日期,而你不再首先将日期转化成字符串然后再将其传递到字符串格式器中:

    import datetime
    print("Today is {:%A}".format(datetime.datetime.now()))
    # Today is Thursday


PEP-0498:字符串内插


尽管这就是现在进行字符串格式化的推荐方式,但是.format太繁琐了:

    a = "Hello"
    b = "World"
    "{} {}".format(a, b)
    # vs.
    "%s %s" % (a, b,)


pep-0498通过提供在其他语言如Ruby,Scala以及Perl中已经普及相当长一段时间的东西:内插字符串,尝试着去改善这种处境。其中表达式能够直接被整合进字符串,而这就意味着你不用明确地调用任何额外的函数。


ES2015把这个特性引入到JavaScript-world中的“recently”中,这被称为“模板字符串”:

    const username = "Horst";
    const welcomeMsg = `Hello, ${username}!`;


在python中反引号在python 3.0以上版本中已成为历史了,因此它们并不可得。再次引入它们可能会再一次影响python的基本语法。作为代替,另外的文字前缀被引入了:f。

    a = "Hello"
    b = "World"
    f"{a} {b}"
    f"{a + ' ' + b}"


你不再需要直接调用一个字符串的.format()方法,但是要简单地用前缀f来标记格式以及内联最终字符串中你想要包括的表达式,不然它们就会被期望着去提供如同你从.format()函数得到的相同功能。这些格式化字符串也在文档中被称为“f字符串”。


那事实上看起来十分美好,但因为python 3.6会在未来的12个月后才能够发布,你恐怕还要等上一段时间。话虽这么说,代码却已经在那儿了,所以你能做的就是获取一个python 3.6预发布版本或者使用一些像pyenv的小诀窍,然后让它运行就行了。


其实还有很多,这里有其他的PEP(0501),它想要引入i-strings而这类字符串导致了字符串的懒惰计算,以至于例如你能在最终评估之前能做一些国际化(i18n)或者安检。虽然这个提案已延缓至进一步的讨论,但这看起来是个很好的想法。


但是回到f-strings:如果你想要去了解更多关于为什么字符串内插解决了它存在的方式,那就请看一看PEP-0502,这里面包括了从其他语言上获得这个特性的灵感以及背后的动机的详细讨论。


英文原文:https://zerokspot.com/weblog/2015/12/31/new-string-formatting-in-python/

译者:bio_fresher

 
Python程序员 更多文章 如何使用中文语音编写Python3程序? PyCon 2014视频集锦 《微信思维》送书活动 简明Python教程--介绍 控制流--Python简明教程
猜您喜欢 R语言入门第八讲:编码分类变量(factor) Serverless简介 广州传智播客7月就业报道 想要打造极致的用户体验?用 AppSee 透析二进制程序函数调用关系