Python基础知识

Python基础知识

数据类型

计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值。但是,计算机能处理的远不止数值,还可以处理文本、图形、音频、视频、网页等各种各样的数据,不同的数据,需要定义不同的数据类型。在Python中,能够直接处理的数据类型有以下几种:

  • 整数

Python可以处理任意大小的整数,当然包括负整数,在程序中的表示方法和数学上的写法一模一样,例如:1,100,-8080,0,等等。

计算机由于使用二进制,所以,有时候用十六进制表示整数比较方便,十六进制用0x前缀和0-9,a-f表示,例如:0xff00,0xa5b4c3d2,等等。

  • 浮点数

浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,比如,$1.23 \times 10^9$和$12.3 \times 10^8$是完全相等的。浮点数可以用数学写法,如1.23,3.14,-9.01,等等。但是对于很大或很小的浮点数,就必须用科学计数法表示,把10用e替代,$1.23 \times 10^9$就是$1.23\times e^9$,或者$12.3\times e^8$,0.000012可以写成$1.2\times e^{-5}$,等等。

整数和浮点数在计算机内部存储的方式是不同的,整数运算永远是精确的(除法难道也是精确的?是的!),而浮点数运算则可能会有四舍五入的误差。

  • 字符串

字符串是以单引号’或双引号”括起来的任意文本,比如’abc’,”xyz”等等。请注意,’’或””本身只是一种表示方式,不是字符串的一部分,因此,字符串’abc’只有a,b,c这3个字符。如果’本身也是一个字符,那就可以用””括起来,比如”I’m OK”包含的字符是I,’,m,空格,O,K这6个字符。

1
2
3
4
5
6
7
8
9
10
11
12
import sys
a =3
b =4
c = 1.09
d = 2.35
e = complex(c,d)
f = complex(float(a),float(b))
g = "hello python"
print("a is type ",type(a))
print("c is type ",type(c))
print("e is type ",type(e))
print("g is type ",type(g))

a is type  <class 'int'>
c is type  <class 'float'>
e is type  <class 'complex'>
g is type  <class 'str'>

运算符

Python语言支持以下类型的运算符:

  • 算术运算符
  • 比较(关系)运算符
  • 赋值运算符
  • 逻辑运算符
  • 位运算符
  • 成员运算符
  • 身份运算符

算术运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# coding=utf-8
#两个数字相加
sumNumber=1+2
print(sumNumber) #输出结果:3

#两个字符串相加
sumString="Nice" + "work"
print(sumString) #输出结果:Nicework

#两个数字相减
subNumber=2-1
print(subNumber) #输出结果:1

#两个数字相乘或者字符串重复
multiplicationNumber=2*3
print(multiplicationNumber) #输出结果:6
multiplicationString="hello"*2
print(multiplicationString) #输出结果:hellohello

#两个数相除
divisionNumber=9/2
print(divisionNumber) #输出结果:4
divisionNumber=9.0/2
print(divisionNumber) #输出结果:4.5
divisionNumber=9/2.0
print(divisionNumber) #输出结果:4.5
#/---除数或被除数中有任意一个是小数的话,商也会保留小数,反之取整---/

#除法运算// 返回商的整数部分,抛弃余数
divisorNumber=10//3
print(divisorNumber) #输出结果:3

#除法运算% 返回商的余数部分,抛弃商
divisorNumber=10%3
print(divisorNumber) #输出结果:1
divisorNumber=10%1
print(divisorNumber) #输出结果:0 /--没有余数则返回0--/
divisorNumberx=10//3 #divisorNumberx是商的整数部分
divisorNumbery=10%3 #divisorNumbery是余数
divisorNumberz=3*divisorNumberx+divisorNumbery #divisorNumberz是除数乘以商的整数部分加上余数,得到的divisorNumberz的值就是被除数
print(divisorNumberz) #输出结果:10

#求幂运算
powerNumber=2**3 #相当于2的3次幂,就是2*2*2 关于幂运算大家应该在数学里都很熟悉了
print(powerNumber) #输出结果:8

3
Nicework
1
6
hellohello
4.5
4.5
4.5
3
1
0
10
8

比较(关系)运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#小于符号,返回值是bool值
lessThan=1<2
print(lessThan) #输出结果:True
lessThan=1<1
print(lessThan) #输出结果:False

#大于符号,返回值是bool值
moreThan=2>1
print(moreThan) #输出结果:True
moreThan=2>2
print(moreThan) #输出结果:False

#不等于符号 返回值是Bool值
notEqual=1!=2
print(notEqual) #输出结果:True
notEqual=1!=1
print(notEqual) #输出结果:False

True
False
True
False
True
False

赋值运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/python
# -*- coding: UTF-8 -*-

a = 21
b = 10
c = 0

c = a + b
print("1 - c 的值为:", c)

c += a
print("2 - c 的值为:", c)

c *= a
print("3 - c 的值为:", c)

c /= a
print("4 - c 的值为:", c)

c = 2
c %= a
print("5 - c 的值为:", c)

c **= a
print("6 - c 的值为:", c)

c //= a
print("7 - c 的值为:", c)

1 - c 的值为: 31
2 - c 的值为: 52
3 - c 的值为: 1092
4 - c 的值为: 52.0
5 - c 的值为: 2
6 - c 的值为: 2097152
7 - c 的值为: 99864

逻辑运算符

1
2
3
4
5
6
7
8
9
10
11
12
#逻辑非 not
operationx=True
operationy=not operationx
print(operationy) #输出结果:False
operationz=False
print(not operationz) #输出结果:True

