【问题标题】:[Python]Calling method(self)[Python]调用方法(self)
【发布时间】:2013-11-08 13:07:06
【问题描述】:

我无法理解以下注释行。 这是一个python程序。


class B:
 def bbb(self):
    method = self.commands[0]
    method(self) #I can't umderstand this line

class A(B):
    def aaa(self):
        print 'aaa was called'
    commands = [aaa]

c = A()
c.bbb()

输出: 叫aaa


我认为上面的 aaa 方法不需要参数。 但要运行这段代码,我需要将“self”传递给 aaa 参数。为什么?有没有文档解释这个问题?这个问题属于什么类别?

非常欢迎任何简单的代码。 因为我的英语水平太低了。 所以也欢迎改进这个问题。

我在阅读cpython/Lib/distutils/cmd.py:Command.get_sub_commands()时遇到了这个问题。

感谢您的阅读。

【问题讨论】:

    标签: python class methods abstract self


    【解决方案1】:

    代码示例的完成方式使我们更难判断发生了什么。但是,它相当于:

    child_methods = [] # a list of all the methods in `Child`
    
    class Parent(object):
        def parent_method(self):
            print "parent_method() called"
            method = child_methods[0]
            method(self)
    
    class Child(Parent):
        def child_method(self):
            print "child_method() called"
    
    # add child_method to child_methods
    child_methods.append(Child.child_method)
    

    如您所见,child_methods[0] 实际上是函数Child.child_method,它是一个普通函数,而不是绑定方法。它与Child 的实例无关,这就是您可以而且必须自己传递self 的原因。您将从Child 实例中获得绑定方法:

    child_obj = Child()
    bound_child_method = child_obj.child_method
    

    如果在实例中找不到属性,Python 将在对象类型中查找属性,这一事实使这一点变得不清楚。例如:

    # A dummy class to hold attributes
    class Foo(object):
        pass
    
    Foo.bar = 123 # we're adding an attribute to the type itself
    
    foo1 = Foo()
    print foo1.bar # prints 123
    foo1.bar = 456 # this `bar` attribute "hides" the one on the type
    print foo1.bar # prints 456
    foo2 = Foo()
    print foo2.bar # prints the 123 from the type again
    

    这就是为什么在您的代码示例中,commands 实际上是一个“全局”变量,它只是通过B 的实例被混淆地访问。 (如果只有 B 的对象或其子对象访问此变量,这不一定是一个坏做法,但查找规则是一个小问题。)

    【讨论】:

    • 谢谢。我明白“Unbound method”需要传递“self”。
    • 没错。如果您将 bound 方法添加到列表中,例如使用 child_methods.append(Child().child_method),那么就没有必要了 - 它会使用您从中获取的 Child 实例。
    • 不一样。在问题的代码中,没有未绑定的方法访问。 method 的值是一个正则函数。
    • "commands 确实是一个“全局”变量"commandsA(以及B)的属性,而不是全局变量
    • @newacct 这就是为什么“全球”在引号中。我的意思是它与实例属性相对应,该实例属性具有绑定到对象的生命周期,其中类属性通常可以被认为只是位于不同的命名空间中。 (是的,类也是对象,只有通常恰好是程序中的一个实例,通过类实例访问的函数成为未绑定的方法对象,但是关于 Python 内部的这种详细程度会IMO 使事情变得不太清楚,而不是更多。)我将更改有关未绑定方法的内容,因为那完全是错误的。
    【解决方案2】:

    顺便说一句,最好使用新式类,class A(object):...

    python 中类的所有方法都以 self 作为第一个参数,类方法除外。 以下是关于自我的示例:

    def x(first, arg):
        print "Called x with arg=",arg
        print first
    
    class A(object):
         some_method = x
    
    a = A()
    a.some_method("s")`
    

    http://docs.python.org/2/tutorial/classes.html#random-remarks

    【讨论】:

      【解决方案3】:

      哇,这写的很混乱。从代码本身向后工作:

      c = A()
      

      创建一个 A 的实例。查看 A:

      def aaa(self):
          print 'aaa was called'
      commands = [aaa]
      

      这写得有点混乱;这样更有意义:

      def aaa(self):
          print 'aaa was called'
      
      commands = [aaa]
      

      定义一个方法aaa,然后定义一个类变量 commands,其中包含aaa作为一个元素。现在,看看程序的下一行:

      c.bbb()
      

      由于A没有bbbA继承自B,我们咨询B

      class B:
       def bbb(self):
          method = self.commands[0]
          method(self)
      

      由于我们已经确定commands[aaa],第一行表示method = aaa。所以第二行实际上是aaa(self)

      【讨论】:

      • 谢谢。但是为什么 'aaa(self)' 而不是 'aaa()'。在这段代码中,'aaa()' 不起作用。这是我的问题。
      • 对对象的任何方法调用都会隐式地将对象本身作为第一个参数传递。换句话说,您可以将c.bbb() 视为B.bbb(c)。在这种情况下,您可以重写aaa 不需要selfaaa 将没有参数,而bbb 需要调用method() 而不是method(self)
      • "第一行表示method = aaa" 对,但是aaa来自什么上下文?您所指的变量aaa 在程序中此时不再存在。
      • 嗯。我想说是A.aaa可能更准确?
      • @ChadMiller:在 Python 2.x 上,您会发现 method != A.aaa
      【解决方案4】:

      这一行:

      method(self) #I can't umderstand this line
      

      调用函数aaa()。在你的函数声明中:

      def aaa(self):
      

      aaa 确实接受了一个参数 (self)。这就是为什么你必须用method(self) 来调用它。

      由于self.commands[0]是一个函数,调用method(self)等于:

      aaa(self)
      

      如果您还有其他问题要问,请发表评论!

      【讨论】:

      • 谢谢。是真的。我认为如果 Python 的类方法是绑定方法,Python 会自动将“self”传递给第一个参数。但这只是我的意见。
      • 是的,它会自动完成。
      猜你喜欢
      • 2013-09-11
      • 2023-03-07
      • 1970-01-01
      • 2011-09-28
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      • 2021-04-08
      • 1970-01-01
      相关资源
      最近更新 更多