文章来自《Python cookbook》.

翻译仅仅是为了个人学习,其它商业版权纠纷与此无关!

-- 61.182.251.99 [DateTime(2004-10-09T23:27:13Z)] TableOfContents

描述

Overriding a Built-In Method

覆盖内建方法

Credit: Dave Haynes

问题 Problem

You need to wrap (or, in Python 2.2, inherit from) a list or tuple, delegating several operations to it, and want to provide proper slicing (i.e., through the special method _ _getitem_ _).

需要包装(或者在python 2.2 中使用继承)list或tuple,代理它们的一些操作, 同时提供正确的slice切片分块行为(使用方法 getitem).

解决 Solution

In most cases, overriding special methods of built-in objects when you inherit from those objects (or wrap them with automatic delegation, which is not technically an override) poses no special challenge. When inheriting in Python 2.2, you can call the special method of the superclass with the usual unbound-method syntax. When wrapping, use the syntax that is specific to the operation, such as self.data[someindex] for indexing.

多数情形下, 运用继承或者封装代理操作(技术上这样不是覆盖)来覆盖内建对象的特定方法没有什么挑战。 在python 2.2中运用继承方法,可以调用基类的具有各种方法签名的特定方法。运用封装的方法,应该使用对应于操作的具有特定方法签名的函数,例如,索引操作应具有如下形式: self.data[someindex]。

Slicing is harder, because while slicing should go through the same special method _ _getitem_ _ as indexing (since Python 2.0), lists and tuples still implement an older approach: the more limited special method _ _getslice_ _ (and similarly for _ _setitem_ _ versus _ _setslice_ _ and _ _delitem_ _ versus _ _delslice_ _). So, you must provide a remedy, normally with a try/except:

实现切片分块困难些, 正常情况下切片分块应该使用与索引操作相同的方法getitem(python 2.0以后)。不过,由于 list和tuple仍然保留了slice的旧方法:受限制的特别的getslice方法(相对于setitemsetslice,相对于delitemdelslice ), 因此, 必须提供一个措施来解析方法调用,一般使用 try/except:

   1 class SliceTester:
   2     def _ _init_ _(self):
   3         self.data = ['zero', 'one', 'two', 'three', 'four']
   4 
   5     def  _ _getitem_ _(self, indexOrSlice):
   6         try:
   7             return self.data[indexOrSlice]
   8         except TypeError:
   9             return self.data[indexOrSlice.start:indexOrSlice.stop]

讨论 Discussion

When a user-defined class wraps (or, in Python 2.2, inherits from) a list or tuple, it often needs to define the _ _set*_ _ and _ _get*_ _ special methods and delegate part or all of their operation to the wrapped (or inherited) built-in object to provide the correct access to the data.

当封装(python2.2中,用继承)list或者tuple,生成自定义类型时, 一般需要定义特殊的set*get*方法,代理一些(全部)此类操作到被封装的内置对象, 由被封装对象提供对底层数据的正确访问。

The documentation for Python 2.0 and later deprecates the use of _ _getslice_ _ and _ _setslice_ _. Instead, it suggests providing suitably extended versions of _ _getitem_ _ and _ _setitem_ _. This is a truly excellent idea because it enables the use of the extended-form slicing approaches (including step, ellipsis, and so on) that Numeric Python has made so deservedly popular among its regular users. Unfortunately, if you try to pass a slice object to the item-oriented special methods of a list or tuple object, you get a TypeError; the underlying C API still insists on receiving integer parameters, not slice objects in all their glory, whatever the documentation may say.

Fortunately, working around this problem isn't as dramatic as all that. You just need to trap the TypeError you get from trying to index an old-fashioned sequence with a slice, and remedy it suitably. Here's the typical self-test code that you can append to the recipe's module and execute when it is run as a main script:

   1 if _ _name_ _ == "_ _main_ _":
   2     theSlice = SliceTester(  )
   3     a = theSlice[2]
   4     b = theSlice[:3]
   5     print a
   6     print b

In the recipe's SliceTester example class, the remedy is pretty minimal; it's just an attempt to use start and stop attributes of the noninteger index (presumably an instance of the slice built-in type). You may want to do a lot more (implement step, ellipsis, and so on).

Note that this recipe doesn't cover all of the cases in which slices can be used. There is a third argument to the slice operator that defines the step, or stride, of the slicing. For example, if data is a Numeric Python array (the only widely used software that supports slicing in all its glory), data[0:101:10] returns the sequence data[0], data[10], data[20]梪p to data[100]. Similarly, data[::-1] returns a sequence containing the contents of data reversed. The third argument to the slice operator is stored in the step attribute of slice objects and is set to None if a step isn't specified (as in list[start:end]). Given this, it shouldn't be a surprise that the recipe shown earlier will not magically add support for steps to objects that don't support new-style slices.

The point of this recipe is that you must be aware of these limitations and take precautionary measures. Also, don't type-test for an index of type slice. If normal indexing refuses the index, you are better off catching the TypeError in an except clause and entering another try/except in which you try to use the index as the slice you now expect it to be. This lets client code pass you objects that are polymorphic to slice objects.

参考 See Also

The section of the Language Reference on slicing; the description of the slice built-in function in the Library Reference.