python 格式化输出详解(占位符:%、format、f表达式

python 格式化输出详解(占位符:%、format、f表达式

1.占位符介绍

要实现字符串的拼接,使用占位符是的一种高效、常用的方式。举个例子,下面是不使用占位符的一种写法,直接使用加号拼接字符串

name ="Li hua" age =24print("Hello "+name+", you are "+str(age)+" years old")

换成占位符,可以写成

name ="Li hua" age =24print("Hello %s, you are %d years old"%(name, age))

其中%s%d便是占位符,顾名思义,其作用就是替后面的变量站住这个位置,字符串后面的%是一个特殊的操作符,该操作符会将后面的变量值,替换掉前面字符串中的占位符。对比两种写法,会发现使用占位符可以

  • 将字符串中用到变量集中在一起,方便查找和修改
  • 避免了反复使用引号,导致的引号对应识别困难
  • 能够更直接通顺的看出句子的内容

实际上,占位符的优点还有很多,具体可以在下面的使用中去体会。目前常用的占位符写法有三种

  • %
  • format
  • f表达式

每种方法下,占位符的写法和意思又有不同。下面依次介绍下这三种并给出几个使用示例。

2.%

上文已介绍过,%是一个特殊的操作符,该操作符会将后面的变量值,替换掉前面字符串中的占位符。其详细语法格式如下:

"... %[key][flags][width][.precision][length type]conversion type ..."% values 

其中

%[key][flags][width][.precision][length type]conversion type

是该方法下,占位符详细语法的格式。依次介绍下上面占位符每个符号每个字段的意思

  • %: 必须要有的符号。它标记占位符的开始。
  • key: 选填。映射的键,由带括号的字符序列组成,一般用于后面的values是是字典的场景。
  • flags: 选填。转换标志(Conversion flags), 会影响某些转换类型的结果。
  • width: 选填。最小字段宽度。如果指定为“*”(星号),则实际宽度从值中元组的下一个元素读取,要转换的对象位于最小字段宽度和可选精度之后。
  • precision: 选填。精度,写法为.precision(点+精度)。如果指定为“*”(星号),则实际宽度从值中元组的下一个元素读取,要转换的值位于精度之后。
  • length type: 选填。长度修改器。
  • Conversion type: 必须要有的符号。转换类型,也标记占位符的开始。

下面依次使用一个小示例展示下上面每个字段的用法

Conversion type:由于这个字段是必选字段,所以最先介绍(%写法是固定的,Conversion type则必须要选择一个转换类型)。类型有很多,只介绍三个非常常用的,(更多的建议查阅官方文档:printf-style-string-formatting

Conversion type说明
s字符串(使用str()方法转换任何Python对象)
d十进制整数
f十进制浮点数(小数), 自动保留六位小数。

示例:

print("%s %s %s"%("hello",3,3.1415))print("%s %d %d"%("hello",3,3.1415))print("%s %d %f"%("hello",3,3.1415))print("%s %f %f"%("hello",3,3.1415)) hello 33.1415 hello 33 hello 33.141500 hello 3.0000003.141500

观察上面的示例,不难看出s是一个非常通用的类型,所以很多不讲究的场景,Conversion types是比较可靠的,但是要注意都是字符串类型的。

precision:对于有小数的场景,设置精度是基本操作。其写法为.precision(点+精度)。不设置的话,浮点数默认精度值是6。示例如下:

print('%f'%3.14)print('%.1f'%3.14)print('%.2f'%3.14)#保留多少小数3.140000#默认精度是6 3.13.14

一般来说,%操作符下占位符了解到这里就够了,下面的是比较少用的生僻内容。而且也不实用,复杂的对齐操作推荐使用formatf表达式。

key (不常用):这个选填字段是搭配字典格式的values使用的,示例如下:

print("%(name)s %(age)s"%{"name":"zzz","age":20})print("%(0)s %(1)s"%("zzz",20))#错误的❌❌❌❌---key必须去字典里取值,这样是不行的#输出 zzz 20print("%(0)s %(1)s"%("zzz",20)) TypeError:format requires a mapping #改正print("%(0)s %(1)s"%{"0":"zzz","1":20}) zzz 20

flags :(不常用)该类型可选择的值有:#0-、``、+;这里只介绍其中几种,(更多的建议查阅官方文档:printf-style-string-formatting

flags说明
0数值的转换将被零填充,需搭配width使用(示例见下面的width中的)。
-转化结果左对齐,需搭配width使用(示例见下面的width中的), 该标志符会覆盖0标志符。
``空格, 在带符号的转换产生的正数(或空字符串), 之前留一个空格(方便正负数最后对齐)。
+如果你在格式化数字时使用了 + 标志,那么正数前面会显示 +负数前面会显示 -而且 + 的优先级比“空格标志”更高,会把它顶掉

示例如下

print("% d %+d"%(123,321))print("%d %+d"%(-123,-321))#output123+321-123-321

width:设置字段的最小占位宽度,默认右对齐,内容不够时使用空格填充。

print("%4d,%6d,%10f"%(12,1234,3.14))#用至少4个、6个、10个字符显示一个整数,默认右对齐,不够了就用空格补在左边print("%04d,%06d,%010f"%(12,1234,3.14))#用0来填充不够的位置print("%-4d,%-6d,%-10f"%(12,1234,3.14))#左对齐print("%0-4d,%0-6d,%0-10f"%(12,1234,3.14))#左对齐的时候,0是没有意义的,因为会覆盖0#output12,1234,3.1400000012,001234,003.14000012,1234,3.14000012,1234,3.140000
**Python 的字符串格式化里,没有你需要去“使用”的 length type**它是 C 语言 printf 遗留下来的概念,因此在python中我们可以直接忽略它。

1.什么是 length?(C 语言里的东西)

C 语言 里:

这里的:

这是 C 必须要的,因为 C 是弱类型语言。

2.为社么python不需要length

Python 的整数没有长度限制

Python 的 int任意精度整数。所以:不存在 “int / long / long long” 的区别。也就不需要 length

Python 的格式化是“高层抽象”

都能正常工作。唯一的“历史遗留支持”。Python 的 % 格式化里:

2.type 才是真正重要的东西, **type 决定“怎么解释这个值”, **length 在 Python 中不起作用。

3.format

str.format()是Python2.6开始的新功能,是字符串格式化方法之一,它允许多个替换、值格式化。这个方法允许我们通过位置,格式化连接字符串中的元素。这个方法是一个非常实用且强大的方法。**对于复杂的对齐要求,首选该方法。**其总的语法格式如下:

"... {[field_name][!conversion][:format_spec]} ...".format(arguments)#在 {} 里面可以:#指定 用哪个值(field_name)---必须要的#可选地指定 怎么转换这个值(!conversion)----可选的转换符,能够转换为字符换,ASCⅡ转义等。#可选地指定 怎么格式化显示(:format_spec)#.format(arguments),Python 字符串的方法,用来 把占位符 {} 替换成实际值

3.1 arguments:首先介绍下arguments,其有两种情况:

  • 位置参数(Positional Arguments)-也就是按顺序传递给函数的参数。顺序很重要,如果颠倒就会传错
print("{} {}".format("zhang zhang",668))print("{1} {0} {0} {1}".format("zhang zhang",668))print('{} {} {} {}'.format("zhang zhang",668))#位置参数不够,后便只有两个参数就错了#zhang zhang 668#668 zhang zhang zhang zhang 668#IndexError: Replacement index 2 out of range for positional args tuple
  • 关键字参数(Keyword Arguments)-也就是通过“名字=值”的方式传递参数。顺序不重要
print("{name} {age}".format(name="Li hua", age=24))print("{name} {age} {age} {name}".format("Li hua",24))print("{} {}".format(name="Li hua", age=24))#Li hua 24#KeyError: 'name'#IndexError: Replacement index 0 out of range for positional args tuple
其实位置参数和关键字参数可以混用,但是不推荐混用容易让代码可读性差容易出错(尤其是 {} 没索引时只能用位置参数)

然后介绍下该语法下的占位符格式:

{[field_name][!conversion][:format_spec]}

(1) field_name: 选填。字段名,常使用其基础格式arg_name来指定使用arguments哪一个。对于关键词参数,arg_name必须为其中的关键字,(此时该字段是必填项)比如"{name} {age}".format(name="Li hua", age=24)。对于位置参数,arg_name必须为序号,(此时该字段可不填,不填则默认第一个为0,从前往后依次+1),比如"{0} {1}".format("Li hua", 24)"{} {}".format("Li hua", 24),两者效果一样。

.format() 里,field_name 就是 占位符 {} 里指定的内容,用来告诉 Python 用哪一个参数去填充这个 {}。对于 关键字参数field_name 就是关键字名对于 位置参数field_name 就是参数的序号,也可以省略

该字段完整语法格式为arg_name(.attribute_name | [element_index])*,是在arg_name对应的值为对象、列表或字典时使用,获取其进一步的属性值或者内部值。占位符 {} 不只是可以直接对应参数,还可以“深入访问”参数内部的属性或元素。这里举一个例子:

#也就是说,arg_name可以访问更深层次的属性#例如,最基础的 field_name 就是参数名字或位置号print("{0} {1}".format("Li Hua",24))# 0 → "Li Hua"# 1 → 24#进一步,还可以访问对象属性。如果参数是对象,可以用点号 .属性名 访问对象属性。classPerson:def__init__(self, name, age): self.name = name self.age = age p = Person("Li Hua",24)print("{0.name} {0.age}".format(p))#Li Hua 24#还可以访问列表或者字典元素([element_index]),如果参数是列表、元组或字典,可以用 [] 访问元素。 mylist =["a","b","c"]print("{0[0]} {0[2]}".format(mylist))

conversion:选填。变换,不常用。指定时要用!来开头,指定后会在格式化之前将arguments中对应的值进行类型变换。其有三个值可以指定,分别为

conversion说明
s调用结果对象的str方法进行转换
r调用结果对象的repr方法进行转换
a调用结果对象的ascii方法进行转换

(2)format_spec:选填,格式化具体规范,核心内容,超常用。填写时要用:来开头,填写后,会按照其指定的规则来进行格式化。其详细语法为

在 Python 的 .format()f-string 中,format_spec 用来指定 格式化规则。它总是以 冒号 : 开头,例如:
[[fill]align][sign][#][0][width][grouping_option][.precision][type]

其中所有字段均为选填,下面依次介绍下(其中加粗的为常用),

  • align: 对齐方式,有以下值:

fill: 填充内容,如果指定了宽度,但变量长度不够,会使用该字段值进行填充。设置了fill,后面必须显式设置align。

align说明
<强制左对齐(绝大多数对象默认使用)
>强制右对齐(数字类型默认使用)
=强制将填充内容放在符号(如果有)之后但数字之前,比如输出成+000000120这样的格式。此对齐选项仅对数字类型有效。(当’0’紧接在字段宽度width之前时,它将成为默认值。)
^强制居中对齐
  • sign: 符号展现格式,仅对数字类型有效。有以下值:
sign说明
+正数负数都显示符号,正数用+,负数用-。无论正负,都必须有符号。
-(默认值),仅负数展现符号。默认行为,只给负数加符号
``负数展现符号,正数前面使用一个空格来占位对齐。正数用空格占位,负数用 -
  • grouping_option: 分组选择,有两个选项可选:

width: 最小字段宽度,不设置则字段宽度将始终与填充它的数据长度相同(此时对齐方式align没有意义)。

width ≠ 固定宽度

至少要占这么多字符不够就补够了就不管

0: 当没有设置对齐方式align时, 在宽度字段前面加一个零(‘0’)字符,将等价于填充字符fill0且对齐方式align<

如果你写了 0,但没有写对齐方式Python 会 自动把它理解成:用 0 填充 + 右对齐

#: 复杂生僻,基本不使用,不介绍,有需要的可查阅官方文档(见本部分开头)。

# 的作用主要有两类:进制前缀(二进制 / 八进制 / 十六进制)强制浮点显示小数点
grouping_option说明
,表示使用逗号作为千位分隔符。
_下划线分隔符,复杂生僻,基本不使用,不介绍.
  • type: 类型,决定“怎么显示这个数据”。有很多值,这里只介绍几个常用的:

precision: 精度,指定时要用.来开头,是一个十进制数,指定用’f’和’f’格式化的浮点值在小数点后应该显示多少位,即保留几位小数。

precision 只能写在 . 后面. → 告诉 Python:下面要写“精度”2 → 小数点后保留 2 位f → 浮点数
type说明
s字符串格式。这是字符串的默认类型,可以省略(不填)
d十进制整数
f十进制浮点数(小数), 默认保留六位小数

补充说明1: fill, align只有设置了width才能生效。fill 和 align 的作用对象是“多出来的宽度空间”,如果没有 width,就没有多余空间,所以它们不会生效。简单示例:

#没写的部分 = 使用默认规则,所有规则都是在“width 提供的空间里”起作用print("{:4}{:6},{:10}".format("1","2",3.14))#只有width,没有align-默认右对齐,没有fill-默认填充空格。print("{:4}{:>6}, {:^10}".format("1","2",3.14))#有width,print("{:_<4}{:0>6}, {:^10}".format("1","2",3.14))#有fill。就按照指定的fill填充#output12,3.1412,3.14 1___000002,3.14

4.f 表达式

这是从Python 3.6开始的一个新功能。f表达式(f-string), 又名(formatted string literal), 是前缀为“f”或“f”, 用花括号{}包裹替换字段的字符串文字。其简易格式为: f'{name} is {age} years old'其中花括号{}包裹的是替换字段replacement_field,相当于上面的占位符,但是不同于占位符是先占住位置最后标明变量进行替换,f表达式里的替换字段直接在花括号里面进行变量替换。上面的例子就是用name变量值替换{name}字段,用age变量值替换{age}字段。f表达式详细格式为:

f-string 就是: “在字符串里,用 {} 直接写变量或表达式,Python 会自动替换成结果。”只要字符串前面加了 fF,Python 就会:{} 里面的内容 当成 Python 表达式计算结果再变成字符串,放回原来的位置

其中花括号{}包裹的是替换字段 replacement_field。那么和 .format() / % 的本质区别是?
f'(literal_char | {{ | }} | replacement_field)*'F'(literal_char | {{ | }} | replacement_field)*'


{} 在 f-string 里有 特殊含义,如果你只是想输出一个 **字面量(也就是原来写出来的值,些什么就表示本身,不需要再计算。)的 {}**就必须 转义

以上说明f表达式中的字符串内容,是由任意个literal_char{{}}replacement_field自由组成的。其中literal_char是除花括号{}外的任意字符或空。
f表达式中要表示花括号{}文本,需要进行转义,转义方式为{{, }},

4.1 replacement_field是替换字段,是f表达式的核心。其格式为

{f_expression[=][!conversion][:format_spec]}
  • 替换字段由花括号包裹

f_expression: 必填内容,常规Python表达式,一般要被圆括号包围,只有少数注意事项:1 不允许使用空表达式。

2 lambda和赋值表达式:=必须用显式括号括起来。



在 f-string 的 {} 里:f"{ ... }" 里面只能放“能算出一个值的东西”,不放那些只做动作不产出结果的东西1:数字

2:变量

3:计算

这些都“算得出一个结果”都可以放进 {},但是像x = 10不是算一个值,他是给x赋值的一个命令。但是:=赋值表达式,它在赋值的同时还返回了这个值(x := 10)把10放进x,然后还返回10;大多数表达式 不用括号但有两类表达式 如果不用括号,Python 会“读错”

因为 {} 本身不是一个“完整表达式环境”,而这两种东西语法优先级太特殊,Python 需要你用括号“明确边界”。

:=(赋值表达式,海象运算符)

赋值表达式,意思是一边“赋值”,一边“返回值”

lambda

lambda 是 Python 的匿名函数,也就是“临时函数”,不用给它起名字

3 替换表达式可以包含换行符(例如在三重引号字符串中),但不能包含注释。

4 每个表达式在格式化字符串文本出现的上下文中按从左到右的顺序进行计算。

其完整格式为:

(conditional_expression |* or_expr)(, conditional_expression |,* or_expr)*[,]| yield_expression 

过于复杂,只展示不介绍,详情可查阅官方文档:https://docs.python.org/3/reference/lexical_analysis.html#grammar-token-f-expression

conversion: 选填。转换,指定时要在开头添加!,指定后对表达式求值的结果在格式化之前进行转换。

在表达式后加 ! + 一个字符,对表达式求值的结果在格式化之前进行转换

下方示例中, name = "Ståle"

=: 选填(3.8新版功能), 在表达式后添加等号’=', 可以显示表达式文本及其求值后的值(在调试中很有用),。

在 f-string 的替换字段 {} 内,加上 =,可以打印表达式本身和它的值,主要用于调试,方便看变量名字和对应结果
conversion说明示例输出
s对结果调用str()方法f"His name is {name!s}."'His name is Ståle.'
r对结果调用repr()方法f"His name is {name!r}.""His name is 'Ståle'."
a对结果调用ascii()方法f"His name is {name!a}.""His name is 'St\xe5le'."
  • format_spec: 格式规范, 和本文第二部分format中的format_spec格式规范是一样的。不过这里的可以嵌套使用replacement_field指定其中的值。也就是需要再冒号后写
line ="The output will have the expression text"print(f"{line =}")#变量名+等号,表示显示变量的值。自动打印 “变量名 = 变量的值” width =10#precision = '4f' precision =4 value =12.34567print(f"result: {value:{10}.{4}}")#width 为10, precision精度为4,就是保留小数点后4位print(f"result: {value:{width}.{precision}f}")#{value:{width}.{precision}}#{变量:宽度.精度}#.精度 表示:小数点后保留几位。默认情况下,Python 会四舍五入到指定的精度#在 f-string 里,当你写 {value:宽度.精度} 且 没有指定类型 时,是按浮点数处理,但是实际上更像%g保留的是有效数字的总位数,并且:精度指的是 小数点后显示的位数,会自动四舍五入。#当没有指定类型(比如没有写 :10.4f 而是写 :10.4)时,Python 的行为更像 %g(默认类型是g,没有加字母默认是用%g来格式化浮点数,%g 的聪明之处是:自动去除末尾多余的0,尽量用最简洁的方式显示数字。precision = 4 → %g 会先考虑有效数字最多4位):precision = 有效数字的总位数(整数部分 + 小数部分)。#output line ='The output will have the expression text' result:12.35 result:12.3457

Read more

【C++笔记】STL详解:vector容器的使用

【C++笔记】STL详解:vector容器的使用

前言:         本文在介绍STL框架基础上,进一步讲解了迭代器、auto关键字和范围for循环的使用方法,接下来我们将重点探讨vector类的常用接口及其应用。          一、vector容器的简介             C++ 的 vector 是标准模板库(STL)中最核心且实用的容器之一,其与固定大小的传统数组(如 int arr[10])不同,vector 克服了数组的局限性,它不需要预先确定大小,并且可以动态调整容量。          简单理解为:vector是可变的、经过封装函数功能的数组。                  核心优势:          ①动态扩容:您不需要一开始就告诉它要存多少数据。当空间不够时,它会在底层自动帮您寻找一块更大的内存,把数据搬过去。          ②内存安全:它负责自己内存的分配和释放,大大减少了手动 new 和 delete 带来的内存泄漏风险。          ③功能丰富:它自带了大量现成的工具函数,比如:获取大小、清空数据、在尾部添加数据等。

By Ne0inhk

NumCpp实战指南:从零开始掌握C++数值计算的利器

NumCpp实战指南:从零开始掌握C++数值计算的利器 【免费下载链接】NumCppC++ implementation of the Python Numpy library 项目地址: https://gitcode.com/gh_mirrors/nu/NumCpp NumCpp是一个C++实现的Python Numpy库,为C++开发者提供了强大的数值计算能力。无论是科学计算、数据分析还是工程应用,NumCpp都能帮助开发者轻松处理多维数组和矩阵运算,是C++数值计算的必备工具。 为什么选择NumCpp? 熟悉的Numpy风格API NumCpp采用了与Numpy相似的API设计,让熟悉Python Numpy的开发者能够快速上手。这意味着你可以使用类似的函数名称和参数结构,大大降低了学习成本。 高效的C++性能 作为C++库,NumCpp充分利用了C++的性能优势,比纯Python实现的Numpy在计算密集型任务上更快。这使得NumCpp成为处理大规模数据和复杂算法的理想选择。 丰富的功能模块 NumCpp提供了丰富的功能模块,包括线性代数、傅里叶变换、

By Ne0inhk
C++之模版详解(进阶)

C++之模版详解(进阶)

目录 1. 非类型模板参数 2. 类模板的特化 2.1 函数模板特化 2.2 类模版特化 3. 模板的分离编译 1. 非类型模板参数 模版参数有两种,一种叫类型模版参数,一种叫做非类型模版参数。今天我们来讲讲非类型模版参数。 template <int N> 中的 int N 就是典型的非类型模板参数。这里的 int 是参数的类型,而 N 是参数名,它接收的是一个具体的常量值,而非像普通类型模板参数(如 template <typename T>)那样接收一个 “类型”。 两者核心区别就是: * 类型模板参数:传递 “类型”(如 T

By Ne0inhk
【C++11】列表初始化、新式声明、范围for和STL中的变化

【C++11】列表初始化、新式声明、范围for和STL中的变化

C++11新特性 * C++11新特性 * github地址 * 0. 前言 * 1. C++与C++11简介 * C++的发展简史 * C++11的意义 * 小故事:C++11命名的由来 * 2. 统一的列表初始化 * C++98中传统的{}初始化 * C++11中统一的列表初始化 * 列表初始化 * std::initializer_list * 引入 * initializer_list介绍 * vector补充支持initializer_list的构造 * map相关 * 3. C++11的新声明 * 1. auto * 1. C++类型系统演进 * 1.1 从C到C++的类型困境 * 1.2 typedef的局限性

By Ne0inhk