输入与输出
输入(output)让计算机能够听懂人类的指令,输入(input)能够告诉人类程序目前的状态。
标准输出
print()
在Python3中,print()函数默认会将对象的表现形式输出至屏幕上:
print("hello world")
# hello world
而在Python2中,print后面不必加括号,直接加上对象即可:
print "hello world"
除此之外,print()函数还可以接收3个参数,分别是:sep、end、file
sep参数
该参数用来显示逗号间隔中的链接字符,默认为一个空格:
# 不指定sep参数
print("hello", "world")
# hello world
# 指定sep参数
print("hello", "world", sep="☺")
# hello☺world
end参数
该参数用于指定当print()完成后所在行尾指定的字符,默认为\n即换行符。
print("hello", end="\t")
print("world")
# hello world
file参数
该参数默认内部为标准输出,即输出至用户屏幕,我们可以通过该参数来指定print()的内容写入到某个指定的文件句柄中:
with open("testFile.txt", mode="wt", encoding="utf8") as f:
print("this line written in file", file=f)
格式化输出
如果我们想将一个字符串与一个对象的表现形式相结合,可使用格式化输出。
%
%格式化的历史悠久,很多码龄较长的程序员都喜欢用它进行格式化输出。
我们来看一个例子:
name = "YunYaSir"
age = 19
s1 = "name : %s\nage : %d" % (name, age) # ❶
print(s1)
# name : YunYaSir
# age : 19
❶:字符串中的%s、%d等都是占位符,占位符要和对象匹配,在进行格式化时%char会被对象的表现形式所代替。
常见的占位符如下表所示:
占位符 | 描述 |
---|---|
%s | 接收任意类型的值,以字符串形式显示 |
%r | 接收任意类型的值,以r字符串形式显示 |
%c | 只接收单个字符 |
%b | 接收int类型的值,二进制整数形式显示 |
%d | 接收int类型的值,十进制整数形式显示 |
%i | 接收int类型的值,十进制整数形式显示 |
%o | 接收int类型的值,八进制整数形式显示 |
%x | 接收int类型的值,十六进制整数形式显示 |
%e | 接收float类型的值,指数形式显示 (基底写为e) |
%E | 接收float类型的值,指数形式显示 (基底写为E) |
%f | 接收float类型的值,浮点数形式显示 |
%F | 接收float类型的值,浮点数形式显示 |
%g | 接收float类型的值,指数(e)或浮点数 (根据显示长度) |
%G | 接收float类型的值,指数(E)或浮点数 (根据显示长度) |
%% | 即打印1个百分号 |
位置传参
一个占位符对应一个对象,当对象与占位符有多个时便需要将%后面的对象跟上括号做出一个元组,如若只有一个则不需要加上括号,%后元组中的对象数量必须与占位符的数量一致,且位置要一一对应:
name = "YunYaSir"
age = 19
s1 = "name : %s\nage : %d" % (name, age) # ❶
print(s1)
# name : YunYaSir
# age : 19
如上所示:%s对应name、%d对应age。
- 优点:便于维护
- 缺点:对象与占位符必须一一对应,数量必须保持一致
关键字传参
使用关键字传参可以打破位置传参中占位符和标识符顺序以及数量必须统一的限制:
name = "YunYaSir"
age = 19
s1 = "name : %(name)s\nage : %(age)d" % {"age": age, "name": name} # ❶
print(s1)
# name : YunYaSir
# age : 19
如上所示:%(name)s代表将dict中key为name的值转换为字符串形式显示,而%(age)d则代表将dict中key为age的值转换为字符串形式显示。
- 优点:使用灵活
- 缺点:如果被格式化的占位符过多,可能导致维护不便的情况发生
格式化百分号
如果想打印%占比,则可以使用下面的方式
%%代表一个% 。放在 %d后面的%则代表格式化出后的结果是3%:
s1 = "%d%%"%3
print(s1)
# 3%
格式化精度控制
如果要格式化一个小数,保留点后2位该怎么做?
如下示例:
PI = 3.1415926
print("pi = %.2f" % PI)
# pi = 3.14
format()
%虽然能够满足基本需求。但在Python2.6中新增的format()方法,它更加强大且速度更快。
推荐今后使用format()的方法进行字符串格式化 。
注意:format()中的s只接受str类型的传值而不接受全部类型
如下所示,必须一个{}对应format()中的一个对象:
name = "YunYaSir"
age = 19
s1 = "name : {}\nage : {}".format(name, age) # ❶
print(s1)
# name : YunYaSir
# age : 19
❶:第1个{}对应format()中传入的第1个对象name,而第2个{}对应format()中传入的第2个对象age
或者也可以使用对象的方法调用形式:
name = "YunYaSir"
age = 19
s1 = str.format("name : {}\nage : {}", name, age)
print(s1)
# name : YunYaSir
# age : 19
位置传参
基本使用,采用{}进行占位,需要注意的是format中的s不是接收全部类型的对象,只能接收str类型的对象:
name = "YunYaSir"
age = 19
s1 = "name : {:s}\nage : {:d}".format(name, age)
print(s1)
# name : YunYaSir
# age : 19
如果不指定类型,则{}中默认接收全部类型的对象:
name = "YunYaSir"
age = 19
s1 = "name : {}\nage : {}".format(name, age)
print(s1)
# name : YunYaSir
# age : 19
索引传参
索引传参是format()方法所独有的。
采用{}进行占位,并在其中传入format()中被格式化对象的位置信息,如下所示:
name = "YunYaSir"
age = 19
s1 = "name : {0:s}\nage : {1:d}".format(name, age)
print(s1)
# name : YunYaSir
# age : 19
需要注意,索引传参时必须为正向索引,不支持负向索引。
关键字传参
format()方法传参时使用键值对的方式进行传参:
name = "YunYaSir"
age = 19
s1 = "name : {name:s}\nage : {age:d}".format(name=name, age=age)
print(s1)
# name : YunYaSir
# age : 19
你也可以直接传入一个字典,通过**语法对字典解包:
name = "YunYaSir"
age = 19
s1 = "name : {name:s}\nage : {age:d}".format(**{"name": name, "age": age})
print(s1)
# name : YunYaSir
# age : 19
字符填充功能
format()方法格式化时支持字符填充,如下表所示:
填充位置符号 | 描述 |
---|---|
< | 字符串居左、往右填充数据项 |
> | 字符串居右、往左填充数据项 |
^ | 字符串居中、两侧填充数据项 |
示例如下:
char = "M"
# 右填充*,字符串长度为10时停止填充
rightFill = str.format("{0:*<10}", char)
print(rightFill)
# M*********
# 左填充*,字符串长度为10时停止填充
leftFill = str.format("{0:*>10}", char)
print(leftFill)
# *********M
# 两侧填充*,字符串长度为10时停止填充
midFill = str.format("{0:*^10}", char)
print(midFill)
# ****M*****
格式化百分号
format()方法格式化百分号方法如下,它比%的格式化更加简单:
s1 = str.format("{0}%", 3)
print(s1)
# 3%
格式化{}大括号
如果使用format()方法,格式化时要输出“{char}“该怎么做?
在外部套用2次大括号即可,如下所示:
s1 = str.format("{{{0}}}", "☺")
print(s1)
# {☺}
内部的{0}代表要格式化后面的☺,而外部的2个{}格式化完成后则表现为1个{}。
格式化精度控制
如果要使用format()方法格式化一个小数,保留点后2位该怎么做?
如下示例:
PI = 3.1415926
print("pi = {0:.2f}".format(PI))
# pi = 3.14
其他的格式化
进制转换、如下所示:
# 进制转换
sBit = str.format("{:b}", 10) # 2进制
sOct = str.format("{:o}", 10) # 8进制
sHex = str.format("{:x}", 10) # 16进制
print(sBit) # 1010
print(sOct) # 12
print(sHex) # a
如果1代表百分之百,该怎么表示?如下所示:
# .2%中的2代表保留2小数点后2位
s1 = str.format("{:.2%}", 1)
print(s1)
s2 = str.format("{:.2%}", 0.5)
print(s2)
# 100.00%
# 50.00%
千分位表示,用逗号进行分割:
s = str.format("{:,}", 100000000)
print(s)
# 100,000,000
f
尽管format()已经非常方便了。但是如果传入的参数值太多依旧会看着十分混乱,于是Python3.6中新增了 f 格式字符串的操作。
这种方法的速度最快,但是却不推荐使用,因为程序还要考虑一个向下兼容性的问题。
name = "YunYaSir"
age = 19
s1 = f"name : {name}\nage : {age}"
print(s1)
# name : YunYaSir
# age : 19
具体使用方法参照上面,与原始字符串r使用差不多,用f添加在字符串前面,并且使用{}进行占位,{}中放入对象即可。
关于其他的字符串填充、精度控制、格式化转换等功能均和format()使用相同,这里不再举例。
标准输入
input()
Python2和Python3中均有input()函数来接收用户的输入。
需要注意的是,Python3中input()所得到的所有用户输入的数据,类型都是str,举个例子,用户输入小键盘数字1,程序得到的类型为str而不是int,所以我们可能需要额外的进行类型转换。
而在Python2中,则会自动转换类型为int,Python2会检测用户输入的内容是否符合Python语法,如不符合语法就会抛出异常,因此Python3中才摈弃了这种设定。
Python3中获得的所有输入结果类型均为str:
username = input("Please type in your name:")
userage = input("Please enter age:")
print("value : %r\ntype : %r" % (username, type(username)))
print("value : %r\ntype : %r" % (userage, type(userage)))
# Please type in your name:YunYaSir
# Please enter age:18
# value : 'YunYaSir'
# type : <class 'str'>
# value : '18'
# type : <class 'str'>
用户年龄应当是int类型,所以我们需要对其做一次类型转换:
username = input("Please type in your name:")
userage = int(input("Please enter age:"))
Python2中如果用户没有按照Python语法进行数据的录入,则会抛出异常:
# coding:u8
username = input("Please type in your name:")
userage = input("Please enter age:")
print u"value : %r\ntype : %r" % (username, type(username))
print u"value : %r\ntype : %r" % (userage, type(userage))
# -- 输入了 yunya 会抛出 name 'yunya' is not defined
# -- 而输入了 "yunya" 则会正常
raw_input()
raw_input()是Python2中独有的,与Python3的input()效果相同。
这还是因为Python2中input()的缺点而导致raw_input()的诞生,用户必须熟知Python语法才能与程序进行交互,这是不现实的。
>>> name = input("Please type in your name:")
Please type in your name: yunya ❶
NameError: name 'yunya' is not defined
>>> name = input("Please type in your name:")
Please type in your name: "yunya" ❷
>>> name
'yunya'
❶:这里没加引号,Python2的input()会认为这是一个变量,但该变量并未被定义,所以抛出 yunya 未定义的这么一个异常。
❷:加了引号,表明这是一个字符串
更进一步了解输出
stdin&stdout&stderr
在Linux下,当一个用户进程被创建的时候,系统会自动为该进程创建三个数据流,分别是stdin、stdout、stderr。
-
stdin:标准输入、指向用户键盘
-
stdout:标准输出、指向用户屏幕
-
stderr:标准错误、指向用户屏幕
print()的指向
Python3的print()函数,内部则是引用了stdout,也就是说会默认的将数据显示在用户屏幕上。
我们可以从Python中print()函数签名中看到:
def print(self, *args, sep=' ', end='\n', file=None): # known special case of print
"""
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
"""
pass
而关于flush参数,则可以理解为刷新机制。
默认是False即代表是流式的输出,而改为True则会拥有类似于帧动画的特性,以下代码将进行验证,推荐使用Python IDLE查看效果:
import time
print("downloading\t", end="")
for i in range(100):
time.sleep(0.1)
if i == 99:
print('#', flush=True, end="\tdownload complate\n")
break
print('#', flush=True, end="")