python之封装,多态,函数的重写

  •  封装 enclosure

        封装是值隐藏类的实现细节,让使用者不关心这些细节
        封装的目的是让使用者通过尽可能少的方法(或属性)操作对象


    私有属性和方法
        python类中,以双下划线("__")开头,不以双下划线结尾的标识符为私有成员,私有成员只能使用该类的方法来进行访问和修改
            1.以__开头的属性为私有属性
            2.以__开头的方法为私有方法
        示例:   

# enclosure.py
#此示例示意私有属性和私有方法来实现封装

class A:
    def __init__(self):
        self.__p1 = 100 #<=====__p1为私有属性
        # self.__p2__ = 200  #这不是私有属性

    def show_info(self):
        print(self.__p1) # 此对象的实例方法可以访问和修改私有属性


    def __m(self):
        print('A类对象的__m方法被调用')


a = A()
a.show_info()  #100
print(a._A__p1)   #_类名__p1
print(a.__p1)
print(a.__p2__)
a.__m()  #出错,除A类的实例方法外,不能调用a对象的私有方法
  •     多态 polymocphic

        字面意思:'多种状态'
        多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态

        状态:
            静态(编译时状态)
            动态(运行时状态)
        说明:
            多态调用的方法和对象相关,不写类型相关
            python全部对象只有'运行时状态(动态)',
            没有'c++语言'里的编译时状态(静态)
        示例:

class Shape:
    def draw(self):
        print('Shape的draw()方法被调用')

class Point(Shape):
    def draw(self):
        print('正在画一个点')

class Circle(Point):
    def draw(self):
        print('正在画一个圆')


def my_draw(s):
    s.draw()  #<------此处显示出多态中的'动态'

s1 = Circle()
s2 = Point()
my_draw(s1)
my_draw(s2)


    面向对象编程语言的特征:
        继承
        封装
        多态

    super()函数 就是根据__mro__来调用上层的方法
    练习:
        写一个农民类Peasant有方法:
            def farm(self,plant):
                ...
        写一个工人类Worker
            有方法如下:
            def work(self,that):
                ...
        创建一个农民工为MigrantWorker,让此类的对象拥有上面两个类的全部方法

        person = MigrantWorker()
        person.farm('水稻')  #正在种植 水稻
        person.work('汽车')  #正在制造 汽车

        查看各个类的__mro__属性

class Peasant:
    def farm(self,plant):
        print("正在种植:",plant)

class Worker:
    def work(self,that):
        print('正在制造:',that)

class MigrantWorker(Peasant,Worker):
    pass

person = MigrantWorker()
person.farm('水稻')  #正在种植 水稻
person.work('汽车')  #正在制造 汽车
  •     函数重写 overwrite

    什么是函数重写
            在自定义的类内添加相应的方法,让自定义的类创建的实例能够使用内建函数进行操作
    对象转字符串函数
        repr(x) 返回一个能表示python对象的表达式字符串,通常
            evel(rerp(obj)) == obj
        str(x) 通过给定的对象返回一个字符串(这个字符串通常供人阅读)
    示例:

s = "I'm a teacher"        
print(str(s))   #I'm a teacher        
print(repr(s))  #"I'm a teacher"  相当于一个python能够识别的表达式

    对象转字符串函数的重写方法:


        repr()函数的重写方法:
            def __repr__(self):
                return 字符串

        str()函数的重写方法:
            def __str__(self):
                return 字符串

        str(obj)函数调用方法说明:
            1.str(obj)函数先查找obj.__str__方法,调用此方法并返回结果
            2.如果obj.__str__()方法不存在,则调用obj.__repr__方法
              并返回结果
            3.如果obj.__repr__方法不存在,则调用object类的__repe__
              实例方法显示<__main__.XXXX object at 0xXXXXXXX>格式的
              字符串

            示例:
                

class Mynumber:
    def __init__(self,val):
        self.data = val#在每个对象内部都创建一个实例变量来绑定数据
    def __str__(self):
        # print('__str__方法被调用')
        return '自定义数字:%d'%self.data

    def __repr__(self):
        '''返回的字符串一定是能表示self对象的表达式字符串'''
        return 'Mynumber(%d)'%self.data


n1 = Mynumber(100)
print('str(n1) = ',str(n1))
print('repr(n1) = ',repr(n1))

n2 = Mynumber(200)
print(str(n2))
print(n2.__str__())  #在print内部会将n2用str(x)转为字符串再写到sys.stdout
print(n2)

    内建函数重写
        方法名                                 函数名
    def __abs__(self):                  abs(obj)  函数调用
    def __len__(self):                  len(obj)  函数调用
    def __reversed__(self):             reversed(obj)  函数调用
    def __round__(self):                round(obj)  函数调用

    示例:
        

class Mylist:
    '''这是一个自定义的列表类型,此类型的对象data属性绑定的列表用来存储数据'''
    def __init__(self,iterable = ()):
        self.data = [x for x in iterable]
        

    def __repr__(self):
        return 'Mylist(%s)'%self.data 
    def __len__(self):
        return len(self.data)
    def __abs__(self):
        L = [abs(x) for x in self.data]
        return Mylist(L)  

