使用len()和def __len__(self)来构建一个类

40

只是好奇,

在构建类时,使用len()def __len__()是否有任何区别(优点和缺点)?哪种是最好的Python风格?

   class foo(object):
      def __init__(self,obs=[])
         self.data = obs
         self.max = max(obs)
         self.min = min(obs)
         self.len = len(obs)

或者

   class foo(object):
      def __init__(self,obs=[])
         self.data = obs
         self.max = max(obs)
         self.min = min(obs)
      def __len__(self):
         return len(self.data)

2
第一个和第二个有什么等价的方法? - Markus Unterwaditzer
7
请注意,在关键字参数的默认值中不应使用[],除非您知道自己在做什么。请参阅"Python中的最小惊奇":可变默认参数 - Martijn Pieters
1
在第一个示例中,self.len = len(obs) 将数据成员 self.len 赋值为 obs 的初始长度。self.len 不是一个函数。如果初始化后 obs 发生变化,self.len 不会反映这种变化。 - smci
2个回答

63

有一个巨大的区别。

__len__()方法是一个钩子方法。如果存在__len__方法,len()函数将使用该方法来查询对象的长度。

普通的API人们期望使用的是len()方法,使用.len属性会偏离这个规范。

如果不希望self.data的长度发生变化,可以始终在属性中缓存长度,并让.__len__()返回该属性。

class foo(object):
    def __init__(self, obs=None):
        if obs is None:  # provide a default if no list was passed in.
            obs = []
        self.data = obs
        self.max = max(obs)
        self.min = min(obs)
        self._data_len = len(obs)

    def __len__(self):
        return self._data_len

10
有几个不同之处:
  1. 只有第二种方法才能让你使用熟悉的len(obj)语法来调用foo。第一种方法需要使用obj.len()
  2. 如果self.data的长度在构造后可能会改变,只有第二个版本才会反映出新的长度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接