admin管理员组

文章数量:1530013

目录
一、格式占位符及函数str()、repr()、ascii()
1、格式占位符(格式转换符)
2、函数str()、repr()、ascii()
二、 f''、str.format()和str%()格式化表达式中对对象的引用
三、 f''、str.format()和str%()格式化表达式增加描述的字符

Python中f‘‘、str.format()和str%()的字符串格式化详解

       

       有时候我们需要在print()输出时对对象进行处理或描述,使得输出符合我们的要求,或更好地呈现结果以便我们理解(也即对输出结果增加可读性),这时候,我们可以对print()的打印对象进行一些相关设置,使得print()的打印输出是以一定的格式输出,以实现我们打印输出的要求,通常我们用f''、str.format()和str%()的字符串格式化(格式化字符串、格式化输出)来实现print的打印效果。当然,f''、str.format()和str%()也可以用在其它场景。f''字符串格式化通常称为f-string字符串格式化。

一、格式占位符及函数str()、repr()、ascii()

       对于f''、str.format()和str%()的字符串格式化的具体使用,有的会涉及到占位符,因而,这里先介绍python的格式占位符(format placeholder)。这三种字符串格式化也可以简写为f格式化、format格式化、%操作符格式化。

1、格式占位符(格式转换符)

        格式占位符,该名称起源于C语言,表示在该位置有输入或输出(比如:scanf()、printf()等函数中使用),占位符表示在该位置产生某种格式的数据,在python中,也可以理解为格式转换符,也有表示为对象做相关的转换的意思,这里沿用以前的称呼。下面表1-1中是几种常用的格式占位符(格式转换符)。

表1-1 常用格式占位符(格式转换符)

s

字符串 (采用str()的显示),也可用ns,n表示输出宽度,即输出的占位个数

r

字符串 (采用repr()的显示),也可用nr,n同上

a

字符串 (采用ascii()的显示),也可用na,n同上

c

单个字符,也可用nc,n同上

b

二进制整数,只能在f''、str.format()中使用,也可用nb,n同上

d

十进制整数,也可用nd,n同上

o

八进制整数,也可用no,n同上

x

十六进制整数,可以用X,也可用nx,n同上

f

十进制的浮点数,也即小数

.mf

m是精度,表示保留m位小数

n.mf

n表示输出宽度,即输出的占位个数,m表示保留m位小数,.m可以缺省

e

科学计数法,指数形式,底数为e(相当于10),也可用E

.me

m表示保留m位小数

n.me

n表示输出宽度,即输出的占位个数,m表示保留m位小数,.m可以缺省

g

若指数小于-4或指数大于5,则使用e,否则,默认用d或f,也可用G

.mg

保留m位(个)有效数字,若指数小于-4或大于m-1,则使用e,否则,使用d

n.mg

n为输出宽度,即输出的占位个数,m同上 ,值的形式同上,.m可以缺省

%

%字符

      上面列出的格式占位符在str%()、f''、str.format()中都会增加相应的符号,比如:str%()中的占位符会增加符号%,在f''和str.format()格式化表达式中是用其它符号。str%()不支持转换为二进制%b,会提示unsupported format character 'b'。

       python提供了多种形式的数据类型,这些数据类型实际是由字符型和数字型两大类型中衍生出来的,字符和数字也正是我们日常使用自然语言的基本形式,因而格式站位符主要也是针对字符和数字的。

2、函数str()、repr()、ascii()

       表1-1中格式占位符s采用的是函数str()的结果,获取适合人阅读的文本字符串。由于str()的结果适合人阅读,str()通常用于输出和显示给用户。

       格式占位符r采用的是函数repr()的结果,将对象转化为比较适合解释器读取的形式,也即获取对象的“官方、正式”字符串表示形式,其返回值也是字符串类型。由于repr()的返回值是字符串格式,因而也可以讲,repr()把对象转换为字符串表示。从使用角度上讲,很多时候,repr()函数给表达式相当于增加一对引号的作用。repr()通常用于开发和调试场景,能够保留对象的完整性,以便重新创建对象。

       函数str()调用__str__(),函数repr()调用__repr__()方法。方法__repr__()和__str__()的返回值必须是字符串格式。

       Python解释器在解释执行时,python中的任何一个对象都会对应一个类(这个类默认由元类type创建),这个对象也是由这个类实例化实现的,对象会备份类的属性。 python中所有类都默认继承object类的属性,而object类含有__str__()、__repr__()方法,因而python中的类都能继承__str__()、__repr__()方法。函数print()打印对象时会默认调用对象的__str__()或__repr__()方法,这两个方法的返回值是字符串格式,因而print()打印输出的对象应该是字符串格式,当这两个方法都存在时print()只调用__str__()方法。

       函数print()是从左到右的打印,其打印也是把执行的结果展现到窗口(即输出到屏幕)中,字符串中有转义符会执行转义符。print()打印展现在窗口的字符串是去掉了字符串的最外层一对引号的,方便人的阅读。