#逻辑与 and
print(True and True) #输出结果:True

#逻辑或 or
print(False or False) #输出结果:False

False
True
True
False

位运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#按位与运算&, 按位与是指一个数字转化为二进制,然后这些二进制的数按位来进行与运算
operationNumber=7&18
print(operationNumber) #输出结果:2


#按位或运算|, 按位或是指一个数字转化为二进制,然后这些二进制的数按位来进行或运算
operationNumber=7|18
print(operationNumber) #输出结果:23 #结题思路和按位与运算的一样,可以参考按位与运算

#按位异或
operationNumber=7^18
print(operationNumber) #输出结果:21 #结题思路和按位与运算的一样,可以参考按位与运算

#按位翻转 ~ 按位翻转公式: ~x= - (x+1)
operationNumber=~12 #~12=- (12+1) = -13
print(operationNumber) #输出结果:-13 #结题思路和按位与运算的一样,可以参考按位与运算

#左移<<
operationNumber=12<<1
print(operationNumber) #输出结果:24
operationNumber=3<<3
print(operationNumber) #输出结果:24

#右移>>
operationNumber=12>>1
print(operationNumber) #输出结果:6
operationNumber=12>>2
print(operationNumber) #输出结果:3

2
23
21
-13
24
24
6
3

成员运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/python
# -*- coding: UTF-8 -*-

a = 10
b = 20
list = [1, 2, 3, 4, 5 ];

if ( a in list ):
print("1 - 变量 a 在给定的列表中 list 中")
else:
print("1 - 变量 a 不在给定的列表中 list 中")

if ( b not in list ):
print("2 - 变量 b 不在给定的列表中 list 中")
else:
print("2 - 变量 b 在给定的列表中 list 中")

# 修改变量 a 的值
a = 2
if ( a in list ):
print("3 - 变量 a 在给定的列表中 list 中")
else:
print("3 - 变量 a 不在给定的列表中 list 中")

1 - 变量 a 不在给定的列表中 list 中
2 - 变量 b 不在给定的列表中 list 中
3 - 变量 a 在给定的列表中 list 中

身份运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/python
# -*- coding: UTF-8 -*-

a = 20
b = 20

if ( a is b ):
print("1 - a 和 b 有相同的标识")
else:
print("1 - a 和 b 没有相同的标识")

if( a is not b ):
print("2 - a 和 b 没有相同的标识")
else:
print("2 - a 和 b 有相同的标识")

# 修改变量 b 的值
b = 30
if ( a is b ):
print("3 - a 和 b 有相同的标识")
else:
print("3 - a 和 b 没有相同的标识")

if ( a is not b ):
print("4 - a 和 b 没有相同的标识")
else:
print("4 - a 和 b 有相同的标识")

1 - a 和 b 有相同的标识
2 - a 和 b 有相同的标识
3 - a 和 b 没有相同的标识
4 - a 和 b 没有相同的标识

运算符优先级

容器

本文整理几种基本容器:

  • 列表(list)
  • 元组(tuple)
  • 字典(dict)
  • 集合(set)

列表

list是一种有序的集合,可以随时添加和删除其中的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 初始化列表
li = [1, 2, 3, 'abc', 4.5, [2, 3, 4], {1:'one'}]

# 获取长度
print(len(li)) # 结果为:7
print('')

# 根据索引读写
print(li[0]) #索引从零开始,结果为:1
print(li[3]) #结果为:'abc'
print(li[-1]) #索引从后往前,结果为:{1: 'one'}
print(li[-3]) #结果为:4.5
print('')

# 添加元素
li = [1, 2, 3]
li.append('a')
li.append('b')
print(li) #结果为:[1, 2, 3, 'a', 'b']
li.append([4, 5, 6]) #添加一个列表[4,5,6]
print(li) #结果为:[1, 2, 3, 'a', 'b', [4, 5, 6]]
li = [1, 2, 3]
li.extend([4, 5, 6]) #往列表中添加数字4,5,6
print(li) #结果为:[1, 2, 3, 4, 5, 6]
print('')

# 删除元素
li = [1, 2, 3, 4, 5]
li.pop() #采用pop的方法,按照栈的方式弹出,结果为:[1, 2, 3, 4]
print(li)
del(li[0]) #删掉第一个数据,现在li的数据排列为[2,3,4,5]
del(li[1]) #删掉[2,3,4,5]中的第二个数据
print(li) #结果为:[2, 4]
print('')

# 元素是否存在
li = [1, 2, 3, 4, 5]
print(1 in li) #结果为True
print(6 in li) #结果为False
print('')

# 列表是否为空
li = []
if not li:
print('Empty')
else:
print('Not empty')
print('')

# 字符串
ss = 'abcdefg'
li = list(ss)
li[4] = 'E' #取第五个字符并置为'E'
li[5] = 'F' #取第六个字符并置为'F'
print(li) #结果为:['a', 'b', 'c', 'd', 'E', 'F', 'g']
ss = ''.join(li) #去掉引号
print(ss) #结果为:abcdEFg
print('')

# 遍历
li = [1, 2, 3]
for i in li:
print(i)
for i in range(len(li)):
print(li[i])

7

1
abc
{1: 'one'}
4.5

[1, 2, 3, 'a', 'b']
[1, 2, 3, 'a', 'b', [4, 5, 6]]
[1, 2, 3, 4, 5, 6]

[1, 2, 3, 4]
[2, 4]

True
False

Empty

