2015-09-10 6 views
2

https://gist.github.com/rjurney/1e8454af8e44312d02d7Класс Python: Почему я не могу использовать метод len() внутри __eq __ (self, other)?

class FrozenSortedTuple: 
    """A frozenset that cares about order of tuples. And is not actually frozen.""" 
    def __init__(self, vals): 
    if type(vals) not in [list, set, tuple]: 
     raise Exception('Value not a list or set') 
    self.vals = list(vals) 

    def __eq__(self, other): 
    if len(self.vals) != len(other): 
     return False 
    if type(self.vals) != type(other): 
     return False 
    if type(other) not in [list, set, tuple]: 
     return False 
    other_list = list(other) 
    for i,item in enumerate(self.vals): 
     if item != other_list[i]: 
     return False 
    return True 

Вызывается в IPython:

In [2]: a = ['a','b'] 

In [3]: b = ['b','a'] 

In [4]: c = ['a','b'] 

In [5]: a == b 
Out[5]: False 

In [6]: FrozenSortedTuple(a) 
Out[6]: <__main__.FrozenSortedTuple instance at 0x103c56200> 

In [7]: fa = FrozenSortedTuple(a) 

In [8]: fb = FrozenSortedTuple(b) 

In [9]: fa == fb 

Ошибка:

--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 
<ipython-input-9-317181571e4d> in <module>() 
----> 1 fa == fb 

<ipython-input-1-ef99f0af5061> in __eq__(self, other) 
    15 
    16 def __eq__(self, other): 
---> 17  if len(self.vals) != len(other): 
    18  return False 
    19  if type(self.vals) != type(other): 

AttributeError: FrozenSortedTuple instance has no attribute '__len__' 

Я запутался.

+5

Проблема не «вы не можете назвать' 'len' внутри __eq__ '». Проблема заключается в том, что «вы не можете называть« len »в любом месте», потому что вы никогда не вживляли его в этот класс. 'len (fa)' потерпит неудачу в основной области одинаково. – Kevin

+0

Почему все глобальные функции исчезают внутри класса? – rjurney

+0

OH! Я понял. Благодарю. – rjurney

ответ

1

Спасибо, на основе других ответов, что я хотел это:

class FrozenSortedTuple: 
    """A frozenset that cares about order of tuples. And is not actually frozen.""" 
    def __init__(self, vals): 
    if type(vals) not in [list, set, tuple]: 
     raise Exception('Value not a list or set') 
    self.vals = vals 

    def __len__(self): 
    return len(self.vals) 

    def __iter__(self): 
    return iter(self.vals) 

    def __getitem__(self, key): 
    return list(self.vals)[key] 

    def __eq__(self, other): 
    if len(self) != len(other): 
     print "len(self)" 
     return False 

    for i,item in enumerate(self.vals): 
     if item != other[i]: 
     return False 
    return True 

    def __str__(self): 
    str_val = str() 
    for val in self: 
     str_val += str(val) 
    return str_val 

    def __hash__(self): 
    return hash(str(self)) 

Тесты:

# FrozenSortedTuple Tests 
a = ['a','b'] 
b = ['b','a'] 
c = ['a','b'] 

fa = FrozenSortedTuple(a) 
fb = FrozenSortedTuple(b) 
fc = FrozenSortedTuple(c) 

fa == fb 
fa == fc 
fa == ['a','b'] 
fa == ['b','a'] 
fa == ('a','b') 
fa == ('b','a') 

a = set([fa, fb, fc]) 
b = set([fa, fb, fc]) 
c = set([fa, fc, fb]) 
a == b 
b == c 
fa in a 
fb in b 

d = set([fb]) 
fa in d 
3

Если вы пытаетесь напрямую сравнить структуру и содержимое значений двух FrozenSortedTuples, измените все свои экземпляры other на other.vals.

def __eq__(self, other): 
    if len(self.vals) != len(other.vals): 
     return False 
    if type(self.vals) != type(other.vals): 
     return False 
    if type(other.vals) not in [list, set, tuple]: 
     return False 
    other_list = list(other.vals) 
    for i,item in enumerate(self.vals): 
     if item != other_list[i]: 
     return False 
    return True 

Конечно, это не будет работать, если other не FrozenSortedTuple. Например, fa == 23 не будет работать, потому что номер 23 не имеет атрибута «vals».

+0

Или просто реализовать 'def __len __ (self): return len (self.vals)'. –

+0

Да, но тогда 'if type (self.vals)! = Type (other)' будет работать не так, как ожидалось, и так далее для всех его других условностей. – Kevin

+1

Да, остальная часть кода, конечно, должна быть соответствующим образом адаптирована. –

2

способ определения __eq__(self, other), равенство может быть достигнуто только тогда, когда другой экземпляр типа вы оборачивать, то есть список, набор, или кортеж. Вы запускаете ошибку, сравнивая два экземпляра FrozenSortedTuple. Сообщение об ошибке сообщает вам, что len() не может быть вызвано в таком экземпляре, и это связано с тем, что вы не определили метод __len__(self) в своем классе.

Если вы укажете __len__() для своего класса, это сработает. См. the Python Documentation (это ссылки на документы 2.7, но они должны работать одинаково в Python 3.x) В качестве альтернативы вы можете сравнить len(self.vals) == len(other.vals) для сравнения FrozenSortedTuple экземпляров.