import os
'''os是“operating system”的缩写,os模块提供各种 Python 程序与操作系统进行交互的接口,
从而调用操作系统的部分功能来快速、高效地管理文件和目录,
是Python中整理文件和目录最为常用的模块,该模块提供了非常丰富的函数、方法用来处理文件和目录。'''

'''函数print()在打印时会默认调用__str__()或__repr__()方法,这两个方法的返回值是字符串格式,
因而print()打印输出的对象应该是字符串格式,当这两个方法都存在时print()只调用__str__()方法。
函数print()是从左到右的打印,其打印也是把执行的结果展现到窗口(即输出到屏幕)中,字符串中有转义符会执行转义符。
print()打印展现在窗口的字符串是去掉了字符串的最外层一对引号的,方便人的阅读。'''

'''repr()将对象转化为比较适合解释器读取的形式,也即获取对象的“官方、正式”字符串表示形式,
从使用角度上讲,很多时候,repr()函数相当于给表达式增加一对引号的作用。'''

#os.linesep是Python标准库中os模块的一个属性,
#os.linesep获取当前操作系统的换行符,换行符在不同的操作系统中是不一样的。
print(repr(os.linesep))#相当于得到''\r\n''字符串,由于是双层引号,会判断为一般字符,打印时去掉最外层引号。
print(os.linesep)#print()打印字符串'\r\n',遇到转义符会执行转义符。

sr1 = 'Hello,\nPython'
#print打印字符串,遇到转义符会执行转义符,展现在窗口的字符串是去掉了字符串的最外层引号的,方便人的阅读。
print(sr1)

#repr(sr1)实际获得的值为''Hello,Python\n'',
#print打印字符串,由于是双层引号,这里的\n在打印会判断为一般字符,而不是转义符,
#展现在窗口的字符串是去掉了字符串的最外层引号的,方便人的阅读,
#因而显示为'Hello,Python\n'。
print(repr(sr1))
#上面相当于下面。
#格式占位符表示该位置会产生一个什么格式的数据。
#str%()中格式占位符都会增加符号%,下面%r表示该位置产生repr()函数返回的字符串格式的数据,
#实际也是依次引用右边小括号的实参进行格式化。
print('%r'%(sr1))

#数字的字符串格式。
sr2=str(123)
#print打印字符串,遇到转义符会执行转义符,展现在窗口的字符串是去掉了字符串的最外层引号的,方便人的阅读。
print(sr2,type(sr2))
#sr2已经代表字符串,下面处理后相当于再增加引号,即''123'',
#print打印字符串,遇到转义符会执行转义符,展现在窗口的字符串是去掉了字符串的最外层引号的,方便人的阅读,
#因而打印出来的结果为'123'。
print(repr(sr2),type(repr(sr2)))
#相当于整型123增加引号变为字符串'123',
#print打印字符串,遇到转义符会执行转义符,展现在窗口的字符串是去掉了字符串的最外层引号的,方便人的阅读,
#因而打印显示的是字符串格式的123。
print(repr(123),type(repr(123)))

运行结果:

        repr()把对象转换为字符串表示,可以用eval()函数处理这个字符串,从而重新获取该对象并执行。

import datetime
today = datetime.datetime.now()
#下面两个效果一样,因为第一个print会自动调用方法__str__(),
#第二个print中相当于两次使用了方法__str__()。
print(today)
print(str(today))#适合人阅读的字符串。

print('\n')
#将对象转化为比较适合解释器读取的形式,
#然后print打印,也会自动调用方法__str__(),打印输出的也是字符串格式。
print(repr(today))
#上面repr()也可以理解为把对象转换为字符串表示,
#eval()函数的作用是将字符串解析为Python表达式,并执行该表达式。
rr1=repr(today)
print(eval(rr1))

运行结果:

        注意,repr(),eval()函数的上述用法不能称为序列化与反序列化,实现序列化和反序列化的转换,可以借助pickle、json等模块。我们讲到的str、list、tuple是常用的序列化数据类型,而集合(set)、函数的代码等都不是序列化的。

      方法__repr__()和__str__()的返回值是字符串格式。方法__repr__()和__str__()在类中被重写时,返回值应该为字符串格式的对象,否则会提示TypeError: __str__ returned non-string。 

       当类中重写了__repr__()方法,而没有重写__str__()方法,repr ()、print()作用类的实例化时会自动执行__repr__()方法。另外__repr__()方法的返回值应该为字符串格式,否则,提示异常TypeError: __str__ returned non-string。同理当类中重写了__str__()方法,而没有重写__repr__()方法时。

