现在关注Python的输入输出,这里并不会对各种输入输出语法进行详细的介绍,只是针对几种可能的需求,够用就行。

函数原型

1
2
3
4
5
6
7
def print(
*values: object,
sep: str | None = " ",
end: str | None = "\n",
file: SupportsWrite[str] | None = None,
flush: Literal[False] = False,
) -> None: ...

例子

1
2
3
4
5
print("hello,world!")
# hello,world!

a = 1; b = 2; print("a=",a,"b=",b)
# a= 1 b= 2

这里如果连续打印多个项,会默认加上空格分隔,可以用关键字参数更改sep

1
2
print("hi","Alex",sep='-')
# hi-Alex

除了分隔符,还可以指定结束符end,默认是回车。

1
2
print("hi","Alex",sep='-',end="!\n")
# hi-Alex!

将输出的值转成字符串,可以使用 repr()str() 函数来实现:

  • str():函数返回一个用户易读的表达形式。
  • repr():产生一个解释器易读的表达形式。

字符串格式化

经典格式化

与 C 语言的 printf 中使用的格式化方案非常相似,例如

1
2
3
4
5
6
7
8
day = 18
print("day = %d" % day)
# day = 18

year = 2023
month = 4
day = 18
print("date: %d-%d-%d" %(year,month,day))

使用 % 后接所有参数组成的元组,对于只有一个参数的则不需要括号。

常用的格式如下:

  • %d 整数
  • %f 浮点数
  • %e%E 科学计数法
  • %c ASCII 字符,可以使用字母或者对应 ASCII 码,展示一个字符
  • %s 字符串,会使用 str() 将表达式转换为字符串

format 格式化

基于 str.format() 方法进行的格式化,比经典格式化更好用。

使用大括号占位,在后面按照位置顺序输入即可,例如

1
2
3
s1 = "a={},b={},c={}".format(1,2,3)
print(s1)
# a=1,b=2,c=3

还可以在大括号中指定位置顺序,按照指定的顺序输入,例如

1
2
3
s2 = "a={0},b={2},c={1}".format('x','y','z')
print(s2)
# a=x,b=z,c=y

或者使用关键字参数,就像函数调用一样,此时不允许使用位置参数,必须在 format 中使用关键字参数,例如

1
2
3
4
5
s3 = "a={aa},b={bb},c={cc}".format(1,2,3) # 语法错误

s3 = "a={aa},b={bb},c={cc}".format(bb=1,cc=2,aa=3)
print(s3)
# a=3,b=1,c=2

这几种方式可以混合使用,但是有点绕,略。

并且在 {} 内部还可以更细致地控制输出格式,以冒号开始,例如

1
2
3
4
5
6
7
8
9
table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
for name, phone in table.items():
print(f'{name:10} ==> {phone:10d}')

'''
Sjoerd ==> 4127
Jack ==> 4098
Dcab ==> 7678
'''

f-string 字符串

f-string无疑是最好用的一种格式化方案,同时它还比前两者方案更快。

str.format 方法不同,f-string 可以解决代码冗余的问题,可以在 {} 内部使用任何变量或表达式,在生成字符串的过程中就会替换变量的值,或者执行表达式并填入相应位置。

例如在字符串中嵌入变量或者简单表达式

1
2
3
4
5
6
7
8
year = 2023
month = 4
day = 18

s = f'data: {year}-{month}-{day},\nnextday:{day+1 }'
print(s)
# data: 2023-4-18,
# nextday:19

甚至在表达式中支持函数调用,lambda表达式等

1
2
3
4
5
a = 1
b = 2
s = f'result is {(lambda x,y:x+y)(a,b)}'
print(s)
# result is 3

由于使用输出查看一个变量的需求很常见,f-string提供了很便利的方式,被称为自记录表达式

1
2
3
4
5
6
7
8
9
10
a = 2

s0 = f'a={a}'
# 'a=2'

s1 =f'{a=}'
# 'a=2'

