Size: 6713
Comment:
|
← Revision 6 as of 2009-12-25 07:18:49 ⇥
Size: 6713
Comment: converted to 1.6 markup
|
No differences found! |
:status: 草稿|校对|正式;HuangYi;完成度60%; .. contents:: :depth: 3 ======== 类与实例 ======== 通常大家说的是"类与对象",不过 python 中万物皆"对象",对象这个词语的含义太宽泛。 实际上我们这里要讨论的只是用户自定义的类和这些类的实例而已,类及其实例都只是对象这个大家族中的一员。 定义类 ------ :: >>> class Klass(object): ... ' docstring... ' ... def __init__(self, a): ... self.attr_a = a ... >>> Klass.__doc__ ' docstring... ' >>> obj = Klass(1) >>> obj.attr_a 1 关键字 ``class`` 定义一个类, ``Klass`` 是类的名字,括号中 ``object`` 是它的基类, python 中所有的 ``class`` 都是从 ``object`` 继承而来 (虽然在目前的 python 版本中还存在一类所谓的 old-style class ,他们是不从 ``object`` 继承而来的,不过这只是为了保持向后兼容性并且很快就要在 python3.0 中彻底退出历史舞台,所以我们这里直接忽略它了)。 和许多语言不同的是,python 中构造函数叫做 ``__init__`` ,第一个参数传递的就是将要初始化的实例对象本身,类似许多语言中的 ``this`` 。 和函数一样,class 也可以定义文档字符串,同样是通过 ``__doc__`` 访问。 创建实例对象并不需要学习新的语法,创建实例和函数调用一摸一样。传给 ``Klass`` 的参数最终传给构造函数 ``__init__`` ,而返回值便是新创建的实例对象。 属性 ---- 在构造函数中的 ``self.attr_a = a`` 便给 ``self`` 这个对象增加了一个名为 ``attr_a`` 的属性,其绑定的对象就是传入的参数 ``a`` 所绑定的对象。 对象的 ``__dict__`` 属性可以让你以字典的方式查看对象的所有属性::: >>> obj.__dict__ {'attr_a': 1} 不光在构造函数中,其实在任何时候你都可以给对象增加属性,你只需要给不存在的属性绑定对象即可,python 会自动创建不存在的属性::: >>> obj.attr_b = 1 >>> obj.attr_b 1 >>> obj.__dict__ {'attr_b': 1, 'attr_a': 1} 讲到属性,需要明确的一个概念就是不光实例对象有属性,类也是对象,类自然也有属性!:: >>> class Klass1(object): ... ' docstrign... ' ... class_attr1 = 'hello' ... def __init__(self, a): ... self.attr_a = a ... >>> Klass1.class_attr1 'hello' 我们也可以使用 ``__dict__`` 来查看类对象的所有属性: >>> from pprint import pprint >>> pprint(dict(Klass1.__dict__)) {'__dict__': <attribute '__dict__' of 'Klass1' objects>, '__doc__': ' docstrign... ', '__init__': <function __init__ at 0x00FBAEF0>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Klass1' objects>, 'class_attr1': 'hello'} class 的属性比较多,为了方便查看我们使用了 ``pprint`` 模块中的 ``pprint`` 方法,其功能是以更可读的方式输出一些复杂数据结构, 具体用法可以查看 python 自带手册。 当访问实例对象的属性时,如果属性不存在,将自动查找其对应的类对象的属性::: >>> obj1 = Klass1(1) >>> obj1.class_attr1 'hello' 类属性是和类对象的属性,同一个类对象的所有实例都共享同一份类属性::: >>> obj2 = Klass1(2) >>> Klass1.class_attr1 = 'changed' >>> obj1.class_attr1 'changed' >>> obj2.class_attr1 'changed' 方法 ---- :: >>> class Klass(object): ... def __init__(self, name): ... self.name = name ... def greet_to(self, name): ... print self.name, 'say hello to', name ... >>> obj = Klass('HuangYi') >>> obj.greet_to('you') HuangYi say hello to you >>> pprint(dict(Klass.__dict__)) {'__dict__': <attribute '__dict__' of 'Klass' objects>, '__doc__': None, '__init__': <function __init__ at 0x010122B0>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Klass' objects>, 'greet_to': <function greet_to at 0x010122F0>} 方法其实也是属性!准确地说还是属于类对象的属性。在 ``Klass`` 中我们定义了两个方法: 构造函数 ``__init__`` 和普通方法 ``greet_to`` 。 方法本质上说其实是对函数的一层简单包装,这层包装的作用就是将调用方法的这个对象当做第一个参数传进去, 所以在定义方法的时候千万别忘了声明第一个参数,按照约定,这个参数我们叫它 ``self`` 。:: >>> obj.greet_to <bound method Klass.greet_to of <__main__.Klass object at 0x0101C550>> >>> Klass.__dict__['greet_to'] <function greet_to at 0x010122F0> 直接通过实例对象 ``obj`` 访问属性 ``greet_to`` 时得到的其实是对这个函数包装后产生的"方法"。 直接通过 ``Klass.__dict__`` 取 ``greet_to`` 属性实际绑定的对象时,你得到的才是这个还没有经过包装的"纯净"的函数! >>> func = Klass.__dict__['greet_to'] >>> func(obj, 'you') HuangYi say hello to you 如果你要问这个包装是何时以及如何产生的,这其实又涉及到 python 中另一个相对高级的概念: Descriptors。 如果有兴趣可以查看 Raymond 写的精彩教程(http://users.rcn.com/python/download/Descriptor.htm),本书将不做更多介绍。 不过当我们认识到方法与函数的这一层关系后,我们已经可以利用它来实现一些有意思的功能了,比如在运行时给类添加方法::: >>> class Klass(object): ... pass ... >>> obj = Klass() >>> def print_id(obj): ... print id(obj) ... >>> Klass.print_id = print_id # 等价于 Klass.__dict__['print_id'] = print_id >>> obj.print_id() # 等价于 print_id(obj) 16892848 特殊属性 -------- 所谓特殊属性就是那些名字前后都是两个下划线的属性。这种属性往往都会被 python 特殊处理,用来实现一些特定功能用的。 所以定义你自己的属性时千万记得不要定义这种"风格"的属性。 构造析构函数 ============ 构造函数我们前面已经见识过了 ``__init__`` 便是,而析构函数叫做 ``__del__`` 。 TODO 介绍析构函数 操作符重载 ========== TODO 自定义属性访问 ============== TODO 继承 ---- 小结 ----- 练习 ----- .. macro:: [[PageComment2(nosmiley=1, notify=1)]] .. macro:: -- HuangYi [[[DateTime(2007-06-26T05:39:25Z)]]]