我正在尝试编写一个类似于一个集合的类,其中包含可以想象的每个可能的对象。这将允许我通过连续的交叉点整齐地精炼集合。例如。如果我有这个对象的构造函数,让我们称之为UniversalSet(),然后我想做类似以下的事情:
myset = UniversalSet()
for subset in subsets:
myset = myset & subset
最终的myset
对象将是set
中所有subset
个对象的交集。
现在我知道还有其他方法可以实现上述目标,但部分是作为一项智力练习,部分是因为我认为这有可能重用,我实施了以下内容:
class UniversalSet(set):
"""
A set that contains every object.
As we don't know what every object consists of, we just assume that
adding anything doesn't change it, and testing for anything in that
set returns true.
Use case is for continual refinement, e.g.:
myset = UniversalSet()
for subset in subsets:
myset = myset & subset
"""
def __and__(self,other):
if type(other) is UniversalSet:
return self
elif type(other) is set:
return other
raise TypeError('Cannot "and" UniversalSet with non-set')
def __contains__(self,elem):
return True
def __eq__(self,other):
if type(other) is UniversalSet:
return True
elif type(other) is set:
return False
raise TypeError(
'Cannot compare UniversalSet with non-set')
def __ge__(self,other):
if type(other) is UniversalSet:
return True
elif type(other) is set:
return True
raise TypeError(
'Cannot compare UniversalSet with non-set')
def __gt__(self,other):
if type(other) is UniversalSet:
return False
elif type(other) is set:
return True
raise TypeError(
'Cannot compare UniversalSet with non-set')
def __iand__(self,other):
self = self.__and__(other)
return self
def __init__(self):
super(UniversalSet,self).__init__([])
def __ior__(self,other):
if type(other) is UniversalSet:
return self
elif type(other) is set:
return self
raise TypeError('Cannot "or" UniversalSet with non-set')
def __isub__(self,other):
raise TypeError('Cannot subtract from universal set')
def __iter__(self):
raise TypeError('Cannot iterate through universal set')
def __ixor__(self,other):
raise TypeError('Cannot ixor universal set')
def __le__(self):
if type(other) is UniversalSet:
return True
elif type(other) is set:
return False
raise TypeError(
'Cannot compare UniversalSet with non-set')
def __len__(self):
return self.len()
def len(self):
return int_inf.IntegerInfinity()
def __lt__(self,other):
if type(other) is UniversalSet:
return False
elif type(other) is set:
return False
raise TypeError(
'Cannot compare UniversalSet with non-set')
def __repr__(self):
return 'UniversalSet()'
def __str__(self):
return 'UniversalSet()'
def __sub__(self,other):
raise TypeError('Cannot subtract from universal set')
def __or__(self,other):
if type(other) is UniversalSet:
return self
elif type(other) is set:
return self
raise TypeError('Cannot or UniversalSet with non-set')
您会注意到len
函数使用特殊对象,因为普通的无限对象不是int
所需的类型。所以我实现了额外的IntegerInfinity
对象。这是:
import numpy as np
class IntegerInfinity(int):
def __eq__(self,other):
if type(other) is IntegerInfinity:
return True
return False
def __ge__(self,other):
if type(other) is IntegerInfinity:
return True
if other == np.inf:
return False
elif type(other) is float or type(other) is int:
return True
raise TypeError(
'Cannot compare type %r with IntegerInfinity' % type(other))
def __gt__(self,other):
if type(other) is IntegerInfinity:
return False
elif other == np.inf:
return False
elif type(other) is float or type(other) is int:
return True
raise TypeError(
'Cannot compare type %r with IntegerInfinity' % type(other))
def __le__(self,other):
if type(other) is IntegerInfinity:
return True
if other == np.inf:
return True
elif type(other) is float or type(other) is int:
return False
raise TypeError(
'Cannot compare type %r with IntegerInfinity' % type(other))
def __lt__(self,other):
if type(other) is IntegerInfinity:
return False
elif other == np.inf:
return True
elif type(other) is float or type(other) is int:
return False
raise TypeError(
'Cannot compare type %r with IntegerInfinity' % type(other))
def __init__(self):
super(int,self).__init__(0)
def __repr__(self):
return 'int_inf'
def __str__(self):
return 'int_inf'
UniversalSet
的其余部分对我来说似乎都很好用,除了当我在我的对象上调用len
时,它不会给我很好的IntegerInfinity
对象。相反,它给出了0
,即
>>> uniset = UniversalSet()
>>> # desired result
... IntegerInfinity()
int_inf
>>> # actual result
... len(uniset)
0
而且,这个零似乎无处不在。我在__init__
UniversalSet
函数中尝试了一个不同的虚设集,我在__init__
的{{1}}函数中尝试了一个不同的虚拟整数值,但都没有改变以上输出。
任何人都可以解释为什么会这样吗?和/或建议一个给我IntegerInfinity
的解决方法?
Martijn的答案涵盖了我的想法。答案不是实现UniversalSet
或len
函数,而是删除__len__
对象。更好的是,如果调用IntegerInfinity
,我会提出错误。
答案 0 :(得分:1)
使用PyInt_AsSsize_t()
API function,len()
函数会将__len__
方法返回int
的任何内容投射:
首先会尝试将对象转换为
PyIntObject
或PyLongObject
,如果它不是一个,然后将其值返回为Py_ssize_t
。
其中Py_ssize_t
是您的体系结构指针大小(通常为64位或32位)。请参阅source for the type.slot_sq_length
slot。
由于您已将int
子类化,但未提供__new__
方法,因此在转换为0
时,它具有默认值int()
。
您不能希望通过len()
函数获取自定义类型作为返回值; len()
始终返回int()
;你希望实现的最好的就是返回sys.maxsize
。
如果你的对象是不合格的,你可能不应该实现__len__
。改为使对象成为迭代器。