cha*_*ver 13 python inheritance list
我想创建一个只能接受某些类型的列表.因此,我试图从Python中的列表继承,并覆盖append()方法,如下所示:
class TypedList(list):
def __init__(self, type):
self.type = type
def append(item)
if not isinstance(item, type):
raise TypeError, 'item is not of type %s' % type
self.append(item) #append the item to itself (the list)
Run Code Online (Sandbox Code Playgroud)
这将导致无限循环,因为append()的主体调用自身,但我不知道除了使用self.append(item)之外还要做什么.
我该怎么做呢?
Ale*_*lli 47
我想创建一个只能接受某些类型的列表.因此,我试图从Python中的列表继承
不是最好的方法!Python列表有很多变异方法,你必须覆盖一堆(并且可能会忘记一些).
相反,包装一个列表,继承collections.MutableSequence并在极少数" MutableSequence依赖点"方法中添加您的检查,这些方法依赖于实现所有其他方法.
import collections
class TypedList(collections.MutableSequence):
def __init__(self, oktypes, *args):
self.oktypes = oktypes
self.list = list()
self.extend(list(args))
def check(self, v):
if not isinstance(v, self.oktypes):
raise TypeError, v
def __len__(self): return len(self.list)
def __getitem__(self, i): return self.list[i]
def __delitem__(self, i): del self.list[i]
def __setitem__(self, i, v):
self.check(v)
self.list[i] = v
def insert(self, i, v):
self.check(v)
self.list.insert(i, v)
def __str__(self):
return str(self.list)
Run Code Online (Sandbox Code Playgroud)
该oktypes说法通常是要允许类型的元组,但它的确定有通过单一类型的,当然(和,通过使一种类型的抽象基类,ABC,你可以轻松地执行任何种类的类型检查的您选择的方式 - 但是,这是一个不同的问题).
以下是使用此类的一些示例代码:
x = TypedList((str, unicode), 'foo', 'bar')
x.append('zap')
print x
x.append(23)
Run Code Online (Sandbox Code Playgroud)
输出是:
['foo', 'bar', 'zap']
Traceback (most recent call last):
File "tl.py", line 35, in <module>
x.append(23)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_abcoll.py", line 556, in append
self.insert(len(self), value)
File "tl.py", line 25, in insert
self.check(v)
File "tl.py", line 12, in check
raise TypeError, v
TypeError: 23
Run Code Online (Sandbox Code Playgroud)
特别注意我们没有覆盖append- 但是追加是存在的并且行为与预期一样.
在回溯中揭示了这一点魔法背后的不那么秘密:( _abcoll.py模块中抽象基类的实现collections模块),在第556行,通过调用我们实现追加insert- 当然,我们已经正确覆盖.
这种"模板方法设计模式"(对于各种OOP来说绝对珍贵 - 在youtube上寻找我对设计模式的讨论,你会发现原因;-),以及其他优点,给我们"阻塞点效应"我前面提到过:通过在必须实现的极少数方法上添加一些检查,你可以获得这些检查适用于_all__其他相关方法的优点(Python中的可变序列有很多这些;-).
毫不奇怪,我们最终得到了一个非常强大和经典的"幕后"设计模式,因为这个实施策略背后的整个理念来自不朽的经典"设计模式"一书(其作者通常统称为四个人的团队";-):更喜欢对象组合而不是继承.继承(来自具体类)是一种非常严格的耦合机制,一旦你试图用它来做任何事情,即使只是稍微外面,它就会充满"陷阱"它的严格限制;组合非常灵活和有用,从适当的抽象类继承可以很好地完成图片.
Scott Meyers的优秀"Effective C++",第33项,更强烈地说:使非叶类抽象化.因为"非叶子"他的意思是"任何曾经继承过的阶级",所以相同的措词将是"永远不会从具体阶级继承".
当然,Scott正在用C++语言写作,但是Paul Haahr对Java给出了完全相同的建议,表达为不要具体类的子类 - 我通常将它用于Python,尽管我赞成四人组合更柔和的措辞,更喜欢构成而不是(具体阶级)继承(但我明白斯科特和保罗都经常为观众写作,需要非常直接和强烈措辞的建议,几乎被称为"诫命"而不是建议,而不是更柔和的措辞他们可能太容易忽视他们的便利;-).
Man*_*dan 17
我对你的班级做了一些改动.这似乎有效.
一些建议:不要type用作关键字 - type是内置函数.使用self.前缀访问Python实例变量.所以使用self.<variable name>.
class TypedList(list):
def __init__(self, type):
self.type = type
def append(self, item):
if not isinstance(item, self.type):
raise TypeError, 'item is not of type %s' % self.type
super(TypedList, self).append(item) #append the item to itself (the list)
from types import *
tl = TypedList(StringType)
tl.append('abc')
tl.append(None)
Traceback (most recent call last):
File "<pyshell#25>", line 1, in <module>
tl.append(None)
File "<pyshell#22>", line 7, in append
raise TypeError, 'item is not of type %s' % self.type
TypeError: item is not of type <type 'str'>
Run Code Online (Sandbox Code Playgroud)
虽然我喜欢@Alex Martini 的答案,但不幸的是,它对于大多数情况来说并不实用。在标准库和其他库代码中,有太多的东西期望列表类型继承自list. 除非您为您的类型编写自己的序列化方法,否则 您甚至不能不json.dumps()继承。list
我不同意@msw,因为你可能想在库中公开类似的东西,而无法控制其他代码。
不幸的是,该类list不允许您像 Alex 的示例中那样重写单个函数。以下内容覆盖可能添加到列表中的所有函数(有关所有列表函数,请参阅此处: https: //docs.python.org/2/library/stdtypes.html#mutable-sequence-types)。
import collections
class CheckedList(list, collections.MutableSequence):
def __init__(self, check_method, iterator_arg=None):
self.__check_method = check_method
if not iterator_arg is None:
self.extend(iterator_arg) # This validates the arguments...
def insert(self, i, v):
return super(CheckedList, self).insert(i, self.__check_method(v))
def append(self, v):
return super(CheckedList, self).append(self.__check_method(v))
def extend(self, t):
return super(CheckedList, self).extend([ self.__check_method(v) for v in t ])
def __add__(self, t): # This is for something like `CheckedList(validator, [1, 2, 3]) + list([4, 5, 6])`...
return super(CheckedList, self).__add__([ self.__check_method(v) for v in t ])
def __iadd__(self, t): # This is for something like `l = CheckedList(validator); l += [1, 2, 3]`
return super(CheckedList, self).__iadd__([ self.__check_method(v) for v in t ])
def __setitem__(self, i, v):
if isinstance(i, slice):
return super(CheckedList, self).__setitem__(i, [ self.__check_method(v1) for v1 in v ]) # Extended slice...
else:
return super(CheckedList, self).__setitem__(i, self.__check_method(v))
def __setslice__(self, i, j, t): # NOTE: extended slices use __setitem__, passing in a tuple for i
return super(CheckedList, self).__setslice__(i, j, [ self.__check_method(v) for v in t ])
Run Code Online (Sandbox Code Playgroud)
而不是self.append(item)使用super(TypedList, self).append(item)(请参阅http://docs.python.org/library/functions.html#super)