class Member:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def func(self):
        return (self.name, self.age)

    def __repr__(self):
        return 'Member(name,age).func()'

name='Bor'
age=23
#返回类实例对象地址。
im1 = Member(name,age)
#当类重写了__repr__()方法后,repr()或print()作用类的实例化时会自动执行__repr__()方法。
#注意__repr__()方法的返回值必须为字符串格式,否则会出现异常。
print(im1)
rr1=repr(im1) 

print(rr1)
#eval()函数的作用是将字符串解析为Python表达式,并执行该表达式。
print(eval(rr1))

运行结果:

      当类中都重写__str__()和__repr__()方法时,函数str()调用__str__(),函数repr()调用__repr__()方法,而print()作用类的实例化时默认只执行__str__()方法。

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def func(self):
        return 'name is %s,age is %d'%(self.name,self.age)

    def joy(self):
        return {self.name:self.age}

    def __repr__(self):
        return 'Student(name,age).func()'

    def __str__(self):
        return 'Student(name,age).joy()'

name='Bor'
age=23
it1=Student(name,age)
#类重写了__repr__()、__str__()方法, print()作用类的实例化时默认只执行__str__()方法。
print(it1)

rp1=repr(it1)#相当于调用__repr__()。
st1=str(it1)#相当于调用__str__()。
print(rp1)
print(st1)

#eval()函数的作用是将字符串解析为Python表达式,并执行该表达式。
print(eval(rp1))
print(eval(st1))

运行结果:

       

       表1-1中格式占位符a采用的是函数ascii()的结果,返回是根据ASCII编码标准解码的字符,若不能用ASCII编码,则会用 \x、\u (或 \U) 进行转义,然后增加引号,类似repr()函数,但repr()解码时的编码标准与ascii()不同。

sr1='abc\n'
#对字符串增加引号,是ASCII解码的字符串。
print(ascii(sr1),type(ascii(sr1)))
print('%a'%(sr1))

运行结果:

sr2='你好'
#对汉字字符串增加引号,不能用ASCII解码,则会用\x、\u进行转义。
print(ascii(sr2),type(ascii(sr2)))

print(repr(sr2),type(repr(sr2)))

print(sr2,type(sr2))

运行结果:

n1=129
#对整型增加引号,是ASCII解码的数字字符串。
print(ascii(n1),type(ascii(n1)))

print(repr(n1),type(repr(n1)))

print(str(n1),type(str(n1)))

运行结果:

       ascii()的结果用ASCII 编码标准解码或进行转义,然后增加引号。

       下面,我们将讲述f''、str.format()和str%()的字符串格式化的具体使用。f''字符串格式化通常称为f-string字符串格式化。

二、 f''str.format()str%()格式化表达式中对对象的引用

        f''、str.format()、str%()对对象的引用的基本形式为:

        f’{name}’, 该表达式不支持对参数对象的引用,其中name表示名称(对象的标识),是对对象的引用,这里的name是不能缺省的;

       ‘{name}’. format(),其中,format()的小括号里是参数,可以是位置参数或关键字参数,即支持str.format(*args,**kwargs),name也是对这里的实参的对象的引用,但这里的name是format()中的位置实参对应的序数(序数从0开始)或关键字参数的关键字,当format()中为关键字实参,name不能缺省,若引号里是对仅有的一个位置实参整体操作或按顺序对每个位置实参整体操作,则表示序数的name可以缺省,若是对位置实参进行局部操作,则表示序数的name不可以缺省;

       ‘%(name)’% (),该表达式不适合引用关键字参数,其中, 右边小括号()里是参数,若参数为字典,可以使用name对字典中的对象进行引用,否则,name缺省。另外,右边小括号()中若只有一个参数,这个小括号可以缺省。

       f''的name引用与参数无关,而str.format()、str%()的name引用与参数有关,而且str.format()、str%()对字典中的对象进行引用比较特殊,与关键字参数的引用相比有差异,str.format()、str%()对字典中的对象进行引用,只能是某些数据类型才能作为引用name,而且这个name是以标识符的形式(样式)进行引用,但name并不一定符合标识符的构成标准(规范),具体参加下面实例,下面实例是各格式表达式对对象的引用。

