Python_面向对象_深入_下篇
程序员文章站
2022-05-08 14:45:03
...
特殊方法和运算符重载
Python类中有大量的特殊方法,其中比较常见的是构造函数(_init_())和析构函数(_del_())。
- 在python中除了构造函数与析构函数以外,还有大量的特殊方法支持更多的功能,例如运算符重载就是通过在类中重写特殊函数来实现的
Python类特殊方法
案例
- 自定义一个数组类,支持数组与数字之间的四则运算,数组之间的加法运算,内积运算和大小比较,数组元素访问和修改,以及成员测试等功能
class MyArray:
"""All the elements in this array must be numbers"""
__value = []
__size = 0
def __is_number(self, n):
if (not isinstance(n, int)) and (not isinstance(n, float)) and (not isinstance(n, complex)):
return False
return True
def __init__(self, *args):
if not args:
self.__value = []
else:
for arg in args:
if not self.__is_number(arg):
print('All elements must be numbers')
return
self.__value = list(args)
def __add__(self, n): # 数组中每个元素都与数字n相加,或两个数组相加
if self.__is_number(n):
b = MyArray()
for v in self.__value:
b.__value.append(v + n)
return b
elif isinstance(n, MyArray):
if len(n.__value) == len(self.__value):
c = MyArray()
for i, j in zip(self.__value, n.__value):
c.__value.append(i + j)
return c
else:
print("Length not equal")
else:
print("not supported")
def __sub__(self, n): # 数组中每个元素都与数字n相减,返回新数组
if not self.__is_number(n):
print(r'-operating with', type(n), 'and number type is not supported')
return
b = MyArray()
for v in self.__value:
b.__value.append(v - n)
return b
def __mul__(self, n): # 数组中每个元素都与数字n相乘,返回新数组
if not self.__is_number(n):
print(r'* operating with', type(n), 'and number type is not supported')
return
b = MyArray()
for v in self.__value:
b.__value.append(v * n)
return b
def __truediv__(self, n): # 数组中每个元素都与数字n相除,返回新数组
if not self.__is_number(n):
print(r'/ operating with', type(n), 'and number type is not supported')
return
b = MyArray()
for v in self.__value:
b.__value.append(v / n)
return b
def __floordiv__(self, n): # 数组中每个元素都与数字n整除,返回新数组
if not self.__is_number(n):
print(r'// operating with', type(n), 'and number type is not supported')
return
b = MyArray()
for v in self.__value:
b.__value.append(v // n)
return b
def __mod__(self, n): # 数组中每个元素都与数字n求余数,返回新数组
if not self.__is_number(n):
print(r'% operating with', type(n), 'and number type is not supported')
return
b = MyArray()
for v in self.__value:
b.__value.append(v % n)
return b
def __pow__(self, n): # 数组中每个元素都与数字n进行幂运算,返回新数组
if not self.__is_number(n):
print(r'** operating with', type(n), 'and number type is not supported')
return
b = MyArray()
for v in self.__value:
b.__value.append(v ** n)
return b
def __len__(self):
return len(self.__value)
def __repr__(self): # 直接使用对象作为语句时调用该函数
"""equivalent to return 'self.__value'"""
return repr(self.__value)
def __str__(self): # 使用print函数输出对象时调用该函数--相当于Java的toString方法
return str(self.__value)
def append(self, v): # 追加元素
if not self.__is_number(v):
print('Only number can be appended')
return
self.__value.append(v)
def __getitem__(self, index):
"""获取指定位置的元素值"""
if self.__is_number(index) and 0 <= index < len(self.__value):
return self.__value[index]
else:
print("invalid index!")
def __setitem__(self, index, v):
"""修改指定下标的元素值"""
if not self.__is_number(v):
print(v, 'is not number')
elif (not isinstance(index, int)) or index < 0 or index >= len(self.__value):
print('Index type error or out of range')
else:
self.__value[index] = v
def __contains__(self, item):
"""成员测试运算符 in"""
if item in self.__value:
return True
else:
return False
def dot(self, v):
"""模拟向量内积"""
if not isinstance(v, MyArray):
print(v, 'must be an instance of MyArray')
return
if len(v) != len(self.__value):
print('The size must be equal.')
return
b = MyArray()
for m, n in zip(v.__value, self.__value):
b.__value.append(m * n)
return sum(b.__value)
def __eq__(self, v):
"""关系运算符=="""
if not isinstance(v, MyArray):
print(v, 'must be an instance of MyArray')
return False
if self.__value == v.__value:
return True
return False
def __lt__(self, v):
"""关系运算符<"""
if not isinstance(v, MyArray):
print(v, 'must be an instance of MyArray')
return False
if self.__value < v.__value:
return True
return False
if __name__ == '__main__':
print('Please use me as a module---provided by ChanZany')
Please use me as a module---provided by ChanZany
继承机制
- Python支持多继承,如果父类中有相同的方法名,而在子类中使用时没有指定父类名。则python解释器将从左向右按顺序搜索
- 注意,最好不要使用多继承!会引起依赖混乱,程序的耦合度高
- 例子:
首先设计Person类,然后以Person为基类派生Teacher类,分别创建Person类和Teacher类的对象,并在派生类对象中调用基类方法
- 例子:
class Person(object):
def __init__(self, name="", age=20, sex='man'):
self.set_name(name)
self.set_age(age)
self.set_sex(sex)
def set_name(self, name):
if not isinstance(name, str):
print('name must be string.')
return
self.__name = name
def set_age(self, age):
if not isinstance(age, int):
print('age must be integer.')
return
self.__age = age
def set_sex(self, sex):
if sex != 'man' and sex != 'woman':
print('sex must be "man" or "woman"')
return
self.__sex = sex
def show(self):
print("Name:", self.__name)
print("Age:", self.__age)
print("Sex:", self.__sex)
class Teacher(Person):
"""Person的派生类"""
def __init__(self, name='', age=30, sex='man', department='computer'):
super(Teacher, self).__init__(name, age, sex)
self.set_department(department)
def set_department(self, department):
if not isinstance(department, str):
print('department must be string.')
return
self.__department = department
def show(self):
super().show()
print('Department:', self.__department)
if __name__ == '__main__':
zhangsan = Person('zhangsan', 19, 'man')
zhangsan.show()
print("*" * 30)
lisi = Teacher('Li Si', 32, 'man', 'Math')
lisi.show()
lisi.set_age(40)
lisi.show()
Name: zhangsan
Age: 19
Sex: man
******************************
Name: Li Si
Age: 32
Sex: man
Department: Math
Name: Li Si
Age: 40
Sex: man
Department: Math
- 为了更好的理解Python类的继承机制,再来看下面的代码
class A(object):
def __init__(self):
self.__private() #私有方法
self.public() #公共方法
def __private(self):
print('__private() method in A')
def public(self):
print("public() method in A")
class B(A):
def __private(self):
print('__private() method in B')
def public(self):
print('public() method in B')
b = B()
print(dir(b))
__private() method in A
public() method in B
['_A__private', '_B__private', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'public']
class C(A):
def __init__(self):
"""显式定义构造函数会重写父类的构造函数,因此这里调用的方法都是属于C类自己的而非A类的"""
self.__private()
self.public()
def __private(self):
print('__private() method in C')
def public(self):
print('public() method in C')
c = C()
print(dir(c))
__private() method in C
public() method in C
['_A__private', '_C__private', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'public']