Python核心编程笔记 - 第13章 面向对象编程 (一)

Chapter 13. OOP

子类如果不定义自己的构造器(__init__()),基类的构造器就会被调用。然而,子类如果重写基类的构造器,基类的构造器就不会被自动调用了。这样,基类的构造器就必须显式地写出来才会被执行。

类名通常用大写字母打头,这是标准惯例。

Python不支持纯虚函数。

bound method 和 unbound method:

方法必须绑定到一个实例才能被直接调用;非绑定的方法可能可以被调用,但实例对象一定要明确给出,才能保证调用成功。

类的属性

要知道一个类有哪些属性,有2个方法:

  • 用内建函数dir()
  • 访问类的字典属性__dict__

内建的vars()函数接受类对象作为参数,返回类的__dict__属性的内容。

对于任何类C,其必有的所有特殊属性如下:

  • C.__name__ 类C的名字(字符串)
  • C.__doc__ 类C的文档字符串(文档字符串不会被派生类继承)
  • C.__bases__ 类C的所有父类构成的元组
  • C.__dict__ 类C的所有属性
  • C.__module__ 类C定义所在的模块
  • C.__class__ 实例C所对应的类(仅新式类),如’type’

__init_()_ 和 __new__()

用户可以对内建类型(如字符串、数字)进行派生,因此,需要一种途径来实例化不可变对象,比如派生字符串、派生数字等。在这种情况下,解释器调用类的__new__()方法,一个静态方法,并且传入的参数是类实例化操作时生成的。__new__()会调用父类的__new__()来创建对象(向上代理)。
__new__()必须返回一个合法的实例,这样解释器在调用__init__()时,就可以把这个实例作为self传给它。所以,__new__()的执行是在__init__()之前的。

__del__()

相应的desctructor方法名为__del__(). 由于Python具有垃圾对象回收机制(靠引用计数),这个函数要直到该实例对象所有的引用都被清除掉后才会执行。
关于__del__()的总结:

  • 不要忘记首先调用父类的__del__()
  • 调用 del x 仅仅表示减少 x 的引用计数,并不会去调用 __del__()
  • 一般不要去实现 __del__()

类属性与实例属性

对实例属性的赋值会创建一个实例属性(如果不存在的话),但如果类属性中存在同名属性,就会有副作用。
看下面的代码:

class Foo(object):
    x = 1.5

foo = Foo()
print foo.x     # 1.5

foo.x = 2
print foo.x     # 2 (实例属性)
print Foo.x     # 1.5

del foo.x
print foo.x     # 1.5 (类属性)

再看一段代码,在类属性可变的情况下,就有不同了:

class Foo(object):
    x = {2003: 'poe2'}

foo = Foo()
print foo.x     # {2003: 'poe2'}

foo.x[2004] = 'poe3'
print foo.x     # {2003: 'poe2', 2004: 'poe3'}
print Foo.x     # {2003: 'poe2', 2004: 'poe3'}  竟然一样了!

del foo.x       # 会报AttributeError,因为没有遮蔽掉类属性

绑定和方法调用

方法只有在其所属的类拥有实例的时候,才能被调用。当存在一个实例时,方法才被认为是绑定到那个实例的;没有实例时,方法就是未绑定的。

调用非绑定方法:
需要调用一个还没有任何实例的类中的方法的一个主要场景是:在派生一个子类,而且要覆盖父类的构造方法,这时你需要调用父类中那个想要被覆盖掉的构造方法。

class B(A):
    def __init__(self, name, phone):
        A.__init__(self)
        self.name = name
        self.phone = phone

所以,典型的非绑定方式调用函数如下:

MyClass.method(instance)

静态方法(staticmethod) 和 类方法(classmethod)

class TestStaticMethod(object):
    @staticmethod
    def foo():
        print "calling static method foo()"

class TestClassMethod(object):
    @classmethod
    def foo(cls):
        print "calling class method foo()"
        print "foo() is part of class: ", cls.__name__