['a', 'b', 'c', 'd', 'E', 'F', 'g']
abcdEFg

1
2
3
1
2
3

元组

另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改
其中需要注意的是:tuple所谓的“不变”是说,tuple的每个元素,指向永远不变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#创建 tuple
number_tuple = (1,3,5,7,9) #数字
print("number_tuple: " + str(number_tuple))
print(number_tuple[4])

string_tuple = ("adc","sdf","python") #字符串
print("string_tuple: " + str(string_tuple))
print(string_tuple[1])

mixed_tuple = ("python",1,5) #数字+字符串
print("mixed_tuple: " + str(mixed_tuple))
print(mixed_tuple[0])

#访问tuple元素
a = number_tuple[2]
b = string_tuple[1]
c = mixed_tuple [0]
print("a:{0}\nb:{1}\nc:{2}\n".format(a,b,c))

#tuple的截取
abcd_tuple = ('a','b','c','d')
print(abcd_tuple[1])
print(abcd_tuple[-2])
print(abcd_tuple[1:])

#tuple 中嵌入list
mix_tuple = (1,2,['a','b'])
print("mix_tuple: " + str(mix_tuple))
mix_tuple[2][0] = 'c'
mix_tuple[2][1] = 'd'
print("mix_tuple: " + str(mix_tuple))

#list 中嵌入tuple
mix_list = [1,2,('a','b')]
print("mix_list: " + str(mix_list))
mix_list[2] = ('c','d')
print("mix_list: " + str(mix_list))

# 遍历
tup = (1,2,3)
for i in tup:
print(i)
for i in range(len(tup)):
print(tup[i])

number_tuple: (1, 3, 5, 7, 9)
9
string_tuple: ('adc', 'sdf', 'python')
sdf
mixed_tuple: ('python', 1, 5)
python
a:5
b:sdf
c:python

b
c
('b', 'c', 'd')
mix_tuple: (1, 2, ['a', 'b'])
mix_tuple: (1, 2, ['c', 'd'])
mix_list: [1, 2, ('a', 'b')]
mix_list: [1, 2, ('c', 'd')]
1
2
3
1
2
3

字典

字典由keys(键)和values(值)组成。字典的每个键值(key=>value)对,用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中.键必须是唯一的,但值则不必值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 初始化
d = {'a':1, 2:'b', 'c':3, 4:'d'}
print(d) #结果为:{'a': 1, 2: 'b', 'c': 3, 4: 'd'}
print(d.keys()) #结果为:dict_keys(['a', 2, 'c', 4])
print(d.values()) #结果为:dict_values([1, 'b', 3, 'd'])
print('')

# 获取长度
print(len(d)) #结果为:4
print('')

# 根据key读写
d['a'] = 100
d[4] = 'dd'
print(d) #结果为:{'a': 100, 2: 'b', 'c': 3, 4: 'dd'}
print('')

# 添加元素
d['e'] = 5
d[6] = 'f'
print(d) #结果为:{'a': 100, 2: 'b', 'c': 3, 4: 'dd', 'e': 5, 6: 'f'}
print('')

# 删除元素
d = {'a':1, 2:'b', 'c':3, 4:'d'}
del(d['a'])
del(d[2])
print(d) #结果为:{'c': 3, 4: 'd'}
print('')

# 判断key是否存在
d = {'a':1, 2:'b', 'c':3, 4:'d'}
if 'a' in d:
print('a in d')
if 2 in d:
print('2 in d')
if not ('x' in d):
print('x not in d')
print('')

# 判断字典是否为空
d = {}
if not d:
print('d is empty')
print('')

# 遍历
d = {'a':1, 2:'b', 'c':3, 4:'d'}
for k in d.keys():
print(str(k) + ': ' + str(d[k]))
for k, v in d.items():
print(str(k) + ': ' + str(v))

{'a': 1, 2: 'b', 'c': 3, 4: 'd'}
dict_keys(['a', 2, 'c', 4])
dict_values([1, 'b', 3, 'd'])

4

{'a': 100, 2: 'b', 'c': 3, 4: 'dd'}

{'a': 100, 2: 'b', 'c': 3, 4: 'dd', 'e': 5, 6: 'f'}

{'c': 3, 4: 'd'}

a in d
2 in d
x not in d

d is empty

a: 1
2: b
c: 3
4: d
a: 1
2: b
c: 3
4: d

集合(set)

set是基本数据类型的一种集合类型,它有可变集合(set())和不可变集合(frozenset)两种。创建集合set、集合set添加、集合删除、交集、并集、差集的操作都是非常实用的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 初始化
s_a = set([1, 2, 3, 4, 5])
s_b = set([1, 1, 2, 2, 3, 4, 5])
print(s_a) # 结果为:{1, 2, 3, 4, 5}
print(s_b) # 结果为:{1, 2, 3, 4, 5}
print('')

# 获取长度
print(len(s_a)) # 结果为:5
print(len(s_b)) # 结果为:5
print('')

# 添加元素
s_a.add(6)
s_a.add(6)
s_a.update([5, 6, 7, 8, 9])
print(s_a) # 结果为:{1, 2, 3, 4, 5, 6, 7, 8, 9}
print('')

# 删除元素
s_a.remove(8)
s_a.remove(9)
print(s_a) # 结果为:{1, 2, 3, 4, 5, 6, 7}
print('')

# 判断元素是否存在
print(1 in s_a) # 结果为:True
print(10 in s_a) # 结果为:False
print('')

# 判断集合是否为空
s_a = set([])
if not s_a:
print('set is empty')
else:
print('set is not empty')
print('')

