2.1.2.4 标准类库中的实例

首先,应该说明,在标准类库中有一些有用的修饰器。有三类装饰器确实构成了语言的一部分:

  • classmethod 造成函数成为“类方法”,这意味着不需要创建类的实例就可以激活它。当普通的方法被激活后,解释器将插入一个实例对象作为第一个位置参数,self。当类方法被激活后,类自身被作为一点参数,通常称为cls

类方法仍然可以通过类的命名空间访问,因此,他们不会污染模块的命名空间。类方法可以用来提供替代的构建器:

In [1]:

  1. class Array(object):
  2. def __init__(self, data):
  3. self.data = data
  4. @classmethod
  5. def fromfile(cls, file):
  6. data = numpy.load(file)
  7. return cls(data)
  1. 这是一个清洁器,然后使用大量的标记来`__init__`
  • staticmethod用来让方法“静态”,即,从根本上只一个普通的函数,但是可以通过类的命名空间访问。当函数只在这个类的内部需要时(它的名字应该与_为前缀),或者当我们想要用户认为方法是与类关联的,尽管实施并不需要这样。

  • property是对getters和setters pythonic的答案。用property修饰过的方法变成了一个getter,getter会在访问属性时自动调用。

In [2]:

  1. class A(object):
  2. @property
  3. def a(self):
  4. "an important attribute"
  5. return "a value"

In [3]:

  1. A.a

Out[3]:

  1. <property at 0x104139260>

In [4]:

  1. A().a

Out[4]:

  1. 'a value'

在这个例子中,A.a是只读的属性。它也写入了文档:help(A)包含从getter方法中拿过来的属性的文档字符串。将a定义为一个属性允许实时计算,副作用是它变成只读,因为没有定义setter。

要有setter和getter,显然需要两个方法。从Python 2.6开始,下列语法更受欢迎:

In [5]:

  1. class Rectangle(object):
  2. def __init__(self, edge):
  3. self.edge = edge
  4. @property
  5. def area(self):
  6. """Computed area.
  7. Setting this updates the edge length to the proper value.
  8. """
  9. return self.edge**2
  10. @area.setter
  11. def area(self, area):
  12. self.edge = area ** 0.5

这种方式有效是因为property修饰器用property对象替换getter方法。这个对象反过来有三个方法,gettersetterdeleter,可以作为修饰器。他们的任务是设置property对象的getter、 setter和deleter(存储为fgetfsetfdel属性)。当创建一个对象时,getter可以像上面的例子中进行设置。当定义一个setter,我们已经在area下有property对象,我们通过使用setter方法为它添加setter。所有的这些发生在我们创建类时。

接下来,当类的实例被创建后,property对象是特别的,当解释器执行属性访问,属性赋值或者属性删除时,任务被委托给property对象的方法。

为了让每个事情都清晰,让我们定义一个“debug”例子:

In [6]:

  1. class D(object):
  2. @property
  3. def a(self):
  4. print "getting", 1
  5. return 1
  6. @a.setter
  7. def a(self, value):
  8. print "setting", value
  9. @a.deleter
  10. def a(self):
  11. print "deleting"

In [7]:

  1. D.a

Out[7]:

  1. <property at 0x104139520>

In [8]:

  1. D.a.fget

Out[8]:

  1. <function __main__.a>

In [9]:

  1. D.a.fset

Out[9]:

  1. <function __main__.a>

In [10]:

  1. D.a.fdel

Out[10]:

  1. <function __main__.a>

In [12]:

  1. d = D() # ... varies, this is not the same `a` function
  2. d.a
  1. getting 1

Out[12]:

  1. 1

In [13]:

  1. d.a = 2
  1. setting 2

In [14]:

  1. del d.a
  1. deleting

In [15]:

  1. d.a
  1. getting 1

Out[15]:

  1. 1

属性是修饰语语法的极大扩展。修饰器语法的一个前提-名字不可以重复-被违背了,但是,到目前位置没有什么事变糟了。为getter、setter和deleter方法使用相同的名字是一个好风格。

一些更新的例子包括:

  • functools.lru_cache 记忆任意一个函数保持有限的arguments\:answer对缓存(Python 3.2)
  • functools.total_ordering是一类修饰器,根据单一的可用方法(Python 2.7)补充缺失的顺序方法(lt, gt, le, …)。