语法进阶
一、数据结构
1、列表
列表可以修改,而字符串和元组不能
方括号表示这个参数是可选的,而不是要求你输入一对方括号,你会经常在 Python 库参考手册中遇到这样的标记。
方法 | 描述 |
---|---|
list.append(x) | 尾插(a[len(a):] = [x]) |
list.extend(L) | 通过添加指定列表的所有元素来扩充列表(a[len(a):] = L) |
list.insert(i, x) | 头差( a.insert(0, x) 会插入到整个列表之前) |
list.remove(x) | 删除列表中第一个值为 x 的元素(没有x报错) |
list.pop([i]) | 从列表的指定位置移除元素,并将其返回。如果没有指定索引,a.pop()返回最后一个元素。元素随即从列表中被移除。 |
list.clear() | 清空(del a[:]) |
list.index(x) | 返回列表中第一个值为 x 的元素的索引(没有x报错) |
list.count(x) | 返回 x 在列表中出现的次数 |
list.sort() | 对列表中的元素进行排序。 |
list.reverse() | 翻转列表 |
list.copy() | 返回列表的浅复制(a[:]) |
2、列表->堆栈
append() 方法:把一个元素添加到堆栈顶
不指定索引的 pop() 方法:把一个元素从堆栈顶释放出来
3、del 语句
使用 del 语句可以从一个列表中根据索引来删除一个元素,而不是值来删除元素
可以用 del 语句从列表中删除一个切割,或清空整个列表
>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.25, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.25, 1234.5]
>>> del a[:]
>>> a
[]
4、遍历
1)字典的items()
items() :同时解读关键字和对应的值
info = {'name' : 'wmh', 'web' : 'rexhao.work'}
for k,v in info.items():
print(k,v)
# name wmh
# web rexhao.work
2)序列的enumerate()
enumerate():在序列中遍历时,同时得到索引位置和对应值
for i, v in enumerate(['rex', 'hao', 'work']):
print(i, v)
# 0 rex
# 1 hao
# 2 work
3)同时遍历多个序列
>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
... print('What is your {0}? It is {1}.'.format(q, a))
...
What is your name? It is lancelot.
What is your quest? It is the holy grail.
What is your favorite color? It is blue.
4)反向遍历
>>> for i in reversed(range(1, 10, 2)):
... print(i)
5)排序后遍历
sorted() :返回一个已排序的序列,并不修改原值
>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
... print(f)
...
apple
banana
orange
pear
二、模块
1、import 语句
import module1[, module2[,... moduleN]
当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入
搜索路径是一个解释器会先进行搜索的所有目录的列表(搜索路径是由一系列目录名组成的,解释器就依次从这些目录中去寻找所引入的模块)
查看搜索路径:导入sys包、打印sys.path
sys.path的其中第一项是空串''
:代表当前目录
2、from … import 语句
从模块中导入一个指定的部分到当前命名空间中
这个声明不会把整个fibo模块导入到当前的命名空间中,它只会将fibo里的fib函数引入进来
from … import *
:把一个模块的所有内容全都导入到当前的命名空间
3、__name__属性
每个模块都有一个__name__
属性,当其值是'__main__
'时,表明该模块自身在运行,否则是被引入
4、dir() 函数
内置的函数 dir() 可以找到模块内定义的所有名称。返回一个字符串列表
5、包
包是一种管理 Python 模块命名空间的形式,采用"点模块名称"
目录只有包含一个叫做 __init__.py
的文件才会被认作是一个包
- 对于
from package import item
,对应的 item 可以是包里面的子模块(子包),或者包里面定义的函数,类或者变量。 import
会首先把 item 当作一个包定义的名称,再试图按照一个模块去导入。没找到抛出:exc:ImportError
异常。import item.subitem.subsubitem
:除了最后一项,都必须是包,最后一项则可以是模块或者是包(但是不可以是类,函数或者变量)
三、输入输出
1、输出的值转成字符串
str(): 函数返回一个用户易读的表达形式。
repr(): 产生一个解释器易读的表达形式。
>>> s = 'Hello, rex'
>>> str(s)
'Hello, rex'
>>> repr(s)
"'Hello, rex'"
2、输出格式美化
str.format()使用
>>> print('{}网址:"{}!"'.format('blog', 'rexhao.work'))
blog网址: "rexhao.work"
# 括号中的数字用于指向传入对象在 format() 中的位置
>>> print('{0} 和 {1}'.format('Google', 'wmh'))
Google 和 wmh
>>> print('{1} 和 {0}'.format('Google', 'wmh'))
wmh 和 Google
# 使用了关键字参数
>>> print('{name}网址:"{web}!"'.format(name='blog', web='rexhao.work'))
blog网址: "rexhao.work"
# 可选项:和格式标识符可以跟着字段名,或者传入一个整数, 可以保证该域至少有这么多的宽度
>>> import math
>>> print('π = {0:.3f}。'.format(math.pi))
π = 3.142。
3、旧式字符串格式化
%
操作符也可以实现字符串格式化。
类似于c中的printf
>>> import math
>>> print('常量 PI 的值近似为:%5.3f。' % math.pi)
常量 PI 的值近似为:3.142。
4、读取键盘输入
str = input("请输入:");
print ("你输入的内容是: ", str)
四、File
1、open()概述
open()
:方法用于打开一个文件,并返回文件对象。如果该文件无法被打开,会抛出 OSError
使用open()
方法一定要保证关闭文件对象,即调用close()
方法
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
2、open()参数说明
- file: 必需,文件路径(相对或者绝对路径)。
- mode: 可选,文件打开模式
- buffering: 设置缓冲区
- encoding: 一般使用utf8
- errors: 报错级别
- newline: 区分换行符
- closefd: 传入的file参数类型
- opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。
3、mode 参数
| 模式 | 描述 | | : | :----------------------------------------------------------- | | t | 文本模式 (默认)。 | | x | 写模式,新建一个文件,如果该文件已存在则会报错。 | | b | 二进制模式。 | | + | 打开一个文件进行更新(可读可写)。 | | U | 通用换行模式(Python 3 不支持)。 | | r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 | | rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。 | | r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 | | rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 | | w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 | | wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 | | w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 | | wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 | | a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 | | ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 | | a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 | | ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
默认为文本模式,如果要以二进制模式打开,加上 b
4、file对象方法
- file.close():关闭文件。关闭后文件不能再进行读写操作
- file.flush():刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。
- file.fileno():返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。
- file.isatty():如果文件连接到一个终端设备返回 True,否则返回 False。
- file.read([size]):从文件读取指定的字节数,如果未给定或为负则读取所有。
- file.readline([size]):读取整行,包括 "\n" 字符。
- file.readlines([sizeint]):读取所有行并返回列表,若给
- sizeint>0,返回总和大约为sizeint字节的行, 实际读取值可能比 sizeint 较大, 因为需要填充缓冲区。
- file.seek(offset[, whence]):移动文件读取指针到指定位
- file.tell():返回文件当前位置
- file.truncate([size]):从文件的首行首字符开始截断,截断文件为 size 个字符,无 size 表示从当前位置截断;截断之后后面的所有字符被删除,其中 windows 系统下的换行代表2个字符大小
- file.write(str):将字符串写入文件,返回的是写入的字符长度
- file.writelines(sequence):向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。
五、异常
1、异常概述
即便 Python 程序的语法是正确的,在运行它的时候,也有可能发生错误。运行期检测到的错误被称为异常。
大多数的异常都不会被程序处理,都以错误信息的形式展现在控制台
2、异常处理
1)try/except
类似与javase的try...catch...
while True:
try:
x = int(input("请输入数字: "))
break
except ValueError:
print("您输入的不是数字,请再次尝试输入!")
一个 try 语句可能包含多个except子句,分别来处理不同的特定的异常,但最多只有一个分支会被执行
一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组
2)try/except...else
try/except
语句还有一个可选的else
子句,如果使用这个子句,那么必须放在所有的 except
子句之后。
else 子句将在 try 子句没有发生任何异常的时候执行
3)try-finally
类似与java的try...catch...finally
finally 语句:无论是否发生异常都将执行的代码
4)抛出异常
Python 使用 raise 语句抛出一个指定的异常
raise [Exception [, args [, traceback]]]
raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)
3、自定义异常
通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承
大多数的异常的名字都以"Error"结尾,就跟标准的异常命名一样
六、面向对象
1、面向对象简介
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- **方法:**类中定义的函数。
- **类变量:**类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- **数据成员:**类变量或者实例变量用于处理类及其实例对象的相关的数据。
- **方法重写:**如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- **局部变量:**定义在方法中的变量,只作用于当前实例的类。
- **实例变量:**在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
- **继承:**即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例:Dog是一个Animal)。
- **实例化:**创建一个类的实例,类的具体对象。
- **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
2、类定义
class ClassName:
<statement-1>
.
.
.
<statement-N>
3、类对象
类对象支持两种操作:属性引用和实例化
属性引用使用和 Python 中所有的属性引用一样的标准语法:obj.name
类对象创建后,类命名空间中所有的命名都是有效属性名
__init__()
构造方法:类实例化时会自动调用
4、类方法
类的方法与普通的函数只有一个特别的区别:必须有一个额外的第一个参数名称,按照惯例它的名称是 self
class people:
name = ''
age = 0
#定义构造方法
def __init__(self,n,a):
self.name = n
self.age = a
def speak(self):
print("%s:9%d 岁。" %(self.name,self.age))
# 实例化类
p = people('wmh',10)
p.speak()
5、继承
Python 同样支持类的继承,如果一种语言不支持继承,类就没有什么意义
子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法。
BaseClassName(实例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用
class DerivedClassName(modname.BaseClassName):
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age))
#单继承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
s = student('ken',10,60,3)
s.speak()
6、多继承
Python同样有限的支持多继承形式
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>
需要注意:圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索(方法在子类中未找到时,从左到右查找父类中是否包含方法)
7、方法重写
super()
:用于调用父类(超类)的一个方法
class Parent: # 定义父类
def myMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
8、类的私有
__private_attrs:私有变量,两个下划线开头,只能在类中使用( self.__private_attrs
)
__private_method:私有方法,两个下划线开头,只能在类的内部调用 (self.__private_methods
)
9、运算符重载
Python同样支持运算符重载,我们可以对类的专有方法进行重载
__init__
:构造函数,在生成对象时调用__del__
:析构函数,释放对象时使用__repr__
:打印,转换__setitem__
:按照索引赋值__getitem__
:按照索引获取值__len__
:获得长度__cmp__
:比较运算__call__
:函数调用__add__
:加运算__sub__
:减运算__mul__
:乘运算__truediv__
:除运算__mod__
:求余运算__pow__
:乘方
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(1,3)
v2 = Vector(2,4)
print (v1 + v2)
# Vector(3, 7)
七、命名空间和作用域
1、命名空间
- 内置名称(built-in names): Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
- 全局名称(global names):模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称(local names):函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间。
命名空间的生命周期:取决于对象的作用域,若对象执行完成,该命名空间的生命周期就结束
2、作用域
规则顺序: L –> E –> G –> B
- L(Local):最内层,包含局部变量,比如一个函数/方法内部。
- E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
- G(Global):当前脚本的最外层,比如当前模块的全局变量。
- B(Built-in): 包含了内建的变量/关键字等,最后被搜索。
if/elif/else/、try/except、for/while等是不会引入新的作用域的,这些语句内定义的变量,外部也可以访问
3、全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
global
关键字:修改全局变量
num = 1
def fun1():
global num # 需要使用 global 关键字声明
print(num) # 1
num = 123
print(num) # 123
fun1()
print(num) # 123
nonlocal
关键字:声明外部嵌套函数内的变量(类似于c中的static,函数调用完但是变量不会消失)