# 遍历
s_a = set([1, 2, 3, 4, 5])
for i in s_a:
print(i)
print('')

# 集合操作
s_a = set([1, 2, 3, 4, 5])
s_b = set([4, 5, 6, 7, 8])
# 并集
print(s_a | s_b) # 结果为:{1, 2, 3, 4, 5, 6, 7, 8}
print(s_a.union(s_b)) # 结果为:{1, 2, 3, 4, 5, 6, 7, 8}
# 交集
print(s_a & s_b) # 结果为:{4, 5}
print(s_a.intersection(s_b)) # 结果为:{4, 5}
# 差集 s_a - (s_a and s_b)
print(s_a - s_b) # 结果为:{1, 2, 3}
print(s_a.difference(s_b)) # 结果为:{1, 2, 3}
# 对称差
print(s_a ^ s_b) # 结果为:{1, 2, 3, 6, 7, 8}
print((s_a | s_b) - (s_a & s_b)) # 结果为:{1, 2, 3, 6, 7, 8}
print(s_a.symmetric_difference(s_b)) # 结果为:{1, 2, 3, 6, 7, 8}

{1, 2, 3, 4, 5}
{1, 2, 3, 4, 5}

5
5

{1, 2, 3, 4, 5, 6, 7, 8, 9}

{1, 2, 3, 4, 5, 6, 7}

True
False

set is empty

1
2
3
4
5

{1, 2, 3, 4, 5, 6, 7, 8}
{1, 2, 3, 4, 5, 6, 7, 8}
{4, 5}
{4, 5}
{1, 2, 3}
{1, 2, 3}
{1, 2, 3, 6, 7, 8}
{1, 2, 3, 6, 7, 8}
{1, 2, 3, 6, 7, 8}

判断

1
2
3
4
5
6
7
8
9
10
number = 59
guess = int(input("Enter an integer:"))
print("guess is " + str(guess))
if guess == number:
print("you are right!")
elif guess < number:
print("the number is higher than that")
else:
print("the number is lower than that")
print("Done!")

Enter an integer:58
guess is 58
the number is higher than that
Done!

循环

for

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
for i in range(1,5):
print(i)
else:
print("the for loop is over")

a_list = [1,3,5,7,9]
for i in a_list:
print(i)

a_tuple = (1,3,5,7,9)
for i in a_tuple:
print(i)

a_dict = {'Tom':111,'Jerry':222,'Cathy':333}
for ele in a_dict:
print(ele)
print(a_dict[ele])

for key,elem in a_dict.items():
print(key,elem)

# 例子
number = 59
guess_flag = False
num_chances = 3
print("you have only 3 chances to guess")
for i in range(1,num_chances + 1):
print("chace" + str(i))
guess = int(input("Enter an integer:"))
if guess == number:
print("you are right!")
break
elif guess < number:
print("the number is higher than that,you have only " + str(num_chances-i) + "chance!")
else:
print("the number is lower than that,you have only " + str(num_chances-i) + "chance!")

1
2
3
4
the for loop is over
1
3
5
7
9
1
3
5
7
9
Tom
111
Jerry
222
Cathy
333
Tom 111
Jerry 222
Cathy 333
you have only 3 chances to guess
chace1
Enter an integer:57
the number is higher than that,you have only 2chance!
chace2
Enter an integer:58
the number is higher than that,you have only 1chance!
chace3
Enter an integer:59
you are right!

while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
number = 59
guess_flag = False

while guess_flag == False:
guess = int(input("Enter an integer:"))
print("guess is: " + str(guess))
if guess == number:
print("you are right!")
guess_flag = True
elif guess < number:
print("the number is higher than that")
else:
print("the number is lower than that")
print("Done!")

Enter an integer:1
guess is: 1
the number is higher than that
Enter an integer:2
guess is: 2
the number is higher than that
Enter an integer:3
guess is: 3
the number is higher than that
Enter an integer:59
guess is: 59
you are right!
Done!

break && continue && pass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#break && continue example
number = 59
while True:
guess = int(input("Enter an integer:"))
print("guess is: " + str(guess))
if guess == number:
print("you are right!")
break
elif guess < number:
print("the number is higher than that")
continue
else:
print("the number is lower than that")
continue
print("Done!")

#continue && pass example
a_list = [1,0,2,3]
print("using continue:")
for i in a_list:
if not i:
continue
print(i)
print("using pass:")
for i in a_list:
if not i:
pass
print(i)

函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#默认参数(放在函数参数末尾)
def repeat_str(s,times = 1):
repeat_strs = s * times
return repeat_strs

repeat_strings = repeat_str('Happy Birthday!')
print(repeat_strings)

repeat_strings = repeat_str('Happy Birthday!',3)
print(repeat_strings)


#关键字参数
def func(a,b = 4,c = 8):
print('a is ',a,'and b is',b,'and c is',c)

func(13,17)
func(125,c = 24)
func(c = 40,a = 80)

#varargs 参数
def print_paras(fpara,*num,**words):
print("fpara: " + str(fpara))
print("num: " + str(num))
print("words: " + str(words))

print_paras("Hello",1,2,3,5,7,word = 'python',nexword = 'Java')

面型对象(初级篇)

面向对象的三大特性是指:封装、继承和多态。

封装

封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:

  • 将内容封装到某处
  • 从某处调用被封装的内容

第一步:将内容封装到某处

