Python程序设计之面向对象程序设计(2)

1.关于属性
类中的属性与普通变量不同,Python2.x中通过property()函数或者@property来声明一个属性,不用显性声明就可以通过对属性的重新赋值,来隐藏对象的原有属性值,会创建一个新值,但不会覆盖原有对象的属性值,但Python3.x中需要显性声明属性值的调用状态,才可有相应操作。
①只能读取属性值的案例

class myClass5:
    def __init__(self,a):
        self.__value=a
    @property
    def myFunction(self):   #只能读取,无法修改属性的值
        return self.__value
    @property
    def value(self):
        return self.__value   #只允许读取,无法修改

读取操作如下:

c=myClass5(6)
#在改变对象的值的时候会添加一个新成员,但是不会改变原有属性的值
print('打印原有的私有属性值:',c.myFunction,end='\n')
c.value=5
print('打印修改后的重新创建的新变量的值:',c.value,end='\n')
print('原有属性的值:',c._myClass5__value,end='\n')
print('\n')

输出结果会报错,因为不能修改属性值,只能进行读操作

Traceback (most recent call last):
  File "C:/Users/QinHsiu/PythonProjects/String/oobject.py", line 112, in <module>
    c.value=5
AttributeError: can't set attribute

②可以对属性值读取,修改和删除操作的案例

class myclass6:
    def __init__(self,value):
        self.__value=value
    def __get(self):    #可以查看原有属性值
       return self.__value
    def __set(self,a):  #可以修改属性值,通过set()函数实现
        self.__value=a
    def __del(self):      #可以删除原有属性值
        del self.__value
    # 声明属性
    value= property(__get, __set,__del)
    def show(self):
        print('属性原有值:',self.__value,end='\n')

实例化代码:

#初始化类对象
l=myclass6(3)
#调用公有方法
l.show()
#通过__get()访问属性值
print('查看原有值:',l.value,end='\n')
#通过__set()修改变量值
l.value=5
print('打印修改后的值:',l.value,end='\n')
#通过1公有方法查看原有属性是否被修改
l.show()
#通过__del()删除原有属性值
del l.value
#通过__set()对属性赋值
l.value=100
l.show()

输出结果如下:

属性原有值: 3
查看原有值: 3
打印修改后的值: 5
属性原有值: 5
属性原有值: 100

2.Python的特殊方法,与运算符重载密切相关

#Python特殊方法:
__init__()  #构造函数,生成对象时调用(可以不用显示声明,Python会自动生成构函数)
__del__()   #析构函数,释放对象时调用(不显示声明,系统会默认生成一个构造函数)
__add__(),__radd__()    #左+函数&右+函数
__sub__()   #表示-
__mul__()   #表示*
__dic__(),__truediv__() #Python2.x使用前者,Python3.x使用后者
__floordiv__()  #整除
__mod__()   #表示%
__pow__()   #表示**
__cmp__()   #比较运算
__repr__()  #打印,转换
__setitem__()   #按照索引赋值
__getitem__()   #按照索引取值
__len__()   #计算长度
__call__()  #函数调用
__contains__()  #测试是否包含某个元素
__eq__(),__ne__(),__lt__(),__le__(),__gt__(),__ge__()   #分别表示==,!=,<,<=,>,>=
__str__(),rshift__()    #分别表示<<,>>
__and__(),__or__(),__invert__() #分别表示&,|,~
__iadd__(),__isub__()   #分别表示+=,-=

运算符重载案例①,通过运算符重载实现对列表的一系列操作

