Python学习笔记(四)面向对象高级编程
1.使用__slots__:
想要限制实例能够添加的属性时,使用__slots__:
[code]class Student(object): __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
[code]>>> 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__加上父类的
__slots__。
2.@property:Python内置的
@property装饰器就是负责把一个方法变成属性调用的:
[code]""" 请利用@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,valu): self._height=valu @property def resolution(self): return self._width * self._height s = Screen() s.width = 1024 s.height = 768 print('resolution =', s.resolution) if s.resolution == 786432: print('测试通过!') else: print('测试失败!')
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性。
@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
3.多重继承:通过多重继承,一个子类就可以同时获得多个父类的所有功能。
[code]class Animal(object): pass # 大类: class Mammal(Animal): pass class Bird(Animal): pass # 各种动物: class Dog(Mammal): pass class Bat(Mammal): pass class Parrot(Bird): pass class Ostrich(Bird): 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
在设计类的继承关系时,通常,主线都是单一继承下来的,例如,
Ostrich继承自
Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让
Ostrich除了继承自
Bird外,再同时继承
Runnable。这种设计通常称之为MixIn。
[code]class Dog(Mammal, RunnableMixIn, CarnivorousMixIn): pass
4.定制类
__str__:
[code]class friends(object): def __init__(self,name): self.name=name def __str__(self): return 'friends object (name:%s)'%self.name print(friends("we"))
输出是:friends object (name:we),如果不用__str__,输出就会是<__main__.friends object at 0x000002590A676748>
__iter__:如果一个类想被用于
for ... in循环,类似list或tuple那样,就必须实现一个
__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的
__next__()方法拿到循环的下一个值,直到遇到
StopIteration错误时退出循环。
我们以斐波那契数列为例,写一个Fib类,可以作用于for循环:
[code]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 # 返回下一个值
现在,试试把Fib实例作用于for循环:
[code]>>> for n in Fib(): ... print(n) ... 1 1 2 3 5 ... 46368 75025
__getitem__:Fib实例虽然能作用于for循环,看起来和list有点像,但是,把它当成list来使用还是不行,比如,取第5个元素:Fib()[5]就不可以,要表现得像list那样按照下标取出元素,需要实现
__getitem__()方法:
[code]class Fib(object): def __getitem__(self, n): a, b = 1, 1 for x in range(n): a, b = b, a + b return a
现在,就可以按下标访问数列的任意一项了。
但是使用切片时对于Fib却报错。原因是
__getitem__()传入的参数可能是一个int,也可能是一个切片对象
slice,所以要做判断:
[code]class Fib(object): def __getitem__(self, n): if isinstance(n, int): # n是索引 a, b = 1, 1 for x in range(n): a, b = b, a + b return a if isinstance(n, slice): # n是切片 start = n.start stop = n.stop if start is None: start = 0 a, b = 1, 1 L = [] for x in range(stop): if x >= start: L.append(a) a, b = b, a + b return L
这时切片就可以使用了,但是对于step参数,负数等还是不支持,所以,要正确实现一个
__getitem__()还是有很多工作要做的。
此外,如果把对象看成
dict,
__getitem__()的参数也可能是一个可以作key的object,例如
str。
与之对应的是
__setitem__()方法,把对象视作list或dict来对集合赋值。最后,还有一个
__delitem__()方法,用于删除某个元素。
总之,通过上面的方法,我们自己定义的类表现得和Python自带的list、tuple、dict没什么区别,这完全归功于动态语言的“鸭子类型”,不需要强制继承某个接口。
__getattr__:正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。要避免这个错误,Python有一个机制,那就是写一个
__getattr__()方法,动态返回一个属性。如下:
[code]class Student(object): def __init__(self): self.name = 'Michael' def __getattr__(self, attr): if attr=='score': return 99
当调用不存在的属性时,比如
score,Python解释器会试图调用
__getattr__(self, 'score')来尝试获得属性,这样,我们就有机会返回
score的值。
返回函数也是完全可以的,只是调用方式变为s.age():
[code]class Student(object): def __getattr__(self, attr): if attr=='age': return lambda: 25
Python的class允许定义许多定制方法,可以让我们非常方便地生成特定的类,还有很多可定制的方法,具体参考Python的官方文档。
5.枚举类
定义常量时,除了可以通过大写字母定义之外,还可以为这样的枚举类型定义一个class类型,然后,每个常量都是class的一个唯一实例。Python提供了
Enum类来实现这个功能:
[code]from enum import Enum, unique @unique cl 4000 ass Weekday(Enum): Sun = 0 # Sun的value被设定为0 Mon = 1 Tue = 2 Wed = 3 Thu = 4 Fri = 5 Sat = 6 print(Weekday.Mon.value)#输出为1 for name, member in Weekday.__members__.items(): print(name, '=>', member.value)#输出为Sun=>0 Mon=>1 ...Sat=>6
其中
value属性则是自动赋给成员的
int常量,默认从
1开始计数。@unique装饰器可以帮我们检查保证没有重复值。
6.元类
type()函数既可以返回一个对象的类型,又可以创建出新的类型。比如,我们可以通过
type()函数创建出
Hello类,而无需通过
class Hello(object)...的定义:
[code]def fn(self, name='world'): # 先定义函数 print('Hello, %s.' % name) Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class h = Hello() print(h.hello()) print(type(Hello)) print(type(h))
要创建一个class对象,
type()函数依次传入3个参数:
1.class的名称;
2.继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
3.class的方法名称与函数绑定,这里我们把函数
fn绑定到方法名
hello上。
metaclass:元类,详情略。
- python2.7学习笔记(10) ——面向对象高级编程
- Python学习笔记 - 面向对象高级编程
- 【Python】学习笔记——-8.4、面向对象高级编程:4.定制类
- 初学Python的学习笔记9----面向对象编程(获取对象信息、实例属性和类属性)、面向对象高级编程(使用__slots__、使用@property)
- 【Python】学习笔记——-8.1、面向对象高级编程:1.使用__slots__
- 【Python】学习笔记——-8.5、面向对象高级编程:5.使用枚举类
- 【Python】学习笔记——-8.3、面向对象高级编程:3.多重继承
- python学习笔记(七) - 面向对象高级编程
- Python面向对象高级编程——学习笔记
- 廖雪峰Python教程 学习笔记11 面向对象高级编程
- 【Python】学习笔记——-8.2、面向对象高级编程:2.使用@property
- 【Python】学习笔记——-8.6、面向对象高级编程:6.使用元类
- 面向对象高级编程——Python学习笔记08
- Python3 高级功能学习笔记(面向对象和正则表达式)
- python第七天学习记录——面向对象高级以及socket编程
- Geekband_C++面向对象高级编程_第三周学习笔记
- python学习(13)——面向对象高级编程
- Python学习----面向对象高级编程
- Python3.X之面向对象高级编程笔记
- Python学习系列:面向对象高级编程(-)