s2 = f'{ a = }'
# ' a = 1'

注意这里的最后一个例子中,{ a = }内部对应位置的空格会被保留,但是其他情形下,{}内部的空格并不会保留。

f-string也提供了精细化的格式设置,这里只关注数值的格式化,形式为[[0]<width>][.<precision><style>]

  • <width>:非负整数,设置数值的最小总宽度(含小数点),自身宽度超过时不会被截断
  • 0可选,使用0<width>时不足时用0填充占位,否则默认用空格占位
  • <precision>:非负整数,设置数值的精度,保留的小数点后的位数,小数点后的位数过多会截断,过少会补0
  • <style>:可选f(小数),e/E(科学计数),%(百分数)。不管什么风格,<precision>都是控制小数点后的位数,对于浮点数是底数的小数点后位数,eE的区别就是结果用e还是E。除此之外还可以选择g/G(通用形式),自动判断选择定点数或浮点数

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
pi = 3.1415926

f'{pi:5}'
# 宽度超过<width>不会被截断
# '3.1415926'

f'{pi:10}'
# 宽度不足用空格占位
# ' 3.1415926'

f'{pi:010}'
# 宽度不足用0占位
# '03.1415926'

f'{pi:.4f}'
# 小数位数过多截断
# '3.1416'

f'{pi:.14f}'
# 小数位数过少补充
# '3.14159260000000'

f'{pi:.4e}'
# 小数位数过多截断
# '3.1416e+00'

f'{pi:.14e}'
# 小数位数过少补充
# '3.14159260000000e+00'

f'{pi:.2%}'
# 百分数同理
# '314.16%'

由于f-string使用了{}作为特殊用途,因此如果需要在字符串中包含{},需要使用连续两次

1
2
3
4
a = 3
s = f"{{{a}}}"
print(s)
# {3}

利用上文的三种字符串格式化即可,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
year = 2023
month = 4
day = 18

message = "hello,world"

print('data: %d-%d-%d, %s' %(year,month,day,message))
print('data: {}-{}-{}, {msg}'.format(year,month,day,msg=message))
print(f'data: {year}-{month}-{day}, {message}')

# data: 2023-4-18, hello,world
# data: 2023-4-18, hello,world
# data: 2023-4-18, hello,world

input 输入

例子即可,用到的情况很少

1
2
3
s = input("Please input an integer number:")
# 脚本执行会暂停,等待输入
# jupyter会弹出对话框,等待输入

注意输入后得到的总是一个字符串,因此需要使用类型转换,例如

1
2
s1 = int(input("Please input an integer number:"))
s2 = float(input("Please input a float number:"))

命令行参数

例子即可,如下在命令行中执行脚本,附带了三个参数,在脚本中可以读取它们

1
$ python demo.py 1 2 abc

所有的命令行参数被打包为一个字符串列表,即 sys.argv。脚本中可以读取命令行参数,注意第一个参数总是脚本的文件名称

1
2
3
4
import sys

print ('Number of arguments:', len(sys.argv), 'arguments.')
print ('Argument List:', str(sys.argv))

使用情况如下

1
2
3
4
5
6
7
$ python .\demo.py
Number of arguments: 1 arguments.
Argument List: ['.\\demo.py']

$ python .\demo.py 1 2 3
Number of arguments: 4 arguments.
Argument List: ['.\\demo.py', '1', '2', '3']

文件 IO

打开关闭文件

文件打开方式基本同 C 语言:

  • r 读取方式
  • w 写入方式(文件已存在则清空重写)
  • a 追加写入方式
  • ...

打开文件

1
2
3
f = open("test.txt")      # 默认为r,读取方式
f = open("test.txt",'w') # 写入方式
f = open("test.txt",encoding = 'utf-8') # 指定编码方式

关闭文件

1
f.close()

关闭文件之后不可以再次进行读取或写入,除非重新打开文件。

检查文件是否关闭

1
2
f.closed
# True/False