class MyArray:
    '''All the elements in this array must be numbers'''
    __value = []

    def __IsNumber(self, n):
        if not isinstance(n, (int, float, complex)):
            return False
        return True

    def __init__(self, *args):
        if not args:
            self.__value = []
        else:
            for arg in args:
                if not self.__IsNumber(arg):
                    print('All elements must be numbers')
                    return
            self.__value = list(args)

    #重载运算符+
    #数组中每个元素都与数字n相加,或两个数组相加,返回新数组
    def __add__(self, n):
        if self.__IsNumber(n):
            #数组中所有元素都与数字n相加
            b = MyArray()
            b.__value = [item+n for item in self.__value]
            return b
        elif isinstance(n, MyArray):
            #两个等长的数组对应元素相加
            if len(n.__value)==len(self.__value):
                c = MyArray()
                c.__value = [i+j for i, j in zip(self.__value, n.__value)]
                #for i, j in zip(self.__value, n.__value):
                #    c.__value.append(i+j)
                return c
            else:
                print('Lenght not equal')                
        else:
            print('Not supported')

    #重载运算符-
    ##数组中每个元素都与数字n相减,返回新数组
    def __sub__(self, n):
        if not self.__IsNumber(n):
            print('- operating with ', type(n), ' and number type is not supported.')
            return
        b = MyArray()
        b.__value = [item-n for item in self.__value]
        return b

    #重载运算符*
    #数组中每个元素都与数字n相乘,返回新数组
    def __mul__(self, n):
        if not self.__IsNumber(n):
            print('* operating with ', type(n), ' and number type is not supported.')
            return
        b = MyArray()
        b.__value = [item*n for item in self.__value]
        return b

    #重载运算符/
    #数组中每个元素都与数字n相除,返回新数组
    def __truediv__(self, n):
        if not self.__IsNumber(n):
            print(r'/ operating with ', type(n), ' and number type is not supported.')
            return
        b = MyArray()
        b.__value = [item/n for item in self.__value]
        return b

    #重载运算符//
    #数组中每个元素都与数字n整除,返回新数组
    def __floordiv__(self, n):
        if not isinstance(n, int):
            print(n, ' is not an integer')
            return
        b = MyArray()
        b.__value = [item//n for item in self.__value]
        return b

    #重载运算符%
    #数组中每个元素都与数字n求余数,返回新数组
    def __mod__(self, n):
        if not self.__IsNumber(n):
            print(r'% operating with ', type(n), ' and number type is not supported.')
            return
        b = MyArray()
        b.__value = [item%n for item in self.__value]
        return b

    #重载运算符**
    #数组中每个元素都与数字n进行幂计算,返回新数组
    def __pow__(self, n):
        if not self.__IsNumber(n):
            print('** operating with ', type(n), ' and number type is not supported.')
            return
        b = MyArray()
        b.__value = [item**n for item in self.__value]
        return b

    def __len__(self):        
        return len(self.__value)

    #直接使用该类对象作为表达式来查看对象的值
    def __repr__(self):
        #equivalent to return `self.__value`
        return repr(self.__value)

    #支持使用print()函数查看对象的值
    def __str__(self):
        return str(self.__value)

    #追加元素
    def append(self, v):
        if not self.__IsNumber(v):
            print('Only number can be appended.')
            return
        self.__value.append(v)

    #获取指定下标的元素值,支持使用列表或元组指定多个下标
    def __getitem__(self, index): 
        length = len(self.__value)
        #如果指定单个整数作为下标,则直接返回元素值
        if isinstance(index, int) and 0<=index<length: 
            return self.__value[index]
        #使用列表或元组指定多个整数下标
        elif isinstance(index, (list,tuple)):
            for i in index:
                if not (isinstance(i,int) and 0<=i<length):
                    return 'index error'
            result = []
            for item in index:
                result.append(self.__value[item])
            return result
        else:
            return 'index error'

    #修改元素值,支持使用列表或元组指定多个下标,同时修改多个元素值
    def __setitem__(self, index, value):
        length = len(self.__value)
        #如果下标合法,则直接修改元素值
        if isinstance(index, int) and 0<=index<length:
            self.__value[index] = value
        #支持使用列表或元组指定多个下标
        elif isinstance(index, (list,tuple)):
            for i in index:
                if not (isinstance(i,int) and 0<=i<length):
                    raise Exception('index error')
            #如果下标和给的值都是列表或元组,并且个数一样,则分别为多个下标的元素修改值
            if isinstance(value, (list,tuple)):
                if len(index) == len(value):
                    for i, v in enumerate(index):
                        self.__value[v] = value[i]
                else:
                    raise Exception('values and index must be of the same length')
            #如果指定多个下标和一个普通值,则把多个元素修改为相同的值
            elif isinstance(value, (int,float,complex)):
                for i in index:
                    self.__value[i] = value
            else:
                raise Exception('value error')
        else:
            raise Exception('index error')

    #支持成员测试运算符in,测试数组中是否包含某个元素
    def __contains__(self, v):        
        if v in self.__value:
            return True
        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
        return sum([i*j for i,j in zip(self.__value, v.__value)])
        #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

3.继承机制
继承机制,子类可以继承父类的公有方法和属性,不能继承私有成员,如果需要在子类中调用父类方法,需要使用super()函数或者以父类名.方法名()来实现。支持多继承机制,如果在父类中出现了同名字方法,按照从左到右原则调用。
案例:

class Person(object):
    def __init__(self, name = '', age = 20, sex = 'man'):
        self.setName(name)
        self.setAge(age)
        self.setSex(sex)
        
    def setName(self, name):
        if not isinstance(name, str):
            print('name must be string.')
            return
        self.__name = name
        
    def setAge(self, age):
        if not isinstance(age, int):
            print('age must be integer.')
            return
        self.__age = age
        
    def setSex(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):
    def __init__(self, name='', age = 30, sex = 'man', department = 'Computer'):
        super(Teacher, self).__init__(name, age, sex)
        ## or, use another method like below:
        #Person.__init__(self, name, age, sex)
        self.setDepartment(department)
    def setDepartment(self, department):
        
        if not isinstance(department, str):
            print('department must be a string.')
            return
        self.__department = department
        
    def show(self):
        super(Teacher, self).show()
        print('Department:', self.__department)

if __name__ =='__main__':
    zhangsan = Person('Zhang San', 19, 'man')
    zhangsan.show()

    lisi = Teacher('Li Si',32, 'man', 'Math')
    lisi.show()
    lisi.setAge(40)
    lisi.show()

输出结果如下:

Name: Zhang San
Age: 19
Sex: man
Name: Li Si
Age: 32
Sex: man
Department: Math
Name: Li Si
Age: 40
Sex: man
Department: Math

学习笔记:
1.面向对象程序设计三要素:封装(通过类、方法以及模块的作用域来实现)、继承(通过子类继承一个或多个父类来实现代码的重用)、多态(主要是运算符重载,还有通过参数不同实现方法重载);
2.可以动态为类增加新成员,通过对象.新成员名=赋值来实现;
3.如果通过类名来调用公有方法,实现形式如下:

class A:
    def hello(self):
        print('hello',end='\n')
b=A
A.hello(b)

输出结果:hello
错误使用:

class A:
    def hello(self):
        print('hello',end='\n')
A.hello()

输出错误信息:

TypeError: hello() missing 1 required positional argument: 'self'

4.变量名以下划线开头有特殊含义:

m=10 #公有属性
_m=100  #保护属性
__m=10000 #类中私有成员,只能内部访问或者在外部使用特殊函数例如下面:
#对象名._类名__m来访问

5.在IDLE中,单个下划线表示上次语句正常执行的输出结果;

面向对象基础知识请参看:
https://blog.csdn.net/qxyloveyy/article/details/104554448

发布了78 篇原创文章 · 获赞 83 · 访问量 5413

猜你喜欢

转载自blog.csdn.net/qxyloveyy/article/details/104563445