self 是一个形式参数,
当执行 obj1 = Foo('wupeiqi', 18 ) 时,self 等于 obj1
当执行 obj2 = Foo('alex', 78 ) 时,self 等于 obj2

所以,内容其实被封装到了对象obj1obj2中,每个对象中都有nameage属性,在内存里类似于下图来保存。

第二步:从某处调用被封装的内容

调用被封装的内容时,有两种情况:

  • 通过对象直接调用
  • 通过self间接调用

1、通过对象直接调用被封装的内容
上图展示了对象obj1obj2在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名

1
2
3
4
5
6
7
8
9
10
11
12
13
class Foo:

def __init__(self, name, age):
self.name = name
self.age = age

obj1 = Foo('wupeiqi', 18)
print(obj1.name) # 直接调用obj1对象的name属性
print(obj1.age) # 直接调用obj1对象的age属性

obj2 = Foo('alex', 73)
print(obj2.name) # 直接调用obj2对象的name属性
print(obj2.age) # 直接调用obj2对象的age属性

wupeiqi
18
alex
73

2、通过self间接调用被封装的内容

执行类中的方法时,需要通过self间接调用被封装的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Foo:

def __init__(self, name, age):
self.name = name
self.age = age

def detail(self):
print(self.name)
print(self.age)

obj1 = Foo('wupeiqi', 18)
obj1.detail() # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18

obj2 = Foo('alex', 73)
obj2.detail() # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78

wupeiqi
18
alex
73

综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。

继承

继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。

例如:

  猫可以:喵喵叫、吃、喝、拉、撒

  狗可以:汪汪叫、吃、喝、拉、撒

如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class 猫:

def 喵喵叫(self):
print('喵喵叫')

def(self):
# do something

def(self):
# do something

def(self):
# do something

def(self):
# do something

class 狗:

def 汪汪叫(self):
print('喵喵叫')

def(self):
# do something

def(self):
# do something

def(self):
# do something

def(self):
# do something

上述代码不难看出,吃、喝、拉、撒是猫和狗都具有的功能,而我们却分别的猫和狗的类中编写了两次。如果使用 继承 的思想,如下实现:

  动物:吃、喝、拉、撒

   猫:喵喵叫(猫继承动物的功能)

   狗:汪汪叫(狗继承动物的功能)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class 动物:

def(self):
# do something

def(self):
# do something

def(self):
# do something

def(self):
# do something

# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class(动物)

def 喵喵叫(self):
print('喵喵叫')

# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类
class(动物)

def 汪汪叫(self):
print('喵喵叫')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Animal:

def eat(self):
print("%s 吃 " %self.name)

def drink(self):
print("%s 喝 " %self.name)

def shit(self):
print("%s 拉 " %self.name)

def pee(self):
print("%s 撒 " %self.name)


class Cat(Animal):

def __init__(self, name):
self.name = name
self.breed = '猫'

def cry(self):
print('喵喵叫')

class Dog(Animal):

def __init__(self, name):
self.name = name
self.breed = '狗'

def cry(self):
print('汪汪叫')


# ######### 执行 #########

c1 = Cat('小白家的小黑猫')
c1.eat()

c2 = Cat('小黑的小白猫')
c2.drink()

d1 = Dog('胖子家的小瘦狗')
d1.eat()

所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。

注:除了子类和父类的称谓,你可能看到过 派生类 和 基类 ,他们与子类和父类只是叫法不同而已。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Animal:

def eat(self):
print("%s 吃 " %self.name)

def drink(self):
print("%s 喝 " %self.name)

def shit(self):
print("%s 拉 " %self.name)

def pee(self):
print("%s 撒 " %self.name)


class Cat(Animal):

def __init__(self, name):
self.name = name
self.breed = '猫'

def cry(self):
print('喵喵叫')

class Dog(Animal):

def __init__(self, name):
self.name = name
self.breed = '狗'

def cry(self):
print('汪汪叫')


# ######### 执行 #########

c1 = Cat('小白家的小黑猫')
c1.eat()

c2 = Cat('小黑的小白猫')
c2.drink()

d1 = Dog('胖子家的小瘦狗')
d1.eat()

那么问题又来了,多继承呢?

  • 是否可以继承多个类
  • 如果继承的多个类每个类中都定了相同的函数,那么那一个会被使用呢?

1、Python的类可以继承多个类,Java和C#中则只能继承一个类

2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先广度优先

当类是经典类时,多继承情况下,会按照深度优先方式查找
当类是新式类时,多继承情况下,会按照广度优先方式查找
经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 经典类多继承
class D:

def bar(self):
print('D.bar')


class C(D):

def bar(self):
print('C.bar')


class B(D):

def bar(self):
print('B.bar')


class A(B, C):

def bar(self):
print('A.bar')

a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()

A.bar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 新式类多继承
class D(object):

def bar(self):
print('D.bar')


class C(D):

def bar(self):
print('C.bar')


class B(D):

def bar(self):
print('B.bar')


class A(B, C):

def bar(self):
print('A.bar')

a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()

A.bar

经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错

新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错

注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

多态

Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,其Python崇尚“鸭子类型”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Python伪代码实现Java或C#的多态
class F1:
pass


class S1(F1):

def show(self):
print('S1.show')


class S2(F1):

def show(self):
print('S2.show')


# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象

def Func(F1 obj):
"""Func函数需要接收一个F1类型或者F1子类的类型"""

print(obj.show())

s1_obj = S1()
Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show

s2_obj = S2()
Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Python “鸭子类型”
class F1:
pass


class S1(F1):

def show(self):
print('S1.show')


