【问题标题】:Should I use python magic methods directly?我应该直接使用python魔术方法吗?
【发布时间】:2020-07-17 04:28:30
【问题描述】:

我从一个人那里听说你不应该直接使用魔法方法。而且我认为在某些用例中我必须直接使用魔术方法。这么有经验的开发者,是不是应该直接用python魔术方法呢?

【问题讨论】:

  • 不,你不应该。所有“魔法”方法都有一个等效的内置函数或语法来调用它们
  • 当你需要他们所做的特定工作时你应该这样做,但大多数魔法方法只负责部分你可能认为他们的工作。例如,__add__ 不负责整个 + 操作,__getattribute__ 不是整个属性访问协议,并且并非所有可迭代对象都有 __iter__ 方法。
  • 当你“从一个人那里听到的”事情实际上是正确的时候,这是一个相对罕见的时刻。现在可能是玩彩票的好时机。

标签: python magic-methods


【解决方案1】:

我不是高级开发人员,但根据我的经验,你不应该直接调用魔法方法。

应该使用魔术方法来覆盖对象的行为。例如,如果你想定义你的对象是如何构建的,你覆盖__init__。之后当你想初始化它时,你使用MyNewObject()而不是MyNewObject.__init__()

对我来说,我倾向于欣赏 Alex Martelli here 给出的答案:

当您看到对内置函数 len 的调用时,您可以确定,如果程序在此之后继续而不是引发异常,则该调用返回了一个整数、非负数且小于 2 **31 -- 当您看到对xxx.__len__() 的调用时,您并不确定(除非代码的作者不熟悉 Python 或不擅长;-)。

如果您想进一步了解 Python 的魔法方法,我强烈建议您查看 Rafe Kettler 制作的文档:https://rszalski.github.io/magicmethods/

【讨论】:

    【解决方案2】:

    不,你不应该。

    可以在hackerrank等快速代码问题中使用,但不能在生产代码中使用。当我问这个问题时,我只将它们用作函数对象。我的意思是,我使用xlen = x.__len__ 而不是xlen = lambda: len(x),这很方便。在简单的程序中使用这些类似 sn-ps 是可以的。

    至于直接调用dunder方法的其他情况,我对此毫无疑问。我和我以前的自己肯定会更喜欢y = len(x) 而不是y = x.__len__(),因为显然它看起来更干净。有关使用 python 提供的方法来调用 dunder 方法的其他优点,请参阅@SorousH Bakhtiary 的答案。

    【讨论】:

      【解决方案3】:

      我打算展示直接使用魔法方法的一些好处:

      1- 可读性:

      使用像len() 这样的内置函数比相关的魔术/特殊方法__len__() 更具可读性。想象一个充满魔法方法而不是内置函数的源代码......成千上万的下划线......


      2- 比较运算符:

      class C:
          def __lt__(self, other):
              print('__lt__ called')
      
      class D:
          pass
      
      c = C()
      d = D()
      
      d > c
      d.__gt__(c)
      

      我还没有为这两个类实现__gt__,但是在d > c 中,当python 看到该类D 没有__gt__ 时,它会检查类C 是否实现@987654330 @。确实如此,所以我们在输出中得到'__lt__ called',而d.__gt__(c) 的情况并非如此。


      3- 额外检查:

      class C:
          def __len__(self):
              return 'boo'
      
      obj = C()
      print(obj.__len__())  # fine
      print(len(obj))       # error
      

      或:

      class C:
          def __str__(self):
              return 10
      
      obj = C()
      print(obj.__str__())  # fine
      print(str(obj))       # error
      

      如您所见,当 python 隐式调用该魔术方法时,it does some extra checks 也是如此。


      4- 这是最不重要的,但与__len__() 相比,在诸如str 等内置数据类型上使用len() 会提供一点速度:

      from timeit import timeit
      
      string = 'abcdefghijklmn'
      
      print(timeit("len(string)", globals=globals(), number=10_000_000))
      print(timeit("string.__len__()", globals=globals(), number=10_000_000))
      

      输出:

      0.5442426
      0.8312854999999999
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-29
        • 2018-01-23
        • 1970-01-01
        相关资源
        最近更新 更多