TestStaticMethod.foo()
TestClassMethod.foo()

执行效果如下:

>>> execfile("./1.py")
calling static method foo()
calling class method foo()
foo() is part of class:  TestClassMethod

方法解释顺序(MRO: Method Resolution Order)

经典类,使用深度优先算法。
新式类,使用新的C3算法,广度优先,子类在前,父类在后。

新式类有一个 __mro__ 属性,告诉你查找顺序是怎样的。

类、实例 和 其他对象的内建函数

issubclass(son, parent)

判断一个类是否是另一个类的子类或子孙类.
从Python2.3开始,issubclass()的第二个参数可以是一个元组(tuple)。这时,只要第一个参数是给定元组中任何一个类的子类,就会返回True.

isinstance(obj, cls)

如果obj是类cls的一个实例,或者是cls的子类的一个实例,就返回True.

isinstance()也可以使用一个元组作为第二个参数。如果第一个参数是第二个参数(元组)中的任何一个类的实例,就返回True.

hasattr(), getattr(), setattr(), delattr()

*attr()系列函数可以在各种对象下工作,不限于类和实例。第一个参数是需要被处理的对象,第二个参数是某属性名字的字符串。

  • hasattr(obj, attr): 检查某个对象是否具有某个特定的属性。
  • getattr(obj, attr[, default]): 取得某个对象的某属性值。
  • setattr(obj, attr, val): 要么加入一个新的属性,要么取代一个已存在的属性。
  • delattr(obj, attr): 从一个对象中删除属性。

dir(obj=None)

  • dir()作用在实例上(经典类或新式类)时,显示实例变量,还有实例所在的类以及所有它的基类中定义的方法和类属性;
  • dir()作用在类上(经典类或新式类)时,则显示类以及它的所有基类的__dict__中的内容;不会显示定义在元类(metaclass)中的类的属性;
  • dir()作用在模块上时,显示模块的__dict__的内容;
  • dir()不带参数时,显示调用者的局部变量。

super()

另有博文详述。

vars(obj=None)

vars()内建函数与dir()相似,只是给定的对象参数都必须有一个__dict__属性。
vars()返回一个字典,包含了对象存储于其__dict__中的属性(key)和值。

如果vars()不带参数,则显示一个包含本地名字空间的属性(key)及其值的字典,也就是locals().

迭代器 (用类实现)

先看示例代码randSeq.py:

from random import choice

class RandSeq(object):
    def __init__(self, seq):
        self.data = seq

    def __iter__(self):
        return self

    def next(self):
        return choice(self.data)

以上代码中,重要的是函数__iter__(), 它仅返回self,就正是如何将一个对象声明为迭代器的方式;
最后调用next()来得到迭代器中连续的值。这个迭代器是一个没有终点的迭代器。

__slots__ 类属性

用户可以用__slots__属性代替__dict__.
基本上,__slots__是一个类变量,由一个序列型对象组成,由所有合法标识构成的实例属性的集合来表示。它可以是一个列表、元组或可迭代对象,也可以是标识实例能拥有的唯一的属性的简单字符串。
任何试图创建一个其名不在__slots__中的名字的实例属性都将导致AttributeError异常。

class SlottedClass(object):
    __slots__ = ('foo', 'bar')

>>> c = SlottedClass()
>>> c.xxx = "don't think so"
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'SlottedClass' object has no attribute 'xxx'

这种特性的主要目的是节约内存。其副作用是某种类型的“安全”,它能防止用户随心所欲地动态增加实例的属性。
带__slots__的类定义不会包含__dict__了。

__getattribute__ 特殊方法

  • __getattr__(),它仅当属性无法在实例的 __dict__ 或 它的类的__dict__ ,或 祖先类的__dict__中找到时,才被调用。
  • __getattribute__ (), 执行对每一个属性的访问,无论是否能找到。
  • 如果类同时定义了__getattribute__()和 __getattr__() 方法,除非明确从__getattribute__()调用,或__getattribute__()引发了AttributeError异常,否则后者不会被调用。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值