sr1,sr2='ab','cd'
te1 = {'kr': 'ij', 10: 31, '12': 89,'15y':76}
lt1=[1,2,3]

print("f'':")
#f''是通过名称引用对象,对字典的键值的引用是通过键名引用,这也是字典的引用方式。
print(f'{sr1},{sr2},{te1},{te1["kr"]},{te1[10]},{te1["12"]},{te1["15y"]}')

print('\nstr.format():')
#对于位置实参,str.format()若是按顺序引用小括号()中的位置实参,{}中可缺省序数。
#不能出现有的有序数,有的缺省序数这种形式。对于关键字实参,关键字不能缺省。
print('{},{z},{},{}'.format(sr1,sr2,te1,z=3))
#但引用对象的局部的元素时,应该使用序数。
print('{0},{1[0]},{2}'.format(sr1,sr2,te1))
#序数代表了对应的位置实参。
print('{1},{2},{0}'.format(sr1,sr2,te1))

#下面是借助键名对位置参数字典中的对象(键值)进行引用,
#但不支持键名为数字字符串的,其它都支持,并且引用方式类似标识符引用,
#而不是直接使用键名(字典的引用方式)。
#下面键名10、'15y'类似标识符进行引用,但不支持数字字符串键名'12',
#注意,对参数te1里面再次进行引用,这时不再是参数引用。
print('{0[kr]},{0[10]},{0[15y]}'.format(te1))

#下面是关键字参数进行引用,因为函数的关键字参数对应为变量,关键字参数实际也是变量,
#而变量名(变量名也是标识符)的首个符号不能是数字,因此,下面只能使用关键字kr。
#下面是对实参**te1进行解包,对关键字参数进行引用,具体可以参加前面讲到的动态参数。
print('{kr}'.format(**te1))

#下面是对位置实参的引用。
print('{2},{0},{1}'.format(*lt1))

#str.format()可以通过关键字引用关键字实参,也可以引用其局部元素。
print('{y},{y[1]}'.format(y=[7,8,9]))

print('\nstr%():')
#str%()不适合引用关键字参数。
#格式占位符表示该位置会产生一个什么格式的数据。
#str%()中格式占位符都会增加符号%,下面%s表示该位置产生字符串格式的数据,
#实际也是依次引用右边小括号的实参进行格式化。
print('%s,%s'%(sr1,sr2))
#借助键名对位置参数字典中的对象进行引用,
#但不支持数字的键名,其它都支持,并且引用方式类似标识符引用,
#而不是直接使用键名(字典的引用方式)。
#下面键名'kr'、'12'、'15y'类似标识符进行引用,但不支持数字键名10。
print('%(kr)s,%(12)s,%(15y)s'%(te1))

print('\n通过路径引用对象:')
class AA:
    a1=1
    a2=2

print(f'{AA.a1},{AA.a2}')
print(f'{AA().a1},{AA().a2}')
#下面只能变成关键字参数才能引用。
print('{t.a1},{t.a2}'.format(t=AA))
print('{t.a1},{t.a2}'.format(t=AA()))

运行结果:

       f''、str.format()、str%()的使用有一定互补性,各有自己的特点。而且,f''、str.format()可以不使用占位符,上面代码中f''、str.format()未使用占位符,但str%()需要占位符。f''的name必须存在,不能缺省。

      在python中,对对象的引用一般有三种基本形式。一种是借助序号来引用,比如: sr1[2],2是索引。另一种是借助键名来引用,是键名性质的引用,比如:字典dt1[‘bd’],‘bd’是键名。还有一种是借助标识符来引用,比如:变量num=856,num是变量。从上面例子,我们可以看到str.format()、str%()的name引用存在一定的特殊性,存在一种近似标识符的引用,但又不符合标识符的规范。

三、 f''str.format()str%()格式化表达式增加描述的字符

sr1='abc'
k1=len(sr1)

#f''
print(f'字符串{sr1}的长度是{k1}')
#或用str.format()
print('字符串{0}的长度是{1}'.format(sr1,k1))
#或用str%()
print('字符串%s的长度是%d'%(sr1,k1))

运行结果:

       上面列出了f''、str.format()和str%()三种格式化表达式。上面打印输出就是以一定格式进行打印输出,这种格式化输出,其打印的结果更有可读性,若用print(sr1,k1),显然可读性比较差,单纯看结果不直观,但上面描述性的格式化打印,打印输出的结果让我们一目了然。

       最后,欢迎你点击下面链接参与一个小问卷,你的举手之劳,让博主受宠若惊,不胜感激!

https://www.wjx/vm/w42huU2.aspx#

本文标签: 字符串详解函数对象str