自我论证如何神奇地传递给实例方法?

Zac*_*ith 4 python self

我正在做代码学院流,我有一点Ruby经验.我不明白为什么check_angles(self)函数需要self参数.

我感到困惑的原因是我不明白在调用函数时是什么将self参数传递给函数.似乎函数调用(代码块的最后一行)是隐式传递,但该函数需要将self明确定义为参数.

为什么是这样?

class Triangle(object):
    def __init__(self, angle1, angle2, angle3):
        self.angle1 = angle1
        self.angle2 = angle2
        self.angle3 = angle3

    number_of_sides = 3

    def check_angles(self):
        sum_angles = self.angle1 + self.angle2 + self.angle3
        if sum_angles == 180:
            return True
        else:
            return False

    tri = Triangle(45,34,78)
    tri.check_angles(EMPTY BUT WHY)
Run Code Online (Sandbox Code Playgroud)

Eri*_*lun 8

这在Python中的工作方式是,一旦Foo使用方法实例化一个类,bar(self)用于创建方法的函数将包装在一个类型的对象中,该对象将instancemethod它"绑定"到实例,以便调用foo_inst.bar()实际调用Foo.bar(foo_inst).

class Foo(object):
    def bar(self):
        print "called bar on %s" % self

foo_inst = Foo()

# these 2 calls are equivalent
foo_inst.bar()
Foo.bar(foo_inst)
Run Code Online (Sandbox Code Playgroud)

或者,以交互方式:

>>> Foo.bar
<unbound method Foo.bar>

>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x10675ecd0>>
Run Code Online (Sandbox Code Playgroud)

所以你可以看到,虽然仍然直接附加到类,bar是一个未绑定的方法self,但仍然有参数,但是,当从Foo实例中检索方法对象时,它已成为一个绑定方法,self参数已经预先设置为从中检索方法对象的实例.

这也是为什么self可以真正被称为任何你想要的东西,如arg0(stifflersmomallyourbase).

另请参阅 Python描述符@ https://docs.python.org/2/howto/descriptor.html,了解其实现方式以及如何自行实现类似方案.


事实上,在这个例子中,方法实际上是功能更加明显:

class Foo(object):
    pass

def bar(arg0):
    print "called bar with %s" % arg0

Foo.bar = bar

Foo().bar()  # prints: called bar with <Foo object at 0x10675b2d0>
Run Code Online (Sandbox Code Playgroud)

注意:在声明了类对象之后将它们分配给类对象(称为monkeypatching)并不是动态语言(如Python)中推荐的编程风格,因为它是A)容易出错(可能会覆盖同一类的未来版本中的某些内容,因为没有编译器来验证不是这种情况)和B)难以理解(不可能通过查看类定义来知道类的实例具有哪些实例,因为没有编译器/ IDE来查找添加的方法).