class S2(F1):

def show(self):
print('S2.show')

def Func(obj):
print(obj.show())

s1_obj = S1()
Func(s1_obj)

s2_obj = S2()
Func(s2_obj)

以上就是本节对于面向对象初级知识的介绍,总结如下:
面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用
类是一个模板,模板中包装了多个“函数”供使用
对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
面向对象三大特性:封装、继承和多态

面型对象(高级篇)

将详细介绍Python类的成员、成员修饰符、类的特殊成员。

类的成员

类的成员可以分为三大类:字段、方法和属性

注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。

字段

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,

  • 普通字段属于对象
  • 静态字段属于类
1
2
3
4
5
6
7
8
9
10
11
12
#字段的定义和访问
class Province:
#静态字段
country='中国'
def __init__(self, name):
#普通字段
self.name = name
# 直接访问普通字段
obj = Province('河北省')
print(obj.name)
# 直接访问静态字段
Province.country

河北省

'中国'

由上述代码可以看出普通字段需要通过对象来访问,静态字段通过类访问,在使用上可以看出普通字段和静态字段的归属是不同的。其在内容的存储方式类似如下图:

由上图表示:

  • 静态字段在内存中只保存一份
  • 普通字段在每个对象中都要保存一份

应用场景:通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段

方法

方法包括:普通方法、类方法、静态方法,三种方法在内存中都归属于类,区别在于调用方式不同。

  • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self
  • 类方法:由调用; 至少一个cls参数;执行类方法时,自动将调用该方法的复制给cls
  • 静态方法:由调用;无默认参数;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#方法的定义和使用
class Foo:

def __init__(self,name):
self.name = name

def ord_func(self):
""" 定义普通方法,至少有一个self参数 """

# print self.name
print ('普通方法')