myl = Mylist([1,-2,3,-4])
print(myl) #Mylist([1, -2, 3, -4])
print(len(myl)) # 4
print(abs(myl)) #Mylist([1, 2, 3, 4])

    数值转换函数的重写:
    def __complex__(self):              complex(obj)函数调用
    def __init__(self):                 init(obj)   函数调用
    def __float__(self):                float(obj)  函数调用
    def __bool__(self):                 bool(obj)   函数调用
    示例见:
        

class Mynumber:
    def __init__(self,val):
        self.data = val#在每个对象内部都创建一个实例变量来绑定数据
    # def __str__(self):
    #     # print('__str__方法被调用')
    #     return '自定义数字:%d'%self.data

    def __repr__(self):
        '''返回的字符串一定是能表示self对象的表达式字符串'''
        return 'Mynumber(%d)'%self.data
    def __int__(self):
        '''重写int(obj)函数'''
        return int(self.data)
    def __float__(self):
        return float(self.data)


n1 = Mynumber(100)
n = int(n1)  #出错
print(n)

f = float(n1)
print(f)

c = complex(n1) #当没有n1.__complex__()时会调用n1.__float__
print(c)


    布尔测试函数的重写
        格式:
            def __bool__(self):
                ...
        作用:
            用于bool(obj)函数取值
            用于if语句真值表达式中
            用于while语句的真值表达式中
        说明: 
            1.当自定义类内有__bool__(self)方法时,此方法的返回作为
              bool(x)的返回值
            2.当不存在__bool__(self)方法时,返回__len__(self) 
              方法的返回值是否为非零来测试布尔值
            3.当不存在__len__(self)方法时,则直接返回True

    对象的属性管理函数:
        getattr(obj,name[,default])
        从一个对象用字符串name得到对象的属性,getattr(x,'y')等于同于x.y;
        当属性不存在时,如果给定default参数返回default,如果没有给出default
        则触发一个AttributError错误

        hasattr(obj,name)
        用给定的name字符串返回obj是否有此属性,此种做法可以避免在getattr(obj,name)时引发错误
        
        setattr(obj,name,value),
        给对象obj的名为name的属性设置相应的值vlaue,setattr(x,'y',v)
        等同于x.y = v

        delattr(obj,name) 删除对象obj中的name属性 del(x,'y') 等同于del x.y

  •     迭代器(高级)

        什么是迭代器
        由iter(x)函数返回,可以通过next(it)函数取值的对象就是迭代器

        迭代器协议:
            迭代器协议是指对象能够使用next()函数获取下一项数据,在没有下一项数据时,触发一个StopIteration

            异常来终止迭代的约定

        迭代器协议的实现方法:
            def __next__(self):
                ...
            注:此方法需要实现迭代器协议

        什么是可迭代对象
            是指能用iter(obj)函数返回迭代器的对象(实例)
            可迭代对象内部都要定义__iter__(self)方法来返回迭代器对象

        示例:
            


class Mylist:
    '''这是一个自定义的列表类型,此类型的对象data属性绑定的列表用来存储数据'''
    def __init__(self,iterable = ()):
        self.data = [x for x in iterable]
        
    def __repr__(self):
        return 'Mylist(%s)'%self.data
    def __iter__(self):
        '''此方法用于返回一个能访问self对象的迭代器'''
        # print('__iter__被调用')
        return MylistIterator(self.data)   #创建迭代器并返回

#迭代器
class MylistIterator:
    '''此类用来描述能够访问Mylist类型的对象的迭代器'''
    print('__next__方法被调用')
    def __init__(self,lst):
        self.data_lst = lst
        self.cur_index = 0 #迭代器访问的起始位置
    def __next__(self):
        '''此方法用来实现迭代器协议'''
        if  self.cur_index >= len(self.data_lst):
            raise StopIteration

        r = self.data_lst[self.cur_index]
        self.cur_index += 1
        return r

myl = Mylist([2,3,5,7])
it = iter(myl)  #等同于调用it = myl.__iter__()
print(next(it))  #2
for x in myl:
    print(x)
L = [x**2 for x in myl]
print(L)


    练习:
        1.实现原学生信息管理系统的student类的封装,让除student实例方法外的函数或其   他方法都不能访问姓名,年龄,成绩等属性
        2.写一个实现迭代器协议的类,让此类可以生成从b开始的n个素数
        class Prime:
            def __init__(self,b,n):
                ...
            def __ iter__(self):
                ....
        L = [x for x in Prime(10,4)]
        print(L) #L = [11,13,17,19]
        3.写一个类Fibonacci实现迭代器协议,此类的对象可以作为可迭代对象生成斐波那契数名
        1 1 2 3 5 8 13
        class Fibonacci:
            def __init__(self,n):
                ....
            ...    
        for x in Fibonacci(10):
            print(x) #打印 1 1 2 3 5 8 ...
看答案请留言

猜你喜欢

转载自blog.csdn.net/zhangshuaijun123/article/details/82118841