【问题标题】:Magic methods and definition order魔术方法和定义顺序
【发布时间】:2015-08-07 06:59:57
【问题描述】:

我正在查看 trie implementation 的源代码

在第 80-85 行:

def keys(self, prefix=[]):
    return self.__keys__(prefix)

def __keys__(self, prefix=[], seen=[]):
    result = []
    etc.
  1. def __keys__ 是什么? 那是自创的魔法物品吗?如果是这样,这是糟糕的代码吗?或者__keys__ 是否作为标准的 Python 魔术方法存在?不过,我在 Python 文档的任何地方都找不到它。

  2. 为什么在 def __keys__ 甚至实例化之前调用 self.__keys__ 的函数是合法的? def __keys__ 不必在 def keys 之前调用(因为 @987654329 @呼叫__keys__)?

【问题讨论】:

  • def keys 定义了 keys 函数,它实际上不会调用 self.__keys__ 直到有人调用它,例如trie.keys()。到那时,__keys__ 将被定义。

标签: python trie magic-methods


【解决方案1】:

对于第二个问题,这是合法的,类的函数是在定义类时定义的,因此您可以确定在调用 keys() 之前定义了两个函数,该逻辑也适用于普通函数,我们可以做 -

>>> def a():
...     b()
...
>>> def b():
...     print("In B()")
...
>>> a()
In B()

这是合法的,因为a()b() 都是在调用a() 之前定义的。如果您在定义b() 之前尝试调用a(),那将是非法的。请注意,定义函数不会自动调用它,并且 python 在定义函数时不会验证函数中使用的任何函数是否已定义(直到运行时,当调用函数时,在这种情况下它会抛出 NameError )

对于您的第一个问题,我不知道有任何这种称为 __keys__() 的魔术方法,在文档中也找不到。

【讨论】:

    【解决方案2】:

    所有真正的“魔法方法”都在data model documentation中; __keys__ 不是其中之一。 style guide 说:

    永远不要发明这样的名字;仅按文档说明使用。

    所以是的,编造一个新的形式是不好的(惯例是称之为_keys)。

    您问题的第二部分没有意义;即使这不是一个类,也不需要按照调用顺序定义方法和函数。只要它们存在 在实际调用时,这不是问题。我倾向于在私有方法之前定义公共方法,即使前者可能会调用后者,只是为了方便读者。

    【讨论】:

      【解决方案3】:
      1. 没有名为__keys__() 的神奇方法,所以你怀疑这只是糟糕的命名。

      2. 类定义中的代码可以是任意顺序。在下游进行实际调用时已定义的所有事项。

      【讨论】:

        【解决方案4】:

        没有名为__keys__ 的神奇方法,所以它只是一个错误的命名约定。看代码,作者只是想有一个内部使用的私有方法,也来自公共方法keys。如您所见,__keys__ 接受一个附加参数。

        关于第二个问题,没有必要按照它们调用的顺序定义函数。它将在编译代码时可用。

        【讨论】:

          【解决方案5】:

          在 Python 中类的编译是在类被实例化之前完成的。

          每当创建类类型时,都会编译并执行类块的主体。然后,所有函数要么转换为绑定句柄(普通函数),要么转换为 classmethod/staticmethod 对象。然后,当创建一个新实例时,该类型的 __dict__ 的内容被复制到该实例(并且绑定的句柄被转换为方法)。

          因此,在调用instance.keys() 的那一刻,实例已经拥有keys__keys__ 方法。

          此外,据我所知,在任何数据模式下都没有__keys__ 方法。

          【讨论】:

          • 您对如何创建对象的描述在应用于新型类(这是 Python 3 中唯一的一类)时不是很准确。虽然链接类没有 object 作为基础,但它可能应该!在新型类中,定义的函数不会变成任何特殊的东西(除非它们被修饰)。只有在它们被绑定的实例上查找它们时(通过描述符协议)。此外,没有任何内容从类 __dict__ 复制到实例的 __dict__,因为如有必要,属性查找将检查类字典(以及任何基的字典)。
          • @Blckknght 据我所知,所有内容仍会复制到实例中,因为如果您尝试使用类变量,则可以在不修改类变量的情况下修改实例中的副本。此外,即使使用新样式类,函数也会在 python2 中更改为绑定对象(Foo.method 是绑定函数,因为它需要 Foo 作为第一个参数)。
          • 不会自动将任何内容复制到实例字典中。您的“修改后的”类变量可能正在作为实例变量重新绑定,以便它隐藏旧值,而不是实际被修改到位。关于方法,部分正确的是,在 Python 2 中,当您在类上查找方法时,您会得到一种特殊的“未绑定”方法,但您对何时发生这种情况是错误的。只有当您进行查找时才会发生绑定。如果你查看 __dict__ 类,你会看到未修改的函数。
          猜你喜欢
          • 2013-01-30
          • 1970-01-01
          • 1970-01-01
          • 2011-06-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-07
          • 2015-09-13
          相关资源
          最近更新 更多