Python -- 面向对象高级编程

作者: 2023开始学 | 来源:发表于2019-03-03 19:32 被阅读13次

    面向对象设计中最基础的3个概念:数据封装、继承和多态

    使用_ slots _

    _ slots _的作用:限制实例的属性

    为了达到限制的目的,在定义class时,定义一个_ slots _特殊变量,来限制该class实例添加的属性:

    注意:
    1、_ slots _仅对当前类实例起作用,对继承的子类是不起作用的

    2、如果子类中也定义_ slots ,那么子类实例允许添加的属性就是自身的 slots 加上父类的 slots _

    3、使用_ slots _添加属性时,一定要给属性加上引号

    方法:为了给各个实例都绑定方法,可以给class绑定方法

    通常情况下,添加方法可直接定义在类中,但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。

    class Student(object):
        __slots__=('name','age') #用tuple定义允许绑定的属性名称
    
    s=Student() #创建一个实例
    s.name='Maria'
    s.age=23
    # s.score=99  由于在类Student中限制了属性,所以添加score就会报错
    print("s.name:",s.name)
    print("s.age:",s.age)
    
    print("给s实例添加score属性后,报错类型为:")
    try:
        s.score=99
    except AttributeError as e:
        print("AttributeError:",e)
    
    print('    ')
    print("下面定义了子类:")
    class Graduate(Student):  #继承了Student类,那么也继承了Student类的_ _slots_ _
        __slots__=('score')  #这在子类中也定义了_ _slots_ _
    #看出下面g.name和g.age都正常,说明子类继承了Student类的_ _slots_ _
    g=Graduate()
    g.score=99
    g.name='shirley'
    g.age=34
    print("g.name,g.age:",g.name,g.age)
    print("g.score:",g.score)
    
    image.png

    @property

    class Student(object):
        @property
        def score(self):
            return self._score  #是self._score,不是self.score,中间的下划线不能省略
    
        @score.setter
        def score(self,value):   #都是raise ValueError, V和E要大写,先判断输入的数是不是Int,再判断是否在100以内
            if not isinstance(value,int):
                raise ValueError("please input an integer")
            elif value<0 or value>100:
                raise ValueError("请输入0到100之间的数!!!")
            else:
                self._score=value
    
    s=Student()
    s.score=99
    print("s.score:",s.score)
    print("    ")
    s1=Student()
    s1.score=999
    print("s1.score的分数:",s1.score)
    
    image.png
    class Screen(object):
        __width = 0
    
        def get_width(self):
            return self.__width
    
        @property
        def width2(self):
            return self.__width
    
    s = Screen()
    print("type(s.get_width)类型为:",type(s.get_width)) # <class 'method'>
    print("type(s.width2)类型为:",type(s.width2)) # <class 'int'>
    
    image.png

    实战:请利用@property给一个Screen对象加上width和height属性,以及一个只读属性resolution:

    class Screen(object):
        @property
        def width(self):
            return self._width
        @width.setter
        def width(self,value):
             self._width =value
    
        @property
        def height(self):
            return self._height
        @height.setter
        def height(self,value):
             self._height=value
    
        @property
        def resolution(self):  #此处将resolution定义为只读属性
            return self.width*self.height
    
    s = Screen()
    s.width = 1024
    s.height = 768
    print('resolution =', s.resolution)
    if s.resolution == 786432:
        print('测试通过!')
    else:
        print('测试失败!')
    

    运行结果:


    image.png

    多重继承

    参考:https://kevinguo.me/2018/01/19/python-topological-sorting/

    多重:多个, 多重继承:即同时继承多个对象
    
     通过多重继承,一个子类就可以同时获得多个父类的所有功能
    

    MixIn

    在设计类的继承关系时,通常,主线都是单一继承下来的,但是,如果需要“混入”额外的功能,通过多重继承就可以实现,这种设计通常称之为MixIn.

    python允许使用多重继承,因此,MixIn就是一种常见的设计

    只允许单一继承的语言(如JAVA),不能使用MixIn设计

    目的:MixIn主要解决对同一对象用不同标准来分类的问题。从性别划分,你是男人;从国家划分,你是中国人;从职业划分,你是程序员; mixin可以轻松定义具备跟你一样特征的人:中国男程序员(天朝屌丝逗比程序员)

    定制类

    _ str _

    将__str__方法理解成,规范化输出格式,输出用户能看懂的格式
    

    _ repr _

    1、直接显示变量调用的不是str( ),而是repr( ),两者的区别:

          __str__( )返回用户看到的字符串
    
         __repr__( )返回程序开发者看到的字符串,__repr__( )是为调试服务的
    

    2、通常情况下,repr( )和 str( )的代码相同,所以偷懒时可以写成这种形式:repr=str ,类似赋值,把str 里的代码赋给repr

    class Student(object):
        def __init__(self,name):
            self.name=name
    
    s = Student("Michael")
    print(s)
    

    运行结果:

    image.png

    下面使用了str方法后:

    class Student(object):
        def __init__(self,name):
            self.name=name
        def __str__(self):
            return 'Student Object (name :%s) ' % self.name  #返回的内容,自己可以修改
    
    s=Student("Michael")
    print(s)
    

    运行结果:


    image.png

    str方法 return 后面的语句可以自己修改

    class Student(object):
        def __init__(self,name):
            self.name=name
        def __str__(self):
            return "Hello, My name is %s" % self.name
    
    s=Student("Michael")
    print(s)
    

    运行结果:


    image.png

    _ iter _

    如果一个类想被用于for ……in 循环,类似list、tuple那样,就必须使用一个iter( )方法, 该方法返回一个迭代对象

    举例:以斐波那契数列为例,写一个Fib类,可以作用于for循环:

    #下面是__iter__方法
    class fib(object):
        def __init__(self):
            self.a,self.b=0,1
    
        def __iter__(self):  #__iter__方法,返回一个迭代对象
            return self
    
        def __next__(self):
            self.a,self.b=self.b,self.a+self.b
            if self.a>100:
                raise StopIteration
            return self.a
    
    for n in fib():
        print(n)
    
    image.png

    _ getitem _

      取下标
    
    __getitem__( self, item)方法
    

    item看作是“下标”, getitem( )传入的参数可能是一个int,也可能是一个切片对象slice

     与 __getitem__对应的是__setitem__( )方法,__delitem__( )方法
    
    class fib(object):
        def __init__(self):
            self.a,self.b=0,1
    
        def __iter__(self):  #__iter__方法,返回一个迭代对象
            return self
    
        def __next__(self):
            self.a,self.b=self.b,self.a+self.b
            if self.a>100:
                raise StopIteration
            return self.a
    
        def __getitem__(self,n):  #__getitem__方法
            a,b=1,1
            for x in range(n):
                a,b = b, a+b
            return a
    
    f=fib()
    print('f[0]:',f[0])
    print("f[1]:",f[1])
    print("f[2]:",f[2])
    print("f[3]:",f[3])
    print("f[13]:",f[13])
    

    运行结果:


    image.png

    _ getattr _

     正常情况下,当调用的类的方法或属性不存在时,就会报错。
    
    class Student(object):
        def __init__(self):
            self.name="lily"
    
    s=Student()
    print("s.name:",s.name)
    print("    ")
    print("s.score:",s.score)
    print("s.score函数:",s.score())
    
    由于类中没有score属性时,调用会报错
    

    print("s.score:",s.score)语句的报错结果:

    image

    print("s.score函数:",s.score)语句的报错结果:

    image

    添加getattr方法后: return 99,所以调用时s.score即可

    class Student(object):
        def __init__(self):
            self.name="lily"
    
        def __getattr__(self, attr): #__getattr__方法
            if attr == 'score':
                return 99
               
    
    
    s=Student()
    print("s.name:",s.name)
    print("    ")
    print("s.score:",s.score)
    

    返回函数也是可以的: return lambda : 25,所以调用时是s.score()

    class Student(object):
        def __init__(self):
            self.name="lily"
    
        def __getattr__(self, attr): #__getattr__方法
            if attr == 'score':
                return lambda :25  #此处是匿名函数lambda, 之前只是返回一个数值, return 99
                # print('hell')
    
    
    s=Student()
    print("s.name:",s.name)
    print("    ")
    print("s.score:",s.score())#由于return后面返回的是一个函数,因此这里调用时应该是s.score(),带上括号,
    # 而如果是return 99, 则调用时不必带括号
    

    运行结果和上面相同:

    image

    _ call _

    调用实例方法时,使用“instance.method( )”形式来调用
    

    问题:能不能直接在实例本身上调用呢?在python中,是肯定的

    结果:任何类,只需要定义一个__call( )方法,就可以直接对实例进行调用
    
    class Student(object):
        def __init__(self,name):
            self.name=name
    
        def __call__(self):
            return 'my name is %s' %self.name
    
    s=Student('lily')
    print(s())
    
    image.png

    相关文章

      网友评论

        本文标题:Python -- 面向对象高级编程

        本文链接:https://www.haomeiwen.com/subject/nqumuqtx.html