9月22日:《基础教程》基础知识
第1章 快速改造:基础知识
- 长整数,python2和python3有关长整数的区别?
python2中有long类型
python3中没有long类型,只有int类型
>>> 1000000000000000000 #教材
1000000000000000000L
>>> 1000000000000000000L
1000000000000000000L
>>> 1000000000000000000 #测试
1000000000000000000
>>> 1000000000000000000L
SyntaxError: invalid syntax
>>> 0xAF #十六进制数前面是0x
175
>>> 010 #八进制数前面是0
8
·模块导入
- 除非真的需要from这个形式的模块导入语句,否则应该坚持使用普通的import。
>>> import math #正常导入模块,使用导入模块中的函数
>>> math.floor(32.9)
32
--------------------
>>> from math import sqrt #使用from可以直接使用函数不用加模块,但是会有不同模块重名函数的现象需要注意
>>> sqrt(9)
3.0
·用变量引用函数(或者Python中大多数的对象)
>>> foo=math.sqrt
>>> foo(4)
2.0
·将数值转换成字符串的方法:str类型、repr函数
- 将数值转换成字符串的方法:str类型、repr函数和 反引号(反引号在python 3中已经不再使用)
>>> temp=23
>>> print("The temperature is "+ repr(temp))
The temperature is 23
9月23日:列表、元组
第2章 列表和元组
2.1序列概览
- 序列(内建序列):列表、元组、字符串、buffer对象、xrange对象
·序列索引可以为负数:
索引范围为[ (-n) ~ (n-1) ]
sequence = [1,2,3,4,5]
print("sequence[4] = " + str(sequence[4]))
print("sequence[-5] = " + str(sequence[-5]))
sequence[4] = 5
sequence[-5] = 1
·序列的分片和步长
- 冒号“:”实现分片 和 步长,步长隐式设置为1
- 形式为:number[ a : b [ : c ] ]
- c不能为0,默认为;a为分片的首个元素索引,b为分片最后一个元素的下一个元素索引,也就是a在分片中,b不在分片中
- 从首个元素开始取时可以空置a,取到最后一个元素时可以空置b
- 如果c是正数(比如隐式设置),那么number[a]必须在number[b]左边;如果c是负数,那么number[a]必须在number[b]右边。
number = [1,2,3,4,5,6,7,8,9,10]
print("number[2:10] = " + str(number[2:10])) #冒号“:”实现分片,步长隐式设置为1
print("number[2:10:2] = " + str(number[2:10:2])) #冒号“:”实现分片 和 步长,步长隐设置为2
print("number[:8] = " + str(number[:8])) #从首个元素开始,a为0,也可以空置
print("number[2:] = " + str(number[2:])) #d到最后一个元素结束,b为n,也可以空置
print("number[10:0:-2] = " + str(number[10:0:-2])) #步长为负数,a索引元素必须在b索引元素右边
print("number[::2] = " + str(number[::2])) #a,b都空置
print("number[::] = " + str(number[::])) #a,b,c都空置
number[2:10] = [3, 4, 5, 6, 7, 8, 9, 10]
number[2:10:2] = [3, 5, 7, 9]
number[:8] = [1, 2, 3, 4, 5, 6, 7, 8]
number[2:] = [3, 4, 5, 6, 7, 8, 9, 10]
number[10:0:-2] = [10, 8, 6, 4, 2]
number[::2] = [1, 3, 5, 7, 9]
number[::] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
·序列相加,乘法;列表和字符串不能相加
number1 = [1,2,3]
number2 = [4,5,6]
string1 = "Hello,"
string2 = "World!"
print("number1 + number2 =" + str(number1 + number2)) #列表相加
print("string1 + string2 =" + string1 + string2)
#print("number1 + string1 =" + str(number1 + string1))
#这句报错,列表和字符串不能相加
print("number1 * 3 = " + str(number1 * 3)) #列表相乘
number1 + number2 =[1, 2, 3, 4, 5, 6]
string1 + string2 =Hello,World!
number1 * 3 = [1, 2, 3, 1, 2, 3, 1, 2, 3]
·in运算符 测试成员资格
subject = "$$$ Get rich now!!! $$$"
if "$$$" in subject : print("'$$$' in subject\n")
'$$$' in subject
9月24日:序列分片,列表方法,字符串格式化
2.3 列表:Python的苦力
·list函数:将 所有类型的序列 转换成 列表
temp = list("Hello!")
print(temp)
['H', 'e', 'l', 'l', 'o', '!']
·删除列表元素 del
names = ['Alice','Beth','Cecil','Dee-Dee','Earl']
print(names)
del names[2]
print(names)
del names[1:3]
print(names)
['Alice', 'Beth', 'Cecil', 'Dee-Dee', 'Earl']
['Alice', 'Beth', 'Dee-Dee', 'Earl']
['Alice', 'Earl']
·分片赋值 name[a:b]
- 可以通过 分片 进行多个元素赋值;
- 也可以与原序列不等长的赋值;
- 还可以通过 分片赋值 插入或者删除元素;
name = list('Perl')
name[2:] = list('ar') #通过分片进行多个元素赋值
print(name)
name[1:] = list('ython') #与原序列不等长的赋值
print(name)
name[1:1] = list('&&&&&&&') #通过 分片赋值 插入新的元素
print(name)
name[1:12] = [] #通过 分片赋值 删除元素
print(name)
['P', 'e', 'a', 'r']
['P', 'y', 't', 'h', 'o', 'n']
['P', '&', '&', '&', '&', '&', '&', '&', 'y', 't', 'h', 'o', 'n']
['P', 'n']
·列表方法
- 列表方法:append,count,extend,index,insert,pop,remove,reverse,sort
·列表方法作用和返回值 表格
列表方法 |
作用 |
返回值 |
相关内容 |
append |
列表末尾追加元素 |
None |
|
count |
元素出现次数 |
次数 |
|
extend |
列表末尾扩展另一个序列 |
None |
末尾分片赋值 |
index |
第一个匹配值的索引 |
索引 |
|
insert |
列表插入元素 |
None |
分片赋值 |
pop |
移除最后一个元素 |
元素 |
insert(0,…),pop(0), append(),pop() |
remove |
移除匹配项的第一个元素 |
None |
|
reverse |
列表反向 |
None |
reversed ( ) 函数返回迭代器 可以使用 y = list(reversed(x)) |
sort |
列表排序 |
None |
sorted ( ) 函数返回列表 可以使用 y = sorted(x) |
·高级排序,sort方法的使用
- number.sort(cmp,key=None,reverse=False)
- sort方法三个参数,第一个cmp函数;
- 第二个key关键字参数,排序过程中使用的函数,如len;
- 第三个reverse,布尔值,默认设置为False不反向;
- 以上三个参数适用于sorted()函数;
·元组:不可变序列
- 一个元素的元组,必须加逗号,否则即使加圆括号也不行;
print(3*(42))
print(3*(42,))
126
(42, 42, 42)
1、元组可以作为映射的键使用;
2、元组一般作为内建函数和方法的返回值;
第3章 使用字符串
·字符串格式化 %
- 下面例子中values如果是序列,会被解释成一个值;
- 如果本身就有%,那么必须使用%%,%才不会被认为是 转换说明符;
string1 = "Hello,%s! %s enough fo ya?"
values = ("world","Hot") #values如果是序列,会被解释成一个值
print(string1 %values)
Hello,world! Hot enough fo ya?
#对比
string1 = "Hello,%s! enough fo ya?"
values = ["world","Hot"] #values如果是序列,会被解释成一个值
print(string1 %values)
Hello,['world', 'Hot']! enough fo ya?
string1 = "Pi with three decimals: %.3f."
from math import pi
print(string1 % pi)
Pi with three decimals: 3.142.
·字符串格式化转换说明符
|
内容 |
说明 |
1 |
%字符 |
标记转换说明符的开始 |
2 |
转换标志 (可选) |
- 表示左对齐; + 表示在转换值之前要加上正负号; “ ”(空白字符)表示正数之前保留空格; 0 表示转换值若位数不够则用0填充 |
3 |
最小字段宽度 (可选) |
转换后的字符串至少应该具有该值指定的宽度。 如果是 * ,则宽度会从值元组中读出 |
4 |
点( . )后跟精度值 (可选) |
如果转换的是实数,精度值就表示出现在小数点后的位数。 如果转换的是字符串,那么该数字就表示 最大字段宽度。 如果是 * ,那么精度将会从元组中读出。 |
5 |
转换类型 |
下表 |
转换类型 |
含义 |
d,i |
带符号的十进制整数 |
o |
不带符号的八进制 |
u |
不带符号的十进制 |
x |
不带符号的十六进制(小写) |
X |
不带符号的十六进制(大写) |
e |
科学计数法表示的浮点数(小写) |
E |
科学计数法表示的浮点数(大写) |
f,F |
十进制浮点数 |
g |
如果指数大于-4或者小于精度值则和e相同,其他情况与f相同 |
G |
如果指数大于-4或者小于精度值则和E相同,其他情况与F相同 |
C |
单字符(接受整数 或者 单字符字符串) |
r |
字符串(使用 repr 转换任意Python对象) |
s |
字符串(使用 str 转换任意Python对象) |
from math import pi
print("%10f" % pi) #字段宽度 10
print("%10.2f" % pi) #字段宽度 10,精度 2
print("%*.*s" % (10,5,"abcdefgh")) #使用 * 作为字段宽度或者精度(或者两者都使用*),数值会从元组参数中读出
3.141593
3.14
abcde
from math import pi
print("%010.2f" % pi) #字段宽度 10,精度 2,位数不够用 0 填充
print("%-10.2f" % pi + "abcd") #字段宽度 10,精度 2,- 表示左对齐数值,打印出来的数字右侧有额外的空格
print("% 5d" % 10 + "\n" + "% 5d" % -10) #" "意味着在正数前面加上空格,
print("%+5d" % 10 + "\n" + "%+5d" % -10) # + 表示不管是正数负数都标示出符号
0000003.14
3.14 abcd
10
-10
+10
-10
·字符串 常用方法
|
|
string1.find(string2[,a[,b]]) |
字符串string1起始a和终止b范围内查找字符串string2,并返回最左端索引值,没找到返回-1, 可以不提供a,b;也可以只提供 a 起始 |
string1.join(string2) |
返回用string1连接string2中元素的字符串 |
string1.split([separate[,maxsplit]]) |
返回字符串string1中用字符串separate分隔所得的所有 单词的列表,maxsplit指定最多切割几次; separate默认设置空格“ ”,maxsplit默认设置无穷大 |
string.lower() |
返回字符串string的小写字母版本 |
string1.replace(old,new[,max]] |
返回字符串string1的副本,用new字符串替换old字符串,最多替换max次 |
string1.strip([chars]) |
返回字符串string1的副本,其中string1开头和结尾所有的位于字符列表[chars]中的字符都被去除; [chars]隐形设置为所有的空白字符,如空格、tab和换行符 |
string.translate(table[,deletechars]) |
返回字符串的副本,其中所以字符都是用table进行了转换,可选择删除出现在deletechars中的所有字符; table由string模块中的maketrans函数构造 |
table = str.maketrans("cs","kz") #注意python 3 中maketrans的使用方式
string1 = "this is an incredible test"
string2 = string1.translate(table)
print(string1 + '\n' + string2 + '\n')
this is an incredible test
thiz iz an inkredible tezt
9月25日:字典方法,python基本语句
·字典基本操作
- dict函数建立字典,类似list、tuple、str一样;
dict可以通过其他字典 或者 (键-值)对的序列建立字典;
也可以通过关键字参数创建字典;
- 字典 是唯一内建的映射类型;
- len(d);del d[k];k in d;等操作都可用,只不过k in d 查找的是键的成员资格,而不是值得成员资格;
items = [('name','Gumby'),('age',42)]
d = dict(items) #通过其他字典 或者 (键-值)对的序列建立字典;
print(d)
d2 = dict(number = 54,name = 'Richard') #通过关键字参数创建字典;
print(d2)
{'name': 'Gumby', 'age': 42}
{'number': 54, 'name': 'Richard'}
·字典的格式化字符串
- 字典除了可以元组一样使用字符串格式化功能,还可以在每个转换说明符中的 % 字符后面,加上(键),后面再跟其他元素说明;
items = [('name','Gumby'),('age',42)]
d = dict(items) #通过其他字典 或者 (键-值)对的序列建立字典;
print("%(name)s's age is %(age)d!" %d) #在每个转换说明符中的 % 字符后面,加上(键),后面再跟其他元素说明
Gumby's age is 42!
·字典方法
字典方法 |
作用 |
返回值 |
相关 |
d.clear() |
清除字典中所有的项 |
None |
|
d.copy() |
浅复制一个拥有相同键-值对的新字典,一般用deepcopy函数进行深复制 |
dict |
deepcopy(dict) |
dict.fromkeys(sequence[,value]) |
返回从sequence中获得的键和被设置为value的值(value的默认设置值None)的字典。可以直接在字典类型dict上作为类方法调用 |
dict |
|
d.get(key[,default]) |
如果d[key]存在,那么将其返回;否则返回给定的默认值default(default不设置默认None) |
d[key]或default |
|
d.items() |
返回字典d中(键,值)对的列表 |
list |
|
d.iteritems() |
和d.items()相同,只不过返回的是迭代器,是列表中的一个可迭代对象 |
iterator |
|
d.keys() |
返回字典d的键的列表 |
list |
|
d.iterkeys() |
和d.keys()相同,只不过返回的是迭代器,是列表中的一个可迭代对象 |
iterator |
|
d.values() |
返回字典d的值得列表 |
list |
|
d.itervalues() |
和d.values()相同,只不过返回的是迭代器,是列表中的一个可迭代对象 |
iterator |
|
d.pop(key[,default]) |
移除,并且返回d[key],如果d[key]不存在则返回default |
|
|
d.popitem() |
移除,并返回字典d中任意一个(键-值)对 |
tuple(键,值) |
|
d.setdefault(key[,default]) |
返回d[key];d[key]不存在返回给定的默认值default(默认为None)并将d[key]的值绑定给default |
d[key]或default |
|
d.update(other) |
other如果是字典,会将other每一项都加入d中(可能会改写已存在项);other也可以是(键-值)对的序列或关键字参数,update方法和dict函数一样使用 |
None |
|
·python基本语句
- print语句用(,)逗号间隔参数,打印的结果每个逗号都有一个空格;
- import语句可以加as用于别名,也可以结合 from * import * as *;
·赋值语句
- 序列解包:
-多个赋值操作可以同时进行,也可以交换多个变量,还可以结合(*)星号运算符;
x,y,z = 1,2,3 #多个赋值操作可以同时进行
print(x,y,z)
x,y = y,x #也可以交换多个变量
print(x,y,z)
x,y,*rest,z = 1,2,3,4,5 #还可以结合(*)星号运算符
print(x,y,rest,z)
1 2 3
2 1 3
1 2 [3, 4] 5
- 链式赋值:x = y = somefunction()
- 增量赋值:+=;-=;*=;/=;%=;
·条件语句
- 布尔值为假:False,0;None,(),"";[];{};
- if / elif / else
- 比较运算符 连接使用 :0 < age < 100;
- is:同一性运算符:判定 同一性 而不是 相等性;
- and、or、not:布尔运算符
- a if b else c
print("abc" if True else "ABC") # a if b else c
print("abc" if False else "ABC")
abc
ABC
age = -1
assert 0<age<100 "The age must be realistic!"
print(age)
assert 0<age<100 "The age must be realistic!" ^
SyntaxError: invalid syntax
·循环语句
- range()函数 和 xrange()函数:内建的范围函数
·range()函数以此创建整个序列,而xrange()函数一次只创建一个数,效率更高
·注意:python3 中取消了 range 函数,而把 xrange 函数重命名为 range,所以现在直接用 range 函数即可
for number in range(1,101,20): #range([start,] end [,step])
print(number)
1
21
41
61
81
- 并行迭代:zip()函数
·zip()函数:可以把两个序列“压缩”在一起,然后返回一个元组的列表;
·zip可以处理不等长的序列,当最短的序列“用完”为止;
names = ['anne','beth','george','damon']
ages = [12,45,109]
for name,age in zip(names,ages): #把两个序列“压缩”在一起,然后返回一个元组的列表
print(name,'is',age,'years old') #names有四个元素,ages有三个元素,zip可以处理不等长的序列,当最短的序列“用完”为止;
anne is 12 years old
beth is 45 years old
george is 109 years old
- 内建的enumerate()函数:可以在提供索引的地方迭代 索引-值 对;
names = ['anne','beth','george','damon']
for index,name in enumerate(names):
print(index,name)
0 anne
1 beth
2 george
3 damon
·while True实现一个永远不会停止的循环,但是在循环内部的if语句用break语句跳出
while True:
word = input("Please enter a word:")
if not word:
break
print ('The word was ' + word)
Please enter a word:Richard
The word was Richard
·列表推导式——轻量级循环
abc = [x*x for x in range(10)] #列表推导式:工作方式类似于for循环
print(abc)
abc = [x*x for x in range(10) if x%3==0] #可以通过增加一个if部分添加到列表推导式中
print(abc)
abc = [(x,y) for x in range(3) for y in range(3)] #也可以增加更多for语句的部分
print(abc)
abc = [(x,y) for x in range(3) for y in range(3) if x<y]
print(abc)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[0, 9, 36, 81]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
[(0, 1), (0, 2), (1, 2)]
·其他语句:pass、del、exec和eval
- pass语句:python中控代码块是非法的,解决方法就是在语句块中加上一个pass语句;
names = ['Richard','Tom','Jerry']
for name in names:
if name == 'Richard':
print('Welcome!')
elif name == 'Tom':
pass #不允许有空代码块
elif name == 'Jerry':
print('Access Denied!')
Welcome!
Access Denied!
- del语句:不仅会移除一个对象的引用,也会移除那个名字本身;
- exec执行字符串;eval求值字符串;命名空间:in scope;
9月26日:
·直接赋值,浅拷贝copy、深拷贝deepcopy
- 直接赋值:传递对象的引用而已,原始列表改变,被赋值的也会做相同的改变
·列表list、字典dict都是如此;
·对象拷贝的是引用
xo=[1,2,3,4,5]
yo=xo #列表list直接赋值
yo[1]=200
print(xo)
print(yo)
[1, 200, 3, 4, 5]
[1, 200, 3, 4, 5]
- 浅拷贝copy:没有拷贝子对象,所以原始数据改变,子对象会改变
·对象拷贝的是数据
·子对象拷贝的是引用
import copy
xo=[1,2,3,[4,5,'a'],6]
yo=copy.copy(xo) #浅拷贝
yo.append(7) #结果原始对象没有改变,因为原始对象拷贝的是原始数据
print(xo)
print(yo)
xo=[1,2,3,[4,5,'a'],6]
yo=copy.copy(xo) #浅拷贝
yo[3].append('b') #结果子对象改变了,因为子对象拷贝的是引用
print(xo)
print(yo)
[1, 2, 3, [4, 5, 'a'], 6] #结果原始对象没有改变,因为原始对象拷贝的是原始数据
[1, 2, 3, [4, 5, 'a'], 6, 7]
[1, 2, 3, [4, 5, 'a', 'b'], 6] #结果子对象改变了,因为子对象拷贝的是引用
[1, 2, 3, [4, 5, 'a', 'b'], 6]
- 深拷贝deepcopy:包含对象里面的子对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
·对象拷贝的是数据
·子对象拷贝也是数据
import copy
xo=[1,2,3,[4,5,'a'],6]
yo=copy.deepcopy(xo) #深拷贝
yo.append(7) #结果原始对象没有改变,因为原始对象拷贝的是原始数据
print(xo)
print(yo)
xo=[1,2,3,[4,5,'a'],6]
yo=copy.deepcopy(xo) #深拷贝
yo[3].append('b') #结果子对象也没有改变,因为子对象拷贝的是也是原始数据
print(xo)
print(yo)
[1, 2, 3, [4, 5, 'a'], 6] #结果原始对象没有改变,因为原始对象拷贝的是原始数据
[1, 2, 3, [4, 5, 'a'], 6, 7]
[1, 2, 3, [4, 5, 'a', 'b'], 6] #结果子对象也没有改变,因为子对象拷贝的是也是原始数据
[1, 2, 3, [4, 5, 'a', 'b'], 6]
·函数
·文档化函数
- 可以加入注释(#开头)
- 在 def 语句后面,函数的开头写下字符串,他就会作为函数的一部分进行存储,成为 文档字符串
- 可以用 hanshuming.__doc__进行访问(注意这里前后都是双下划綫)
def square(x):
'Calculates the square of the number x.'
return x*x
print(square.__doc__)
Calculates the square of the number x.
·位置参数、关键词参数、提供默认值
- 位置参数:用 参数的顺序 作为区分参数的依据
- 关键词参数:指定 每个关键词 的参数,关键词要相同,顺序可以不同
- 提供默认值:函数定义的时候,直接将关键词赋值,这样调用函数的时候可以不提供这些参数的值,而是用定义时候的默认值
def hello_1(greeting,name): #位置参数,按照参数顺序进行传参
print('%s,%s!' %(greeting,name))
hello_1('Hello','world')
hello_1(name = 'all the people',greeting = 'Nice to meet you') #关键词参数,按照关键词进行传参,无关顺序
def hello_2(greeting = 'Hello',name = 'World'): #greeting参数没有提供,使用了默认值,name没有
print('%s,%s!' %(greeting,name))
hello_2(name = 'Richard')
Hello,world!
Nice to meet you,all the people!
Hello,Richard!
·收集参数:定义函数时允许使用不定数目的参数
- 用星号(*)将剩下的 位置参数 收集到一个元组中
- 用双星号(**)将剩下的 关键字参数 收集到一个字典中
def print_param(x,y,z=3,*pospar,**keypar):
# x,y,z三个参数有默认值
# *pospar将剩下的 位置参数 收集到一个元组中
# **keypar将剩下的 关键字参数 收集到一个字典中
print(x,y,z)
print(pospar)
print(keypar)
print_param(1,2,3,4,5,6,7,foo=1,bar=2)
1 2 3
(4, 5, 6, 7)
{'foo': 1, 'bar': 2}
·收集参数逆过程:调用函数时“分割”字典或者序列
- 用星号(*)在调用函数时“分割”序列
- 用双星号(*)在调用函数时“分割”字典
def add(x,y):
print('x + y = ' + str(x+y))
params = (1,2)
add(*params) #用星号(*)在调用函数时“分割”序列
def hello(greeting,name):
print('%s,%s!' %(greeting,name))
params2 = {'greeting': 'Hello', 'name': 'world'}
hello(**params2) #用双星号(*)在调用函数时“分割”字典
x + y = 3
Hello,world!
·全局变量与局部变量
- 在子函数中,使用globals()[“ 全局变量名 ”]使用全局变量
- locals()函数和globals()函数使用相同,会返回局部变量值
- 在子函数中,想要声明全局变量,可以使用 global 关键词
- 在子函数中,想要声明外部作用域变量,如上一层函数的局部变量,可以使用 nonlocal 关键词
9月28日:抽象、异常
·多态、封装、继承
多态:可以对不同类的对象使用同样的操作;不需要检测类型
封装:对外部世界隐藏对象的工作细节;
继承:以通用的类为基础建立专门的类对象;
- 唯一能毁掉多态的是,使用函数显式的检查类型,比如type、isinstance、issubclass等,要避免使用这些;
- 方法(method)和特性(attribute)是构成对象(object)的一部分;
·类和类型
- 旧版本中,类和类型区别明显,内建的对象基于类型,自定义的对象基于类,可以创建类不能创建类型;新版本中可以创建内建类型的子类型,类和类型区别不大;
- 描述对象的类:习惯使用单数名词,首字母大写,如Bird、Lark;
- 定义子类只是个定义更多(或者是重载已经存在的)的方法的过程;
·特性、函数和方法
- self参数:定义方法时对于对象自身的引用;
- 可以将特性绑定到一个普通函数上,也可以使用其他变量引用同一个方法:
class Bird:
song = 'Squaawk!'
def sing(self):
print(self.song)
def method(self):
print('I have a self!')
def function():
print('I don\'t ...')
instance = Bird()
instance.method()
instance.method = function #将特性绑定到一个普通函数上
instance.method()
bird = Bird()
bird.sing()
birdsong = bird.sing #使用其他变量引用同一个方法
birdsong()
I have a self!
I don't ...
Squaawk!
Squaawk!
·私有
- python并不直接支持私有方式,为了让方法或者特性变为私有(从外部无法访问),只要在它的名字前面加上 双下划线 。
class Secretive:
def __inaccessible(self):
print("Bet you can\'t see me...")
def accessible(self):
print("The secret message is:")
self.__inaccessible()
s = Secretive()
s.accessible() #没加双下划綫的方法或特性可以被外部访问
try:
s.__inaccessible() #加双下划线的方法或特性不能被外部访问
except AttributeError as e:
print(e)
The secret message is:
Bet you can't see me...
'Secretive' object has no attribute '__inaccessible'
- 类的内部定义中,所有以双下划线开始的名字,都被“翻译”成前面加上单下划线和类名的形式:
print(Secretive._Secretive__inaccessible)
<function Secretive.__inaccessible at 0x02E540B8>
- 所以基于上面的“解释”,还是可以在类外访问这些私有方法,尽管不应该这么做:
s._Secretive__inaccessible()
Bet you can't see me...
- 如果不需要使用这种方法但是又想让其他对象不要访问内部数据,可以使用 单下划线 进行习惯说明;比如所有前面有下划线的名字都不会被带星号的import语句导入
from module import *
;
·类的命名空间
- 类的定义就是执行代码块,所以定义类时会生成这个类的命名空间,这个命名空间可以由 类内的所有成员 访问;
class C:
members = 0
def init(self):
C.members += 1
x = C()
x.init()
print(C.members)
y = C()
y.init() #members特性是C类的所有实例共同的,而不是每个实例都有一个
print(C.members)
1
2
·超类、检查继承,多类继承
- 定义类时在括号里指定超类(基类);
- 使用内建函数issubclass函数检查一个类是不是另一个的子类;
- 想要知道已知类的基类们,可以直接使用类的特殊特性__bases__;
- 检查一个对象是否是一个类的实例,可以使用isinstance函数;
- 想知道一个对象属于哪个类,可以使用__class__特性;
- 多类继承时,写在前面的先继承的超类会重写后面超类的同名方法;多类继承要避免使用;
- 查看对象内存储的值,可以使用__dict__特性;
class C:
def method(self):
print('This is a superclass C!')
class D:
def method(self):
print('This is a superclass D!')
class SubCD(C,D):
members = 0
def submethod(self):
self.id = 0
print('This is a subclass SubCD!')
print(issubclass(D,C),issubclass(SubCD,C)) #使用内建函数issubclass函数检查一个类是不是另一个的子类;
print(SubCD.__bases__) #想要知道已知类的基类们,可以直接使用类的特殊特性__bases__;
subcd = SubCD()
print(isinstance(subcd,SubCD),isinstance(subcd,C)) #检查一个对象是否是一个类的实例,可以使用isinstance函数;
print(subcd.__class__)
subcd.submethod()
subcd.method() #多类继承,写在前面的先继承的超类会重写后面超类的同名方法,这里method是C的而不是D的
print(subcd.__dict__) #查看对象内存储的值
False True
(<class '__main__.C'>, <class '__main__.D'>)
True True
<class '__main__.SubCD'>
This is a subclass SubCD!
This is a superclass C!
{'id': 0}
·异常
-
异常基类:Exception,内建异常都在exceptions模块中;
-
raise可以引发异常,不用参数(except子句内重引发当前捕捉到的异常),也可以 raise IndexError('index out of bounds')
;
-
except子句:except (ZeroDivisionError,TypeError) as e:
注意必须有圆括号
-
try / except / except / else / finally语句:
except子句,捕捉到异常以后做什么
else子句,没有捕捉到异常做什么
finally子句,不管捕捉到还是没捕捉到,做完finally子句中的事再结束,一半用于关闭文件或者网络套接字
-
栈跟踪:如果异常在函数内引发而没有被捕捉处理,它会“浮”到函数调用的地方,还没有被处理的话则会一直传播到主程序,如果主程序没有异常处理程序,程序会带着 栈跟踪 中止。
10月5日:
·魔法方法、属性和迭代器
·新式类
- 使用新式方法:
__metaclass__ = type
;
- 如果没有兼容之前旧版本Python的需要,那么所有的类都写为新式的类,并且使用super函数这样的特性;
·构造方法
- 自己写构造方法:
def __init__(self)
;
- 析构方法:
__del__(self)
,因为调用的具体时间是不可知的,所以要尽力避免使用__del__函数;
- 子类的构造方法必须调用超类的构造方法来确保进行基本的初始化,方法:(1)调用超类构造方法的未绑定版本;(2)使用super函数。
class Bird:
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print("Aaaah...")
self.hungry = False
else:
print("No,Thanks!")
class SongBird(Bird):
def __init__(self):
Bird.__init__(self) #旧版本Python使用的是旧式类,需要调用超类构造方法的未绑定版本
super(SongBird,self).__init__() #新式类 使用super函数
self.sound = "Squawk!"
def sing(self):
print(self.sound)
sb = SongBird()
sb.sing()
sb.eat()
sb.eat()
Squawk!
Aaaah...
No,Thanks!
(1)在调用一个实例的方法时,该方法的self参数会被自动绑定到实例上(这成为绑定方法)。但如果直接调用类的方法(比如Bird.__init__
),那么就没有实例会被绑定,这样就可以自由地提供需要的self参数,这样的方法成为未绑定方法。
(2)当前的类和对象可以作为super函数的参数使用,调用函数返回的对象的任何方法都是调用超类的方法,而不是当前类的方法。super函数会查找所有的超类(以及超类的超类),知道找到所需的特性为止(或者引发一个AttributeError异常)
·魔法方法创建序列和映射、子类化列表字典字符串
·属性
# 定义一个类
class A(object):
# 类属性,直接在类中定义的属性是类属性
# 类属性可以通过类或类的实例访问到
count = 0
def __init__(self):
# 实例属性,通过实例对象添加的属性属于实例属性
# 实例属性只能通过实例对象来访问和修改,类对象无法访问修改
self.name = '孙悟空'
self.count += 1 #这里self.count和A.count是不同的,A.count是类属性,self.count是实例属性
# 实例方法
# 在类中定义,以self为第一个参数的方法都是实例方法
# 实例方法在调用时,Python会将调用对象作为self传入
# 实例方法可以通过实例和类去调用
# 当通过实例调用时,会自动将当前调用对象作为self传入
# 当通过类调用时,不会自动传递self,此时我们必须手动传递self
def test(self):
print('这是test方法~~~ ' , self)
# 类方法
# 在类内部使用 @classmethod 来修饰的方法属于类方法
# 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
# 类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
# 类方法可以通过类去调用,也可以通过实例调用,没有区别
@classmethod
def test_2(cls):
print('这是test_2方法,他是一个类方法~~~ ',cls)
print(cls.count)
# 静态方法
# 在类中使用 @staticmethod 来修饰的方法属于静态方法
# 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用
# 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
# 静态方法一般都是一些工具方法,和当前类无关
@staticmethod
def test_3():
print('test_3执行了~~~')
a = A()
#a.count = 10
#A.count = 100
#print('A ,',A.count)
#print('a ,',a.count)
#print('A ,',A.name)
#print('a ,',a.name)
# a.test() 等价于 A.test(a)
# A.test_2() 等价于 a.test_2()
A.test_3()
a.test_3()
·迭代器
- 只要实现了
__iter__
方法的对象都能进行迭代,不止序列和字典;
-
__iter__
方法会返回一个迭代器,所谓的迭代器就是具有next
方法。Python 3.0迭代器对象实现__next__
方法而不是next
方法,新的内建函数next()
可以用于访问这个方法,也就是next(it)
等同于以前的it.next()
;
- 可以用list构造方法显式地将迭代器转化成列表
class TestIterator: #TestIterator是一个迭代器
value = 0
def __next__(self): #使用next函数会出错误,必须使用__next__函数
self.value += 1
if self.value > 10:
raise StopIteration
return self.value
def __iter__(self):
return self #返回自身
ti1 = TestIterator()
for v in ti1:
if v>5 :
print(v)
break
ti2 = TestIterator()
li = list(ti2) #使用list构造方法显式地将迭代器ti2转化成列表
print(li)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
6
·生成器
- 生成器是一种用普通的函数语法定义的迭代器,是一个饱含
yield
关键字的函数;就算不使用生成器也是也可以的,但是生成器更优雅;
def flatten(nested): #生成器就是带有关键字yield的函数
for sublist in nested:
for element in sublist:
yield element #yield关键字
nested = [[1,2],[3,4],[5]]
for num in flatten(nested):
print(num)
li = list(flatten(nested))
print(li)
1
2
3
4
5
[1, 2, 3, 4, 5]
- 递归的生成器处理多层嵌套
- 不能迭代类似于字符串的对象,一是字符串不应该被展开而应该作为一个原子值,二是字符串强行被展开的时候会导致无穷递归,因为一个字符串的第一个元素是另一个长度为1的字符串,而长度为1的字符串的第一个元素就是字符串本身。
- 检查一个对象是不是类似于字符串最简单、最快速的方法:试着将对象和一个字符串拼接,看会不会出现
TypeError
。不是用isinstance
函数检查类型是不是字符串,而是检查对象的行为是不是像一个字符串。
def flatten(nested):
try:
#不要迭代类似于字符串的对象,
try:
nested + ' '
except TypeError:
pass
else:
raise TypeError #而是把字符串当成一个整体原子值
for sublist in nested:
for element in flatten(sublist): #这利用了递归处理嵌套多层的列表
yield element
except TypeError:
yield nested
nested = [[1,2,[3,[4]]],[[5,6],7],[8],'qwe',[9,["asd",10]]] #有多层嵌套列表,列表中也有字符串,
li = list(flatten(nested))
print(li)
[1, 2, 3, 4, 5, 6, 7, 8, 'qwe', 9, 'asd', 10]
-
yield
是一个表达式,而不是语句使用,也就是说yield
方法返回值,返回的是外部通过send
方法发送的值;
- 生成器在旧版本中没有,可以用列表和
append
方法进行模拟
·八皇后问题
- 这里用生成器解决八皇后问题还需要继续理解一下,特别是相比return
def conflict(state,nextX):
nextY = len(state)
for i in range(nextY):
if (state[i]==nextX)or((i-state[i])==(nextY-nextX))or((i+state[i])==(nextY+nextX)):
#if abs(state[i]-nextX) in (0,nextY-i): #两个点的横坐标差 等于 纵坐标差
return True
return False
def queen(num=4,state=()):
for pos in range(num):
if not conflict(state,pos):
if len(state)==num-1:
yield (pos,)
else:
for result in queen(num,state+(pos,)):
yield (pos,)+result
li=list(queen(4))
print(li)
[(1, 3, 0, 2), (2, 0, 3, 1)]
附录A:到时待办
附录B:资料
- 1、Github100天学Python项目:https://github.com/jackfrued/Python-100-Days
- 2、菜鸟教程 python 3 教程:https://www.runoob.com/python3/python3-tutorial.html