5.8. 类属性介绍
Description: Python from novice to pro
Keywords: Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free

# 深入 Python :Dive Into Python 中文版 Python 从新手到专家 [Dip_5.4b_CPyUG_Release] | Find:

## 5.8. 类属性介绍

你已经知道了数据属性，它们是被一个特定的类实例所拥有的变量。Python 也支持类属性，它们是由类本身所拥有的。

### 例 5.17. 类属性介绍

    class MP3FileInfo(FileInfo):
        "store ID3v1.0 MP3 tags"
        tagDataMap = {"title"   : (  3,  33, stripnulls),
                      "artist"  : ( 33,  63, stripnulls),
                      "album"   : ( 63,  93, stripnulls),
                      "year"    : ( 93,  97, stripnulls),
                      "comment" : ( 97, 126, stripnulls),
                      "genre"   : (127, 128, ord)}

    >>> import fileinfo
    >>> fileinfo.MP3FileInfo
    <class fileinfo.MP3FileInfo at 01257FDC>
    >>> fileinfo.MP3FileInfo.tagDataMap
    {'title': (3, 33, <function stripnulls at 0260C8D4>),
    'genre': (127, 128, <built-in function ord>),
    'artist': (33, 63, <function stripnulls at 0260C8D4>),
    'year': (93, 97, <function stripnulls at 0260C8D4>),
    'comment': (97, 126, <function stripnulls at 0260C8D4>),
    'album': (63, 93, <function stripnulls at 0260C8D4>)}
    >>> m = fileinfo.MP3FileInfo()
    >>> m.tagDataMap
    {'title': (3, 33, <function stripnulls at 0260C8D4>),
    'genre': (127, 128, <built-in function ord>),
    'artist': (33, 63, <function stripnulls at 0260C8D4>),
    'year': (93, 97, <function stripnulls at 0260C8D4>),
    'comment': (97, 126, <function stripnulls at 0260C8D4>),
    'album': (63, 93, <function stripnulls at 0260C8D4>)}

| `MP3FileInfo` 是类本身，不是任何类的特别实例。
| `tagDataMap` 是一个类属性：字面的意思，一个类的属性。它在创建任何类实例之前就有效了。
| 类属性既可以通过直接对类的引用，也可以通过对类的任意实例的引用来使用。

在 Java 中，静态变量 (在 Python 中叫类属性) 和实例变量 (在 Python 中叫数据属性) 两者都是紧跟在类定义之后定义的 (一个有 `static` 关键字，一个没有)。在 Python 中，只有类属性可以定义在这里，数据属性定义在 `__init__` 方法中。

类属性可以作为类级别的常量来使用 (这就是为什么我们在 `MP3FileInfo` 中使用它们)，但是它们不是真正的常量。你也可以修改它们。

在 Python 中没有常量。如果你试图努力的话什么都可以改变。这一点满足 Python 的核心原则之一：坏的行为应该被克服而不是被取缔。如果你真正想改变 `None` 的值，也可以做到，但当无法调试的时候别来找我。

### 例 5.18. 修改类属性

    >>> class counter:
    ...     count = 0
    ...     def __init__(self):
    ...         self.__class__.count += 1
    ...
    >>> counter
    <class __main__.counter at 010EAECC>
    >>> counter.count
    0
    >>> c = counter()
    >>> c.count
    1
    >>> counter.count
    1
    >>> d = counter()
    >>> d.count
    2
    >>> c.count
    2
    >>> counter.count
    2

| `count` 是 `counter` 类的一个类属性。
| `__class__` 是每个类实例的一个内置属性 (也是每个类的)。它是一个类的引用，而 `self` 是一个类 (在本例中，是 `counter` 类) 的实例。
| 因为 `count` 是一个类属性，它可以在我们创建任何类实例之前，通过直接对类引用而得到。
| 创建一个类实例会调用 `__init__` 方法，它会给类属性 `count` 加 `1`。这样会影响到类自身，不只是新创建的实例。
| 创建第二个实例将再次增加类属性 `count`。注意类属性是如何被类和所有类实例所共享的。