《python 程序设计》读书笔记
笔者对于csdn博客的运用还是不太熟练,希望大家能够见谅。以后会不断提升写作的手法。这篇博客是我在学习python程序设计时候的笔记。我也是选择学习了大部分。因为有些模块我也不是很感兴趣和实用。
第一章:概述
1.为了编写计算机程序,需要向cpu提供一系列能够执行的命令,因为一条一条的命令容易出错,所以发明了高级编程语言, 这些语言允许程序员在高层指定一些程序任务,然后高级指令会被转换为cpu所需要的更详细的指令.
2.python程序由python解释器负责解释和执行
3.python的交互式环境,可以在终端里面输入python3命令,>>>这个是提示符,表示可以输入python的命令
>>>
4.python解释器,python虽然是解释性语言,一条一条语句的执行,但是实际的情况却有不同,解释器内部是由编译器的,解释器会吧整个任务切分,读取程序并且理解指令 这样的任务会被编译器执行一次,编译器读取包含源代码(你编写的python指令)的文件,然后把这些指令翻译成字节码,也就是一些很容易被虚拟机(一个类似于计算机cpu的独立程序理解的简单指令)当编译器完成源码到虚拟机在指令的转换之后,这些程序就可以反复多次被虚拟机执行了。
python虚拟机讲解
第二章:数字和在字符串编程
变量:变量是一个存储位置,每个变量都有名字并且包含一个值,变量就相当于一个标识符
上面这个图说明变量在第一次出现的时候就被定义了,以后再赋值就是替换了,也就是说一个第一次变量赋值就相当于c语言里面的声明初始化。
=:赋值语句
数据类型:决定了数据再计算机内部怎么表示,还决定了能对数据进行怎么样的操作。一旦你使用一个特点类型的值初始化了某个变量,你应该注意保持他的类型不变。
整数:是一个完全不包含小数部分的数字。
浮点数:就是一个数字常量包含小数点`
1E6
1E6是浮点型,指数形式的数字总是具有float类型
变量名:
1.这个名字最好可以解释这个变量名字的用途。
2.变量名的开头首字母必须是_和字母,其他的组成部分可以是数字和字母和_
3.名字对大小写敏感
4.不能用if和class这个的保留字
变量名的一些硬性的规则:使用描述性的名字,因为尽管自己看得懂,但是如果别人要再你的程序上面改动,就不一定能够理解这些变量的意义了,使用大写的名字表示常量,大写开头的的名字一般表示用户定义的类型
常量:指指定了初始化之后,其值不应该再改变,python由程序猿自己保证常量的值不被改变,常量名全部是大写是一个惯例。
不要使用幻数:意思就是不要在一个运算的式子里面写1,2,3,4…这样的数字,要学变量名,因为这样方便修改,而且也能够让别人理解这样做的意义。
运算符:+,-,*,/
表达式:就是由变量和常量和括号还有运算符的组合
** 运算符:**运算符具有比其他的运算符更高的优先级,幂运算符是从右往左求值的
#例子
>>> a=10**2**3
>>> a
100000000
整除和余数
/
>>> 7/5
1.4
>>> 1/1
1.0
也就是说两个数用/相除,就会变成浮点数
//
>>> 7//5
1
>>> -1//5
-1
与c语言做一个比较:c语言如果两个整数相除,会在得到的小数的基础上面截掉小数的部分,两边是浮点数,最后的值也是浮点数,也就是说c语言里面主要是看这个/运算符两边值得类型,在python里面:/最后都会得到一个浮点数,而//最后得到得都是整数,这个整数是比/的带得小数小得最小得整数
float a=1/8;
printf("%f",a);
//输出实际上是0.000000
float a=1/8.0;
printf("%f",a);
//输出是0.125000
字符串:
因为字符串子啊c语言中包含两种界定符,所以在python中很容易的包含撇号或者引号
在python 中你可以使用+号来连接两个字符
可以对一个字符重复的操作生成字符串
>>> a="*"*10
>>> a
'**********'
把字符串转换成数字的时候空格会被忽视掉
>>> int( "4564")
4564
>>> a="hello"
>>> b="world"
>>> c=a+b
>>> c
'helloworld'
对象是表示具有特定行为的值的实体,对象的行为通过方法来指定。方法和函数类似,是执行特定任务的一系列程序指令。
方法和函数:
方法
>>> name = 'John Smith'
>>> uppercaseName = name.upper()
方法名紧跟在对象之后,并且使用一个圆点(.)分隔对象和方法名。
函数
len(name)
输入数字
函数input 只能从用户哪里得到一个字符串.
所以我们需要强制类型转换
>>> usrinput = input("please enter the number of bottle:")
please enter the number of bottle:24
>>> usrinput
'24' #得到的是一个字符串
>>> int(usrinput)
24 #强制类型转换,得到的是一个数字
>>> usrinput
'24' #但是实际上是没有改变原来的值的
>>>
我们来看一下变量内部的变化
格式化输出
%不仅可以用来求余,还可以用来格式化字符串,叫做字符串格式化运算符。
>>> a=5
>>> "%d"%a
'5'
>>> a=5
>>> b="%d"%a
>>> print(b)
5
>>> type(b)
<class 'str'>
与c语言相同,格式化的结果都是字符串。虽然输出的时候显示5的时候没有加引号
注意:格式化多个值的时候,要把这些值放到一个括号里面。
简单绘图
这里我们用到ezgraphics模块,为了找到这个模块,我也是花了很长的时间,这里我把这个模块下载的地址告诉大家。
ezgraphics模块下载地址
这个地址里面没有上面的模块,但是也有很多的模块
这个里面也包含了很多的模块
顺便讲一下安装模块的方法
1.直接把.py文件放进lib目录里面
2.在bash里面输入命令,不仅在linux里面可以,在windows里面也支持,值得一提的是,有的模块不支持这种方法,不如这里要用到的ezgraphics模块,还有就是在安装python的时候,要仔细一点,如果要采用这种方法的花,在安装的界面哪里有pip3的安装,要点勾,因为如果使用命令行安装的方式的化,就需要pip3了。
3.安装其他可指向的程序的时候可以直接把可执行程序放进Script这个目录,这个目录是属于python的目录,就是设置环境变量。
创建窗口
注下面使用的方法在最后面的方法那里有总结。
1.导入GraphicsWindow类
#引入模块的方式很多,这个只不过是其中之一
from ezgraphics import GraphicsWindow
#创建图形的窗口
win = GraphicsWindow()
#这个默认生成的是400*400的窗口,你也可以传递参数值指定高度和宽度
#访问图形窗口中的画布
canvas = win.canvas()
#在创建GraphicsWindow类的对象时会自动创建GraphicsCanvas类的对象,通过canvas方法可以访问表示画布的对象
#在画布上画图
canvas.drawRect(5,10,20,30)
#等待用户关闭窗口
win.wait()
>>> win = GraphicsWindow(500,500)
画布上的点与屏幕上的像素对应,因此,画布和几何形状的真实大小依赖于屏幕分辨率。
from ezgraphics import GraphicsWindow
win = GraphicsWindow(400,200)
canvas = win.canvas()
#canvas = GraphicsWindow(400,200).canvas()
#注释里面这样写也是可以的
canvas.drawRect(0,10,200,10)
canvas.drawRect(0,30,300,10)
canvas.drawRect(0,50,100,10)
win.wait()
from ezgraphics import GraphicsWindow
win = GraphicsWindow(400,200)
canvas = win.canvas()
#设置颜色
canvas.setColor("red")
canvas.drawRect(0,10,200,10)
canvas.setColor("green")
canvas.drawRect(0,30,300,10)
canvas.setColor("blue")
canvas.drawRect(0,50,100,10)
win.wait()
交互式图形程序
from ezgraphics import GraphicsWindow
from sys import exit
win = GraphicsWindow()
canvas = win.canvas()
x = int(input("please enter the x coordinate: "))
y = int(input("please enter the y coordinate: "))
if x < 0 or y < 0:
exit("Error:x and y must be >=0.")
canvas.drawOval(x - 5,y - 5,10,10)
win.wait()
from ezgraphics import GraphicsWindow
from sys import exit
win = GraphicsWindow()
canvas = win.canvas()
point = win.getMouse()
x = point[0]
y = point[1]
canvas.drawOval(x,y,10,10)
win.wait()
#这个就会以用户鼠标单击的位置作为左上角绘制一个原型
相交的圆
sympy模块
下载方式
pip3 install sympy:输入命令,pip3怎么安装在已经说过了。
也可以下载下来,然后放在lib目录下。
>>> from sympy import *
>>> f=sympify("x**2*sin(x)")
>>> f
x**2*sin(x) #这是一个符号表达式,这个x不是变量,是sympy处理的特殊数据类型
>>> sympify("x*x**2")
x**3 #sympify知道x的2次方乘以x等于x的三次方
你可以先定义一个符号表达式x并保存到一个变量中,然后把那个变量也命名为x,然后使用运算符和函数来构造sympy表达式
>>> x = sympify("x")
>>> f= x ** 2 * sin(x)
>>> f
x**2*sin(x)
>>> x = sympify("x") #事先让x等于特殊处理的类型"x"
>>> expand((x+1)*(x-1))
x**2 - 1
>>> expand((x-1)**5)
x**5 - 5*x**4 + 10*x**3 - 10*x**2 + 5*x - 1
解方程
用solve方法
>>> f=expand((x+1)*(x-1))
>>> solve(f)
[-1, 1]
>>>
用solve方法,会返回一个列表,里面的值带进去会得到令方程等于0。
>>> f=expand((x+1)*(x-1))
>>> solve(f)
[-1, 1]
>>> f=x**2*sin(x)
>>> diff(f) #算导数
x**2*cos(x) + 2*x*sin(x)
>>> g = integrate(f) #算积分
>>> g
-x**2*cos(x) + 2*x*sin(x) + 2*cos(x)
>>> g
-x**2*cos(x) + 2*x*sin(x) + 2*cos(x)
>>> result = g.subs(x,0) #就是把表达式中的x换成指定的值
>>> result
2
result = g.subs(x,0).evalf() #把最后的值换成浮点数
>>> result
2.00000000000000
>>> plot(-x**2*cos(x)+2*x*sin(x)+2*cos(x),(x,-20,20))
240 | . .
| . .
|
| . .
|
| . .
| \ /
| . . . . . .
| . ........... .
| . .. .. .
-45 |------------.-----..---------------..-----.------------
|
| . .
|. . . .
| . .
| . .
|
|
|
|
-330 |_______________________________________________________
-20 0 20
<sympy.plotting.plot.Plot object at 0x0000025A3FE7BEB0>
#后面指定x的范围,这里我们指定了x的范围是(-10,10)
1
第三章:选择结构
if语句:
if语句后面的:表示后面的东西是一个符合语句。
if和else 必须要对齐
复合语句
可以跨越多行,并且有一个头部和一个语句块。
if totalsales > 100.0: #头部以冒号结束
...
...
#后面的就是语句块,注意语句块要缩进相同的层次
缩进作为语法的一部分,python要求块结构代码,对齐方式表明了那些语句是给定语句块的一部分。语句要么使用空格对齐,要么使用制表符对齐,但是切忌不要同时使用制表符和空格。
最好使用空格,因为制表符没有统一的宽度标准。
条件表达式
value1 if condition else value2
#当条件表达式成立的时候值是value1 否则就是value2
优先级:关系运算符是比算数运算符低的,在c语言里面也是这样的,注意 python里面 **的结合性是从右向左的,c语言里面赋值运算符是比关系运算符的优先级还第,c语言里面优先级最低的是逗号。
注意:不能比较‘10’和5的大小,在c语言里面char 类型实际上是整形,但是python里却不是。
浮点数的比较
浮点数的比教在大多时候是没有意义的。相反,我们在应该比较的是他们是否接近。
#例子
>>> from math import sqrt
>>> sqrt(2)
1.4142135623730951
>>> from math import sqrt
>>> EPSILON = 1E-14
>>> r = sqrt(2.0)
>>> if abs(r * r -2.0) <EPSILON:
制定进度表,腾出时间处理意料之外的问题
首先,切合实际地估计一下完成下面的任务需要多长时间:
设计程序逻辑
设计测试用例
输入程序并修改语法错误
测试和调试程序
然后考虑可能会出错的事情,然后吧估计的时间翻倍,避免尴尬和失败。
布尔变量和运算符
可以对变量赋值。注意:与c语言不同,c语言里面的正确和错误是小写的,但是python里面的正确和错误是开头的字母是大写的。
>>> a=True
>>> a
True
>>> a=False
>>> a
False
and 和 or运算符
and和or的运算符的优先级是比关系运算符低的。其中and的优先级是高于or的
not
要注意移入的时候and和or运算符被翻转了,例如:“stat是阿拉斯加或者是夏威夷”这个条件的否定.
not (state == “AK” or state ==“HI”)是“stat 不是阿拉斯加也不是夏威夷”:
state !=“AK” and state !=“HI”
>>> not True #对条件进行求反
False
连用关系运算符
>>> value = 10
>>> 0 <= value <=100
True
python允许这样连续使用关系运算符,表达式被求值的时候,解释器自动插入布尔运算符 and 形成两个独立的关系表达式,如下。
>>> value >= 0 and value <=100
True
大多数的编程语言是不允许这样的,就那c语言与 python做一个比较吧。
if(10<7<8)
printf("hello world!\n");
return 0;
lonelyeagle@lonelyeagle-PC:~$ gcc 测试.c
lonelyeagle@lonelyeagle-PC:~$ ./a.out
hello world!
c语言这样的条件判断就是10<7因为不成立,就变成0了,然后0在于8做比较,最后就打印条件成立就打印出来。
in 和 not in
可以用来确定一个字符串是不是包含另外一个字符串。
结束程序
在标准库sys中定义的exit函数一旦得到执行就会立即结束程序的运行木叶可以供一个可选的信息用来结束之前输出到终端。
>>> from sys import exit
>>> exit("Error:you must enter either n or y.")
在python交互环境下输入exit()窗口直接关闭,连可选的信息都显示不出来。
第四章循环
while condition :
statement
只有条件保存成立,while语句中的语句就一直执行,这个语句叫做while语句的循环体
不知道循环的次数的时候就用while循环
处理警戒值
警戒值:无论何时,只要你读取一些列输入,就需要有个方法能够暗示这个序列的结束。如果允许输入0而不允许输入负数,你可以使用-1表示输入的结束。这样的值不是实际的输入,而是用来作为结束的符号,叫做警戒值。
有些程序员不许换使用警戒值之外的其他初始化输入变量这样的小技巧,这样尽管可以解决问题,但是需要在循环体内使用一个if语句测试警戒值,另一种方法是使用两个输入语句,一个在循环之前获取第一个值,另一个是在循环底部来获取更多的值,如果用户输入的第一个值就是警戒值,那么循环体内的代码永远不会执行。
循环之前的输入操作称作预读取
循环底部的输入操作用来获取下一个输入,一般称作修改读取。
第三种处理的方式,使用不是数字的警戒值,例如字母 Q
>>> inputstr = input("enter a valur or q to quit:")
while inputstr !='q':
value = float(inputstr)
inputstr = input("enter a value or q to quit")
使用布尔类型变量处理警戒值
done = False
while not done:
value = float(input("Enter a salary or -1 to finish:"))
if value <0.0:
done =True
else :
process value
半路循环:用于决定循环是否结束的真正测试是在循环中间进行的,而不是在顶部,这称作半路循环,因为执行到一半才能知道循环是否应该结束。
输入和输出重定向
这个倒是跟c语言的重定向差不多
python sentinel.py < numbers.txt
python sentinel.py < numbers.txt > output.txt
故事板
当你设计一个与用户交互的程序时,你需要为哪个交互做个计划,用户提供什么样的信息?以什么顺序?你的程序会显示什么样的信息,以什么格式?如果出现了错误应该发生什么?程序何时退出?
for循环
stateName = "Virginia"
for letter in stateName:
print(letter)
对于字符串stateName中从第一个位置开始的每个字符,循环体都会被执行。你应该把这个循环体读作:for each letter in stateName
for循环可以迭代任何容器(包含或存储多个元素的对象)内的元素。字符串是个存储多个字符的容器。
python提供了range函数来生成根据提供参数来生成一系列值。
我们把循环分为两类,计数控制的循环会执行定义好的次数,事件控制的循环无法提前知道迭代的次数–事件在特定条件发生之前会一直执行。
函数:
总的来说:
如果 你需要迭代一个容器的所有元素,并且不考虑他们的位置,使用简单的for循环就可以。
如果你需要迭代某个范围内的整数,使用带range的函数的for循环。
其他情况下,使用while循环。
参数end = ""称作具名参数,具名参数允许你为函数或方法中的定义的特定可选参数指定内容。
函数如同黑盒子
作为函数的用户,你不需要知道函数是如何实现的,你只需要知道函数的用法就行了。
def main():
result = cubeVolume(2)
print("A cube with side length 2 has volume",result)
def cubeVolume(sideLength):
volume = sideLength ** 3
return volume
main()
在python中定义和使用函数时,把所有语句都放在函数中并且指定一个函数作为入口点,这是一个非常好的编程习惯,main函数是执行流开始的位置,任何合法的名字对于入口点都是可以的,但是我们还是选择使用main,因为在其他一些常用语句中是这样要求的。
我们必须在程序中包含一条调用main函数的语句,那个语句就是程序的最后一行,main().
函数注释
## Computes the volume of a cube.
# @param sideLength the length of a side of the cube
# @return the volume of the cube
#
def cubeVolume(sideLength):
volume = sideLength ** 3
return volume
这种文档风格是从java语言借鉴过来的,得到了大量文档工具的支持
函数注释的每一行在第一列以(#)开始。使用两个##开始的第一行描述函数的目的,每个@param子句描述一个形参变量,@return子句描述返回值
不要修改形参变量,重新定义一个变量就可以了
在使用变量作为实参调用哈桑农户时,你并没有真正把变量传递过去,仅仅是传递了变量包含的值,这一点跟c语言一样
函数调用完了里面的参数会被删除
避免多个return语句
通过把函数结果保存在以恶搞变量中然后再函数的最后一个语句中返回这个值来避免使用多个return语句
没有返回值的函数。实际上,没有return,其实也会返回一个值,叫做none,但是你不能对这个值左任何事情。
def cubVolume(sideLength):
if sideLength >=0:
volume = sideLength **3
else:
volume = 0
return volume
使用单行符合语句
if digit == 1:
return "one"
if digit == 1 : return "one"#这样也是可以的
编写main函数
def main():
done = False
while not False:
done = processLine()
当调用porcessLine 返回 False的时候就一直调用他。
变量作用域
一个变量的作用域是指能够访问他的代码范围。形式参数变量的作用域是整个函数,在函数中定义的变量叫做局部变量如果局部变量是在一个代码块中定义的,那么他从定义的位置开始到所有函数结束的代码中都是可以访问的
for循环中的循环变量是局部变量,和其他局部变量一样,他的作用域从被延申到其所在的函数结束
def main1():
for i in range(10):
print(i)
def main():
print(i)
main1()
main() #这个代码执行的时候是会报错的,因为在main函数里面i是没有被定义的
for i in range(10):
print(i)
def main():
print(i)
main()
#输出如下,这个i没有定义在函数里面,就相当于是一个全局的变量的
0
1
2
3
4
5
6
7
8
9
9
避免全局变量
带有全局变量的程序很难为何和扩展,因为你不能在把函数看作简单地接收参数和返回结果的黑盒子,当很难理解函数调用的效果。尽量把不要使用全局变量,而是使用函数形参和返回值在程序中的不同部分之间交换信息。
第六章 列表
列表是用来收集多个值的基本机制。
values = [32,54,67.5,29,35,80,115,44.5,100,65]
方括号表示我们表示我们正在创建列表,元素是按给出的顺序存储的。
列表和字符串都是序列,[]可以访问任何序列中的元素。
列表和字符串的不同之处:列表可以包含任意类型的值,而字符串是字符序列,另外字符串是不可变的,意思就是你不能够修改序列中的字符。
但是列表是可变的,你可以把列表中的一个元素替换为另一个。
values[5] = 87; #现在索引为5的元素被替换为87
反向下标
python支持反向下标,下标-1可以访问列表中的最后一个元素,values[-2]是倒数第二个元素。
>>> personalData = ["John Q. public",25,485.25,"10 wide"]
这种就是一个很糟糕的设计,让程序猿记住这邪恶数据中哪一个存储在什么位置,这是很无聊的一件事。
c语言的数组跟列表是不一样的
index方法
列表的index方法会返回元素第一次出现的索引
>>> personalData = ["John Q. public",25,485.25,"10 wide"]
>>> friends =[ "Harry","Emily","Bob","Emily"]
>>> n = friends.index("Emily")
>>> n
1
>>> n2 = friends.index("Emily",n+1)
>>> n2
3
>>>
删除元素
pop方法删除指定位置上的元素
frineds = ["Harry","Cindy","Emily","Bob","Cari","Bill"]
>>> frineds.pop(1)
'Cindy'
>>> frineds
['Harry', 'Emily', 'Bob', 'Cari', 'Bill']
>>>
传递给pop方法的索引必须在有效范围之内
列表中被删除的元素会被pop方法返回,这允许你把两个操作合并为一个–访问一个元素同时删除他。
>>> frineds
['Harry', 'Emily', 'Bob', 'Cari', 'Bill']
>>> print("the removed item is",friends.pop(1))
the removed item is Emily
如果pop方法没有参数的化,那么删除的就是最后一个元素。
remove方法
remove 方法按值来删除元素,不是按照位置啦删除一个元素。
为了保证能够删除一个元素,你应该保证删除的那个元素在列表中是存在的。用in
连接与重复
两个列表连接之后得到一个新列表。其中首先包含第一个列表中的元素,然后是第二个列表中的元素。
>>> myfriends = ["Fritz","Cindy"]
>>> yourfriends = ["Lee","pat","phuong"]
>>> ourfriends = myfriends + yourfriends
>>> ourfriends
['Fritz', 'Cindy', 'Lee', 'pat', 'phuong']
连接同一个列表多次,使用重复运算符(*)
>>> monthInQuarter = [1,2,3] * 4
>>> monthInQuarter
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
比较
>>> [1,4,9] == [1,4,9]
True
>>> [1,4,9] == [1,9,4]
False
>>>
求和,最大值,最小值,和排序
sum函数
max函数
sort方法对数字或字符串列表进行排序
>>> values = [1,16,9,4]
>>> values.sort()
>>> values
[1, 4, 9, 16]
复制列表
列表常用函数和运算符
** 切片**
注意:这个是左开又必区间,跟range相似
temperatures = [18,21,24,28,33,39,40,39,36,30,22,18]
>>> thirdQuarter = temperatures[6:9]
>>> thirdQuarter
[40, 39, 36]
>>> temperatures[0:6]
[18, 21, 24, 28, 33, 39]
>>> temperatures[6:]
[40, 39, 36, 30, 22, 18]
>>> temperatures[:]
[18, 21, 24, 28, 33, 39, 40, 39, 36, 30, 22, 18]
str方法
>>> temperatures[:]
[18, 21, 24, 28, 33, 39, 40, 39, 36, 30, 22, 18]
>>> values = [32,54,67.5,29,35]
>>> str(values)
'[32, 54, 67.5, 29, 35]'
在函数中使用列表
def mutiply(values,factor):
for i in range(len(values)):
values[i]=values[i]*factor
def main():
values=['1','2','3','4']
print(values)
mutiply(values,10)
print(values)
main()
#结果
['1', '2', '3', '4']
['1111111111', '2222222222', '3333333333', '4444444444']
步骤
1.创建变量values和factor
2.注意values和scores和同一个列表的引用
3.函数把所有列表元素都乘以10
4.函数返回
传值调用和传址调用
fun(var),就是说var的内容在调用之前和调用之后是一样的。原因:函数被调用时,var的内容会被复制到对应的形参变量中。但是当函数结束的时候,形参被删除。
列表本身不会永远不会被作为参数传递,只有他们的引用会被传递。数字和列表引用都是传值的。
元组
python提供了一个包含任意数据的不可改变的数据类型,元组非常类似于列表,但是一旦创建其内容无法被修改,元组通过指定其内容为逗号分隔的序列来创建,你可以用元括号来界定这个序列。
triple = (5,10,15)
triple = 5,10,15 #省略括号
但是我们更倾向于使用元括号的这种写法,使代码更加家清晰
更多的方法操作原组
通过位置访问元组中的单个元素
使用len函数获取元组中原素的数量
使用for循环迭代元组中的元素
使用in和not in测试成员
任何不修改元组的操作都可以用于元组,元组只不过是列表的不可变副本
def studentGrades(idNum,name,*grades):
print(grades)
def main():
studentGrades(1,2,4,5,6)
main()
#结果
(4, 5, 6)
前两个参数需要传递并且赋值给形式参数变量idnum和name,任何剩余的实参会保留到grades元组中,当与固定形参变量组合时,元组形参变量必须时最后一个
def sum(*values):
print(values)
total=0
for element in values:
total = total + element;
print(total)
def main():
sum(1,2,3,4,5,6)
main()
#输出
(1, 2, 3, 4, 5, 6)
21
形参变量之前的*号表示函数可以接受任意多个参数,形参变量values实际上是一个包含传递给函数的所有实参的元组
def sum(*values):
print(values)
def main():
sum((1,2,3),(4,5,6))
main()
#输出
((1, 2, 3), (4, 5, 6))
元组赋值
>>> (price,quantity) = (19.95,12)
>>> a=(price,quantity) = (19.95,12)
>>> a
(19.95, 12)
>>> price,quantityity = 19.95,12
>>> a=price,quantityity = 19.95,12
>>> a
(19.95, 12)
>>>
上面的两种操作都是合法的。
(values[i],values[j]) = (values[j],values[i])
这种赋值时不会同时存在的,真相是,右边的值先保存在一个临时元组中,然后这个元组中的值被赋值
def readDate():
print("Enter a data:")
month = int(input(" month: "))
day = int(input(" day: "))
year = int(input(" year: "))
return (month,day,year)
#这些注释的东西都是可以的,当然我们返回一个列表也是可以的。
#return month,day,year
#date = readDate()
#(month,day,year) = readDate()
# month,day,year = readDate()
修改算法
smallestPosition = 0
for i in range(1,len(values)):
if values[i] < values[smallestPosition]:
smallestPosition = i
#这样的化,这样的化就没有理由再跟踪最小值了,values[smallestPosition]就是最小值。
表格
python中没有适合创建表格的数据类型,到那时二维表格结构可以使用python列表创建。
>>> counts = [[0,3,0],[0,0,1],[0,0,1],[1,0,0],[0,0,1],[3,1,1],[0,1,0],[1,0,1]]
>>> counts
[[0, 3, 0], [0, 0, 1], [0, 0, 1], [1, 0, 0], [0, 0, 1], [3, 1, 1], [0, 1, 0], [1, 0, 1]]
>>> counts[1]
[0, 0, 1]
>>> counts[0]
[0, 3, 0]
ROWS = 5
COLUMNS = 20
table=[]
for i in range(ROWS):
row = [0] * COLUMNS
table.append(row)
print(table)
再函数中使用表格
如果values是一个表格
len(values)是行的数量
len(values[0])是列的数量
def sum(values):
total = 0
for i in range(len(values)):
for j in range(len(values[0)):
total = total + values[i][j]
return total
行长度可变的表格
b=[]
for i in range(3):
b.append([0]*(i+1))
for i in b:
print(i)
[0]
[0, 0]
[0, 0, 0]
b=[]
for i in range(3):
b.append([0]*(i+1))
for row in b:
for element in row:
print(element,end = " ")
print()
0
0 0
0 0 0
第七章文件与异常
file = open("测试.py","r")
#调用open函数返回的文件对象必须保存在一个变量中。所以的文件
#操作都通过这个文件对象来完成
file = open("测试.py","w")
#如果输出文件已经存在,那么他在写入新数据之前会被清空,如果文件不存在,会创建一个
#空文件
file.close()
#通过close方法来关闭文件
打开和关闭文件
读取文件
>>> infile = open("测试.py","r")
>>> infile.readline()
'flying\n'
>>> infile.readline()
'circus\n'
>>> infile.readline()
''
>>> infile.close()
readline方法只能返回字符串,如果文件中包含数字数据,使用int或float函数吧字符转换成数字。
value = float(line)
#注意,在字符串转换成数字时尾部的换行符会被忽略。
```python
>>> file = open("测试.txt","r")
>>> value = int(file.readline())
>>> value
520
>>>
写入文件
>>> infile = open("测试.txt","w")
>>> infile.write("hello world!")
>>>print("Hello world!",file = infile)
#只要是格式化输出都可以,write参数也可以格式化输出
文件名中的反斜杠
infile = open("c:\\homework\\input.txt","r")
字符串内一个反斜杠是转义字符,和下一个字符组成特殊含义,例如\n表示换行符。\表示单个反斜杠
迭代文件中的行
>>> file = open("测试.txt","r")
>>> for line in file:
... print(line)
...
hello world!1
hello world!2
hello world!3
hello world!4
测试.py buffers
1 file = open("测试.txt","r")
2 for line in file:
3 print(line,end="");
python3 ./测试.py
hello world!1
hello world!2
hello world!3
hello world!4
1 file = open("测试.txt","r")
2 for line in file:
3 line = line.rstrip()
4 print(line)
lonelyeagle@lonelyeagle-PC:~/python$ python3 测试.py
hello world!1
hello world!2
hello world!3
hello world!4
** 在输入字符串之前必须删除换行符**
用rstrip方法删除制定的字符
>>> line = "5201314.?"
>>> print(line.rstrip(".?"))
5201314
读取单个单词
>>> line = "mary had a little lamb"
>>> wordline =line.split()
>>> wordline
['mary', 'had', 'a', 'little', 'lamb']
文件中读取单个单词的方法,你必须首先读取一行,然后将其切分成独立的单词,这里可以使用split 方法。split方法返回在每个空开字符处对原始字符进行切分得到的子字符串的列表。** 这些空白字符不是字符串的组成部分,他们只在切分字符串时起到分割字符串的作用**。split方法把连续的空格当作一个分隔符来处理。
默认的split方法使用空白字符作为分隔符,你也可以使用不同的分隔符切分字符串
>>> line = "apples:pears:oranges:grapes"
>>> substrings = line.split(":")
>>> substrings
['apples', 'pears', 'oranges', 'grapes']
>>> line = "apples:pears:oranges::grapes"
>>> substrings = line.split(":")
>>> substrings
['apples', 'pears', 'oranges', '', 'grapes']
read方法
>>> file = open("测试.txt","r")
>>> char = file.read(1)
>>> char
'h'
>>> char = file.read(2)
>>> char
'el'
>>> char = file.read(3)
>>> char
'lo '
明确使用utf-8编码
infile = open("input.txt","r",encoding = "utf-8")
outfile = open("output.txt","w",encoding = "utf-8")
处理文件和文件夹
getcwd
获取当前工作目录的路径
>>> import os
>>> name =os.getcwd()
>>> name
'/home/lonelyeagle'
修改工作目录
chdir()ist
>>> subdir = "cmu"
>>> import os
>>> os.chdir(subdir)
>>> os.getcwd()
'/home/lonelyeagle/cmu'
#chdir函数来修改当前的工作目录
exists()
exists函数接受文件名作为参数并返回表示文件是否存在的布尔值
>>> filename = "cmu"
>>> os.path.exists(filename)
False
listdir函数
返回一个字符串列表,每个字符串表示当前文件夹中的一个文件
os.getcwd()
'/home/lonelyeagle/cmu'
>>> os.listdir()
['2']
>>> os.chdir("..")
>>> os.getcwd()
'/home/lonelyeagle'
>>> os.listdir()
['.sunpinyin', '.vimrc.custom.config', 'getchar.txt', 'cs107', '.deepin-calculator', '.recently-used', '.themes', 'Startify', 'python', '面试题2.c', 'Desktop', '.config', '测试.txt', '.icons', '面试题1.c', '.mono', 'vim82', '.LfCache', 'my_ls', '.ycm_extra_conf.py', 'Downloads', '.ssh', '.deepinwine', '.Xauthority', '任务', '.python_history', 'a.out', '主题', 'Videos', '大话数据结构', '面试题', 'cmu', '.presage', 'eagle', '.pki', '.vimplus', '.Templates', '.bash_history', '.bashrc', '.vimrc', 'my_ls2.c', '.xsession-errors.old', '.local', '.profile', 'my_ls1.c', 'Pictures', 'cpp', 'linuxc编程实战', 'Music', '.cache', '.viminfo', '.gtkrc-2.0', '.imwheelrc', '.gnupg', '.vim', '测试.c', 'Documents', '.dbus', '.bash_logout', 'putchar.txt', 'my_ls.c', '.xsession-errors', '.vimrc.custom.plugins', '.Public', '文件操作', '.dmrc']
>>>
测试列表中的字符串是否是一个文件或者是否是一个文件夹的名字
>>> os.path.isfile("文件操作")
False
>>> os.path.isdir("文件操作")
True
os.path.join
>>> entry=os.path.join("cmu","2")
>>> entry
'cmu/2'
>>> os.path.isdir(entry)
True
文本格式和二进制格式
在文本格式中,数据项以人类可读的形式表示为字符序列
例如在文本格式中,整数12345保存为5个字符的序列
“1” “2” “3” “4” “5”
在二进制格式中,数据项使用字节来表示。图像和声音的文件通常以二进制格式保存信息。
二进制文件保存整数时比按位存储使用更少的空间
文本编辑器中打开一个二进制文件,你将不能正常查看其中的内容。处理二进制文件需要专门用来读写二进制的程序。
对于二进制文件,你不能读取文本字符串,而是独立的字节。
>>> file = open("测试.c","rb")
>>> theBytes = file.read(4)
>>> theBuyes
>>> theBytes
b'#inc'
>>> value = theBytes[0]
>>> value
35
#一个bytes序列中的元素是介于0到255之间的整数值
>>> value = theBytes[0]
>>> value
35
>>> value = file.read(1)[0] #读取单个字符
>>> value
108
>>> chr(value)
'l'
bytes函数
>>> file = open("测试.txt","wb")
>>> thebytes = bytes([64,255,1,0])
>>> thebytes
b'@\xff\x01\x00'
>>> file.write(thebytes)
4
顺序访问:一次从文件中读取或往文件中读取或往文件中写入一个字符串,不能往前跳或者往后跳。
随机访问:我们需要在没有读取前面所有项的情况下直接访问特点的项,这种访问模式叫做随机访问。
infile.seek(position) #可以吧这个标记移动到相对于当前位置的某个位置
infile.seek(4,SEEK_CUR) #向前移动四个字节
infile.seek(-3,SEEK_CUR) #向后移动3个字节
position = infile.tell() #获取当前位置
处理异常
处理异常用try/except语句处理异常。如果有异常没有处理,你的程序会输出一个错误信息然后结束执行。
try块包含一个或多条可能会引发你将要处理的类型的异常的语句。每个except字句包含一个类型的异常处理代码。
try :
2 filename = input("Enter file name: ")
3 infile = open(filename,"r")
4 line = infile.readline()
5 value = int(line);
6 except IOError:
7 print("Error:file not found")
8
9 except ValueError as exception: #你可以使用as语法吧异常对象保存到一个变量中
#当valueError 的处理得到执行时,exception 被设置为那个异常对象。
#在我们的代码中,会通过str(exception)来获取那个信息。你可以认为这个操作是吧异常对象转换为字符串
10 print("Error:",str(exception))
第八章 集合和字典
集合是包含一组唯一值的容器。和列表不一样,集合中的元素不以任何特点的顺序存储,不能通过位置进行进行访问。集合对象可用的操作和在数学中集合上的操作是一样的,因为集合不需要维护特点的顺序,集合操作和等价的列表操作相比要快得多。
创建和使用集合
cast = {
"Luigi","Gumbys","Spiny"}
或者
set函数吧任何序列转换成集合
>>> names =["Luigi","Gumbys","Spiny"]
>>> cast = set(names)
len
获取集合中元素的数量
in和not in
不能使用位置来访问,但是可以使用for循环来访问
元素访问的顺序依赖于他们在内部是如何存储的。
>>> hello = set("hello world!")
>>> hello
{
'!', 'w', 'o', 'e', 'r', 'd', ' ', 'l', 'h'}
>>> for i in hello:
... print(i)
...
!
w
o
e
r
d
l
h
add方法
>>> cast =set(["Luigi","Gumbys","Spiny"])
>>> cast
{
'Gumbys', 'Luigi', 'Spiny'}
>>> cast.add("Arthur")
>>> cast
{
'Gumbys', 'Luigi', 'Arthur', 'Spiny'}
删除的方法
>>> cast.discard("Gumbys")
>>> cast
{
'Luigi', 'Arthur', 'Spiny'}
>>> cast.remove("dasdasd")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'dasdasd'
>>> cast.discard("dasdasd")
>>> cast.clear()
>>> cast
set()
也就是说remove删除的时候,如果不存在的化就会报错,可以用clear方法删除集合所有的元素
issubset方法
返回True 或 False 来表示一个集合是否是另一个集合的子集
>>> []==[]
True
>>> ()==()
True
>>> a={
"1","2"}
>>> b={
"1"}
>>> a.issubset(b)
False
>>> b.issubset(a)
True
>>> b.add("2")
>>> b.issubset(a)
True
>>> {
}=={
}
True
union方法
获取两个集合的并集
>>> b.remove("2")
>>> c=a.union(b)
>>> c
{
'1', '2'}
>>> a
{
'1', '2'}
>>> b
{
'1'}
**intersection方法 **
>>> a
{
'1', '2'}
>>> b
{
'1'}
>>> c=a.intersection(b)
>>> c
{
'1'}
difference方法 差集
>>> file = open("测试.txt","r")
>>> file
<_io.TextIOWrapper name='测试.txt' mode='r' encoding='UTF-8'>
>>> for i in file:
... print(i)
...
hello world!
#这样能够吧所有的内容都读出来
哈希
集合能以更快的速度找到元素,因为集合不需要维护元素的顺序,在内部,python使用一个叫做哈希表的数据结构。
哈希的基本思想,集合元素被分组为共享特征的更小元素组。哈希使用可以从元素计算得到的整数值**(散列码)**
可以使用hash函数来计算散列码
在python中你只可以使用可哈希的值来组建集合。但是不能对一个可变的值(例如列表或集合)进行哈希。
也就是说必须要是不可改变。
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
字典
字典是建和值之间保持关联的容器。字典中每个健都有个关联的值,健是唯一的,但是一个值可以关联到多个健上面。字典结构也叫映射,因为他吧一个唯一健映射到哦哦值上,字典存储健,值以及他们之间的关联。
ditc函数
可以用这个来创建一个字典的副本。
字典不是像列表那样的顺序类型的容器,即使下标运算可以用于字典,也不能通过索引或者位置来访问字典中的项。值只能通过与之关联的健来访问。
**in 或者 not in **
判断一个健是否在字典中存在。
get方法
>>> contact = {
"hello":"world"}
>>> a=contact.get("a",123456)
>>> a
123456
>>> a=contact.get("a","123456")
>>> a
'123456'
>>> a=contact.get("hello","123456")
>>> a
'world'
遍历字典
for key in contacts:
print(key)
for key in contacts:
print("-10%s %d"%(key,contacts[key]))
for key in sorted(contacts):
print("%-10s %d"%(key,contacts[key]))
迭代字典项
>>> contacts = {
'1':1,'2':2}
>>> contacts.items()
dict_items([('1', 1), ('2', 2)])
> >> for (key,value) in contacts.items():
... print(key,value)
...
1 1
2 2
>>> for item in contacts.items():
... print(item[0],item[1])
...
1 1
2 2
包含集合的字典。
>>> a = {
"a":[1,2]}
>>> a
{
'a': [1, 2]}
>>> a['a']
[1, 2]
>>> a['a'][0]
1
用户模块
大型python程序包含一个驱动程序和一个多个补充模块。驱动模块包含main函数,如果不使用main函数的话,就包含第一条执行语句。补充模块包含支持函数和常量。
第九章 对象和类
具有同样行为的对象被分组为类。程序员通过这些类指定和实现方法来提供预期的行为。
面向对象编程
每个对象拥有自己的数据集,以及用来操作数据集的一组方法。
类描述一组具有同样行为的对象。
公开接口
一个类提供的所有的方法的集合以及他们行为的描述。
**封装:**提供公开借口而隐藏内部是实现细节的过程。
方法的定义
方法的定义类似于函数
1 def click(self):
2 self._value = self._value + 1
方法的第一个形参变量是self。
方法定义是类定义的一部分。
对象吧数据存储在实例变量中,一个类的实例是该类的一个对象。
一个实例变量就是就是该类的每个对象都存在的一个存储位置。在count中,每个count对象都有一个名为_value的实例变量。
定义一个类
```python
#这个模块定义了Counter类
2 class Counter :
3 def getValue(self):
4 return self._value
5 def click(self):
6 self._value = self._value + 1
7 def reset(self):
8 self._value = 0
from counter import Counter
2
3 tally = Counter()
4 tally.reset()
5 tally.click()
6 tally.click()
7
8 result = tally.getValue()
9 print("Value:",result)
10
11 tally.click()
12 result = tally.getValue
13 print("Value:",result)
指定类的公开接口
设计一个类时,你需要为其指定公开接口,一个类的公开接口包含该类用户可能想应用与该类的所有方法。
数据和方法体构成了该类的私有实现
一旦对象被创建,我们就可以调用对象了。
修改器方法会修改他操作的对象。
访问器方法查询对象的某些信息而不修改它。
对象吧数据保存在实例便可中,也就是在类中声明的变量。
便利所有方法并考虑他们的数据需求,从访问器方法开始是一个好主意。
把所有实例变量设置为似有,大多数方法设置为公开。
类的设计人员必须标明那些实例变量和方法是似有的,而不违背这个私有性质则是用户的责任。
python程序员使用以一个下划线开头的名字作为似有实例变量和方法是很常见的。使用封装,所有实例变量都是私有的,只能使用方法来操作。
一般方法是公开的,有时候你会定义一个被其他方法当作辅助函数的方法,如果这样,你应该吧辅助方法定义为似有的,在其名字前面加上一个下划线
构造函数定义和初始化一个对象的实例变量,这是在创建对象时自动调用的。
register = CashRegister()
这个语句创建了一个对象,并且自动调用了CashRegister 类的函数构造,这个构造函数不需要参数。
返回一个新创建和初始化的对象的引用。引用被保存到一个变量中,以便我们后面可以通过该对象调用方法。
每个类定义一个构造函数。但是你可以定义带默认值参数的构造函数
一个方法需要调用同一个对象中的另一个方法,你需要调用self对象的那个方法。
def addItems(self,quantity,price):
2 for i in range(quantity):
3 self.addItem(price)
``![在这里插入图片描述](https://img-blog.csdnimg.cn/20210329204724161.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MTc4MTU0Nw==,size_16,color_FFFFFF,t_70#pic_center)
**类变量**
有时候,一个值是属于类的,而不属于该类的任何对象,你可以使用**类变量**来实现这个目的。(类变量通常被称为“**静态变量”**
```python
class BankAccount :
2 _lastAssignedNumber = 1000
3
4 def __init__(self):
5 self._balance = 0
6 BankAccount._lastAssignedNumberNumber = BankAccount._lastAssignedNumber + 1
7 self._accountNumber = BankAccount._lastAssignedNumber
~ _lastAssignedNumber s _lastAssignedNumber =
类变量是和方法在同一个级别上声明的(实例变量是在结构函数中创建的。)
你应该使用BankAccount._lastAssignedNumber
class menu:
def __init__(self,a):
self._options = []
print(a) #可以传递参数过来
def addOption(self,option) :
self._options.append(option)
def getInput(self) :
done = False
while not done :
for i in range(len(self._options)) :
print("%d %s"%(i + 1,self._options[i]))
unserChoice = int(input())
if userChoice >= i and userChice < len(self._options):
done = True
return userChoice
管理一个类都遵守同样的基本模式
确定影响总数的方法并提供合适的代码来增加或减少他,确定报告或使用这个总数的方法,让那些方法读取当前总数的值。
使用唯一状态建模对象
class Fish :
2 #常量状态值
3 NOT_HUNGRY = 0
4 SOMEWHAT_HUNGRY = 1
5 VERY_HUNGRY = 2
6
7 def __init__(self):
8 self._hungry = Fish.NOT_HUNGRY
9 def eat(self) :
10 self._hungry = Fish.VERY_HUNGRY
11 def move(self) :
12 if self._hungry == Fish.VERY_HUNGRY
13 look for food.
对象引用
在python中,变量并不真正保存对象,而只是保存对象的内存地址,对象本身则保存在另外的地方。
我们使用技术术语对象引用来表示一个对象的内存地址,当一个变量包含一个对象的内存地址时,我们称它引用了一个对象。
例如
reg1 = CashRegister()
变量reg1引用了创建cashregister对象,从技术上来讲,构造函数返回新对象的引用,而那个引用则保存在reg1变量中。
共享引用
你可以通过吧一个变量赋值给另一个变量让两个或者更多变量保存在同一个对象的引用。
None引用
如果一个对象引用根本没有引用任何对象,他会拥有一个特殊的值None,使用None 值来表示一个变量还没有被设置值是很常见的情况。
使用运算符is(不是==)测试一个对象引用是否为None
>>> middleinital =None
>>> middleinital == None
True
>>> middleinital is None
True
self引用
每个方法都有一个调用该方法的对象的引用,保存在self形参变量中。
当这个方法被调用时,形参变量self引用和reg1相同的对象。
self引用用来访问调用该方法的对象的实例变量。
1 def addItem(self,price):
2 self._itemCount = self._itemCount + 1
3 self._totalPrice = self._totalprice + price
你也可以在self上调用一个方法。
def __init__(self):
2 self.clear()
有时你会吧正在创建的对象的引用传递给另一个方法
1 def isFriend(self,other):
2 return self.likes(other) and other.likes(self)
对象的生命周期```
只要有至少一个变量在引用它,这个对象和它所有的实例变量就处于存活状态。如果一个对象不再被引用,就会被虚拟机中的
“垃圾回收器“删除。
当使用的构造函数创建对象时,对象被创建,并且构造函数的self变量被设置为该对象的内存地址。
当使用的构造函数对象时,对象被创建,并且构造函数的self变量被设置为该对象的内存地址。
最初的时候这个对象不包含实例变量,当构造函数执行下面的语句时:
self._itemCount = 0
#实例变量被增加到该对象上,最后,当构造函数推出时,返回该对象的一个引用。通畅会吧这个引用保存到一个变量中。
**isinstance函数**
python提供了内置函数要求两个整数,我们可以使用isinstance函数来检查参数的类型并在必要时抛出。
```python
>>> isinstance(1,int)
True
第10章继承
继承是指通用型(称作超类)和专用类(称为子类)之间的关系。子类从超类中继承的行为。
根据替换原则,在需要一个超类对象的时候总是能够使用子类对象。例如,考虑一个接受vehicle类型参数的时候:
processVehicle(vehicle)
#因为car 是vehicle的子类,你可以使用一个car对象调用哪个函数
myCar = car(...)
processVehicle(myCar)
因为他可以处理任意类型的交通工具(包括Truck和Motorcycle对象)一般的,当我们把类分组到继承结构层次中时,就可以在类之间共享通用代码了。
值变化的话使用单个类,行为变化的话使用继承
继承的目的:是对具有不同行为的的类型进行建模。
实现子类
把choiceQuestion实现为Question类的子类,这会允许choiceQuestion子类继承Question类的特征和行为。
在python中,通过指定子类和超类的不同之处来构建子类。
子类对象自动具有在超类中声明的实例变量,你只需要声明那些在超类对象中没有的实例变量。子类继承超类的所有方法,你需要爱定义子类的心方法,并且如果继承来的行为不合适的话就修改继承来的方法的实现。为继承来的方法提供新的实现时,你就覆盖了那个方法。
choiceQuestion对象和Question对象有三处不同:
该类对象为答案保存多个选项
有个用于增加答案选项的方法
choiceQuestion类的display方法显示这些选项使得答案人能够从中选择一个
在choiceQuestion 类从Question类继承时,需要明确说明这三处不同。
#定义时,头部圆括号里的类名表示继承
class ChoiceQuestion(Question):
2 #子类拥有自己的构造函数
3 def __init__(self):
4 ...
5 #为子类增加实例对象
6 self._choices = []
7 #为子类增加方法
8 def addChoice(self,choice,correct):
9 ...
10 #覆盖从超类继承而来的方法
11 def display(self):
12 ...
choiceQuestion对象,不仅拥有在超类Question中声明的实例变量_text和_answer,又增加了额外的实例变量_choices.
class Question:
2 ##使用空的问题和答案字符串构造一个问题
3 #
4 def __init__(self):
5 self._text = ""
6 self._answer = ""
7 ##设置问题文本
8 #
9 def setText(self,question):
10 self._text = question
11 #设置该问题的答案
12 def setAnswer(self,correctResponse):
13 self._answer = correctResponse
14 #检查给定响应的正确性
15 def checkAnswer(self,response):
16 return response == self._answer
17 #显示问题
18 def display(self):
19 print(self._text)
display方法是在超类中就已经存在的方法,子类覆盖了这个方法,使得选项能够正确显示
question类的所有其他方法都自动被ChoiceQuestion类继承
混淆超类和子类
比较choiceQuestion 类型的对象和 Question类型的对象,你会发现
choiceQuestion对象更大一些,他有个增加的实例变量_choices.
choiceQuestion对象功能更强大,他有个addchioce方法
超/子这个术语来自集合论,choiceQuestion对象的集合是所有 Question对象集合的子集,而Question对象集合是choiceQuestion对象集合的超集。子集中更加专用的对象具有更丰富的状态和更多的功能。
调用超类构造函数
子类构造函数只能定义子类的实例变量,但是超类实例变量也需要定义。
子类构造函数必须显示调用超类的构造函数。为了构造超类的构造函数,你必须在调用构造函数时在self引用的位置使用super函数.
class ChoiceQuestion(Question):
def __init__(self):
super().__init__()
self._choices = []
如果超类构造函数需要参数,你必须把他们作为参数提供给__init__方法
class ChoiceQuestion(Question):
def __init__(self,questionText):
super().__init__(questionText)
self._choices = []
class Vehicle:
2 def __init__(self,numberOfTires):
3 self._numberOfTires = numberOfTires
4 def getNumberOfTires(self):
5 return self._numberOfTires
6 def setNumberOfTires(self,newValue):
7 self._numberOfTires = newValue
8 def getDescription(self):
9 return "A vehicle with " + self._numberOfTires + " tires"
class Car(Vehicle):
2 def __init__(4):
3 #调用超类构造函数来定义他的实例变量
4 super().__init__(4)
5 self._plateNumber = "??????"
6 def setLicensePlateNumber(self,newValue):
7 self._plateNumber = newValue
8 def getDescription(self):
9 return "A car with license plate " + self._plateNumber
覆盖方法
子类继承了超类的方法,如果你对继承来的方法的行为不满意,可以通过在子类中指定一个新的实现它。
你不能直接访问超类的文本变量,因为他是似有的,相反,你可以使用super函数调用超类的display方法:
1 def display(self):
2 super().display() #ok
1 def display(self):
2 self.display() #这个是错误的,这个自己调用自己
在期望得到一个子类的对象时,你不能替换为超类对象,但是,在期望得到超类对象的时候,你可以替换为子类对象。
动态方法查询:动态方法查询允许我们使用一致的方式处理不同的类型的对象。
多态:我们要求多个对象执行一个任务,然后每个对象按照自己的方式去完成。多态似的程序非常容易拓展。
子类和实例
isinstance函数可以用来决定一个对象是否为特定类的实例。但是isinstance函数也可以决定一个对象是否是一个子类的实例。
isinstance(q,Question) #如果哦q是Question类的化就返回True,如果不是的花就返回False
如果传递给函数的是非法类型类型的对象,抛出一个TypeError异常。
1 if not isinstance(q,Question):
2 raise TypeError("The argument is not Question or one of its subclasses")
动态方法的查询
class Question:
2 ...
3 def presentQuestion(self):
4 self.display()
5 response = input("your answer:")
6 print(self.checkAnswer(response))
7
8 #考虑下面的调用
9 cq = ChoiceQuestion()
10 cq.setText("In which county was the inventor of python born?")
11 ...
12 cq.presentQuestion()
self 引用参数是调用该方法的对象的引用,在这里。self引用的是choiceQuestion类型的对象。由于动态方法查询,会自动调用choiceQuestion版本的display和checkanswer。即使presentQuestion方法是在Question类中生命的。该Question类甚至可能不知道choiceQuestion类的存在,也会发生这样的情况。
抽象类
在对已有类进行扩展时,你可以选择是否覆盖超类中的方法,而有时可能需要强制程序员覆盖一个方法,如果难以为超类定义一个合适的默认实现,而只是子类程序员才知道如何实现该类方法时,会发生这种情况。
class Account :
2 ...
3 def deductFees(self):
4 ...
我们可以让deductFees什么都不做,更好的做法是指定deductFees方法为一个抽象方法,抽象方法没有任何实现,这样强制子类的实现者说明该方法的具体实现。(当然有些子类可能决定实现一个什么也不做的的方法,但那样是他们的选择——而不是悄无生息的继承默认的方法)
包含一个方法的类叫做抽象类,不包含抽象方法的类有时叫做具体类
没有显示的方法用来说明一个方法是抽象方法,python程序员最常采用的方式是抛出一条异常语句:
1 class Account:
2 ...
3 def deductFees(self):
4 raise NotImplementedError #表示有缺失的实现
使用抽象类的原因是强制程序员创建子类。通过指定特定方法是抽象的,你可以避免设计可能会被其他人无意中继承的无用默认方法。
不使用类型测试
1 if isinstance(q,ChoiceQuestion): #不要这样做
2 #如果条件成立做的事情
不论何时,如果你发现自己试图在类的层次结构中使用类型测试,不要使用类型测试,因为我们使用的是多态。
解决的方法是在超类中定义方法,并在子类中覆盖调用。
开发一个继承层次结构
在处理一组类时,其中有一些更加通用而另外一些则更加专用,这时候你会把他们组织为一个继承层次结构。这样可以使你使用统一方式处理不同类的对象。
步骤
1.列出属于该层次结构的类。
有些类会有些重复的功能,我们需要一个可以实现通用功能的类。如果问题中没有显示的提到这个类,那么我们需要自己发现他。
2.把类组织进一个继承层次结构。
绘制一个显示超类和子类的继承图。
3.决定通用职称。
第二步中,确定层次结构根部的一个类。编写一个伪代码。
4.决定在子类中覆盖哪里功能
对于每个子类和每个通用指责,决定那个行为可以被继承或者是否需要覆盖他。确保在继承成次的根部声明被继承或被覆盖的方法。如果都要覆盖的化,那就可以考虑抽象类。
5.定义每个子类的公开接口。
6.确定实例变量。
列出每个类的实例变量。如果你发现一个所有类共有的实例变量,一定要在根部定义他。就是在超类中定义他。
7.实现结构函数和方法。
如果方法必须在子类中实现并为那个类型的帐号执行合适的处理。我们选择让那个方
8.创建不同子类的对象并处理他们。
1 def monthEnd(self):
2 return #让这个方法抛出异常也是一样合适的,那样的化就表示这个方法是抽象的。并且应该在子类中覆盖。
`导入模块的方法
#导入模块里面的函数
>>> from math import sqrt,sin,cos
#把一个模块中的全部内容导入到你的程序中
>>> from math import *
#导入模块
>>> import math
>>> y=math.sqrt(1) #这样的写法可以可以清晰的知道一个特定的函数属于哪个模块
>>> y
1.0
增加和修改项
可以使用下标运算符[]为字典增加新的项。也可以使用[]来修改新的项。
删除项
pop方法
pop方法会删除整个项,吧健作为参数。
>>> contact = {
"hello":"world"}
>>> a = contact.pop("hello")
>>> a
'world'
内置函数:可以不导入任何得模块任意使用。这些函数被定义为语言得一部分。
print函数
print()
print(value1,value2,…,value n)
print(”the answer is", 6+7, "!")
总结:也就是说可以参数的个数是可变的,而且打印的类型不是指定的,这个跟c语言就由不同,c语言是格式化输出,输出的实际上是格式化出来的字符串。 不管由没有参数的情况输出都会换行。
print("the answer is",6+7,"!")
print("the answer is", 6+7, "!")
输出如下:
the answer is 13 !
>>> ord('h') #返回表示指定字符的数字
104
>>> chr(104)#与ord 相反。返回与字符码对应的字符。
'h'
print函数里面的end = 参数
>>> print('hello world',end = 'hello world')
hello worldhello world>>>
>>> print('hello world',end ='\n')
hello world
>>> print('hello world')
hello world
>>>
上面的结果依旧很明显的说明了end = 参数应该怎么使用
>>> first = input("输入hello world!")
输入hello world! hello world
>>> first
' hello world' #得到一个结论,默认输入的是一个字符串
总结:也就是说input的时候空格不会被忽略掉,这个跟c原因的scanf不一样,scanf会忽略空格,换行,和指标符。
上面的两种输出的方式都是一样的,也就是说参数前面有没有空格都是一样的。
range函数
range函数根据提供的参数生成一系列值,第一个参数是序列中的第一个值,小于第二个参数值的数值会被包含进这个序列。
默认的,python函数以1为步长创建序列,可以通过第三个参数来设置步长、
range函数可以设置步长是正数,还可以设置步长是负数,也可以不设置步长,默认为1,range 函数也可以只要一个参数,就相当于忽略了第一个参数,只有一个参数的时候,也就是说相当于设置了第二个参数,第一个参数,步长为1
range函数 相当于一个左必右开区间
>>> for i in range(10,0,-1):
... print(i)
...
10
9
8
7
6
5
4
3
2
1
>>> for i in range(0,10,-1):
... print(i)
... #这样是打印不出来内容的
>>> for i in range(10):
... print(i)
...
0
1
2
3
4
5
6
7
8
9
random函数
调用random()可以产生一个大于等于0并且小于1的随机浮点数,在次调用random(),你会得到一个不同的数字。实际上他们并不是完全随机的,他们是从一个在很长时间都不会重复的数字序列中提取出来的。他们通常被称作伪随机数。
randint(a,b)
返回一个介于a与b之间的随机数,与range不同的是,生成的数是闭区间的。
方法
用法: 方法名紧跟在对象之后,并且使用一个圆点(.)分隔对象和方法名。
任意方法的调用都不能修改字符串的值
replace :其中给定子字符串的每次出现都被替换为第二个字符串。
name2=name.replace("John","Jane")
常用的字符串方法
方法 | 返回值 |
---|---|
s.lower() | 字符串s的小写版本 |
s.upper() | 字符串s的大写版本 |
– | – |
s.replace(old,new) | 返回一个新字符串,其中子字符串old在s中的每次出现都被替换为字符串new |
测试字符串的运算
substring in s | 如果字符串s包含substring那就返回true |
---|---|
s.count(substring) | 返回substring 在s中不重叠出现的次数 |
>>> a='asd'
>>> c='asdasdasd'
>>> c.count(a)
3 #重复出现了3次
s.endswith(substring) | 如果s以substring结束就返回true,如果不是就返回false |
---|---|
s.find(substring) | 返回substring在s中的索引,如果没有找到那就返回-1 |
>>> a='a.html'
>>> a.endswith('html')
True
>>> a.endswith('l')
True
>>> a='0123456789'
>>> a.find('0')
0
>>> a.find('9')
9
>>>
s.startswith(substring) | 如果s以substring开头就返回true,如果不是就返回false |
---|
>>> s='hello world'
>>> s.startswith('h')
True
>>> s.startswith('hello ')
True
>>>
测试字符串特征的方法
s.isalnum() | 如果字符串s只包含字母或数字并且包含一个字符就赶回true,否则false |
---|---|
s.isalpha() | 如果字符串s只包含并且至少包含一个字符就就返回true,否则返回false |
s.isdigit() | 如果字符串s中包含数字并且至少一个字符就返回true,否则返回true |
– | – |
s.islower() | 如果字符串s至少包含一个字母并且字符串中所有字母都是小写就返回true,否则返回false |
s.isspace | 如果字符串s只包含空白字符(空格,换行符,制表符)并且至少包含一个字符就返回true,否则返回false |
– | – |
s.isupper() | 如果字符串s至少包含一个字母并且字符串中所有字母都是大写就返回true,否则返回false |
>>> '-1729'.isdigit()
False #-号不是数字字符
GraphicsWindow类的方法
w=GraphicsWindow() | 创建包含一个空白画布的图形窗口,画布尺寸默认时400*400 |
---|---|
w=GraphicsWindow() | |
w.canvas() | 返回包含在图形窗口中的画布的对象 |
– | – |
w.wait() | 保持图形窗口处于打开状态,等待用户单机 关闭 |
canvas.drawLine(x1,y1,x2,y2 | 在画布的点(x1,y1)和(x2,y2)之间绘制一条直线 |
– | – |
canvas.drawRect(x,y,width,height) | 绘制一个矩形,左上角坐标位为(x,y)并且使用给定的宽度和高度 |
GraphicsCanvas类的颜色方法
c.setColor(colorname) | 把颜色和轮廓设置为相同的颜色,颜色可以通过名字或者颜色分量的值来设置 |
---|---|
c.setFill() c.setFill(colorname) | 设置填充几何图形的颜色,如果没有参数的化表示清除颜色 |
c.setOutline() c.setOutline(colorname) | 设置绘制直线或文本的颜色,如果没有参数的化就表示清楚轮廓的颜色 |
---|---|
GraphicsCanvas类的绘图方法
方法 | 结果 |
---|---|
c.drawLine(x1,y1,x2,y2) | 绘制一条直线,(x1,y1)和(x2,y2)时端点 |
c.drawRect(x,y,width,height) | 矩形,(x,y)时坐上角 |
– | – |
c.drawOval(x,y,width,height) | (x,y)是限定椭圆的盒子左上角,如果要绘制圆,width和height使用相同的值 |
c.drawText(x,y,text) | (x,y)是定位点 |
– | – |
`