Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Python列表继承后重写append方法_Python_List_Inheritance - Fatal编程技术网

从Python列表继承后重写append方法

从Python列表继承后重写append方法,python,list,inheritance,Python,List,Inheritance,我想创建一个只能接受某些类型的列表。因此,我尝试从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'

我想创建一个只能接受某些类型的列表。因此,我尝试从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)
这当然会导致一个无限循环,因为append()的主体会调用自身,但我不确定除了使用self.append(item)之外还能做什么


我应该怎么做呢?

而不是
self.append(item)
使用
super(TypedList,self)。通过不首先执行来追加(item)

如果你不想在你的列表中出现X类型的东西,为什么要把它放在那里

这不是一个讽刺的回应。在尝试时添加类型限制不是不必要的,就是肯定会适得其反。然而,这是来自具有严格编译时类型检查的语言背景的人的常见请求

出于同样的原因,您不会尝试使用
“字符串”/2.0
,您可以控制列表中的内容。由于列表将乐于包含异构类型,因此运行时TypedList
最多会将运行时TypeError从使用该项的时间点向前移动到将其附加到列表的位置。给定Python的显式检查
isinstance
会阻止以后扩展列表以包含非
type
实例,但不会提供任何好处

添加了订单信息


假设Python2.7或更高版本可以满足注释中的每个请求。根据该文档页,如果您使用的是2.4或更高版本。

我已经对您的类进行了一些更改。这似乎奏效了

一些建议:不要将
type
用作关键字-
type
是一个内置函数。Python实例变量是使用
self.
前缀访问的。因此,请使用
self.

类类型列表(列表):
定义初始化(自我,类型):
self.type=type
def附加(自身,项目):
如果不存在(项目,自我类型):
raise TypeError,“项不是%s“%self.type”类型
super(TypedList,self).append(项目)#将项目附加到自身(列表)
从类型导入*
tl=类型列表(StringType)
tl.append('abc')
tl.append(无)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
tl.append(无)
文件“”,第7行,追加
raise TypeError,“项不是%s“%self.type”类型
TypeError:项不是类型
我想创建一个只能 接受某些类型。因此,我 正在尝试从中的列表继承 蟒蛇

不是最好的方法!Python列表中有太多的变异方法,所以您必须重写一堆(并且可能会忘记一些)

相反,包装一个列表,从
集合.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)
oktypes
参数通常是您想要允许的类型的元组,但是在那里传递一个类型当然是可以的(并且,通过将一个类型设置为抽象基类ABC,您可以轻松地执行您选择的任何类型的类型检查——但是,这是另一个问题)

下面是使用此类的一些示例代码:

x = TypedList((str, unicode), 'foo', 'bar')
x.append('zap')
print x
x.append(23)
输出为:

['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
['foo','bar','zap']
回溯(最近一次呼叫最后一次):
文件“tl.py”,第35行,在
x、 追加(23)
文件“/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_abcoll.py”,第556行,在附录中
self.insert(len(self),值)
文件“tl.py”,第25行,插入
自我检查(五)
检查文件“tl.py”,第12行
提升类型错误,v
打字错误:23
特别要注意的是,我们有被覆盖的
追加
——但追加仍然存在,其行为与预期一样

这一魔法背后的秘密在回溯中被揭示出来:
\u abcoll.py
(集合模块中抽象基类的实现模块),在第556行,通过调用我们的
插入
来实现
追加——当然,我们已经正确地覆盖了它

这种“模板方法设计模式”(对于所有类型的OOP来说都是非常宝贵的——在youtube上查找我关于设计模式的演讲,你会发现原因;-)以及其他优势,给我们带来了我前面提到的“瓶颈效应”:通过在必须实现的极少数方法上添加一些检查,您获得的优势是,这些检查适用于所有其他相关方法(Python中的可变序列有很多;-)

毫不奇怪,我们最终得到了一个非常强大和经典的设计模式“幕后”,因为这个实现策略背后的整个思想都来自不朽的经典“设计模式”一书(其作者通常被统称为“四人帮”;-):更喜欢对象组合而不是继承。继承(来自具体类)是一种非常严格的耦合机制,充满了“陷阱”“只要你想用它做任何事情,哪怕只是稍微超出它严格的限制;合成是非常灵活和有用的,从适当的抽象类继承可以很好地完成这一过程

Scott Meyers出色的“高效C++”甚至更为有力地指出:将非叶类抽象化。因为“non-leaf”的意思是“任何继承自”的类,所以一个等价的短语应该是“从不继承自具体类”

<>史葛在C++上下文中当然是写的,但是对java给出了完全相同的建议,措辞为<强>不要子类具体类< /强> -我一般将它放在Python中,尽管我赞成四个组的软表达式,<强> > <强> >构图(具体类)继承
['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
from array import array
array('c', 'hello world')     # char array
array('u', u'hello \u2641')   # unicode array
array('l', [1, 2, 3, 4, 5])   # long array
array('d', [1.0, 2.0, 3.14])  # double array
chars = array('c')            
chars.extend('foo')
>>> chars.extend([5,10])
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
TypeError: array item must be char  
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 ])