欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python_面向对象_深入_下篇

程序员文章站 2022-05-08 14:45:03
...

特殊方法和运算符重载

Python类中有大量的特殊方法,其中比较常见的是构造函数(_init_())和析构函数(_del_())。

  • 在python中除了构造函数与析构函数以外,还有大量的特殊方法支持更多的功能,例如运算符重载就是通过在类中重写特殊函数来实现的
    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']