一、开始 Python 之旅交互模式
1.Ctrl + D 输入一个 EOF 字符来退出解释器,也可以键入 exit() 来退出
2.#!/usr/bin/env python3
中#!称为 Shebang,目的是告诉shell使用Python 解释器执行其下面的代码。
3.注意遵守以下约定:
- 使用 4 个空格来缩进
- 永远不要混用空格和制表符
- 在函数之间空一行
- 在类之间空两行
- 字典,列表,元组以及参数列表中,在 , 后添加一个空格。对于字典,: 后面也添加一个空格
- 在赋值运算符和比较运算符周围要有空格(参数列表中除外),但是括号里侧不加空格:a = f(1, 2) + g(3, 4)
4.模块是包含能复用的代码的文件,包含了不同的函数定义,变量。模块文件通常以 .py 为扩展名,在使用模块前先导入它。
二、变量和数据类型
1.关键字(不能用于通常的标识符)
2.定义变量
不需要为变量指定数据类型,操作字符串时用单引号或双引号括起来
3.从键盘读取输入
number = int(input("Enter an integer: "))
4.在一行内将多个值赋值给多个变量
>>> a , b = 4, 5
>>> a
4
>>> b
5
用逗号创建元组,在赋值语句的右边创建元组称这为元组封装(tuple packing),赋值语句的左边做的是元组拆封 (tuple unpacking)。
三、运算符和表达式
divmod()
divmod()
函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)
:
若现在通过获得用户输入的天数,算出月份数和天数,则可以使用该函数轻松get到答案:
#!/usr/bin/env python3
days = int(input("Enter days: "))
print("Months = {} Days = {}".format(*divmod(days, 30))) 用 * 运算符拆封这个元组
整除
如果要进行整除,使用 // 运算符,它将返回商的整数部分:
思考:如果是12 / 3
,结果是多少呢?大家一定会说是不是傻?肯定是4啊!那试试呗:
和你想的不一样吧!所以/
不管是不是整除,结果都是浮点数。
逻辑运算符
逻辑运算符 and 和 or 也称作短路运算符:它们的参数从左向右解析,一旦结果可以确定就停止 。作用于一个普通的非逻辑值时,短路运算符的返回值通常是能够最先确定结果的那个操作数。
运算符 | 逻辑表达式 | 描述 |
---|---|---|
and | x and y | 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 |
or | x or y | 如果 x 是非 0,它返回 x 的值,否则它返回 y 的计算值。 |
not | not x | 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 |
>>> 5 and 4 (5为True还要往后看,所以最先确定的操作数是4)
4
>>> 0 and 4 (0为False不需往后看,所以最先确定的操作数是0)
0
>>> False or 3 or 0 (False还要往后看,3为True不需往后看,所以最先确定的操作数是3)
3
运算符优先级
类型转换
类型转换中,int、float转字符串用str()
就行了,非常容易理解,字符串是"数字"字符串(\'1234\')转int也好理解,但如果是字符串\'a\'呢?可能你会想到ASCII,用int(\'a\')
可以吗?
结果显示不可以,所以,再恶补点知识吧!
1.十进制字符串转整数
int(\'12\') ==12
2.十六进制字符转整数
int(\'a\',16) == 10
例MAC地址转整数:
a=\'FF:FF:FF:FF:FF:FF\'.split(:)
int(a[0],16) = 255
int(a[1],16) = 255
int(a[2],16) = 255
int(a[3],16) = 255
int(a[4],16) = 255
int(a[5],16) = 255
3.字符转整数
ord(\'a\')==97
4.整数转为字符
chr(65) == \'A\'
四、循环
range()
range() 生成一个等差数列(并不是列表):
>>> for i in range(3):
... print(i)
...
0
1
2
>>> range(1, 5)
range(1, 5)
>>> list(range(1, 5))
[1, 2, 3, 4]
>>> list(range(1, 15, 3))
[1, 4, 7, 10, 13]
循环的 else 语句
可以在循环后面使用可选的 else 语句,它将会在循环完毕后执行,除非有 break 语句终止了循环。
斐波那契(Fibonacci)数列
Python 中赋值语句执行时会先对赋值运算符右边的表达式求值,然后将这个值赋值给左边的变量。
如果要把结果输出不换行呢?print() 除了打印提供的字符串之外,还会打印一个换行符,所以每调用一次 print() 就会换一次行。可以通过参数 end 来替换换行符:
a, b = 0, 1
while b < 100:
print(b, end=\' \')
a, b = b, a + b
print()
幂级数:e^x = 1 + x + x^2 / 2! + x^3 / 3! + ... + x^n / n! (0 < x < 1)
#!/usr/bin/env python3
x = float(input("Enter the value of x: "))
n = term = num = 1
result = 1.0
while n <= 100:
term *= x / n
result += term
n += 1
if term < 0.0001:
break
print("No of Times= {} and Sum= {}".format(n, result))
打印图形
print("#" * 50)
字符串若是乘上整数 n,则返回由 n 个此字符串拼接起来的新字符串。如要打印出下图:
row = int(input("Enter the number of rows: "))
n = row
while n >= 0:
x = "*" * n
y = " " * (row - n)
print(y + x)
n -= 1
五、数据结构
列表
列表可以写作中括号之间的一列逗号分隔的值。列表的元素不必是同一类型,通过索引来访问列表中的每一个值,列表允许修改元素,允许嵌套。
a.append() 添加元素到列表的末端
a.insert(0, 1) 在列表索引 0 位置添加元素 1
a.count(s) 返回列表中 s 元素出现的次数。
a.remove(s) 移除列表中s元素
a.pop(n) 返回索引为n的元素并把它从列表中删除,无参数时默认最后一个元素
del a[n] 删除索引为n的列表元素
a.reverse() 反转整个列表
a.sort() 给列表排序,排序的前提是列表的元素是可比较的
a.extend(b) 将b列表的所有元素添加到a列表末尾,注意是添加 b 的元素而不是 b 本身
思考:如果列表中有相同的元素,用remove删除的是前面那个还是后面那个,亦或是全删除呢?实践一下呗!
列表推导式由包含一个表达式的中括号组成,表达式后面跟随一个 for 子句,之后可以有零或多个 for 或 if 子句。结果是一个列表,由表达式依据其后面的 for 和 if 子句上下文计算而来的结果构成。以下两种方式等同:
列表推导式也可以嵌套:
>>> a=[1,2,3]
>>> z = [x + 1 for x in [x ** 2 for x in a]]
>>> z
[2, 5, 10]
如果在遍历列表(或任何序列类型)的同时获得元素索引值,可以使用 enumerate()
:
>>> for i, j in enumerate([\'a\', \'b\', \'c\']):
... print(i, j)
...
0 a
1 b
2 c
同时遍历两个序列类型可以使用zip()
:
>>> a = [\'a\', \'b\']
>>> b = [\'c\', \'d\']
>>> for x, y in zip(a, b):
... print("{} and {}".format(x, y))
元组
元组是由数个逗号分割的值组成,且为不可变类型,意味着不能在元组内删除或添加或编辑任何值。
>>> a = \'a\', \'b\', \'c\',
>>> a
(\'a\', \'b\', \'c\')
创建只含有一个元素的元组,在值后面跟一个逗号,这是因为括号()既可以表示元组,又可以表示数学公式中的小括号,这就产生了歧义。
>>> a = (123) 这样定义的将是123这个元素,而不是一个元组。
>>> a
123
>>> type(a)
<class \'int\'>
>>> a = (123, )
>>> b = 321,
>>> a
(123,)
>>> b
(321,)
>>> type(a)
<class \'tuple\'>
>>> type(b)
<class \'tuple\'>
可以对任何一个元组执行拆封操作并赋值给多个变量,注意赋值时数量要匹配:
集合
集合是一个无序不重复元素的集,大括号或 set() 可以用来创建集合
>>> basket = {\'apple\', \'orange\', \'apple\', \'pear\', \'orange\', \'banana\'}
>>> print(basket) 可以看到重复的元素被去除
{\'orange\', \'banana\', \'pear\', \'apple\'}
>>> a = set(\'abracadabra\')
>>> b = set(\'alacazam\')
>>> a
{\'a\', \'r\', \'b\', \'c\', \'d\'} a 去重后的字母
>>> a - b a 有而 b 没有的字母
>>> a | b 存在于 a 或 b 的字母
>>> a & b a 和 b 都有的字母
>>> a ^ b 存在于 a 或 b 但不同时存在的字母
>>> a.add(\'c\')
>>> a
{\'c\',a\', \'r\', \'b\', \'c\', \'d\'} 不同于列表的append(),在起始位置添加
字典
字典是是无序的键值对(key:value)集合,同一个字典内的键必须是互不相同的。一对大括号 {}创建一个空字典。字典中的键必须是不可变类型,比如不能使用列表作为键。
>>> data = {\'kushal\':\'Fedora\', \'kart_\':\'Debian\', \'Jace\':\'Mac\'}
>>> data[\'kart_\']
\'Debian\'
>>> data[\'parthan\'] = \'Ubuntu\' 创建新的键值对
>>> data
{\'kushal\': \'Fedora\', \'Jace\': \'Mac\', \'kart_\': \'Debian\', \'parthan\': \'Ubuntu\'}
>>> del data[\'kushal\'] del 删除任意指定的键值对
>>> data
{\'Jace\': \'Mac\', \'kart_\': \'Debian\', \'parthan\': \'Ubuntu\'
>>> dict(((\'In\',\'Del\'),(\'Bang\',\'Dh\'))) dict() 从包含键值对的元组中创建字典
{\'In\': \'Del\', \'Bang\': \'Dh\'}
>>> for x, y in data.items(): items()获得由键和值组成的列表
... print("{} uses {}".format(x, y))
dic.clear()清空字典
dic.keys()获得键的列表
dic.values()获得值的列表
dic.copy()复制字典
dic.pop(k)删除键k
dic.get(k)获得键k的值
dic.update()更新成员,若成员不存在,相当于加入
很多时候需要往字典中的元素添加数据,使用dict.setdefault(key, default)
:
>>> data = {}
>>> data.setdefault(\'names\', []).append(\'Ruby\')
>>> data
{\'names\': [\'Ruby\']}
>>> data.setdefault(\'names\', []).append(\'Python\')
>>> data
{\'names\': [\'Ruby\', \'Python\']}
>>> data.setdefault(\'names\', []).append(\'C\')
>>> data
{\'names\': [\'Ruby\', \'Python\', \'C\']}
更多详见:
Python中的列表(list),元组(Tuple),字典(Dict)和集合(Set)、Python列表、元组、集合、字典的区别和相互转换
切片
切片的语法表达式为[start_index : end_index : step]
:
- start_index表示起始索引
- end_index表示结束索引
- step表示步长,步长不能为0,且默认值为1
切片操作是指按照步长,截取从起始索引到结束索引,但不包含结束索引的所有元素。
- python3支持切片操作的数据类型有list、tuple、string、unicode、range
- 切片返回的结果类型与原对象类型一致
- 切片不会改变原对象,而是重新生成了一个新的对象
切片的索引可分为正向和负向两种:
举个例子:
>>> C = [\'A\',\'B\',\'C\',\'D\',\'E\',\'F\']
>>> C[0:5:1]
[\'A\', \'B\', \'C\', \'D\',\'E\']
省略 start_index 会从第一个元素开始,省略 end_index 会切到最后一个元素为止:
>>> C[2:]
[\'C\', \'D\', \'E\', \'F\']
步长为负数时即为逆着切,一定要保证start_index到end_index的方向与步长step的方向同向,否则会切出空的序列:
>>> C[0:3:-1]
[]
>>> C[3:0:1]
[]
数据结构举例
1.判断学生成绩是否达标:要求输入学生数量,以及各个学生物理、数学、历史三科的成绩,如果总成绩小于 120,程序打印 “failed”,否则打印 “passed”。
n = int(input("Enter the number of students: "))
data = {} 用来存储数据的字典变量
Subjects = (\'Physics\', \'Maths\', \'History\')
for i in range(1, n+1):
name = input(\'Enter the name of the student {}: \'.format(i))
marks = []
for x in Subjects:
marks.append(int(input(\'Enter marks of {}: \'.format(x))))
data[name] = marks
for x, y in data.items():
total = sum(y)
print("{}\'s total marks {}".format(x, total))
if total < 120:
print(x, "failed :(")
else:
print(x, "passed :)")
运行如下:
2.用以下代码解决矩阵问题:
n = int(input("Enter the value of n: "))
print("Enter values for the Matrix A")
a = []
for i in range(n):
a.append([int(x) for x in input().split()])
print(a)
其实这里不太理解为什么最后结果为列表嵌套列表(str.split(str="", num=string.count(str)),str -- 分隔符,默认为所有的空字符,包括空格、换行(\\n)、制表符(\\t)等,num -- 分割次数)
,而且以为这是生成 n × n 的矩阵,所以进行以下实践:
可以看出,split()最后拆成的是列表,以换行符结束一次循环,并不是生成n × n 的矩阵。相对于split(),join()使用指定字符连接多个字符串,它需要一个包含字符串元素的列表作为输入,然后连接列表内的字符串元素:
>>> "-".join("GNU/Linux is great".split())基于空格分割字符串(列表),再用 "-" 连接
\'GNU/Linux-is-great\'
六、字符串
三引号(triple quotes)
python三引号允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符。
>>> h = \'\'\'hi
Jspo\'\'\'
>>> hi
\'hi\\nJspo\'
>>> print hi
hi
Jspo
三引号让程序员从引号和特殊字符串的泥潭里面解脱出来,自始至终保持一小块字符串的格式是所谓的WYSIWYG(所见即所得)格式的。一个典型的用例是,当需要一块HTML或者SQL时,这时用字符串组合,特殊字符串转义将会非常的繁琐。
此外,在 Python 里使用文档字符串(docstrings)来说明如何使用代码:
def longest_side(a, b):
"""
Function to
"""
return True
字符串常用操作
string.title() 返回字符串的标题版本,即单词首字母大写其余字母小写
string.upper() 返回字符串全部大写版本
string.lower() 返回字符串全部小写版本
string.swapcase() 返回字符串大小写交换后的版本
string.isalnum() 检查所有字符是否为字母数字
string.isalpha() 检查字符串之中是否只有字母
string.isdigit() 检查字符串是否所有字符为数字
strip(chars)用来剥离字符串首尾中指定的字符,不指定参数则默认剥离掉首尾的空格和换行符。用 lstrip(chars) 或 rstrip(chars) 只对字符串左或右剥离:
>>> s = "www.foss.in"
>>> s.lstrip("cwsd.") 删除在字符串左边出现的\'c\',\'w\',\'s\',\'d\',\'.\'字符
\'foss.in\'
>>> s.rstrip("cnwdi.") 删除在字符串右边出现的\'c\',\'n\',\'w\',\'d\',\'i\',\'.\'字符
\'www.foss\'
文本搜索
find() 能帮助找到第一个匹配的子字符串,没有找到则返回 -1。string.find(str, beg=0, end=len(string))
检测 str 是否包含在 string 中,如果 beg 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回-1。
s.startswith(str) 检查字符串是否以 str 开头
s.endswith(str) 检查字符串是否以 str 结尾
字符串更多操作详见:Python 字符串
例题(挑战:字符串操作)
String.txt文件内容为awe3fa8fa4aewfawijfa;fjaweawfeawawefargaefaef5awefasdfeargfasdcds2awea4afadszsdvzxefafzsdva7fasdczdvafedszv6zvczvdsf2awefafzsdccsea
,请把该文件中所有的数字组成一个新的字符串,并且打印出来。
注:学了后面的课程发现这个挑战自己没将文件关闭(file.close()),要养成习惯,不然记得使用 with!
七、函数
def 函数名(参数列表):
函数体
不带表达式的return相当于返回 None。
参数传递
在 python 中,类型属于对象,变量是没有类型。如a=[1,2,3]和a="Jspo"
,[1,2,3] 是 List 类型,"Jspo" 是 String 类型,而变量 a 是没有类型,仅仅是一个对象的引用(一个指针),可以是指向 List 类型对象,也可以是指向 String 类型对象。
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
- 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a
- 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了
python 函数的参数传递:
- 不可变类型:类似值传递,传递的只是a的值,没有影响a对象本身(加
global
变为全局变量) - 可变类型:类似引用传递
参数类型
-
必需参数:以正确的顺序传入函数,调用时的数量必须和声明时的一样
-
关键字参数:形如
keyword = value
,使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值
-
默认参数:调用函数时,如果没有传递参数,则会使用默认参数,默认参数必须放在最后。如上图如果调用者未给出 b、c 的值,那么它们的值默认为5和10
-
不定长参数:需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,声明时不会命名
对不定长参数再说几句:加了星号(*)的变量名会存放所有未命名的变量参数,不能存放dict。加了星号(**)的变量名会存放所有未命名的变量参数(如果在函数调用时没有指定参数,它就是一个空元)。举个例子:
def multiple(arg, *args, **dictargs):
print("arg: ", arg)
#打印args
for value in args:
print("other args:", value)
#打印dict类型的不定长参数 args
for key in dictargs:
print("dictargs:" + key + ":" + str(dictargs[key]))
if __name__ == \'__main__\':
multiple(1,\'a\',True, name=\'Amy\',age=12)
高阶函数
map 接受一个函数和一个序列(迭代器)作为输入,然后对序列(迭代器)的每一个值应用这个函数,返回一个序列(迭代器),其包含应用函数后的结果。
>>> lst = [1, 2]
>>> def s(num):
... return num * num
...
>>> print(list(map(s, lst)))
[1, 4]
注:千万别忘了map前加list!
八、文件处理
常见操作
使用 open() 函数打开文件,需要两个参数,第一个参数是文件路径或文件名,第二个是文件的打开模式:
- "r",以只读模式打开,你只能读取文件但不能编辑/删除文件的任何内容
- "w",以写入模式打开,如果文件存在将会删除里面的所有内容,然后打开这个文件进行写入
- "a",以追加模式打开,写入到文件中的任何数据将自动添加到末尾
例题
例1:拷贝给定的文本文件到另一个给定的文本文件:
import sys
if len(sys.argv) < 3:
print("Wrong parameter")
print("./copyfile.py file1 file2")
sys.exit(1)
f1 = open(sys.argv[1])
s = f1.read()
f1.close()
f2 = open(sys.argv[2], \'w\')
f2.write(s)
f2.close()
sys模块:sys.argv 包含所有命令行参数。
sys.argv 的第一个值是命令自身的名字:
import sys
print("First value", sys.argv[0])
print("All values")
for i, x in enumerate(sys.argv):
print(i, x)
enumerate(iterableobject)可以同时得到索引位置和对应值。
例2:对任意给定文本文件中的制表符、行、空格进行计数。
import os
import sys
def parse_file(path):
fd = open(path)
i = 0
spaces = 0
tabs = 0
for i,line in enumerate(fd):
spaces += line.count(\' \')
tabs += line.count(\'\\t\')
# 现在关闭打开的文件
fd.close()
# 以元组形式返回结果
return spaces, tabs, i + 1
def main(path):
if os.path.exists(path):
spaces, tabs, lines = parse_file(path)
print("Spaces {}. tabs {}. lines {}".format(spaces, tabs, lines))
return True
else:
return False
if __name__ == \'__main__\':
if len(sys.argv) > 1:
main(sys.argv[1])
else:
sys.exit(-1)
sys.exit(0)
小Tips:
如果要统计文件的行数,可以用count = len(open(filepath, \'r\').readlines())
,虽然简单,但是可能比较慢,当文件比较大时甚至不能工作。因此可以利用enumerate():
count = 0
for index, line in enumerate(open(filepath,\'r\')):
count += 1
此外,使用 with 语句处理文件对象会在文件用完后会自动关闭,就算发生异常也没关系。它是 try-finally 块的简写:
with open(\'sample.txt\') as f:
for line in f:
print(line, end = \'\')
九、异常
- 在 Python3 中使用 Python2 独有的语法就会发生 SyntaxError
- 当有人试图访问一个未定义的变量则会发生 NameError
- 当操作或函数应用于不适当类型的对象时引发TypeError,一个常见的例子是对整数和字符串做加法
try--except
- 首先,执行 try 子句 ,如果没有异常发生,except 子句 在 try 语句执行完毕后就被忽略了。
- 如果在 try 子句执行过程中发生了异常,那么该子句其余的部分就会被忽略。
- 如果异常匹配于 except 关键字后面指定的异常类型,就执行对应的 except 子句。然后继续执行 try 语句之后的代码。
- 如果发生了一个异常,在 except 子句中没有与之匹配的分支,它就会传递到上一级 try 语句中。
- 如果最终仍找不到对应的处理语句,它就成为一个 未处理异常,终止程序运行,显示提示信息。
except可以处理一个专门的异常,也可以处理一组圆括号中的异常,如果except后没有指定异常,则默认处理所有的异常。
raise
raise 语句抛出一个异常。如"挑战:玩转函数"中要求用户能够通过命令行输入分钟数,程序需要打印出相应的小时数和分钟数。如果用户输入的是一个负值,程序需要报错 ValueError,在屏幕上打印出ValueError: Input number cannot be negative
提示用户输入的值有误。
import sys
def ToHours(time):
print("{} H, {} M".format(*divmod(time, 60)))
time =int (sys.argv[1])
if time < 0:
try:
raise ValueError
except ValueError:
print("ValueError: Input number cannot be negative")
else:
ToHours(time)
finally
不管有没有发生异常,finally 子句在程序离开 try 后都一定会被执行。当 try 语句中发生了未被 except 捕获的异常(或者它发生在 except 或 else 子句中),在 finally 子句执行完后它会被重新抛出:
>>> try:
... raise KeyboardInterrupt
... finally:
... print(\'Goodbye, world!\')
...
Goodbye, world!
KeyboardInterrupt
Traceback (most recent call last):
File "<stdin>", line 2, in ?
在真实场景的应用程序中,finally 子句用于释放外部资源(文件或网络连接之类的),无论它们的使用过程中是否出错。