I met a weird bug and I don't think it's my code's problem.
Here are the objects I have got:
[1, 10]
, it has a low
attribute and a high
attribute, in this case low = 1
and high=10
[1, 10]U[20, 30]
, stored as self.boundaries = [Boundary([1, 10]), Boundary([20, 30])]
Here's what I am trying to do,
__len__
in boundary, such that len(Boundary([1, 10])) #=> 9
class Boundary:
def __len__(self):
return abs(self.high - self.low)
self.boundaries
, which is a list of Boundary objects. with __len__
in Boundary defined, I coded Lim's __len__
in following:class Lim:
def __len__(self):
return sum([len(bd) for bd in self.boundaries])
Here's how the issue occurred, with following composition:
class Boundary:
def __len__(self):
return abs(self.high - self.low)
class Lim:
def __len__(self):
return sum([len(bd) for bd in self.boundaries])
print(len(Lim([1, 10], [20, 30])))
# Traceback (most recent call last):
# File "boundary.py" in <module>
# print(len(Lim([1, 10], [20, 30])))
# File "boundary.py", in __len__
# return sum([len(bd) for bd in self.boundaries])
# File "boundary.py", in <listcomp>
# return sum([len(bd) for bd in self.boundaries])
# TypeError: 'float' object cannot be interpreted as an integer
But with this composition:
class Boundary:
def __len__(self):
return abs(self.high - self.low)
class Lim:
def __len__(self):
return sum([bd.__len__() for bd in self.boundaries])
print(len(Lim([1, 10], [20, 30])))
# Traceback (most recent call last):
# File "boundary.py",in <module>
# print(len(Lim([1, 10], [20, 30])))
# TypeError: 'float' object cannot be interpreted as an integer
However, the code finally executes with this composition:
class Boundary:
def __len__(self):
return abs(self.high - self.low)
class Lim:
def __len__(self):
return sum([bd.__len__() for bd in self.boundaries])
print(Lim([1, 10], [20, 30]).__len__())
# 19
Why changing len()
to __len__()
will dismiss the error? I will be so glad if you offer some help.
As pointed out in the comments, len
is not compatible with your use case. I do not know how flexible your solution needs to be but I came up with a minimum working example:
from typing import List
def dist(boundary: object, m='euclidean') -> float:
"""Computes a given distance for object-typed boundaries.
"""
return boundary.__dist__(m)
def converge(lim: object) -> float:
"""_Integrates_ the distances over boundaries."""
return lim.__converge__()
class Boundary(object):
low = 0
high = 0
def __init__(self, lo: float, hi: float):
self.low = lo
self.high = hi
def __dist__(self, m: str) -> float:
if m == 'euclidean':
return abs(self.high - self.low)
else:
raise Error(f'Unknown distance {m}')
class Lim(object):
boundaries = []
def __init__(self, boundaries: List[Boundary]):
self.boundaries = boundaries
def __converge__(self) -> float:
return sum([dist(bd) for bd in self.boundaries])
print(converge(Lim([Boundary(1.0, 10.0), Boundary(20.0, 30.0)])))
# expect abs(10-1) + abs(30-20) = 9+10 = 19
that does what you want (to the best of my knowledge). Further, you can introduce different Boundary
classes that base off of the Boundary
class. For the base Boundary
class, you are able to introduce different distance measures and for the Lim
class (being a base class), you can create different convergence schemes. While this answer does not make a single point about your initial problem (it is all in the comments), does that somehow outline a way forward for you?