面向对象的高级编程

来源:互联网 发布:华为数据卡槽不能换 编辑:程序博客网 时间:2024/05/16 04:59

在Python中,面向对象还有很多高级特性,允许我们写出非常强大的功能。
我们会讨论多重继承、定制类、元类等概念。
使用slots
正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的slots变量,来限制该class实例能添加的属性:

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定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:

>>> class GraduateStudent(Student):...     pass...>>> g = GraduateStudent()>>> g.score = 9999

除非在子类中也定义slots,这样,子类实例允许定义的属性就是自身的slots加上父类的slots
使用@property
在绑定属性的时候,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改动。
装饰器可以动态的给函数加上功能,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!')        self._score = value

@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:

>>> s = Student()>>> s.score = 60 # OK,实际转化为s.set_score(60)>>> s.score # OK,实际转化为s.get_score()60>>> s.score = 9999Traceback (most recent call last):  ...ValueError: score must between 0 ~ 100!

多重继承:
通过多重继承,一个子类可以获得多个父类的所有功能。
多重继承这种设计方式称为Mixln,像是JAVA都是值允许单一继承的,感觉python这玩意挺好的。
定制类:
python中很多用特殊用途的函数帮助我们构建定制类

   __repr____str__

直接显示变量调用的不是str(),而是repr(),两者的区别是str()返回用户看到的字符串,而repr()返回程序开发者看到的字符串,也就是说,repr()是为调试服务的。具体代码以及过程见廖雪峰官网。

__iter__

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

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循环,看起来和list有点像,但是,把它当成list来使用还是不行,
要表现得像list那样按照下标取getitem()方法:

class Fib(object):    def __getitem__(self, n):        a, b = 1, 1        for x in range(n):            a, b = b, a + b        return a

定制类
关键字

__str____iter____getitem____getattr____call__

http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319098638265527beb24f7840aa97de564ccc7f20f6000
还有很多参考python官方文档:
https://docs.python.org/3/reference/datamodel.html#special-method-names
使用枚举类:
当我们需要定义常量的时候,我们用枚举类型定义一个class类型
,每个常量都是Class中的唯一一个 实例。python中运用Enum类来实现这个功能:

from enum import EnumMonth = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():    print(name, '=>', member, ',', member.value)

value属性则是自动赋给成员的int常量,默认从1开始计数。
如果需要更精确地控制枚举类型,可以从Enum派生出自定义类:

from enum import Enum, unique@uniqueclass Weekday(Enum):    Sun = 0 # Sun的value被设定为0    Mon = 1    Tue = 2    Wed = 3    Thu = 4    Fri = 5    Sat = 6

@unique装饰器可以帮助我们检查保证没有重复值。
使用元类:静态语言和动态语言最大区别是一个动态语言的函数和类在运行的时候创建。

除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass

但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。
连接起来就是:先定义metaclass,就可以创建类,最后创建实例。
所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。

也就是说用metaclass来修改类定义。

ORM是一个典型的例子:
ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。

metaclass是Python中非常具有魔术性的对象,它可以改变类创建时的行为。这种强大的功能使用起来务必小心。

这看了两遍~还是很多东西没有看懂,不过感觉貌似挺强大的,以后在时间中慢慢理解~加油

0 0