Python程序
输入与输出
输出
用print()
在括号中加上字符串,就可以向屏幕上输出指定的文字。比如输出'hello, world'
,用代码实现如下:
1 | 'hello, world') print( |
print()
函数也可以接受多个字符串,用逗号“,”隔开,就可以连成一串输出:
1 | 'The quick brown fox', 'jumps over', 'the lazy dog') print( |
print()
也可以打印整数,或者计算结果:
1 | >>> print(300) |
因此,我们可以把计算100 + 200
的结果打印得更漂亮一点:
1 | '100 + 200 =', 100 + 200) print( |
输入
现在,你已经可以用print()
输出你想要的结果了。但是,如果要让用户从电脑输入一些字符怎么办?Python提供了一个input()
,可以让用户输入字符串,并存放到一个变量里。比如输入用户的名字:
1 | > name = input() |
当你输入name = input()
并按下回车后,Python交互式命令行就在等待你的输入了。这时,你可以输入任意字符,然后按回车后完成输入。
输入完成后,不会有任何提示,Python交互式命令行又回到>>>
状态了。那我们刚才输入的内容到哪去了?答案是存放到name
变量里了。可以直接输入name
查看变量内容:
1 | name |
例子
接收键盘输入,并输出。
1 | name=input('please input your name')` |
python基础
以#
开头的语句是注释,注释是给人看的,可以是任意内容,解释器会忽略掉注释。其他每一行都是一个语句,当语句以冒号:
结尾时,缩进的语句视为代码块。
缩进有利有弊。好处是强迫你写出格式化的代码,但没有规定缩进是几个空格还是Tab。按照约定俗成的惯例,应该始终坚持使用4个空格的缩进。
缩进的另一个好处是强迫你写出缩进较少的代码,你会倾向于把一段很长的代码拆分成若干函数,从而得到缩进较少的代码。
缩进的坏处就是“复制-粘贴”功能失效了,这是最坑爹的地方。当你重构代码时,粘贴过去的代码必须重新检查缩进是否正确。此外,IDE很难像格式化Java代码那样格式化Python代码。
最后,请务必注意,Python程序是大小写敏感的,如果写错了大小写,程序会报错。
Python使用缩进来组织代码块,请务必遵守约定俗成的习惯,坚持使用4个空格的缩进。
在文本编辑器中,需要设置把Tab自动转换为4个空格,确保不混用Tab和空格。
数据类型与变量
整数
浮点数
字符串
字符串是以单引号'
或双引号"
括起来的任意文本
如果字符串内部既包含'
又包含"
怎么办?可以用转义字符\
来标识,
比如:
1 | 'I\'m \"OK\"!' |
表示的字符串内容是:
1 | I'm "OK"! |
转义字符\
可以转义很多字符,比如\n
表示换行,\t
表示制表符,字符\
本身也要转义,所以\\
表示的字符就是\
,可以在Python的交互式命令行用print()
打印字符串看看:
如果字符串里面有很多字符都需要转义,就需要加很多\
,为了简化,Python还允许用r''
表示''
内部的字符串默认不转义,可以自己试试:
如果字符串内部有很多换行,用\n
写在一行里不好阅读,为了简化,Python允许用'''...'''
的格式表示多行内容,
字符串和字符编码
ASCII编码和Unicode编码的区别:ASCII编码是1个字节,而Unicode编码通常是2个字节。
字母A
用ASCII编码是十进制的65
,二进制的01000001
;
字符0
用ASCII编码是十进制的48
,二进制的00110000
,注意字符'0'
和整数0
是不同的;
汉字中
已经超出了ASCII编码的范围,用Unicode编码是十进制的20013
,二进制的01001110 00101101
。
如果把ASCII编码的A
用Unicode编码,只需要在前面补0就可以,因此,A
的Unicode编码是00000000 01000001
。
新的问题又出现了:如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。
所以,本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8
编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间:
字符 | ASCII | Unicode | UTF-8 |
---|---|---|---|
A | 01000001 | 00000000 01000001 | 01000001 |
中 | x | 01001110 00101101 | 11100100 10111000 10101101 |
从上面的表格还可以发现,UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。
Python字符串
在最新的Python 3版本中,字符串是以Unicode编码的,也就是说,Python的字符串支持多语言,例如:
1 | '包含中文的str') > print( |
对于单个字符的编码,Python提供了ord()
函数获取字符的整数表示,chr()
函数把编码转换为对应的字符:
1 | >>> ord('A') |
如果知道字符的整数编码,还可以用十六进制这么写str
:
1 | '\u4e2d\u6587' > |
两种写法完全是等价的。
由于Python的字符串类型是str
,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str
变为以字节为单位的bytes
。
Python对bytes
类型的数据用带b
前缀的单引号或双引号表示:
1 | x = b'ABC' |
要注意区分'ABC'
和b'ABC'
,前者是str
,后者虽然内容显示得和前者一样,但bytes
的每个字符都只占用一个字节。
以Unicode表示的str
通过encode()
方法可以编码为指定的bytes
,例如:
1 | 'ABC'.encode('ascii') > |
纯英文的str
可以用ASCII
编码为bytes
,内容是一样的,含有中文的str
可以用UTF-8
编码为bytes
。含有中文的str
无法用ASCII
编码,因为中文编码的范围超过了ASCII
编码的范围,Python会报错。
在bytes
中,无法显示为ASCII字符的字节,用\x##
显示。
反过来,如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes
。要把bytes
变为str
,就需要用decode()
方法:
1 | 'ABC'.decode('ascii') > b |
如果bytes
中包含无法解码的字节,decode()
方法会报错:
1 | '\xe4\xb8\xad\xff'.decode('utf-8') > b |
如果bytes
中只有一小部分无效的字节,可以传入errors='ignore'
忽略错误的字节:
1 | '\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore') > b |
要计算str
包含多少个字符,可以用len()
函数:
1 | 'ABC') > len( |
len()
函数计算的是str
的字符数,如果换成bytes
,len()
函数就计算字节数:
1 | 'ABC') > len(b |
可见,1个中文字符经过UTF-8编码后通常会占用3个字节,而1个英文字符只占用1个字节。
在操作字符串时,我们经常遇到str
和bytes
的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对str
和bytes
进行转换。
由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:
1 |
|
第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;
第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。
申明了UTF-8编码并不意味着你的.py
文件就是UTF-8编码的,必须并且要确保文本编辑器正在使用UTF-8 without BOM编码:
格式化
如何输出格式化的字符串。我们经常会输出类似'亲爱的xxx你好!你xx月的话费是xx,余额是xx'
之类的字符串,而xxx的内容都是根据变量变化的,所以,需要一种简便的格式化字符串的方式。
在Python中,采用的格式化方式和C语言是一致的,用%
实现,举例如下:
1 | 'Hello, %s' % 'world' > |
你可能猜到了,%
运算符就是用来格式化字符串的。在字符串内部,%s
表示用字符串替换,%d
表示用整数替换,有几个%?
占位符,后面就跟几个变量或者值,顺序要对应好。如果只有一个%?
,括号可以省略。
常见的占位符有:
占位符 | 替换内容 |
---|---|
%d | 整数 |
%f | 浮点数 |
%s | 字符串 |
%x | 十六进制整数 |
其中,格式化整数和浮点数还可以指定是否补0和整数与小数的位数
如果你不太确定应该用什么,%s
永远起作用,它会把任何数据类型转换为字符串:
1 | >>> 'Age: %s. Gender: %s' % (25, True) |
有些时候,字符串里面的%
是一个普通字符怎么办?这个时候就需要转义,用%%
来表示一个%
:
1 | 'growth rate: %d %%' % 7 > |
format()
另一种格式化字符串的方法是使用字符串的format()
方法,它会用传入的参数依次替换字符串内的占位符{0}
、{1}
……,不过这种方式写起来比%要麻烦得多:
1 | 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125) |
例子
1 | # -*- coding: utf-8 -*- |
list和tuple
list
Python内置的一种数据类型是列表:list。list是一种有序的集合,可以随时添加和删除其中的元素。
比如,列出班里所有同学的名字,就可以用一个list表示:
1 | 'Michael', 'Bob', 'Tracy'] > classmates = [ |
变量classmates
就是一个list。用len()
函数可以获得list元素的个数:
1 | > len(classmates) |
用索引来访问list中每一个位置的元素,记得索引是从0
开始的:
1 | 0] > classmates[ |
当索引超出了范围时,Python会报一个IndexError
错误,所以,要确保索引不要越界,记得最后一个元素的索引是len(classmates) - 1
。
如果要取最后一个元素,除了计算索引位置外,还可以用-1
做索引,直接获取最后一个元素:
1 | 1] > classmates[- |
以此类推,可以获取倒数第2个、倒数第3个:
1 | 2] > classmates[- |
当然,倒数第4个就越界了。
list是一个可变的有序表,所以,可以往list中追加元素到末尾:
1 | 'Adam') > classmates.append( |
也可以把元素插入到指定的位置,比如索引号为1
的位置:
1 | 1, 'Jack') > classmates.insert( |
要删除list末尾的元素,用pop()
方法:
1 | > classmates.pop() |
要删除指定位置的元素,用pop(i)
方法,其中i
是索引位置:
1 | 1) > classmates.pop( |
要把某个元素替换成别的元素,可以直接赋值给对应的索引位置:
1 | 1] = 'Sarah' > classmates[ |
list里面的元素的数据类型也可以不同,比如:
1 | 'Apple', 123, True] > L = [ |
list元素也可以是另一个list,比如:
1 | 'python', 'java', ['asp', 'php'], 'scheme'] > s = [ |
要注意s
只有4个元素,其中s[2]
又是一个list,如果拆开写就更容易理解了:
1 | 'asp', 'php'] > p = [ |
要拿到'php'
可以写p[1]
或者s[2][1]
,因此s
可以看成是一个二维数组,类似的还有三维、四维……数组,不过很少用到。
如果一个list中一个元素也没有,就是一个空的list,它的长度为0:
1 | > L = [] |
tuple
另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改,比如同样是列出同学的名字:
1 | 'Michael', 'Bob', 'Tracy') > classmates = ( |
现在,classmates这个tuple不能变了,它也没有append(),insert()这样的方法。其他获取元素的方法和list是一样的,你可以正常地使用classmates[0]
,classmates[-1]
,但不能赋值成另外的元素。
不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。
tuple的陷阱:当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来,比如:
1 | >>> t = (1, 2) |
如果要定义一个空的tuple,可以写成()
:
1 | > t = () |
但是,要定义一个只有1个元素的tuple,如果你这么定义:
1 | 1) > t = ( |
定义的不是tuple,是1
这个数!这是因为括号()
既可以表示tuple,又可以表示数学公式中的小括号,这就产生了歧义,因此,Python规定,这种情况下,按小括号进行计算,计算结果自然是1
。
所以,只有1个元素的tuple定义时必须加一个逗号,
,来消除歧义:
1 | 1,) > t = ( |
Python在显示只有1个元素的tuple时,也会加一个逗号,
,以免你误解成数学计算意义上的括号。
最后来看一个“可变的”tuple:
1 | >>> t = ('a', 'b', ['A', 'B']) |
这个tuple定义的时候有3个元素,分别是'a'
,'b'
和一个list。不是说tuple一旦定义后就不可变了吗?怎么后来又变了?
别急,我们先看看定义的时候tuple包含的3个元素:
当我们把list的元素'A'
和'B'
修改为'X'
和'Y'
后,tuple变为:
表面上看,tuple的元素确实变了,但其实变的不是tuple的元素,而是list的元素。tuple一开始指向的list并没有改成别的list,所以,tuple所谓的“不变”是说,tuple的每个元素,指向永远不变。即指向'a'
,就不能改成指向'b'
,指向一个list,就不能改成指向其他对象,但指向的这个list本身是可变的!
理解了“指向不变”后,要创建一个内容也不变的tuple怎么做?那就必须保证tuple的每一个元素本身也不能变。
条件判断
计算机之所以能做很多自动化的任务,因为它可以自己做条件判断。
比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,用if
语句实现:
1 | age = 20 |
根据Python的缩进规则,如果if
语句判断是True
,就把缩进的两行print语句执行了,否则,什么也不做。
也可以给if
添加一个else
语句,意思是,如果if
判断是False
,不要执行if
的内容,去把else
执行了:
1 | age = 3 |
注意不要少写了冒号:
。
当然上面的判断是很粗略的,完全可以用elif
做更细致的判断:
1 | age = 3 |
elif
是else if
的缩写,完全可以有多个elif
,所以if
语句的完整形式就是:
1 | if <条件判断1>: |
if
语句执行有个特点,它是从上往下判断,如果在某个判断上是True
,把该判断对应的语句执行后,就忽略掉剩下的elif
和else
,所以,请测试并解释为什么下面的程序打印的是teenager
:
1 | age = 20 |
if
判断条件还可以简写,比如写:
1 | if x: |
只要x
是非零数值、非空字符串、非空list等,就判断为True
,否则为False
。
再议 input
最后看一个有问题的条件判断。很多同学会用input()
读取用户的输入,这样可以自己输入,程序运行得更有意思:
1 | birth = input('birth: ') |
输入1982
,结果报错:
1 | Traceback (most recent call last): |
这是因为input()
返回的数据类型是str
,str
不能直接和整数比较,必须先把str
转换成整数。Python提供了int()
函数来完成这件事情:
1 | s = input('birth: ') |
再次运行,就可以得到正确地结果。但是,如果输入abc
呢?又会得到一个错误信息:
1 | Traceback (most recent call last): |
原来int()
函数发现一个字符串并不是合法的数字时就会报错,程序就退出了。
例子
1 | # -*- coding: utf-8 -*- |