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

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

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

  使用__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__来限制容许的属性。app

>>> 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装饰器。spa

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!

就能像调用普通属性同样方便了!设计

  也能够只定义只读属性:3d

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入门整理后的笔记

相关文章
相关标签/搜索