在Python中对集合进行子类化时定义u_repr_u_u
我试图在Python中对在Python中对集合进行子类化时定义u_repr_u_u,python,set,subclassing,Python,Set,Subclassing,我试图在Python中对set对象进行子类化,使用类似于下面的代码,但我无法为要使用的\uuu repr\uu制定合理的定义 class Alpha(set): def __init__(self, name, s=()): super(Alpha, self).__init__(s) self.name = name 我想定义\uuuu repr\uuuu,以便获得以下输出: >>> Alpha('Salem', (1,2,3)) A
set
对象进行子类化,使用类似于下面的代码,但我无法为要使用的\uuu repr\uu
制定合理的定义
class Alpha(set):
def __init__(self, name, s=()):
super(Alpha, self).__init__(s)
self.name = name
我想定义\uuuu repr\uuuu
,以便获得以下输出:
>>> Alpha('Salem', (1,2,3))
Alpha('Salem', set([1, 2, 3]))
但是,如果我不重写\uuuu repr\uuuu
,我得到的输出将忽略名称
值
>>> Alpha('Salem', (1,2,3))
Alpha([1, 2, 3])
…如果我重写\uuuu repr\uuuu
,则在不创建新集合实例的情况下,无法直接访问集合中的值:
class Alpha(set):
…
def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__, self.name, set(self))
这是可行的,但是为\uu repr\uuu
创建一个新的set实例,然后将其处理,对我来说似乎既笨拙又低效
有没有更好的方法来定义这种类的\uuuuu repr\uuuu
编辑:我想到的另一个解决方案是:我可以在本地存储集合。它似乎比其他选项(为每次调用\uuu repr\uuu\uu
创建和销毁某些内容或使用某种形式的字符串操作)稍微整洁一些,但对我来说仍然不太理想
class Alpha(set):
def __init__(self, name, s=()):
super(Alpha, self).__init__(s)
self.name = name
self._set = set(s)
def __repr__(self):
return "%s(%r, %r)" % (self.__class__.__name__, self.name, self._set)
我找不到比这更好的办法了。不过我想这比扔掉一套要好 (Python 2.x) 或者,如果您不喜欢硬编码的类名(尽管这真的不重要)
我想除了展示一些基准之外,我还有一些东西可以满足你的需求。它们几乎都是等价的,尽管我确信内存使用上存在差异
#!/usr/bin/env python
import time
class Alpha(set):
def __init__(self, name, s=()):
super(Alpha, self).__init__(s)
self.name = name
def __repr__(self):
return '%s(%r, set(%r))' % (self.__class__.__name__,
self.name,
list(self))
class Alpha2(set):
def __init__(self, name, s=()):
super(Alpha2, self).__init__(s)
self.name = name
def __repr__(self):
return '%s(%r, set(%r))' % (self.__class__.__name__,
self.name,
set(self))
class Alpha3(set):
def __init__(self, name, s=()):
super(Alpha3, self).__init__(s)
self.name = name
def __repr__(self):
rep = super(Alpha3, self).__repr__()
rep = rep.replace(self.__class__.__name__, 'set', 1)
return '%s(%r, %s)' % (self.__class__.__name__,
self.name,
rep)
def timeit(exp, repeat=10000):
results = []
for _ in xrange(repeat):
start = time.time()
exec(exp)
end = time.time()-start
results.append(end*1000)
return sum(results) / len(results)
if __name__ == "__main__":
print "Alpha(): ", timeit("a = Alpha('test', (1,2,3,4,5))")
print "Alpha2(): ", timeit("a = Alpha2('test', (1,2,3,4,5))")
print "Alpha3(): ", timeit("a = Alpha3('test', (1,2,3,4,5))")
结果:
Alpha():0.0287627220154
Alpha2():0.0286467552185
Alpha3():0.028522552969如果子类尝试调用
\uuuu init\uuu
,那么调用super
的方式将得到无限递归。super
显式接受类的原因是它知道在方法解析顺序(MRO)中继续的位置。传递Alpha
(或者如果这是标签所指示的3.x,只需使用super()
-它以某种方式做正确的事情)。@delnan:Dang。谢谢你。我当时认为我是在聪明地避免显式指定类。@delnan:出于某种原因,Sven Marnach Brily将这个问题标记为Python 3.x。实际上,我使用的是Python2.6。关于最后一次编辑:我认为您应该避免将集合的副本保存在私有属性中,因为这样您就需要保持它的同步。要做到这一点,您仍然需要在每次需要报告时进行复制。对于这种方法,您可能需要将所有set方法调用转发到私有集,并将其完全用作您的数据。是的,我选择使用list()
,因为这似乎是最简单的,但显然这一点都不重要。我愿意打赌,内存方面,第一个和第二个的效率较低,因为它们正在实例化和丢弃对象。但这只是一个假设,没有实际检查内存/cpu。第三个示例仅获取一个字符串并对其进行重新格式化。我想这是一个问题,set()
或list()
比Alpha3
的两个调用快(基准测试可能会说是)。list()肯定比set()更有效。字符串替换比set()稍微好一点,但为他提供了所需的确切格式。因此,这是一个折腾:我觉得所有这些都不太合适:创建和丢弃实例对于较大的列表来说要昂贵得多,而字符串编辑感觉非常脆弱和“不和谐”。我不会硬编码类名,而是使用self.\uu class.\uu name.\uuu
(像我一样)@gecco:个人偏好。我看不出不硬编码它有多大意义(除非您将有子类化它的类),特别是在某些地方仍然需要它(超级调用)。无论如何,这很容易改变。但是我已经添加了非硬编码的版本以及根据请求添加的版本。我同意@JohnDoe。当您已经需要为super()调用显式使用类名时,我认为这并不重要。但它确实更具动态性。@JohnDoe:我绝对会让类子类化这个类,所以在这里使用动态名称更有意义。
>>> class Alpha(set):
... def __init__(self, name, s=()):
... super(Alpha, self).__init__(s)
... self.name = name
... def __repr__(self):
... return '%s(%r, set(%r))' % (self.__class__.__name__, self.name, list(self))
...
>>> Alpha('test', (1, 2))
Alpha('test', set([1, 2]))
#!/usr/bin/env python
import time
class Alpha(set):
def __init__(self, name, s=()):
super(Alpha, self).__init__(s)
self.name = name
def __repr__(self):
return '%s(%r, set(%r))' % (self.__class__.__name__,
self.name,
list(self))
class Alpha2(set):
def __init__(self, name, s=()):
super(Alpha2, self).__init__(s)
self.name = name
def __repr__(self):
return '%s(%r, set(%r))' % (self.__class__.__name__,
self.name,
set(self))
class Alpha3(set):
def __init__(self, name, s=()):
super(Alpha3, self).__init__(s)
self.name = name
def __repr__(self):
rep = super(Alpha3, self).__repr__()
rep = rep.replace(self.__class__.__name__, 'set', 1)
return '%s(%r, %s)' % (self.__class__.__name__,
self.name,
rep)
def timeit(exp, repeat=10000):
results = []
for _ in xrange(repeat):
start = time.time()
exec(exp)
end = time.time()-start
results.append(end*1000)
return sum(results) / len(results)
if __name__ == "__main__":
print "Alpha(): ", timeit("a = Alpha('test', (1,2,3,4,5))")
print "Alpha2(): ", timeit("a = Alpha2('test', (1,2,3,4,5))")
print "Alpha3(): ", timeit("a = Alpha3('test', (1,2,3,4,5))")