Python 魔术方法与定义顺序

Python 魔术方法与定义顺序,python,trie,magic-methods,Python,Trie,Magic Methods,我正在看一个 在第80-85行: def keys(self, prefix=[]): return self.__keys__(prefix) def __keys__(self, prefix=[], seen=[]): result = [] etc. 什么是def\uuuuuuu键?那是一个自创的神奇物体吗?如果是这样,这是一个糟糕的代码吗?或者,\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

我正在看一个

在第80-85行:

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

def __keys__(self, prefix=[], seen=[]):
    result = []
    etc.
  • 什么是
    def\uuuuuuu键?那是一个自创的神奇物体吗?如果是这样,这是一个糟糕的代码吗?或者,
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    是否作为标准的Python魔术方法?但是,我在Python文档中找不到它

  • 为什么函数调用
    self.\uuuukeys\uuuuu
    def\ukeys\uuuu
    被实例化之前是合法的?
    难道
    def\ukeys\uuuuu
    不必须在
    def keys
    之前调用


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

    无论何时创建类类型,都会编译并执行类块的主体。然后,将所有函数转换为绑定句柄(普通函数)或classmethod/staticmethod对象。然后,当创建一个新实例时,类型的
    \uuuu dict\uuuu
    的内容被复制到实例中(绑定句柄被转换为方法)

    因此,在调用
    instance.keys()
    时,实例已经同时具有
    方法


    而且,据我所知,在任何数据模式下都没有
    \uuuuuuuuuuuuuuuuuuuuuuuu键
    方法

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

    >>> def a():
    ...     b()
    ...
    >>> def b():
    ...     print("In B()")
    ...
    >>> a()
    In B()
    
    这是合法的,因为
    a()
    b()
    都是在调用
    a()
    之前定义的。只有在定义
    b()
    之前尝试调用
    a()
    ,这才是非法的。请注意,定义函数不会自动调用它,python也不会在定义函数时验证函数中使用的任何函数是否已定义(直到运行时,函数被调用时,在这种情况下会抛出NameError)

    对于你的第一个问题,我不知道有任何这样的神奇方法叫做
    \uuuukeys\uuuu()
    ,在文档中也找不到<代码>\uuuu键\uuuu
    不是其中之一。报告说:

    永远不要捏造这样的名字;仅按文件规定使用

    因此,是的,编一个新的是一种糟糕的形式(传统上称之为
    \u keys

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


  • 没有名为
    \uuuu keys\uuuu()
    的神奇方法,所以正如您所怀疑的,这只是一个糟糕的命名

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


  • 没有名为
    \uuuuuuuuuuuuuuuuuuuuuuuu键
    的神奇方法,因此它只是一个错误的命名约定。查看代码,作者只想拥有一个内部使用的私有方法,也可以使用公共方法
    keys
    。正如您所看到的,
    \uuuuuu键
    接受一个附加参数


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

    def keys
    定义了
    keys
    函数,在有人调用它之前,它实际上不会调用
    self.\uuu keys\uuu
    ,例如
    trie.keys()
    。到那时,
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu键
    已经定义好了。当应用到新样式类(Python 3中唯一的一种)时,您对对象创建方式的描述不是很准确。虽然链接类没有
    对象
    作为基础,但它可能应该这样做!在新样式的类中,定义的函数不会转换为任何特殊的函数(除非它们经过修饰)。只有在查找实例时,它们才会被绑定(通过描述符协议)。此外,没有任何内容从类
    \uuuuu dict\uuuu
    复制到实例的
    \uuuu dict\uuuu
    ,因为属性查找将在必要时检查类dict(以及任何基的dict)。@Blckknght据我所知,所有内容仍然复制到实例,因为如果尝试使用类变量,您可以修改实例中的副本,而无需修改类变量。此外,在python2中,即使使用新样式的类,函数也会变为绑定对象(Foo.method是一个绑定函数,因为它要求Foo作为第一个参数)。不会自动将任何内容复制到实例dict中。您的“修改”类变量可能会反弹为实例变量,从而使其隐藏旧值,而不是在适当的地方进行修改。关于方法,在Python2中,当您在类上查找一个方法时,会得到一种特殊的“未绑定”方法,这在一定程度上是正确的,但在这种情况下,您是错误的。只有在执行查找时,才会发生绑定。如果查看类
    \uuuu dict\uuuu
    ,您将看到未修改的函数。