4.2.1 自定义数组
任务:自定义一个数组类,支持数组与数字之间的四则运算,数组之间的加法运算、内积运算、和大小比较,数组元素访问和修改,以及成员测试等功能。
1 class MyArray():
2 '''All the elements in this array must be numbers'''
3
4 def __IsNumber(self,n):
5 if not isinstance(n,(int,float,compile)):
6 return False
7 return True
8
9 #构造函数,进行必要的初始化
10 def __init__(self,* args):
11 if not args:
12 self.__value = []
13 else:
14 for arg in args:
15 if not self.__IsNumber(arg):
16 print('All elements must be numbers')
17 return
18
19 # 将传递进来的参数从tuple类型转换为list类型,这样就能进行后续的操作了。
20 self.__value = list(args)
21
22 #定义一个析构函数,当该类没有实例的时候,释放内部封装的列表
23 def __del__(self):
24 del self.__value
25
26
27 #重载运算符 +
28 #数组中每个元素都与数字n相加,或两个数组相加,返回新数组
29 def __add__(self,n):
30 if self.__IsNumber(n):
31 #数组中所有元素都与数字n相加
32 b = MyArray()
33 b.__value = [item + n for item in self.__value]
34 return b
35
36 elif isinstance(n,MyArray):
37 #两个等成的数组对应元素相加
38 if len(n.__value) == len(self.__value):
39 c = MyArray()
40 c.__value = [i + j for i,j in zip(self.__value,n.__value)]
41
42 #或者用把列表推导改成for遍历,不过还是推导的执行效率高
43 #for i,j in zip(self.__value,n.__value):
44 # c.__value.append(i + j
45
46 return c
47
48 else:
49 print('Length not equal')
50
51 else:
52 print('Not supported')
53
54
55 #重载运算符 -
56 #数组中每个元素都与数字n相减,返回新数组
57 def __sub__(self,n):
58 if not self.__IsNumber(n):
59 print('- operating with',type(n),'and number type is not supported.')
60 return
61
62 b = MyArray()
63 b.__value = [item - n for item in self.__value]
64 return b
65
66 #重载运算符 *
67 #数组中每个元素都与数字n相乘,返回新数组
68 def __mul__(self,n):
69 if not self.__IsNumber(n):
70 print('* operating with',type(n),'and number type is not supported.')
71 return
72
73 b = MyArray()
74 b.__value = [item * n for item in self.__value]
75 return b
76
77 #重载运算符 /
78 #数组中每个元素都与数字 n 相除,返回新数组
79 def __truediv__(self,n):
80 if not self.__IsNumber(n):
81 print(r'/ operating with', type(n), 'and number type is not supported.')
82 return
83
84 b = MyArray()
85 b.__value = [item / n for item in self.__value]
86 return b
87
88
89 # 重载运算符 //
90 # 数组中每个元素都与数字 n 整除,返回新数组
91 def __floordiv__(self, n):
92 if not self.__IsNumber(n):
93 print(r'// operating with', type(n), 'and number type is not supported.')
94 return
95
96 b = MyArray()
97 b.__value = [item // n for item in self.__value]
98 return b
99
100 # 重载运算符 %
101 # 数组中每个元素都与数字 n 取余,返回新数组
102 def __mod__(self, n):
103 if not self.__IsNumber(n):
104 print('% operating with', type(n), 'and number type is not supported.')
105 return
106
107 b = MyArray()
108 b.__value = [item % n for item in self.__value]
109 return b
110
111 # 重载运算符 **
112 # 数组中每个元素都与数字 n 进行幂计算,返回新数组
113 def __pow__(self, n):
114 if not self.__IsNumber(n):
115 print('% operating with', type(n), 'and number type is not supported.')
116 return
117
118 b = MyArray()
119 b.__value = [item ** n for item in self.__value]
120 return b
121
122 def __len__(self):
123 return len(self.__value)
124
125
126 #直接使用该类对象作为表达式来查看对象的值
127 def __repr__(self):
128 return repr(self.__value)
129
130 #支持使用print()函数查看对象的值
131 def __str__(self):
132 return str(self.__value)
133
134
135 #往数组中追加元素
136 def append(self,v):
137 if not self.__IsNumber(v):
138 print('Only number can be appended.')
139 return
140 self.__value.append(v)
141
142 #获取指定下标的元素值,支持使用列表或元组指定多个下标
143 def __getitem__(self, index):
144 length = len(self.__value)
145 #如果指定单个整数作为下标,则直接返回元素值
146 if isinstance(index,int) and 0 <= index <= length:
147 return self.__value[index]
148
149 #使用列表或元组指定多个整数下标
150 elif isinstance(index,(list,tuple)):
151 for i in index:
152 if not (isinstance(i,int) and 0 <= i < length):
153 return 'index error'
154 result = []
155
156 for item in index:
157 result.append(self.__value[item])
158 return result
159 else:
160 return 'index srror'
161
162 #修改元素值,支持使用列表或元组指定多个下标,同时修改多个元素值
163 def __setitem__(self,index,value):
164 length = len(self.__value)
165
166 #如果下标合法,则直接修改元素值
167 if isinstance(index,int) and 0 <= index < length:
168 self.__value[index] = value
169
170 #支持使用列表或元组指定多个下标
171 elif isinstance(index,(tuple,list)):
172 for i in index:
173 if not (isinstance(i,int) and 0 <= i < length):
174 raise Exception('index error')
175
176 #如果下标和给的值都是列表或元组,并且个数一样
177 #则分别为多个下标的元素修改值
178 if isinstance(value,(list,tuple)):
179 if len(index) == len(value):
180 for i,v in enumerate(index):
181 self.__value[v] = value[i]
182 else:
183 raise Exception('values and index must be of the same length')
184
185 #如果指定多个下标和一个普通值,则把多个元素修改为相同的值
186 elif isinstance(value,(int,float,complex)):
187 for i in index:
188 self.__value[i] = value
189 else:
190 raise Exception('value error')
191
192 else:
193 raise Exception('index error')
194
195 #支持成员测试运算符 in ,测试数组中是否包含某个元素
196 def __contains__(self,v):
197 if v in self.__value:
198 return True
199 return False
200
201 #模拟向量内积
202 def dot(self,v):
203 if not isinstance(v,MyArray):
204 print(v,'must be an instance of MyArray.')
205 return
206 if len(v) != len(self.__value):
207 print('The size must be equal.')
208 return
209 return sum([i * j for i,j in zip(self.__value,v.__value)])
210
211 #或者用如下方式实现
212 #b = MyArray()
213 #for m,n in zip(v.__value,self.__value):
214 # b.__value.append(m * n)
215 #return sum(b.__value)
216
217 #重载运算符 == ,测试两个数组是否相等
218 def __eq__(self,v):
219 if not isinstance(v,MyArray):
220 print(v,'must be an instance of MyArray')
221 return False
222 if self.__value == v.__value:
223 return True
224 return False
225
226 #重载运算符 < ,比较两个数组大小
227 def __lt__(self,v):
228 if not isinstance(v,MyArray):
229 print(v,'must be an instace of MyArray.')
230 return False
231 if self.__value < v.__value:
232 return True
233 return False
234
235
236 if __name__ == '__main__':
237 print('Please use me as a module.')
将上面的程序保存为MyArray.py文件,可以作为Python模块导入并使用其中的数组类。
>>> import os
>>> os.getcwd()
'C:\Users\dddd\AppData\Local\Programs\Python\Python35'
>>>
把文件放在这个目录下
1 >>>
2 >>> from MyArray import MyArray
3 >>>
4 >>> #导入模块中自定义的类
5 >>> from MyArray import MyArray
6 >>>
7 >>> #实例化对象
8 >>> x = MyArray(1,2,3,4,5,6)
9 >>> y = MyArray(6,5,4,3,2,1)
10 >>>
11 >>> #返回数组长度,即数组中的元素个数
12 >>> len(x)
13 6
14 >>>
15 >>> #每个元素加5,返回新数组,原数组值不改变
16 >>> x + 5
17 [6, 7, 8, 9, 10, 11]
18 >>>
19 >>> #每个元素值乘以3,返回新数组
20 >>> x * 3
21 [3, 6, 9, 12, 15, 18]
22 >>>
23 >>> #计算两个数组(一维向量)的内积
24 >>> x.dot(y)
25 56
26 >>>
27 >>> #在数组尾部追加新元素
28 >>> x.append(7)
29 >>> x
30 [1, 2, 3, 4, 5, 6, 7]
31 >>>
32 >>> #x数组追加新元素后,两个数组元素数不相等,看看进行内积的计算会如何
33 >>> x.dot(y)
34 The size must be equal.
35 >>>
36 >>> #试图修改元素值
37 >>> x[9] = 8
38 Traceback (most recent call last):
39 File "<pyshell#30>", line 1, in <module>
40 x[9] = 8
41 File "C:\Users\dddd\AppData\Local\Programs\Python\Python35\MyArray.py", line 193, in __setitem__
42 raise Exception('index error')
43 Exception: index error
44 >>> #根据报错内容可知,是下标越界了,因为x数组中只有7个元素
45 >>>
46 >>> #x数组中的每个元素值除以 2
47 >>> x / 2
48 [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5]
49 >>>
50 >>> x // 2
51 [0, 1, 1, 2, 2, 3, 3]
52 >>>
53 >>> x % 3
54 [1, 2, 0, 1, 2, 0, 1]
55 >>>
56 >>> #返回固定位置的元素值
57 >>> x[2]
58 3
59 >>>
60 >>> #测试数组中是否包含某个元素
61 >>> 'a' in x
62 False
63 >>>
64 >>> 3 in x
65 True
66 >>>
67 >>> #比较数组的大小
68 >>> x < y
69 True
70 >>>
71 >>> x = MyArray(1,2,3,4,5,6)
72 >>>
73 >>> #两个数组中对应元素相加,返回新数组
74 >>> x + y
75 Traceback (most recent call last):
76 File "<pyshell#54>", line 1, in <module>
77 x + y
78 File "C:\Users\dddd\AppData\Local\Programs\Python\Python35\MyArray.py", line 30, in __add__
79 if self.__IsNumber(n):
80 File "C:\Users\dddd\AppData\Local\Programs\Python\Python35\MyArray.py", line 5, in __IsNumber
81 if not isinstance(n,(int,float,compile)):
82 TypeError: isinstance() arg 2 must be a type or tuple of types
83 >>>
84 >>>
85 >>> #查看多个位置上的元素值
86 >>> x[[1,3,4]]
87 [2, 4, 5]
88 >>>
89 >>>
90 >>> #同时修改多个元素的值
91 >>> x[[2.3]] = [8,9]
92 Traceback (most recent call last):
93 File "<pyshell#62>", line 1, in <module>
94 x[[2.3]] = [8,9]
95 File "C:\Users\dddd\AppData\Local\Programs\Python\Python35\MyArray.py", line 174, in __setitem__
96 raise Exception('index error')
97 Exception: index error
98 >>>
99 >>> #为多个元素赋值为相同的值
100 >>> x[[1,3,5]] = 0
101 >>> x
102 [1, 0, 3, 0, 5, 0]
103 >>>