您的位置:首页 > 编程语言

面向对象高级编程(__slots__ @property 多重继承 定制类 使用枚举类 使用元类)

2017-09-13 15:57 686 查看
数据封装、继承和多态只是面向对象程序设计中最基础的3个概念。在Python中,面向对象还有很多高级特性,允许我们写出非常强大的功能。

slots

限制实例能添加的属性。

Python允许在定义class的时候,定义一个特殊的 _ slots _ (注意前后都有两个_)变量,来限制该class实例能添加的属性。

_ slots _定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。

在子类中也定义 _ slots _ ,这样,子类实例允许定义的属性就是自身的 _ slots _ 再加上父类的_ slots _。

@property

@property装饰器就是负责把一个方法变成属性调用。

属性一般通过getter和serter方法封装。

@property 装饰器下的是getter方法;属性.setter下的是serter方法。只有一个@property则表示只读。

多重继承

通过继承,子类可以扩展父类的功能。要加入额外的功能,通过多重继承就可以实现。

这种设计通常称之为MixIn。

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

由于Python允许使用多重继承,因此,MixIn就是一种常见的设计。只允许单一继承的语言(如Java)不能使用MixIn的设计。

举个栗子:第一个继承是生父,后边的都是继父。所以,父类有重复地方,首先继承生父的!

类继承关系:

现在python3已经都是新式类了,就讲下新式类的继承

class D(object):
pass

class E(object):
pass

class F(object):
pass

class C(D, F):
pass

class B(E, D):
pass

class A(B, C):
pass

比如说这么一个多重继承,那么继承顺序就是,A-B-E-C-D-F


定制类

这种形如_ xxx_的变量或者函数名,这样有特殊用途的函数,可以帮助我们定制类。

_ str _ 直接显示变量。

当直接打印变量不用print的时候,直接显示变量调用的不是str(),而是repr(),两者的区别是str()返回用户看到的字符串,而repr()返回程序开发者看到的字符串,也就是说,repr()是为调试服务的。

_ iter_ 。

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

#以斐波那契数列为例,
aa27
写一个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 >100: ##退出循环条件
raise StopIteration()
return self.a

for n in fib():
print(n)


3._ getitem_

要表现得像list那样按照下标取出元素,需要实现_ getitem_()方法。

a. _ getitem_()传入的参数可能是一个int,也可能是一个切片对象slice,所以做切片操作前要做判断。

b. 如果把对象看成dict,_ getitem_()的参数也可能是一个可以作key的object,例如str。

c.与之对应的是_ setitem_()方法,把对象视作list或dict来对集合赋值。最后,还有一个_ delitem_()方法,用于删除某个元素。

4._ getattr_(动态返回一个属性)

正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。要避免这个错误,除了可以加上一个属性外,Python还有另一个机制,那就是写一个__

getattr__()方法,动态返回一个属性。

class Student(object):

def __init__(self):
self.name = 'Michael'

def __getattr__(self, attr):
if attr=='score':
return 99


只有在没有找到属性的情况下,才调用_ getattr_,已有的属性,比如name,不会在_ getattr_中查找。

调用不存在的定义的属性会返回None,因为_ getattr_默认返回是None。要让class只响应特定的几个属性,我们就要按照约定,抛出AttributeError的错误。

5._ call_() 可以定义参数。

能被调用的对象就是一个Callable对象,比如函数和我们定义的带有call()的类实例。通过callable()函数,我们就可以判断一个对象是否是“可调用”对象。

Python的class允许定义许多定制方法,可以让我们非常方便地生成特定的类。

枚举类

Enum可以把一组相关常量定义在一个class中,且class不可变,而且成员可以直接比较。定义常量时,使用枚举类可以使每个常量都是class的一个唯一实例。

alue属性则是自动赋给成员的int常量,默认从1开始计数。

@unique装饰器可以帮助我们检查保证没有重复值。

可以用成员名称引用枚举常量,又可以直接根据value的值获得枚举常量。

from enum import Enum, unique

@unique  #保证元素不重复
class weekday(Enum):
Sun = 0  # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6

print(weekday.Sun)
print(weekday(2))


元类

动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。

type()

type()函数可以查看一个类型或变量的类型。

type()函数可以查看一个类型或变量的类型,type()函数既可以返回一个对象的类型,又可以创建出新的类型。

要创建一个class对象,type()函数依次传入3个参数:

class的名称;

继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;

class的方法名称与函数绑定。

通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。

metaclass(元类)

控制类的创建行为,可以把类看成是metaclass创建出来的“实例”。

基本用不到,用到再百度吧。。。

学习网站:www.liaoxuefeng.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: