面向对象的进阶
本单元是Python3中面向对象的一个进阶
上一章只是简单的介绍了一下类的继承,多态等特种本章介绍内容如下:
- 多重继承
- 元类
- 定制类
具体介绍
接下来演示,如何给类或者是实例对象添加新的属性和方法
实例对象
class Person(object):
pass
a = Person()
a.name = '12'
这样就在这个实例对象上增加了一个属性name,但是类并没有增加,所以其它 的实例对象也没有这个属性
如果是想在这个类上添加也是很容易的
class Person(object):
pass
Person.name = '12'
这样的话它的实例对象都可以取到这个属性了。
slots
也就是说这个变量指向一个tuple,在这个tuple中是允许这个对象可以添加的新的属性,如果不在这个序列中,是无法绑定的, 并且它仅仅对于本类的实例对象有效,对于继承它的类来说并没有什么用。
__author__ = 'ThomasHuke'
class Person(object):
__slots__ = ('name', 'year')
p = Person()
p.name = 12
p.year = 12
p.bbt = 12
./slots.py
Traceback (most recent call last):
File "./slots.py", line 13, in <module>
p.bbt = 12
AttributeError: 'Person' object has no attribute 'bbt'
假如我们取消了p.bbt
12 12
一切恢复正常。
这既是slots的功能,可以限制类的实例对象添加的属性。
@property
Python内置的@property装饰器就是负责把一个方法变成属性调用
class Person(object):
@property
def width(self):
return self.width
@width.setter
def width(self, value):
self.width = value
p = Person()
p.name = 12
p.name
>>> 12
如果再使用p.name= xxx 就会报错。
其实也就是说让你在给类或者是实例对象添加属性的时候使用@property 添加的时候有所限制。
多重继承
概念
如tile,
class Animal(object, World):
pass
其实这就是多重继承。
使用都充继承就避免了继承树那种庞大的继承关系,需要什么功能继承就是了,简单明了。
联系到js中的多重继承,多么的不优雅,,,,但是 好特么灵活,它的实现是这样的原理
a要继承 bcd类,那么先封装一个x类,x包括了bcd,使用的时候直接让a继承x就相当于继承了bcd。我曹。反正我感觉这特么的是嘛嘛嘛。。。。好吧,太过于灵活的语言就是这个吊样。。。
str
管理打印
iter
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 # 返回下一个值
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 ... in循环,类似list或tuple那样,就必须实现一个iter()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
getitem
要表现得像list那样按照下标取出元素,需要实现getitem()方法
getattr
当调用不存在的属性时,比如score,Python解释器会试图调用getattr(self, 'score')来尝试获得属性,这样,我们就有机会返回score的值
call
任何类,只需要定义一个call()方法,就可以直接对实例进行调用,当然其实就是调用的class中定义的那个call
枚举类
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
这样我们就获得了Month类型的枚举类,可以直接使用Month.Jan来引用一个常量,或者枚举它的所有成员
type()
类比js 你可以认为是 object.creat()创建一个新的对象。
也就是说不需要你使用
class ClassName(object):
"""docstring for ."""
def __init__(self, arg):
super(, self).__init__()
self.arg = arg
这种style了,直接使用
type(ClassName, 继承的父class, 自己的属性方法)
,好吧,我不是很喜欢这么生成一个类。
动态定义class----metaclass
按照默认习惯,metaclass的类名总是以Metaclass结尾,以便清楚地表示这是一个metaclass
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
有了ListMetaclass,我们在定义类的时候还要指示使用ListMetaclass来定制类,传入关键字参数metaclass:
class MyList(list, metaclass=ListMetaclass):
pass
new()方法接收到的参数依次是:
当前准备创建的类的对象;
类的名字;
类继承的父类集合;
类的方法集合。