@classmethod
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """

print ('类方法')

@staticmethod
def static_func():
""" 定义静态方法 ,无默认参数"""

print ('静态方法')


# 调用普通方法
f = Foo('test')
f.ord_func()

# 调用类方法
Foo.class_func()

# 调用静态方法
Foo.static_func()

普通方法
类方法
静态方法

相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。

不同点:方法调用者不同、调用方法时自动传入的参数不同。

属性

如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种

对于属性,有以下三个知识点:

  • 属性的基本使用
  • 属性的两种定义方式

1、属性的基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 属性的定义和使用
# ############### 定义 ###############
class Foo:

def func(self):
pass

# 定义属性
@property
def prop(self):
pass
# ############### 调用 ###############
foo_obj = Foo()

foo_obj.func()
foo_obj.prop #调用属性

由属性的定义和调用要注意一下几点:

  • 定义时,在普通方法的基础上添加 @property装饰器;
  • 定义时,属性仅有一个self参数
    调用时,无需括号

    方法:foo_obj.func()
    属性:foo_obj.prop
    

    注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象

    属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

实例:对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据(即:limit m,n),这个分页的功能包括:

  • 根据用户请求的当前页和总数据条数计算出 m 和 n
  • 根据m 和 n 去数据库中请求数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# ############### 定义 ###############
class Pager:

def __init__(self, current_page):
# 用户当前请求的页码(第一页、第二页...)
self.current_page = current_page
# 每页默认显示10条数据
self.per_items = 10


@property
def start(self):
val = (self.current_page - 1) * self.per_items
return val

@property
def end(self):
val = self.current_page * self.per_items
return val

# ############### 调用 ###############

p = Pager(1)
print(p.start) #就是起始值,即:m
print(p.end) #就是结束值,即:n

0
10

从上述可见,Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回

2、属性的两种定义方式

属性的定义有两种方式:

  • 装饰器 即:在方法上应用装饰器
  • 静态字段 即:在类中定义值为property对象的静态字段

装饰器方式:在类的普通方法上应用@property装饰器

我们知道Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )

  • 经典类,具有一种@property装饰器(如上一步实例)
1
2
3
4
5
6
7
8
9
10
# ############### 定义 ###############
class Goods:

@property
def price(self):
return "xuke"
# ############### 调用 ###############
obj = Goods()
result = obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
result

'xuke'

  • 新式类,具有三种@property装饰器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# ############### 定义 ###############
class Goods(object):

@property
def price(self):
print('@property')

@price.setter
def price(self, value):
print('@price.setter')

@price.deleter
def price(self):
print('@price.deleter')

# ############### 调用 ###############
obj = Goods()

obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值

obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数

del obj.price # 自动执行 @price.deleter 修饰的 price 方法

@property
@price.setter
@price.deleter

注:经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法

新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法

由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 实例
class Goods(object):

def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8

@property
def price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price

@price.setter
def price(self, value):
self.original_price = value

@price.deleter
def price(self):
del self.original_price

obj = Goods()
obj.price # 获取商品价格
obj.price = 200 # 修改商品原价
del obj.price # 删除商品原价

静态字段方式,创建值为property对象的静态字段

当使用静态字段的方式创建属性时,经典类和新式类无区别

1
2
3
4
5
6
7
8
9
10
class Foo:

def get_bar(self):
return 'xuke'

BAR = property(get_bar)

obj = Foo()
reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值
print(reuslt)

xuke

property的构造方法中有个四个参数

  • 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
  • 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
  • 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
  • 第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Foo:

def get_bar(self):
return 'xuke'

# 必须两个参数
def set_bar(self, value):
return 'set value' + value

def del_bar(self):
return 'xuke'

BAR = property(get_bar, set_bar, del_bar, 'description...')

obj = Foo()

obj.BAR # 自动调用第一个参数中定义的方法:get_bar
obj.BAR = "alex" # 自动调用第二个参数中定义的方法:set_bar方法,并将“alex”当作参数传入
del obj.BAR # 自动调用第三个参数中定义的方法:del_bar方法
obj.BAR.__doc__ # 自动获取第四个参数中设置的值:description...

由于静态字段方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 实例
class Goods(object):

def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8

def get_price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price

def set_price(self, value):
self.original_price = value

def del_price(self):
del self.original_price

PRICE = property(get_price, set_price, del_price, '价格属性描述...')

obj = Goods()
obj.PRICE # 获取商品价格
obj.PRICE = 200 # 修改商品原价
del obj.PRICE # 删除商品原价

所以,定义属性共有两种方式,分别是【装饰器】和【静态字段】,而【装饰器】方式针对经典类和新式类又有所不同。

成员修饰符

类的所有成员在上一步骤中已经做了详细的介绍,对于每一个类的成员而言都有两种形式:

  • 公有成员,在任何地方都能访问
  • 私有成员,只有在类的内部才能方法

私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:__init__、__call__、__dict__等)

1
2
3
4
5
class C:

def __init__(self):
self.name = '公有字段'
self.__foo = "私有字段"

私有成员和公有成员的访问限制不同:

静态字段

  • 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
  • 私有静态字段:仅类内部可以访问;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 公有静态字段
class C:

name = "公有静态字段"

def func(self):
print(C.name)

class D(C):

def show(self):
print(C.name)


C.name # 类访问

obj = C()
obj.func() # 类内部可以访问

obj_son = D()
obj_son.show() # 派生类中可以访问

公有静态字段
公有静态字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
私有静态字段
class C:

__name = "公有静态字段"

def func(self):
print(C.__name)

class D(C):

def show(self):
print(C.__name)


C.__name # 类访问 ==> 错误

obj = C()
obj.func() # 类内部可以访问 ==> 正确

obj_son = D()
obj_son.show() # 派生类中可以访问 ==> 错误

普通字段

  • 公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
  • 私有普通字段:仅类内部可以访问;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 公有字段
class C:

def __init__(self):
self.foo = "公有字段"

def func(self):
print(self.foo)  # 类内部访问

class D(C):

def show(self):
print(self.foo) # 派生类中访问

obj = C()

obj.foo # 通过对象访问
obj.func() # 类内部访问

obj_son = D();
obj_son.show() # 派生类中访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 私有字段
class C:

def __init__(self):
self.__foo = "私有字段"

def func(self):
print(self.foo)  # 类内部访问

class D(C):

def show(self):
print(self.foo) # 派生类中访问

obj = C()

obj.__foo # 通过对象访问 ==> 错误
obj.func() # 类内部访问 ==> 正确

obj_son = D();
obj_son.show() # 派生类中访问 ==> 错误

方法、属性的访问于上述方式相似,即:私有成员只能在类内部使用

类的特殊成员

上文介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:

1、 __doc__

 表示类的描述信息

1
2
3
4
5
6
7
8
class Foo:
""" 类的描述信息 """

def func(self):
pass

print (Foo.__doc__)
#输出:类的描述信息

类的描述信息

2、 __module__ 和 __class__

  __module__ 表示当前操作的对象在那个模块

  __class__ 表示当前操作的对象的类是什么

1
2
3
4
5
6
7
8
9
#!/usr/bin/env python
# -*- coding:utf-8 -*-

class C:

def __init__(self):
self.name = 'wupeiqi'

# lib/aa.py
1
2
3
4
5
from lib.aa import C

obj = C()
print obj.__module__ # 输出 lib.aa,即:输出模块
print obj.__class__ # 输出 lib.aa.C,即:输出类

3、 __init__

  构造方法,通过类创建对象时,自动触发执行。

1
2
3
4
5
6
7
8
class Foo:

def __init__(self, name):
self.name = name
self.age = 18


obj = Foo('xuke') # 自动执行类中的 __init__ 方法

4、 __del__

  析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

1
2
3
4
class Foo:

def __del__(self):
pass

5、__call__

  对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

1
2
3
4
5
6
7
8
9
10
11
12
class Foo:

def __init__(self):
pass

def __call__(self, *args, **kwargs):

print ('__call__')


obj = Foo() # 执行 __init__
obj() # 执行 __call__

6、__dict__

  类或对象中的所有成员

上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Province:

country = 'China'

def __init__(self, name, count):
self.name = name
self.count = count

def func(self, *args, **kwargs):
print ('func')

# 获取类的成员,即:静态字段、方法、
print (Province.__dict__)
# 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}

obj1 = Province('HeBei',10000)
print (obj1.__dict__)
# 获取 对象obj1 的成员
# 输出:{'count': 10000, 'name': 'HeBei'}

obj2 = Province('HeNan', 3888)
print (obj2.__dict__)
# 获取 对象obj1 的成员
# 输出:{'count': 3888, 'name': 'HeNan'}

7、__str__

如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

1
2
3
4
5
6
7
8
9
class Foo:

def __str__(self):
return 'xuke'


obj = Foo()
print (obj)
# 输出:xuke

8、__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Foo(object):

def __getitem__(self, key):
print ('__getitem__',key)

def __setitem__(self, key, value):
print ('__setitem__',key,value)

def __delitem__(self, key):
print ('__delitem__',key)


obj = Foo()

result = obj['k1'] # 自动触发执行 __getitem__
obj['k2'] = 'wupeiqi' # 自动触发执行 __setitem__
del obj['k1'] # 自动触发执行 __delitem__

9、__getslice__、__setslice__、__delslice__

该三个方法用于分片操作,如:列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Foo(object):

def __getslice__(self, i, j):
print ('__getslice__',i,j)

def __setslice__(self, i, j, sequence):
print ('__setslice__',i,j)

def __delslice__(self, i, j):
print ('__delslice__',i,j)

obj = Foo()

obj[-1:1] # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__
del obj[0:2] # 自动触发执行 __delslice__

10、__iter__

用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__

1
2
3
4
5
6
7
8
9
10
11
# 第一步
class Foo(object):
pass


obj = Foo()

for i in obj:
print (i)

# 报错:TypeError: 'Foo' object is not iterable
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 第二步
#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Foo(object):

def __iter__(self):
pass

obj = Foo()

for i in obj:
print (i)

# 报错:TypeError: iter() returned non-iterator of type 'NoneType'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 第三步
#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Foo(object):

def __init__(self, sq):
self.sq = sq

def __iter__(self):
return iter(self.sq)

obj = Foo([11,22,33,44])

for i in obj:
print (i)

以上步骤可以看出,for循环迭代的其实是 iter([11,22,33,44]) ,所以执行流程可以变更为:

1
2
3
4
5
6
7
#!/usr/bin/env python
# -*- coding:utf-8 -*-

obj = iter([11,22,33,44])

for i in obj:
print (i)
1
2
3
4
5
6
7
8
9
# For循环语法内部
#!/usr/bin/env python
# -*- coding:utf-8 -*-

obj = iter([11,22,33,44])

while True:
val = obj.next()
print (val)

11、__new__ 和 __metaclass__

阅读以下代码:

1
2
3
4
5
6
class Foo(object):

def __init__(self):
pass

obj = Foo() # obj是通过Foo类实例化的对象

上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象

如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

1
2
print (type(obj)) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
print (type(Foo)) # 输出:<type 'type'> 表示,Foo类对象由 type 类创建

所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

那么,创建类就可以有两种方式:

a). 普通方式

1
2
3
4
class Foo(object):

def func(self):
print ('hello xuke')

b).特殊方式(type类的构造函数)

1
2
3
4
5
6
7
def func(self):
print ('hello xuke')

Foo = type('Foo',(object,), {'func': func})
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类的成员

因此 类是由type类实例化产生

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyType(type):

def __init__(self, what, bases=None, dict=None):
super(MyType, self).__init__(what, bases, dict)

def __call__(self, *args, **kwargs):
obj = self.__new__(self, *args, **kwargs)

self.__init__(obj)

class Foo(object):

__metaclass__ = MyType

def __init__(self, name):
self.name = name

def __new__(cls, *args, **kwargs):
return object.__new__(cls, *args, **kwargs)

# 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建obj对象
obj = Foo()

异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while True:
try:
x = int(input("please enter a number"))
break
except ValueError:
print("Not valid input , try again...")

try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error :{}".format(err))
except ValueError:
print("Could not convert data to an integer.")
please enter a numberABC
Not valid input , try again...
please enter a number123
OS error :[Errno 2] No such file or directory: 'myfile.txt'

文件读写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
some_sentences = '''\
i love learing python
because python is fun
and also easy to use
'''

f = open('sentences.txt','w')
f.write(some_sentences)
f.close()

f = open('sentences.txt','r')
while True:
line = f.readline()
if len(line) == 0:
break
print(line)
f.close()
i love learing python

because python is fun

and also easy to use

json处理

1
2
3
4
5
6
7
8
9
import json

d = {'Python':100, 'C++':70, 'Basic':60, 'others':{'C':65, 'Java':50}}
jtxt = json.dumps(d)
dd = json.loads(jtxt) #dd为字典类型
print(jtxt)
print(dd)
print(dd['Python'])
print('')
{"Python": 100, "C++": 70, "Basic": 60, "others": {"C": 65, "Java": 50}}
{'Python': 100, 'C++': 70, 'Basic': 60, 'others': {'C': 65, 'Java': 50}}
100

非dict对象如何用json序列化?

1
2
3
4
5
6
7
8
9
10
11
12
class Student:
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score

def __str__(self):
return '%s: %d, %d' % (self.name, self.age, self.score)

s = Student('Tom', 15, 85)
print(s)
print(s.__dict__)
Tom: 15, 85
{'name': 'Tom', 'age': 15, 'score': 85}
  • 方法1
1
2
3
4
5
jtxt = json.dumps(s, default = lambda obj: obj.__dict__)
print(jtxt)
def d2s(d):
return Student(d['name'], d['age'], d['score'])
print(json.loads(jtxt, object_hook = d2s))
{"name": "Tom", "age": 15, "score": 85}
Tom: 15, 85
  • 方法2
1
2
3
4
5
6
def s2d(s):
return s.__dict__
jtxt = json.dumps(s, default = s2d)
print(jtxt)
dd = json.loads(jtxt) #dd为字典类型
print(dd['name'])

{"name": "Tom", "age": 15, "score": 85}
Tom

参考

廖雪峰Python教程(https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000)
Python 运算符 (http://www.runoob.com/python/python-operators.html#ysf6)

Python面向对象(初级篇)(http://www.cnblogs.com/wupeiqi/p/4493506.html)

Python面向对象(高级篇)(http://www.cnblogs.com/wupeiqi/p/4766801.html)

-------------本文结束 感谢您的阅读-------------
0%