• Day-9: 面对对象高级编程


      数据封装、继承和多态只是面向对象编程中最基础的3个概念。

      下面整理面向对象高级编程的更为强大的技巧。

      使用__slots__:Python属于动态语言,可以允许已创建好的类动态地绑定任何属性和方法。但是,给实例绑定后,由该类创建的其他其他实例是没有绑定的;不过,可以给类绑定,那么有该类创建的实例均会拥有该属性和方法。

    >>> class Student(object):
    ...     pass
    ...
    >>> s = Student()
    >>> s.name = 'Michael' # 动态给实例绑定一个属性
    >>> print s.name
    Michael
    >>> def set_age(self, age): # 定义一个函数作为实例方法
    ...     self.age = age
    ...
    >>> from types import MethodType
    >>> s.set_age = MethodType(set_age, s, Student) # 给实例绑定一个方法
    >>> s.set_age(25) # 调用实例方法
    >>> s.age # 测试结果
    25
    >>> def set_score(self, score):
    ...     self.score = score
    ...
    >>> Student.set_score = MethodType(set_score, None, Student)

      同时,正因为动态语言的这种特性,为了避免过于属性绑定,class类中使用__slots__来限制允许的属性。

    >>> class Student(object):
    ...     __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
    ...
    >>> s = Student() # 创建新的实例
    >>> s.name = 'Michael' # 绑定属性'name'
    >>> s.age = 25 # 绑定属性'age'
    >>> s.score = 99 # 绑定属性'score'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Student' object has no attribute 'score'

    __slots__属性只对父类起作用,但继承的子类是不起作用的,除非子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__。

      使用@property装饰器:

      在实际使用中,为了检查修改参数的合法性,会定义一个get和set函数,对set函数进行一系列的严格验证。

    class Student(object):
    
        def get_score(self):
            return self._score
    
        def set_score(self, value):
            if not isinstance(value, int):
                raise ValueError('score must be an integer!')
            if value < 0 or value > 100:
                raise ValueError('score must between 0 ~ 100!')
            self._score = value
    >>> s = Student()
    >>> s.set_score(60) # ok!
    >>> s.get_score()
    60
    >>> s.set_score(9999)
    Traceback (most recent call last):
      ...
    ValueError: score must between 0 ~ 100!

      为了简化上述调用和设置的过程,将两个方法直接变成调用属性一样简单,使用@property装饰器。

    class Student(object):
    
        @property
        def score(self):
            return self._score
    
        @score.setter
        def score(self, value):
            if not isinstance(value, int):
                raise ValueError('score must be an integer!')
            if value < 0 or value > 100:
                raise ValueError('score must between 0 ~ 100!')
            self._score = value
    >>> s = Student()
    >>> s.score = 60 # OK,实际转化为s.set_score(60)
    >>> s.score # OK,实际转化为s.get_score()
    60
    >>> s.score = 9999
    Traceback (most recent call last):
      ...
    ValueError: score must between 0 ~ 100!

    就能像调用普通属性一样方便了!

      也可以只定义只读属性:

    class Student(object):
    
        @property
        def birth(self):
            return self._birth
    
        @birth.setter
        def birth(self, value):
            self._birth = value
    
        @property
        def age(self):
            return 2014 - self._birth
    •  多重继承

      在继承时,由于对象会有多个属性,一般按照继承关系来说,选取其中一个大的类别作为主线,即主线是单一继承下来的。除主线外,其他的属性可以作为功能,多重继承下来。这种设计称为Mixin。

      例如,下面中,Mammal和Bird作为主线,Runnable和Flyable作为Mixin功能增加进去,构成多重继承。

    class Animal(object):
        pass
    
    # 大类:
    class Mammal(Animal):
        pass
    
    class Bird(Animal):
        pass
    class Runnable(object):
        def run(self):
            print('Running...')
    
    class Flyable(object):
        def fly(self):
            print('Flying...')
    class Dog(Mammal, Runnable):
        pass
    class Bat(Mammal, Flyable):
        pass
    • 定制类

      之前提到过的以双下划线开头和结尾的属性,是属于特殊属性,它们是用来定制类的。

      __str__():显示print该类的实例的名称

    >>> class Student(object):
    ...     def __init__(self, name):
    ...         self.name = name
    ...     def __str__(self):
    ...         return 'Student object (name: %s)' % self.name
    ...
    >>> print Student('Michael')
    Student object (name: Michael)

      __repr__():直接显示变量

    class Student(object):
        def __init__(self, name):
            self.name = name
        def __str__(self):
            return 'Student object (name=%s)' % self.name
        __repr__ = __str__
    
    >>>s = Student('Michael')
    >>>s
    Student object (name: Michael)

      __iter__():服务于for...in的迭代循环,该方法返回一个迭代对象,然后,Python的for循环会一直调用next()方法得到循环的下一个值,直到遇到StopIteration错误后退出循环。

    lass Fib(object):
        def __init__(self):
            self.a, self.b = 0, 1 # 初始化两个计数器a,b
    
        def __iter__(self):
            return self # 实例本身就是迭代对象,故返回自己
    
        def next(self):
            self.a, self.b = self.b, self.a + self.b # 计算下一个值
            if self.a > 100000: # 退出循环的条件
                raise StopIteration();
            return self.a # 返回下一个值
    >>> for n in Fib():
    ...     print n
    ...
    1
    1
    2
    3
    5
    ...
    46368
    75025

      __getitem__():允许像list一样按索引取值和切片。

    class Fib(object):
        def __getitem__(self, n):
            if isinstance(n, int):
                a, b = 1, 1
                for x in range(n):
                    a, b = b, a + b
                return a
            if isinstance(n, slice):
                start = n.start
                stop = n.stop
                a, b = 1, 1
                L = []
                for x in range(stop):
                    if x >= start:
                        L.append(a)
                    a, b = b, a + b
                return L
    >>> f = Fib()
    >>> f[0]
    1
    >>> f[1]
    1
    >>> f[2]
    2
    >>> f[3]
    3
    >>> f[10]
    89
    >>> f[100]
    573147844013817084101
    >>> f = Fib()
    >>> f[0:5]
    [1, 1, 2, 3, 5]
    >>> f[:10]
    [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

      __getattr__():当调用类的属性或者方法不存在时,运行__getattr__()方法。

    class Student(object):
    
        def __init__(self):
            self.name = 'Michael'
    
        def __getattr__(self, attr):
            if attr=='score':
                return 99
    >>> s = Student()
    >>> s.name
    'Michael'
    >>> s.score
    99

      __call__():对实例本身进行调用时,启用该方法。

    class Student(object):
        def __init__(self, name):
            self.name = name
    
        def __call__(self):
            print('My name is %s.' % self.name)
    >>> s = Student('Michael')
    >>> s()
    My name is Michael.

    通过callable()函数,可以判断一个对象是否是“可调用”对象。

      更多定制类的方法,参考Python文档

     注:本文为学习廖雪峰Python入门整理后的笔记

  • 相关阅读:
    iOS 添加微信分享
    IOS学习笔记——ViewController生命周期详解
    UI之CALayer详解(转)
    iOS CALayer讲解
    [leetcode] Minimum Path Sum
    [leetcode]Binary Tree Maximum Path Sum
    我是真的想去google啊
    C++ string 用法详解
    继续存博客
    bash中 2>&1 & 的解释
  • 原文地址:https://www.cnblogs.com/likely-kan/p/7512450.html
Copyright © 2020-2023  润新知