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

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

slots

限制实例能添加的属性。

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

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

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

@property

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

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

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

多重继承

通过继承,子类可以扩展父类的功能。要加入额外的功能,通过多重继承就可以实现。
这种设计通常称之为MixIn。

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

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

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

  4. 类继承关系:

现在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_的变量或者函数名,这样有特殊用途的函数,可以帮助我们定制类。

  1. _ str _ 直接显示变量。
    当直接打印变量不用print的时候,直接显示变量调用的不是str(),而是repr(),两者的区别是str()返回用户看到的字符串,而repr()返回程序开发者看到的字符串,也就是说,repr()是为调试服务的。
  2. _ iter_
    如果一个类想被用于for … in循环,类似list或tuple那样,就必须实现一个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 >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的一个唯一实例。

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

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

  3. 可以用成员名称引用枚举常量,又可以直接根据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()函数既可以返回一个对象的类型,又可以创建出新的类型。

    1. 要创建一个class对象,type()函数依次传入3个参数:
      • class的名称;
      • 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
      • class的方法名称与函数绑定。
  • 通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。

    metaclass(元类)
    控制类的创建行为,可以把类看成是metaclass创建出来的“实例”。
    基本用不到,用到再百度吧。。。

学习网站:www.liaoxuefeng.com

你可能感兴趣的:(Python)