输入输出
输入函数input()和raw_input()
- 在Python3.x中只有input()作为输入函数,会将输入内容自动转换str类型;
- 在Python2.x中有input()和raw_input()两个输入函数,对于input()函数,你输入的是什么类型,他就传入什么类型;raw_input()和3.x中的input()作用一样。
>>> a = input()
3
>>> type(a)
<type 'int'>
>>> b = input()
''
>>> type(b)
<type 'str'>
>>> c = raw_input()
3
>>> type(c)
<type 'str'>
输出函数print()
在Python2.7中可以不用括号(用一个空格间隔),但是在Python3.x中统一为print(),必须有括号。
print(self, *args, sep=' ', end='\n', file=None)
- *args:可以输出多个参数。
- sep:指定输出的多个参数之间的间隔符,默认是一个空格。
- end:指定最后一个参数输出之后输出的字符,默认是换行符。
>>> print('a', 'b', 'c', sep='-', end='#')
a-b-c#
>>>
注释
行内注释用#,在一行的#之后被认为是注释。
多行注释用一对三个引号("""或'''都行,在Python中单引号和双引号没有区别)将注释内容引起来。
注:
- 指定Python解释器:“#!/usr/bin/env python”(在环境变量的PATH中寻找Python解释器)或“#!/usr/bin/python”(在路径usr/bin下寻找Python解释器)或“#!/usr/bin/python2”(在路径usr/bin下寻找Python2.x解释器)或“#!/usr/bin/python3”(在路径usr/bin下寻找Python3.x解释器),必须放在文件第一行(“#”后不能有空格),推荐使用第一种方式(因为有可能用户的Python没有安装在路径usr/bin下),如果使用的是Python3编写的脚本,也可以使用最后一种。
- 指定编码格式:“# -*- coding: UTF-8 -*-”或“# coding=utf-8”(放在文件开头第一行或第二行,并且第二种指定方式的等号“=”两边不能有空格),如果代码中包含中文,则必须指定py文件的编码格式为UTF-8(由于Python2.7.x默认的是ASCII,所以需要指定编码格式,Python3.x默认的就是UTF-8,所以不需要特别指定编码格式),不然在读取中文时会报错。另外,在用编辑器保存py文件时,也需要使用UTF-8来保存,不然也会报错的。
- 代码规范:#一般用于单行注释,且放在代码行之上或之后,双引号的三引号用作文档注释,即放在文件头及类和函数的下面用作说明,且这个文档注释可以用模块属性__doc__读取出来。
- 折叠代码块:在PyCharm中会将一对“# region”和“# endregion”看成一个代码折叠块,当然它们本身也是注释。
运算符
/:除运算,结果为浮点数(Python3为浮点数,Python2为整数(商))
//:模运算(在2.7中/和//都是模运算),得到两数相除的商
**:幂运算
*:乘运算,可以在序列中用这个符号定义序列,如lst = [3] * 4,lst为[3, 3, 3, 3],不限于列表,字符串和元组等也可以使用
%:结果为两数相处的余数
+=、-=、*=等:Python中可以使用+=、-=等运算,但是不可以使用“i++”这种运算方式
>=或<=:大于(小于)或等于,Python中可以这样使用:if a <= xxx <= b: pass
位运算符:&(位与),|(位或),^(位异或:当两个对应的二进位不同时,结果为1),~(位取反:对数据的每个二进制位取反,即把1变为0,把0变为1),<<或>>(左移位或右移位)
注:
- divmod(a, b):返回a除以b的商和余数的元组(参数a和b不限于整数)
变量
-
变量类型:Python中的变量在声明时不需要指定其类型,它会根据你的赋值自动判断,其实变量本身是没有类型的,类型指的是这个变量引用的对象的类型;在某些编程规范中,有一种约定是变量名中不要加类型说明,比如:a_int = 3, b_list = [1, 2, 4], c_obj = C()。因为Python是动态语言,它的变量的类型是随时可变的。
- 变量删除:删除变量使用del,删除某个变量“del var”,删除多个变量“del var1, var2, var3”,对于变量的赋值和删除,变量只是对它的引用,删除时并不能直接删除其引用的的对象,删除的是这个变量本身。
- 垃圾回收:Python中的每个对象都有一个引用计数,当其引用计数为0时,即没有其他对象引用它了,Python回收机制就会回收它。其实由于Python中的垃圾回收机制,你并不能真正删除任何东西,由Python自动判断它“没有人用了”才会删除它。
- 变量赋值:多个变量赋同一个值,可以这样:a = b = c = 'python';多个变量同时赋值,可以这样:a, b, c = 1, 2, 3; 对于变量值的交换,Python不需要中间变量,直接交换即可:var1, var2 = var2, var1。
- global:作用域为整个文件的变量为全局变量,在函数中如果想要修改全局变量的值,则需要使用关键字global声明此变量为全局变量。
- nonlocal:Python2中没有这个关键字,Python3中才有,如果想要修改外层非全局作用域中的变量时,需要使用关键字nonlocal声明此变量为局部变量。
注:当前版本的Python的关键字,使用keyword模块的kwlist查看即可。
>>> # global关键字使用 >>> a = 1
>>> def func():
global a
a += 1 >>> func()
>>> a
2
>>> # nonlocal关键字使用
>>> def test_out():
x = 1
def test_in():
nonlocal x
x += 1
test_in()
print(x) >>> test_out()
2
>>>
数字类型
int:有符号整数(如果超出范围会自动转换为长整数)。
long:长整数(其范围取决于用户的虚拟内存),Python3中已没有此类型,只有int类型了。
float:浮点数,即小数。
complex:复数(虚数在数字末尾加字母j表示),比如:3+2j或complex(3, 2)。
bool:布尔值(1代表True,0代表False,True+False的结果为1),另外True和False在Python2中并不是关键字,在Python3中才列入了关键字。
序列
1、元组:是一个有序的不可变的序列,用括号()表示,其中的元素用逗号分隔:
- 字符串:字符串可以看成是由单一数据类型(字符)组成的不用逗号表示的元组,从序列的角度来看它们其实是一样的;
- 不可变:元组和其元素是不可变的,但是元素可以是可变类型,比如list,这个点可能有点绕,可以自己练习下加深理解;
- 有序:元组中的元素是有顺序的,可用下标或分片等方法对其进行读取的操作;
- 空元组和单元素元组:当元组中只有一个元素时,一定要加上逗号,不然Python不会将其当做元组处理的,只会当做一个普通的括号来处理,当然,空元组可以直接使用()表示;
- 新元组:可以使用“+”对多个元组相加,返回一个新的元组;使用下标截取也会返回新的元组。
2、列表:是一个有序的可变的序列,使用中括号[]表示,元素之间用逗号分隔:
- 可变:列表本身和其中的元素都是可以进行“增删改查”的(如果元素类型允许);
- 元素类型:一个列表的每个元素的数据类型可以不同,可以是任意数据类型;
- 有序:列表的元素之间是有顺序的,可用下标或分片等方法对其进行读或改的操作;
- 新列表:两个列表相加“+”会返回一个新的列表,包含两个列表的所有元素,并保有原有的顺序;对列表进行切片截取,返回的也是一个新的列表。
- 切片:切片使用形如list_[start:stop:step]的语句,start和stop表示下标,正数的下标表示正序(从左到右,起始数为0),负数的下标表示反序(从右到左,起始数为-1),step为大于0的正整数时表示正序的切片步长,step为小于0的负整数时表示反序的切片步长;step一般不常用,默认为1,当没有指明对应的start/stop时,默认为正序或反序的起始或结束下标。
3、集合:是一个无序的可变的序列,可以用大括号{}表示(元素用逗号隔开),也可以用set()定义:
- 无序:因为是无序的,不能用下标进行读取等操作;
- 集合运算:它和数学上的集合概念相同,不可以有相同的元素,元素无序,可以进行交集、并集和差集运算;
- 可变和不可变:每个元素都可以是不同的不可变类型,但集合本身是可变的。
4、字典:是一个无序的可变的序列,使用大括号{}表示,字典的元素使用键值对(key: value)表示,元素之间用逗号分隔:
- 新建字典:新建一个字典有几种特别的方法,比如:dict([('a', 'b'), (11, 22), (33, 'cc')]),{i: 'python %s' % i for i in range(3)},以及dict(a='aaa', b='bbb', c='ccc')(这种方式的key只能以参数名的形式定义,最后会自动转换成对应的字符串);
- 可变:可以对字典进行“增删改查”操作;
- key和value:字典中的元素(键值对)都是独立的,所有的key和value可以是不同数据类型,但是key必须是不可变的类型(不可以是列表等可变的类型),且字典中每一个key都是唯一的,value则可以是任意数据类型;
- 无序:字典的元素(键值对)是无序的,不可用下标等有序序列的方法对其进行操作,只能通过元素的key来确定某一个元素(key是唯一的,value可以不唯一)。
注:
1、应用类型:列表,集合和字典属于可变类型,无论在什么地方对它的操作都是基于它本身的,所以需要小心使用,比如将一个列表传入函数后(对于函数来说就是一个参数),如果函数有对它进行了修改操作,那么执行函数后,这个列表也就改变了,如果需要使用它的,但又不想影响到它本身,可以使用深度拷贝(即copy模块的deepcopy()方法复制一个它拷贝)。
2、真假判断:这些值的bool值都为False:0,None,'',[],set(),{}。可直接进行“真假”判断。
>>>#字符串
>>> ch = 'hello python!'
>>> ch[4]
'o'
>>> ch[:4]
'hell'
>>> ch[4:]
'o python!'
>>> #元组
>>> tup = (3, 'aa', {'a': 'b'})
>>> tup
(3, 'aa', {'a': 'b'})
>>> tup = tup + ([1, 2, 3,4],)
>>> tup
(3, 'aa', {'a': 'b'}, [1, 2, 3, 4])
>>> tup[1:-1]
('aa', {'a': 'b'})
>>> tup[1] = 'bb'
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
tup[1] = 'bb'
TypeError: 'tuple' object does not support item assignment
>>> #列表
>>> lst = []
>>> lst = lst + [3, 'a', {'hello': 'python!'}]
>>> lst
[3, 'a', {'hello': 'python!'}]
>>> lst[:2]
[3, 'a']
>>> lst[2:]
[{'hello': 'python!'}]
>>> # 集合
>>> se = set([1, 2, 3])
>>> se
{1, 2, 3}
>>> se1 = set((2, 3, 3, 5, 6))
>>> se1
{2, 3, 5, 6}
>>> se & se1 #交集
{2, 3}
>>> se | se1 #并集
{1, 2, 3, 5, 6}
>>> se - se1 #差集
{1}
>>>
>>> #字典
>>> dct = {1: 'a', 2: 'b', 3: 'c', 4: 'd'}
>>> dct[1] = [1, 2, 3, 4]
>>> dct
{1: [1, 2, 3, 4], 2: 'b', 3: 'c', 4: 'd'}
>>> dct[0] = 'hello'
>>> dct
{0: 'hello', 1: [1, 2, 3, 4], 2: 'b', 3: 'c', 4: 'd'} 简单示例
条件和循环控制
- if条件控制:基本结构为:if-elif-else,if和elif后面跟一个布尔表达式,若值为真,则执行对应子语句块,若值为假,则跳过此条件块。
- while循环控制:while后面跟一个布尔表达式,若值为真,则执行其中的语句块,执行完后再一次判断布尔表达式的值和执行语句块,然后无限重复判断和执行,直到布尔表达式的值为假。可以使用continue结束本层循环的本次循环,而使用break则结束本层的整个循环。
- for循环:for用于遍历一个可迭代对象,使用continue可以结束本层循环的本次循环,而使用break则结束本层的整个循环。
- for和while的else:当for或while正常执行完后接着执行else中的内容,当for或while循环中使用break终止跳出循环后就不会执行else中的内容了。
- 简单语句组:if、while和for语句中的语句块如果只有一条简单的语句,这时候条件判断和字句块可以写在一行,比如:if a > 1: print(a)。
>>> for i in range(5):
print(i)
for j in range(20, 25):
if j == 21:
continue
if j == 23:
break
print(i, j) 0
0 20 #21项没有是因为continue结束了"j == 21"这次循环
0 22 #23项和24项是因为break结束了本层for循环
1
1 20
1 22
2
2 20
2 22
3
3 20
3 22
4 #break并没有作用于外层的for循环,所以会循环到底
4 20
4 22
>>> >>> for i in range(5): # 正常执行完毕
print(i)
else:
print('end') 0
1
2
3
4
end
>>> for i in range(5): # break中断循环后就不会执行else中的内容了
if i % 2 == 1:
break
print(i)
else:
print('end') 0
>>> # 简单语句组
>>> if 3 > 1: print('ok')
ok
>>> a = 3
>>> while a > 0: a -= 1
>>> for i in range(2): print(i)
0
1
>>>
函数
- 函数定义:Python中函数以def定义,用于实现某种功能,若是某段代码被多处使用,不妨将它定义成一个函数,或是它用于实现特定的功能,也可以将它定义成一个函数。
- 函数调用:一个函数func(),func为函数名,是这个函数引用(指向函数的地址);而加上括号func()则表示执行这个函数。
- 函数作用域:在函数中定义的变量为局部变量,在函数体外不可引用它。
- 参数默认值:在定义函数时可以为参数指定默认值,比如func(a=0),当没有传入该参数时,就会使用默认值,传参时如果没有指定参数名,则会按函数定义的顺序给参数赋值。
- 动态参数:使用*(元组)和**(字典)来定义函数的动态参数,动态参数有一个特别的写法“*args”和“**kwargs”,这两个写法合在一起就表示所有参数(“万能”的参数表示法),比如func(*var_tuple, **var_dict),*var_tuple会将传进来的参数以元组的形式存在var_tuple中,**var_dict会将以特定形式传进来的参数以字典的形式存在var_dict中。
- 函数加载:在文件中函数不会被运行,Python只是去加载它,除非它被引用执行;
- 文件加载:Python文件有一个系统变量为“__name__”,默认值为当前文件名,但是被当作主文件执行的文件默认值为“__main__”,所以可以使用"if '__name' == '__main__':"作为文件的执行入口。
- 函数返回值:若是这个函数没有使用return指定这个函数的返回值,那么这个函数的返回值默认为None。
- 匿名函数:使用lambda来创建一个简单的匿名函数,语法为:lambda [arg1 [,arg2,.....argn]]: expression。lambda的主体只是一个简单的表达式,而不是复杂的代码块,函数返回的是表达式的值。
注:
- 参数传值:如果定义函数时既有普通参数,也有指定默认值的参数,那么普通参数必须在前面。
- 参数默认值:建议不要定义为可变类型,因为本质上说,参数也是函数的变量,如果是可变类型,那么多次调用后这个默认值可能就不再是你定义的初始值了,最直观的表现就是两次相同的调用,却返回了不同的值。
- 作用域:Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问。
>>> def func(*args1, **args2): # 动态参数指不用指定参数参数个数和各个参数的形参名
print(args1)
print(args2)
print(args1[2])
print(args2['name']) >>> func
<function func at 0x0000000003450598>
>>> result = func(1, 2, 3, name = 'Jom', age = '')
(1, 2, 3)
{'age': '', 'name': 'Jom'}
3
Jom
>>> print(result) # 没有使用return指定返回值
None >>># 默认值为可变类型,同样的调用返回了却不同的结果 >>> def func(lst=[]):
lst.append(333)
return lst >>> func()
[333]
>>> func()
[333, 333]
>>>
迭代器与生成器
迭代器:
- 特点: 迭代器用于访问集合(此集合非彼集合set())中的元素,使用迭代器不需要提前准备好要迭代的所有元素,只有迭代到某个元素时才会计算该元素,这个元素之前或之后都是没有的,因为迭代器这个特点,它遍历集合元素占用的内存很少,适用于访问一些特别大的甚至是无限的集合。
- 访问迭代器:访问迭代器元素时会使用自身的__next__()方法(Python2为next())不断地去访问下一个元素,且迭代器只能“前进”,不能“后退”,也不能通过下标等去访问某个特定的元素。当访问完迭代器后,这个迭代器就“完了”,要想再遍历这个集合,就要为这个集合再新建一个迭代器了。
- __iter__方法和__next__方法:当将一个类作为迭代器时,即自定义迭代器时,需要实现__iter__和__next__这两个方法(Python2为next()),__iter__用于返回一个定义了__next__方法的对象,__next__方法用于返回每次迭代时的对象,并且需要定义StopIteration异常来标识迭代的完成。
- iter()和next():这是用于迭代器的两个内建函数,iter()用于为一个可迭代对象创建一个迭代器,next()则用于访问迭代器的元素。
注:Python2中迭代器自身的迭代方法是next(),Python3中为__next__()。
>>> # 创建迭代器
>>> class MyIter:
def __init__(self):
self.a = 1 def __iter__(self):
return self def next(self):
a_ = self.a
if a_ < 5:
self.a += 1
return a_
else:
raise StopIteration >>> it = MyIter()
>>> next(it)
1
>>> for item in it:
print(item) 2
3
4
>>> next(it) Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
next(it)
StopIteration
>>>
>>> # iter()和next()方法的使用
>>> lst = ['a', 'b', 'c']
>>> new_it = iter(lst)
>>> next(new_it)
'a'
>>> new_it.next()
'b'
>>> for item in new_it:
print(item) c
>>>
生成器:
- 定义:如果一个函数被调用时返回了一个迭代器,那么这个函数就叫做生成器;如果一个函数中含有yield语法,那么这个函数也是生成器;
- yield语法的特点:当含有yield语法的函数被调用后,执行yield后,就会中断这个函数,继续执行这个函数之后的代码,当下一次这个函数再被调用时,会从这个函数的上次执行的yield之后的代码开始执行。
>>> def generator():
n = 3
while n > 0:
yield 'hello python!' # 含有yield,这个函数即为生成器,每次生成一个字符串“hello python!”
n -= 1 >>> iterator = generator() # 返回一个迭代器
>>> iterator.__next__()
'hello python!'
>>> iterator.__next__()
'hello python!'
>>> iterator.__next__()
'hello python!'
>>> iterator.__next__() # 访问完后就“没有了”,这个迭代器也不能再用了
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
iterator.__next__()
StopIteration
>>>
异常处理
将可能会发生异常错误的代码放在try块里面,如果发生异常就会使用except进行捕捉,并执行except中的代码,最后无论是否发生异常,都会执行finally块中的代码。
如果发生了异常,那么try块中发生异常的代码之后的代码将不会被执行,且如果发生的异常没有任何一个except捕捉到,这个异常又会传递回try语句块中。
如果定义了多个except语句,它们就像条件判断中的elif一样,最多只会执行一个except块。
try...except...else...如果try语句中没有异常发生就会继续执行else中的语句,如果发生了异常就不会去执行else中的语句了。
try:
# 此处为可能会发生异常错误的代码,如果发生异常将会抛出异常
pass
except ValueError as e:
# 捕捉指定的异常ValueError,并取别名为e
# 如果捕捉到指定的异常(如ValueError),就会在进入这里进行处理
pass
except (TypeError, NameError):
# 可以一次指定捕获多个异常,多个异常一元组形式指定即可
pass
except:
# 没有指定异常时,表示捕捉所有异常
# 如果抛出的异常在前面所有指定的异常都没有捕捉到,那么就会进入这里,
pass
finally:
# 无论是否发生异常都会执行此处代码
pass
编程建议:
- 在异常处理时尽量指定需要捕获的异常,虽然except不指定任何异常时可以捕获所有异常,但同时也可能是你错过某些异常(虽然程序没有报错,其实异常可能已经发生了)。
- 尽量使用finally来进行一些无论是否发生异常都要进行的“最后”的处理。
其他知识点:
- 打印异常信息:可以使用trackback模块的format_exc()函数打印异常信息
- 抛出异常:使用“raise MyError”来抛出异常,并在except捕获这个异常
- 自定义异常:自定义的异常类,需要直接或间接继承Exception类,且一般以Error作为后缀