利用异常处理的方式,可以确保文件总是被正常关闭。

1
2
3
4
5
try:
f = open("test.txt",encoding = 'utf-8')
# 执行文件操作
finally:
f.close()

更推荐的用法是 with 语句,在进入时打开文件,退出 with 代码块时自动关闭文件,即使触发了异常也会保证正确关闭文件。

1
2
with open("test.txt",encoding = 'utf-8') as f:
# 执行文件操作

with 语句适合涉及资源管理的过程,工作原理如下:

  • 首先对 with 后面的语句求值;
  • 紧跟 with 后面的语句被求值后,返回对象的 __enter__() 方法被调用,这个方法的返回值将被赋值给 as 后面的变量;
  • 当 with 后面的代码块全部执行完成之后,将调用前面返回对象的 __exit__() 方法。

with 语句调用自定义类型的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Simple:
def __enter__(self):
print("In __enter__()")
return "enter"

def __exit__(self, type, value, trace):
print("In __exit__()")

def get_simple():
return Simple()

with get_simple() as simple:
print("simple:", simple)

'''
In __enter__()
simple: enter
In __exit__()
'''

打开文件通常使用的是相对路径,需要注意相对的是执行脚本时的路径,而不是脚本存放的路径。

读取文件

主要是如下方法:

  • file.read() 读取整个文件,返回一个字符串
  • file.readline() 读取一行返回一个字符串
  • file.readlines() 读取所有行,返回字符串数组

文件读取和 C 语言一样,会记录一个当前位置指针,读取从当前指针开始,如果已经到底文件尾部,会返回 ''

例一,读取如下文件

1
2
3
4
my test file
This file

contains three lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
with open("test.txt","r") as f:
s1 = f.readline() # 读取一行,含回车
print(s1)
s2 = f.read(4) # 读取4个字符
print(s2)

s3 = f.read() # 读取剩余部分,含回车
print(s3)

'''
my test file

This
file

contains three lines
'''

例二,对于文件支持使用 for 遍历来逐行读取:

1
2
3
4
5
6
7
8
9
10
with open("test.txt","r") as f:
for i,line in enumerate(f):
print(i,line, end='') # 避免多个换行

'''
0 my test file
1 This file
2
3 contains three lines
'''

写入文件

主要是两个方法:

  • file.write(str) 将字符串写入文件
  • file.writelines(lines) 将多行文本写入文件中,lines 为字符串组成的列表或元组

例一

1
2
3
4
with open("test.txt",'w',encoding = 'utf-8') as f:
f.write("my test file\n")
f.write("This file\n\n")
f.write("contains three lines\n")

得到的文件如下

1
2
3
4
my test file
This file

contains three lines

例二

1
2
3
lis = ['Python', '是一门解释型语言\n', 'python非常简单']
with open("test.txt",'w',encoding = 'utf-8') as f:
f.writelines(lis)

得到的文件如下

1
2
Python是一门解释型语言
python非常简单

简易数据读写

对于纯数据文件的读写过程,这里只是简易的示例,实际使用时还需要用专业的数据处理模块。

从如下文件中读取

1
2
3
4
1 2 0.3
2 5 1.3
4 6 3.0
3 3 2.9

直接读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
with open("data.txt","r") as f:
for line in f:
s = line.split(' ')
for i,j in enumerate(s):
print(f"({i}) {j} ",end='')
print("")

'''
(0) 1 (1) 2 (2) 0.3

(0) 2 (1) 5 (2) 1.3

(0) 4 (1) 6 (2) 3.0

(0) 3 (1) 3 (2) 2.9

'''

直接写入

1
2
3
4
5
6
7
s = [[1,2,0.3],[2,5,1.3],[3,3,2.9]]

with open("data2.txt","w") as f:
for i in s:
for j in i:
f.write(str(j)+",")
f.write("\n")

写入得到如下文件

1
2
3
1,2,0.3,
2,5,1.3,
3,3,2.9,