基础知识
- Python是一种跨平台、高级的面向对象的解释型程序设计语言。
- 特色:强制用空白符(white space)作为语句缩进;具有丰富和强大的库。
- Python语言程序代码的编译和运行过程:
Python编译过程
- API,Application Programming Interface,即应用程序编程接口。
- 为什么要用IDE(Integrated development environment,集成开发环境)?
- 答:其支持代码高亮、智能提示、可视化等功能,大大提升开发效率。
- 搭建Python开发环境
- 安装官方的Python运行环境:官网http://python.org下载;
- 安装Pycharm(Python的一个IDE)
- Python三种运行方式
- 直接通过Python命令运行
- 在Python IDE中运行
- 在Python的REPL环境中运行(REPL,Read-Eval-Print Loop的缩写,是一个简单的交互式编程环境,也可称之为Python控制台)
- 调试Python程序
- 设置断点(Breakpoint),调试器每次遇到断点时会将当前线程挂起,即暂停当前程序的运行;
- Release和Debug,发行和调试,如观察程序的执行效果,可以选择Release方式;如要调试程序,需使用Debug方式。
- 跟踪调试程序:step into(单独跳入)和step over(单步跳过),step into可以跟踪进入函数内部,step over不会跟踪进入函数内部。
2.语言基础
基本要素
引用模块和声明变量,几乎是每一个Python程序都要用到。
导入Python模块
import语句,语法结构:import module_name;引用模块中的函数的语法:module_name.function_name。
大量使用模块中的某些函数,都要加模块名显得有些麻烦,可以使用from...import...语句将模块中的函数直接暴露出来,语法结构如下:from module_name import function_name,如果要导入所有函数,可以将function_name替换成星号(*)。
注:先引用后执行,否则调用函数会抛出异常。
声明变量
变量(variable)在声明的同时需要为其赋值;变量名通常包含字母、数字和下划线(_)且不能以数字开头。
数字
Python中数字分为整数和浮点数。
基础知识
运算符优先级
序 号 | 运算符 |
---|---|
1 | 圆括号(...) |
2 | 幂运算符(**) |
3 | 负号(-) |
4 | 乘(*)、除(/)、整除(//)、取余(%) |
5 | 加(+)、减(-) |
大整数
对于有符号32位整数来说,可表示的最大值是2^31-1,可表示的最小值是-2^31,如果超出,有符号32位整数就会溢出。不过在Python中,并不受位数限制。
二进制、八进制、十六进制
表示这三个进制的数,必须以0开头,然后分别跟着表示不同进制的字母。二进制字母是b,八进制字母是o,十六进制字母是x。二进制数正确写法0b1011,八进制数是0o5701,十六进制数是0xB975。
二、八、十六进制转换为十进制使用int函数。例如:int(“1011”,2),结果为11.
十进制转换为其他进制,分别使用bin、oct和hex函数,即二进制、八进制、十六进制。
数字的格式化
format函数:第一个参数为要格式化的数字,第二个参数为格式字符串。例如x = 1234.5678
函数 | 结果 | 说明 |
---|---|---|
format(x,’0.2f’) | 1234.57 | 保留两位小数 |
format(x,’>12.1f’) | 1234.6 | 12个字符长度区域内右对齐,并保留1为小数 |
format(x,’0<10.2f’) | 1234.57000 | 10个字符长度区域内左对齐,并保留2位小数,数字后面补0 |
format(x,’,.2f’) | 1,234.57 | 每千位用逗号分隔,保留2位小数 |
获取用户输入
从命令行接收用户的输入数据(交互),需要使用input函数,无论用户录入什么数据,input函数都会以字符串形式返回。
函数
函数function,相当于可重用的代码段。可实现代码重用,还可避免代码冗余。
注释
注释就是用一段文本描述代码的作用、代码的作者或是其他需要描述的东西,在程序编译时被忽略。
Python中,单行注释用井号(#)开头,多行注释用三个引号(单引号或双引号)括起来。
字符串
所有标准的序列操作(索引、分片、乘法、判断是否包含值、长度、最大值和最小值)对字符串同样使用,但字符串是只读的。
转义符
Python中的转义符是反斜杠(\),其功能是告诉Python解释器反斜杠后面的是字符串中的一部分。
1、拼接字符串:+
2、保持字符串的原汁原味:
- repr函数
- 转义符(\)
- 在字符串前加r
格式化
(1)%,字符串格式化操作符:%s
(2)模板字符串:string模块中提供一个用于格式化字符串的Template类(用美元符号$开头,后跟格式化参数名称)。
(3)format方法:”{} {}..”.format(1,2,..)
跟进一步控制字符串格式化参数:{str!s}原样输出、{str!r}调用repr函数、{str!a}输出Unicode编码、{num:f}浮点数、{num:b}二进制、{num:o}八进制、{num:x}十六进制、{num:%}百分比
符号、对齐、用0填充和进制转换:{chapter:02.0f}第一个0表示位数不足时前面补0,2表示整数部分是2位数字,第二个0表示小数位部分被忽略,f表示以浮点数形式格式化;左、中、右对齐分别使用< ^ >,例如{num:<10.2f}左对齐+占10位+保留2位小数。
方法
center方法:将一个字符串在一定宽度的区域居中显示,其有两个参数,第一个参数指定显示的宽度,第二个参数可选,默认是空格。例如:“hello”.center(20,”*”) 等于 “:*^20”.format(“hello”)
find方法:查找子字符串,成功返回第1个字符出现的位置,失败返回-1。
jion方法:连接序列中的元素,是split方法的逆方法。注:与字符串连接的序列元素必须是字符串类型。
split方法:通过分隔符将一个字符串拆成一个序列。如果不指定参数,会把所有空格(空格符、制表符、换行符)作为分隔符。
low、upper方法和capwords函数:low用于将所有字母字符转换为小写;upper大写;capwords函数将一个字符串中独立的单词的首字母都转换为大写。
replace方法:将一个字符串中的子字符串替换成另外一个字符串。
strip方法:用于截取字符串的前后空格,以及截取字符串前后指定的字符。
translate和maketrans方法:translate只用来替换单个字符,多个字符满足条件,全部替换。在使用translate前,需先使用maketrans创建一个替换表,该方法属于字符串本身。
例如:table = str.maketrans(“ak”,”*&”) #将a替换为*;k替换为&
条件、循环和其他语句
有实用价值的程序需要两个功能:选择和重复执行,其在编程语言中分别对应条件和循环。Python中,条件使用if语句实现,循环需要使用while和for语句。
print函数
空格分隔是print函数默认的分隔符,如需修改为逗号(,),在print函数中添加“sep=“,”参数即可。
print函数输出字符串时,默认在结尾添加换行符(\n),不默认的话,修改end=“”参数即可。
赋值操作
序列解包(sequence unpacking):x,y = 1,2 x,y = y,x
链式赋值(chained assignments):x=y=1
增量赋值(augmented assignment):x+=1
代码块
代码块是在条件为真(true)时执行的一组语句,在代码前放置空格来缩进语句即可创建代码块。Python标准推荐使用空格缩进的方式创建代码块,建议使用4个空格缩进方式创建代码块。一个tab为8个空格。
Pascal语言使用begin表示代码块的开始,使用end表示代码块的结束;C风格的编程语言(如Java、C#、C++等)使用一对大括号表示代码块的开始和结束。Python使用冒号(:)表示代码块的开始,代码块中每一条语句都是缩进的(缩进量相同)。当回退到与块的开始语句同样的缩进量时,表示当前块已经结束。
条件和条件语句
布尔值和布尔变量
Python会将布尔值True看作1,将布尔值False看作0。
通过bool函数的转换,可将各种数据类型变成布尔值。
条件语句(if、else、elif)
可以嵌套代码块。
3.4.4比较运算符
逻辑表达式 | 描述 |
---|---|
x == y | x等于y |
x < y | x小于y |
x > y | x大于y |
x >= y | x大于等于y |
x <= y | x小于等于y |
x != y | x不等于y |
x is y | x和y是同一个对象 |
x is not y | x和y是不同的对象 |
x in y | x是y容器的成员 |
x not in y | x不是y容器的成员 |
注:
- x = y = [1,2,3] z = [1,2,3]
x == z,结果是Ture;x is y ,结果是True;x is z ,结果是False。
“==”运算符比较的是对象的值,is运算符用于判断对象的同一性。
多个逻辑表达式组合:and逻辑与,or逻辑或,not逻辑非。
断言
断言(assertions)的使用类似if语句,只是在不满足条件时,直接抛出异常。在TDD(test-drive development,测试驱动开发)中经常使用断言。
Python中,断言使用assert语句,在assert关键字的后面制定断言的条件表达式。如果条件表达式的值是False,那么就会抛出异常,而且断言后面的语句都不会被执行,相当于程序的一个断点。
3.5循环
while循环和for循环
跳出循环:break语句(彻底退出循环),continue语句(终止本次循环,立即开始执行下一次循环)。
注:continue语句中,避免出现死循环。
使用exec和eval执行求值字符串
exec函数不会返回任何值,只是执行Python代码;eval函数用于执行表达式并返回结果值。
实例:计算器
while True:
express = input(“请输入表达式:”)
if express == “end”:
break
else:
print(“计算结果:”,eval(express))
数据结构
数据结构是通过某种方式组织在一起的数据元素的集合。
序列
Python中,最基本的数据结构是序列(sequence)。序列中的每一个元素都被分配一个编号,可以称这个编号为索引。序列的第一个元素的索引号为0,第二个元素的索引为1,以此类推。
定义序列
类似于Java中的数组,使用一对中括号[ ]将序列中的元素值括起来。同一个序列,可以包含相同类型的值,也可以包含不同类型的值。
例如:names = [“James”,”Tom”]
values = [“Bill”,30,12.5,True]
序列的每一个元素还可以是另外一个序列,其实这么定义就相当于一个二维或多维数组。
序列的基本操作
通过索引操作序列元素(indexing):如果索引是0或正整数,那么Python语言会从序列的左侧第1个元素开始取值;如果索引是负整数-1,那么会从序列右侧第1个元素开始取值。索引超出范围时,会抛出异常(list index out of range)。
分片(slicing)操作是从序列A中获取一个子序列B。分片操作需制定两个索引。例如name_seq[2:3]。如果结束索引比开始索引晚出现,那么就会返回一个空序列。设置步长:默认步长是1。开始索引、结束索引和步长之间都是用冒号分隔(:),步长不能为0,但可以是负数,即从右侧开始。
序列相加(+):不是对应的序列元素值相加,而是序列首位相接。
序列乘法:原序列将被重复n次。
in运算符:检查某个值是否属于一个序列。
序列的长度、最大值和最小值:内建函数len、max和min。
列表
列表(list)可以使用所有适用于序列的标准操作。
列表元素赋值和分片赋值:=
删除列表元素:del语句
列表方法
方法和函数非常类似,只是函数是全局的,而方法需要定义在类中,需要通过对象引用。格式:对象.方法(参数)
append:在列表最后插入新的值
insert:用于将值插入到列表的指定位置
sort:用于对列表进行排序【区别于sorted函数】
元组
元组(tuple)也是一种序列,不能修改,即元组是只读的。
定义:逗号(,)分隔一些值即可。使用圆括号()。tuple函数。例如 value=30, value=(30,) value=30 #只是普通值
元组可以在映射中作为键值使用,而列表不能。很多内建函数和方法的返回值就是元组。
字典
字典是Python语言中唯一内建的映射(mapping)类型。
创建和使用
字典是用一对大括号({})来创建的,键与值之间用冒号(:)分隔,每一对键值之间用逗号(,)分隔。字典中键是唯一的。
dict函数:通过其他映射(其他字典)或键值对的序列建立字典。
字典的基本操作
len(dict):返回字典dict中元素(键值对)数量。
dict[key]:返回关联到键key上的值,对于列表,key就是索引。
dict[key]=value:将值value关联到键key上。
del dict[key]:删除键为key的值。
key in dict:检查dict中是否包含键为key的项。
注:字典不同于列表的地方
键类型:字典的键可以是任意不可变类型,而列表的key只能是整数类型。
自动添加:字典可以通过键值自动添加新的项;而列表中,须使用append或insert方法才能添加新的元素。
查找成员:在字典中使用key in dict操作,查找的是key,而不是value。在列表中使用key in dict操作,查找的是值,而不是索引。
字典的格式化字符串
format.map方法,而且格式化参数需要用一对花括号({ })括起来。
序列与迭代
- 获取字典中的key的列表:for key in dict。
- 同时获取字典中的key和value列表:items方法。
- 并行迭代:range函数获取序列索引范围
- 压缩序列:zip函数,将两个或多个序列对应元素作为一个元组放在一起,进行压缩的序列元素个数不同时,以元素个数最少得为准。
- 反序列迭代:reversed函数
字典方法
- clear方法:清空字典中的所有元素。
- copy方法:复制字典,返回复制后的新字典。属于浅复制,只复制第1层的字典数据,至于第2层及以下的所有层,原字典和新字典都指向同一个值。copy模块中的deepcopy函数可对序列进行深层复制。
- fromkeys方法:根据key建立新的字典,默认为每一个key指定None值。
- get方法:用于更宽松的方式从字典中获取key对应的value,key不存在时,返回None值。
- items方法:返回字典中所有的key-value对,获得的每一个key-value对用一个元组表示。keys方法用于返回字典中的所有key。
- pop方法:获取指定key的值,并从字典中弹出这个key-value对。popitem方法用于返回字典中最后一个key-value对。
- setdefault方法:设置key的默认值。
- update方法:用一个字典中的元素更新另外一个字典。
- values方法:用于以迭代器形式返回字典中值的列表,可以有重复的。
函数
交互过程中主要的就是数据交换,而数据的交换就是数据的输入/输出。也就是外部代码需要将数据传给函数,而函数又要将内部的数据传给外部的代码,为了完成这项工作,函数需要具备两个技能:参数和返回值。给函数定义:一个拥有名称、参数和返回值的代码块。
函数基础
创建函数
定义函数使用def语句:
def greet(name):
return ‘Hello {}’.format(name)
函数名是greet,后面是一对圆括号,参数就放在里面。冒号结尾。
python是动态语言,所以函数参数与返回值都不要事先指定数据类型,函数参数就直接写参数名即可,如果函数有多个参数,中间用逗号(,)分隔。如有返回值,直接使用renturn语句(可返回任何东西);如没有,可省略return语句。
添加文档注释
不管是多行注释还是单行注释,在程序编译后,这些注释都会被编译器去掉,无法在程序中通过代码来动态获取注释内容。而文档注释作为程序的一部分一起存储,通过代码可以动态获取这些注释。
为函数添加文档注释,需要在函数头(包含def关键字的那一行)的下一行用一对单引号或双引号将注释括起来。
获取文档注释:使用函数属性“__doc__”(双下划线)获取;或help函数获取。
没有返回值的函数
有些编程语言(如Pascal)中,将无返回值的函数称为过程,还有一些编程语言(如C风格)用void或类似的关键字声明无返回值。而python直接不用return或return后什么也不接。
函数参数
写在def语句中函数名后圆括号中的参数称为形参,而调用函数时指定的参数称为实参。
改变参数的值
值传递和引用传递:如果传递的变量类型是数值、字符串、布尔等类型,那么就是值传递;如果传递的变量类型是序列、对象等复合类型,就是引用传递。
值传递就是在传递时将自身复制一份,而在函数内部接触到的参数实际上是传递给函数的变量的副本,修改副本的值自然不会影响到原始变量。
而像序列、对象这样的复合类型的变量,在传入函数时,实际上也将其复制了一份,但复制的不是变量中的数据,而是变量的引用,因为这些复合类型在内存是用一块连续或不连续的内存空间保存,要想找到这些复合类型的数据,必须得到这些内存空间的首地址,而这个首地址就是复合类型数据的引用。如果将复合类型的变量传入函数,复制的是内存空间的首地址,而不是首地址指向的内存空间本身,函数内部与函数外部定义的变量指向同一个内存空间,所以修改内存空间的数据,自然会影响到函数外部变量的值。
关键字参数与默认值
关键字参数就是函数形参的名字,在混合使用时,关键字参数必须放在位置参数后面,否则会抛出异常。
在函数定义时,可以为函数的形参指定默认值。
可变参数
在形参前面加一个星号(*)可定义函数的参数为可变参数。
在函数中,既有普通参数,也有可变参数时,通常可变参数会放在最后。
将序列作为函数的参数值
函数参数值可以是任何数据类型,将列表或元组中的元素作为单个参数值传递函数时,需在实参前面加星号(*),将字典中的元素作为单个参数传入函数时,要使用两个星号(**)。
作用域
作用域就是变量、函数、类等Python语言元素是否可见的范围。全局作用域与局部作用域。在Python语言中,不管作用域的哪个位置为变量赋值,都会认为这个变量属于当前作用域,而且会隐藏上层作用域同名的变量。
递归
所谓递归,就是在函数内部调用自身。在执行过程中,Python解析器会利用栈(stack)处理递归函数返回的数据,因此递归函数的一个必要条件是要有终止条件,否则栈就会溢出。
典型应用:阶乘和斐波那契数列
类和对象
对象
对象(object)可以看作数据以及可以操作这些数据的一系列方法的集合。包含若干个属性和方法,属性其实就是变量,在类中的函数称为方法。要想访问类中的函数(方法),必须要对类实例化,实例化后的产物称为对象。实例化后,调用方法是需先指定对象名称,然后才可调用方法。
面相对象三大特征:
- 继承(inheritance):当前类从其他类获得资源(数据和方法),以便更好地代码重用,并且可以描述类与类之间的关系。
- 封装(encapsulation):对外部世界隐藏对象的工作细节。
- 多态(polymorphism):意味着同一个对象的同样的操作(方法)在不同的场景会有不同的行为。
类
类是对象的抽象,类实例化后称为对象。类的主要任务是定义对象中的属性和方法。
创建类
Python使用class关键字定义类,类名直接跟在后面。
- 类也是一个代码块,所以类名后面要跟一个冒号(:)。
- 类中的方法就是函数,定义的方法也完全一样,只是由于函数定义在类的内部,为了区分,将定义在类内的函数称为方法。
- 每一个方法的第一个参数都是self,也可以是任何其他名字,但任意一个方法必须至少指定一个self参数。在调用方法时,这个参数的值不需要自己传递,系统会将方法所属的对象传入这个参数。(可以利用这个参数调用对象本身的资源,如属性、方法等)
- 通过self参数添加的name变量是Person类的属性,可以在外部访问。
- 使用类创建对象的方式与调用函数的方式相同。
- 调用对象的方法有两种方式:一种是直接通过对象变量调用方法,另一种是通过类调用方法,并且将相应的对象传入方法的第1个参数。
方法和私有化
Python类默认情况下,所有的方法都可以被外部访问。不过像Java、C#等其他编程语言,都提供了private关键字将方法私有化(只有类内部才能访问),通过正常的方式是无法访问对象的私有化方法。在Python类的方法名前加双下画线(__)可以让该方法在外部不可访问。
注:双下画线并没有将方法真正私有化,而是Python编译器把__fangfaName改为了_ClassName__fangfaName了。
类的继承
Python类的父类需要放在类名后的圆括号中。例如:
class sonClass(fatherClass):
检测继承关系:判断类与类之间的关系可以使用issubclass函数,该函数接收两个参数,第1个参数是子类、第2个参数是父类,是继承关系,返回True,否则返回False。
如果要想获得已知类的父类(们-Python类支持多继承),还可以直接使用“__bases__”,这是类的一个特殊属性。
isinstance函数检测一个对象是否是某一个类的实例。
多继承
某一个类指定多个父类,需要在类名后面的圆括号中设置,多个父类名间用逗号(,)分隔。多个父类中有相同的成员,那么会按照父类书写的顺序继承,写在前面的父类会覆盖写在后面的父类同名的方法。
在Python类中,不会根据方法参数个数和数据类型进行重载。(在Java、C#等面向对象语言中,如果方法名相同,但参数个数和数据类型不同,也会认为是不同的方法,这叫做方法的重载,即拥有方法名相同,但参数不同的多个方法)
接口
在很多面向对象语言(Java、C#等)中都有接口的概念,接口其实就是一个规范,指定了一个类中都有哪些成员。一个类可以有多个接口,也就是多个规范。不过Python语言中没有这些东西。在调用方法之前先使用hasattr函数检测一下,如果方法在对象中存在,返回True,否则返回False。
hasattr(对象名,“方法名”)
getattr函数可以实现hasattr函数同样的功能;与getattr函数对应的是setattr函数,该函数用于设置对象中成员的值。
setattr(对象名,“属性名”,“属性值”)
异常
什么是异常
Python语言用异常对象(exception object)来表示异常情况。当遇到错误后,会引发异常。通常异常信息会告知出现错误的代码行以及其他有助于丁未错误的信息,以便快速定位。
让程序抛出异常的两大分类:系统自己抛出异常和主动抛出异常。
每一个异常就是一个类,抛出异常的过程也就是创建这些类的实例的过程。
主动抛出异常
raise语句
使用raise语句可以直接抛出异常。raise语句后跟一个Exception类,然后为异常信息加上一个描述。
raise Exception(“这是自己主动抛出的一个异常”)
异常类名 | 描述 |
---|---|
Exception | 所有异常的基类 |
AttributeErro | 属性引用或赋值失败时抛出的异常 |
OSError | 当操作系统无法执行任务时抛出的异常 |
IndexError | 在使用序列中不存在的索引时抛出的异常 |
KeyError | 在使用映射中不存在的键值时抛出的异常 |
NameError | 在找不到名字(变量)时抛出的异常 |
SyntaxError | 在代码为错误形式时触发 |
TypeError | 在内建操作或函数应用于错误类型的对象时抛出的异常 |
ValueError | 在内建操作或函数应用与正确类型的对象,但该对象使用了不合适的值时抛出的异常 |
ZeroDivisionError | 在除法或取模操作的第2个参数值为0时抛出的异常 |
自定义异常类:任何一个异常类必须是Exception的子类。
class ZidingyiException(Exception):
pass
捕捉异常
在Python语言中,使用try...except语句进行异常捕捉。如果异常未被捕捉,系统就会一直将异常传递下去,直到程序由于异常而导致中断。
try...except语句
- try...except语句是一个代码块,所以try和except后面都要加冒号(:)。
- try和except之间是正常执行的语句,如果这些代码不发生错误,那么就会正常执行下去,这时except部分的代码是不会执行的。如果try和except之间的代码发生错误,那么错误点后的代码都不会执行,而会调到except子句取执行except代码块中的代码。
- 如果except关键字后面没有指定任何异常类,那么except部分可以捕捉任何的异常。
7.3.2捕捉多个异常 - except子句可以包含任意多个:
except 异常类1:
...
except 异常类n: - 用同一个代码块处理多个异常:
except(异常类1,异常类2,...,异常类n):
捕捉对象
使用except子句捕捉了多个异常,为了更进一步提现异常的差异性,需要为异常类执行一个变量,也可称为异常对象。except子句捕捉到的都是异常对象。为异常对象指定名字需要用到as关键字。
try:
...
except 异常类 as e:
...
异常中的else语句
try...except语句也有else子句,与except子句正好相反,else子句会在try和except之间的代码正常执行后才执行。
异常捕捉中的finally子句
捕捉异常语句的最后一个子句是finally。不管是正常执行,还是抛出异常,最后都会执行finally子句中的代码。所以应该在finally子句中放置关闭资源的代码,如关闭文件,关闭数据库等。
如果使用return语句退出函数,那么会首先执行finally子句中的代码,才会退出函数。
异常、函数与栈跟踪
如果异常被隐藏的很深,而且又不被处理,这种异常是不太好捕捉的,Python解析器可以利用栈进行跟踪。
异常的妙用
例如,通过key从字典获取value值是,为防止由于key不存在而导致的异常,可利用条件语句进行判断:if ‘Key’ in dict:
例如访问对象的属性和方法时:if hasattr(对象名,”属性名”):
代码中充斥太多这样的if语句,会降低代码的可读性,因此可以用try语句来取代if语句,并让程序更加健壮。
try:
print(对象名.属性名)
except AttributeError as e: #捕捉对象属性不存在的异常
print(“异常信息:{}”.format(e))
方法、属性和迭代器
8.1构造方法
构造方法是创建对象的过程中被调用的第一个方法,通常用于初始化对象中需要的资源,如初始化一些变量。
特殊的名称:在定义构造方法时,需要在方法名两侧各加两个下画线,构造方法的方法名是init,完整的构造方法名是__init__。
8.1.1重写普通方法和构造方法
B类继承A类时,B类就会拥有A类的所有成员变量和方法,如果B类中的方法名与A类方法名相同,那么B类中的同名方法就会重写A类中同名方法,构造方法同样适用。
8.1.2适用super函数
在子类中如果重写超类1的方法,通常需要在子类方法中调用超类的同名方法。如果在子类中访问超类的方法,需要使用super函数,该函数返回的对象代表超类对象。
8.2属性
通常会将类的成员变量称为属性(Java语言中将类成员变量称为字段field)。在创建类的实例后,可以通过类实例访问这些属性,也就是读写属性的值,但无法对读写过程进行监视。
8.2.1传统属性
Python语言中,如果要为类增加属性,需要在构造方法(__init__)中通过self添加,如果要读写属性的值,需要创建类的实例,然后通过实例读写属性的值。通过为属性添加getter方法和setter方法的方式,还可同时设置多个属性。此方法可以解决监控属性的问题,但在监控属性值的变化时,就暴露内部的实现机制有些不妥。
8.2.2property函数
在使用属性对象的同时,也可以监控对属性的读写操作,可使用property函数。
通过property函数设置的与属性绑定的方法的名称没有任何限制。
删除对象的属性只是调用了通过property函数绑定的回调方法,并没有真正删除对象的属性。
8.3静态方法和类方法
Python类包含三种方法:实例方法、静态方法和类方法。调用实例方法需要类的实例(对象),而静态方法在调用时根本不需要类的实例(静态方法不需要self参数)。
类方法的调用方式与静态方法完全一样,不同的是,类方法与实例方法的定义方式相同,都需要一个self参数,只是含义不同。对实例方法来说,self参数就代表当前类的实例,可以通过self访问对象中的属性和方法,而类方法的self参数表示类的元数据,也就是类本身,不能通过self参数访问对象中的方法和属性,只能通过self参数访问类的静态方法和静态属性。
定义静态方法需要使用@staticmethod装饰器(decorator)。
class MyClass:
#实例方法
def instanceMethod(self):
pass
#静态方法
@staticmethod
def staticMethods():
pass
#类方法
@classmethod
def classMethods(self):
pass
通过实例定义的变量只能被实例方法访问,而直接在类中定义的静态变量,既可以被实例方法访问,也可以被静态方法和类方法访问。实例方法不能被静态方法和类方法访问,当静态方法和类方法可以被实例方法访问。
迭代器(iterator)
迭代就是循环的意思。
自定义可迭代的类
列表之所以可以用来索引来快速定位其中的任何一个元素,是因为列表是一下子将所有的数据都装载在内存中,而且是一块连续的内存空间,当数据量比较小时,实现比较容易;当数据量很大时,会非常消耗内存资源。而迭代就不同,迭代是读取多少元素,就将多少元素装载到内存中,不读取就不装载。
(类似XML的两种方式:DOM和SAX,DOM是一下子将所有的XML数据都装载到内存中,可快速定位到任何一个元素,代价是消耗内存;而SAX是顺序读取XML文档,没读到的文档内容不会装载到内存中,省内存,但只能从前向后顺序读取XML文档的内容)
如果在一个类中定义__iter__方法,那么这个类的实例就是一个迭代器。
将迭代器转换为列表
迭代器好用,但任然不具备某些功能,如通过索引获取某个元素,进行分片操作。在将迭代器转换为列表时,需给迭代器能够迭代的元素限定一个范围,否则内存就会溢出,要想迭代器停止迭代,只需要抛出StopIteration异常即可,通过list函数可直接将迭代器转换为列表。
生成器(generator)
如果说迭代器是以类为基础的单值产生器,那么生成器就是以函数为基础的单值产生器。迭代器和生成器都只能一个值一个值地生产。
迭代器需要在类中定义__iter__和__next__方法,在使用时需要创建迭代器的实例,而生成器是通过一个函数展现的,可以直接调用。
创建生成器
要定义一个生成器,首先要定义一个函数,在该函数中对某个集合或迭代器进行迭代,然后使用yield语句产生当前要生成的值,这是函数会被冻结,直到调用生成器的代码继续迭代下一个值,生成器才会继续执行。
- Mackbook PyCharm安装包
- 界面右下角,选择Interpreter Settings...
(2)双击打开pip
(3)输入并搜索包,例如click,点击左下角Install Package,安装