Python面向对象高级编程

1.给实例动态绑定方法:

class Student(object):
    pass
>>> s = Student()
>>> def set_age(self, age): # 定义一个函数作为实例方法
...     self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25
给一个实例绑定的方法,对另一个实例是不起作用的:
>>> s2 = Student() # 创建新的实例
>>> s2.set_age(25) # 尝试调用方法
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'set_age'

2.使用__slots__限制实例的属性

    Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:只允许对Student实例添加name和age属性

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'

    'score'没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。

    注意:__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的,除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。

3.使用@property

    在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:

s = Student()
s.score = 9999
    Python内置的@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!')
>>> 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!
    注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:
class Student(object):
    @property
    def birth(self):
        return self._birth
    @birth.setter
    def birth(self, value):
        self._birth = value
    @property
    def age(self):
        return 2015 - self._birth
小结:   @property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。

练习:利用@property给一个Screen对象加上width和height属性,以及一个只读属性resolution:
class Screen(object):
	@property
	def width(self):
		return self._width
	@width.setter
	def width(self, value):
		if not isinstance(value, int):
			raise ValueError('width must be an integer!')
		if value < 0:
			raise ValueError('width must larger than 0 !')
		self._width = value
	@property
	def height(self):
		return self._height
	
	@height.setter
	def height(self, value):
		self._height = value
	@property
	def resolution(self):
		return self._width * self._height

s = Screen()
s.width = 1024
s.height = 768
print(s.resolution)
assert s.resolution == 786432, '1024 * 768 = %d ?'% s.resolution    #测试结果是否正确

一、多重继承

    继承是面向对象编程的一个重要的方式,因为通过继承,子类就可以扩展父类的功能。
    Animal类层次的设计,假设要实现以下4种动物:Dog - 狗狗;Bat - 蝙蝠;Parrot - 鹦鹉;Ostrich - 鸵鸟。
 

class Animal(object):
    pass

# 大类:
class Mammal(Animal):
    pass

class Bird(Animal):
    pass

# 各种动物:
class Dog(Mammal):
    pass

    MixIn

    在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn。

class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):#肉食动物CarnivorousMixIn和植食动物HerbivoresMixIn
    pass

    MixIn的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个MixIn的功能,从而避免设计多层次的复杂的继承关系。

二、定制类

    形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的。

    1.__str__

class Student(object):
     def __init__(self, name):
         self.name = name
print(Student('Michael'))
>>> <__main__.Student object at 0x109afb190>
    定义__str__()方法,可以返回一个好看的字符串:
class Student(object):
    --snip--
     def __str__(self):
         return 'Student object (name: %s)' % self.name
     __repr__ = __str__
>>>print(Student('Michael'))
Student object (name: Michael)
>>> s = Student('Michael')
>>> s
Student object (name: Michael)

    __str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,__repr__()是为调试服务的。但是通常__str__()和__repr__()代码都是一样的。这样打印出来的实例,不但好看,而且容易看出实例内部重要的数据。

    2.__iter__

   如果一个类想被用于for ... in循环,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。

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

class 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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值