len() vs __len__: TypeError: 'float' 对象不能解释为整数

问题描述

我遇到了一个奇怪的错误,我认为这不是我的代码的问题。

这是我得到的对象:

  • 边界:表示域和范围,例如[1,10],它有一个low属性一个high属性,在本例中为low = 1high=10
  • Lim:表示联合集,例如[1,10]U[20,30],存储为self.boundaries = [Boundary([1,10]),Boundary([20,30])]

这就是我想要做的,

  1. 我在边界中定义了 __len__,这样 len(Boundary([1,10])) #=> 9
class Boundary:
    def __len__(self):
            return abs(self.high - self.low)
  1. 在 Lim 对象中,我有 self.boundaries,这是一个边界对象列表。定义了边界中的 __len__,我将 Lim 的 __len__ 编码如下:
class Lim:
    def __len__(self):
            return sum([len(bd) for bd in self.boundaries])

问题的发生方式如下,构成如下:

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,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

但是有了这个组合:

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,30])))

# Traceback (most recent call last):
#   File "boundary.py",in <module>
#   print(len(Lim([1,30])))
# TypeError: 'float' object cannot be interpreted as an integer

然而,代码最终以这样的组合执行:

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,30]).__len__())
# 19

为什么将 len() 更改为 __len__() 会消除错误?如果您提供一些帮助,我会很高兴。

解决方法

正如评论中所指出的,len 与您的用例不兼容。我不知道您的解决方案需要多灵活,但我想出了一个最低限度的工作示例:

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

做你想做的事(据我所知)。此外,您可以引入基于 Boundary 类的不同 Boundary 类。对于基 Boundary 类,您可以引入不同的距离度量,而对于 Lim 类(作为基类),您可以创建不同的收敛方案。虽然这个答案并没有说明您最初的问题(全部在评论中),但它是否以某种方式为您勾勒了前进的道路?