【问题标题】:What is function binding in python?python中的函数绑定是什么?
【发布时间】:2020-03-20 15:02:56
【问题描述】:

我试图理解 python 中的 kivy 库。下面是完整的代码。

import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button

class MyGrid(GridLayout):
    def __init__(self, **kwargs):
        super(MyGrid, self).__init__(**kwargs)
        self.cols = 1

        self.inside = GridLayout()
        self.inside.cols = 2

        self.inside.name = TextInput(multiline=False)
        self.inside.add_widget(self.inside.name)
        self.inside.add_widget(Label(text="Name: "))

        self.inside.name = TextInput(multiline=False)
        self.inside.add_widget(self.inside.name)
        self.inside.add_widget(Label(text="Email: "))

        self.inside.name = TextInput(multiline=False)
        self.inside.add_widget(self.inside.name)
        self.inside.add_widget(Label(text="Phno: "))

        self.add_widget(self.inside)

        self.submit = Button(text="Submit", font_size=40)
        self.submit.bind(on_press=self.pressed)
        self.add_widget(self.submit)        

    def pressed(self, instance):
        print("pressed")



class MyApp(App):
    def build(self):
        return MyGrid()


if __name__ == "__main__":
    MyApp().run()

在这里,在 MyGrid 类中,在 init 方法下,当我尝试将提交按钮 (self.submit.bind) 与 pressed 方法绑定时,带有 on_press 的参数不包含括号。

self.submit.bind(on_press=self.pressed)

为什么有效?是否因为在将括号传递给方法时不包含括号是 Python 的惯例?

在pressed方法中实例参数的用途是什么?

【问题讨论】:

  • self.pressed 是对实例的MyGrid.pressed 方法的引用。您不想实际调用该代码行上的方法,您只想将引用存储起来,以便以后调用。
  • 在python中,函数就是对象。如果没有括号,您将函数对象作为参数传递 - 这在绑定回调函数时非常典型。这就是说“当 on_press 事件被触发时执行这个函数”。如果您要添加括号,您将显式调用该函数,对其进行评估,并尝试将该函数的返回值绑定为回调,这没有意义(除非该函数返回一个函数对象)。跨度>
  • @PeterWood 谢谢你,你能解释一下在pressed方法中实例参数的使用吗?
  • @py_G 我对 kivy 知之甚少。我原以为文档会解释,it does。您可以将相同的处理函数绑定到多个按钮的on_press 回调。为了区分按钮,它作为instance 参数传递。

标签: python kivy


【解决方案1】:

如果你传递不带括号的函数,你传递的是函数对象本身

self.submit.bind(on_press=self.pressed)

这通常用于回调机制等。如果您添加了括号,self.pressed() 将在该语句处立即被调用,而不是 on_press 保存该函数以供稍后调用,以响应按钮单击。

【讨论】:

  • 你没有传递一个函数对象。您将获得一个 method 的实例,该实例是通过对表达式 self.pressed 的求值按需创建的。
【解决方案2】:

括号调用方法。在您省略它们的情况下,您将方法本身作为回调传递给稍后。调用该方法时,会涉及括号,但直到那时才涉及。

【讨论】:

    【解决方案3】:

    Python 是一种面向对象的语言,因为一切都是对象(甚至是方法)。在上面的示例中,bind 方法将可调用对象作为参数(因此是另一个方法)。

    要获取可调用对象而不是调用方法,请省略括号。

    【讨论】:

    • 每个名字都指一个对象。
    【解决方案4】:

    这有助于查看 self.pressed 的实际计算结果。

    实例self 没有名为pressed 的属性。不过,它的类MyGrid 有一个function-valued 属性。

    所以self.pressed 的计算结果为MyGrid.pressed。但是,因为function 类实现了描述符协议,所以您不会得到对function 对象的引用。相反,您会得到MyGrid.pressed.__get__(self, MyGrid) 的结果。 that 返回一个method 类型的可调用对象。该对象在调用时将接受它接收到的任何参数并立即将self 和这些参数传递给对MyGrid.pressed 的调用。

    简而言之,self.pressed 的值看起来很像一个可能被定义为的函数

    def bound_method(*args, **kwargs):
        return MyGrid.pressed(self, *args, **kwargs)
    

    self.pressed == MyGrid.pressed
                 == MyGrid.__dict__['pressed'].__get__(self, MyGrid)
    

    self.pressed 最终被调用时,

    self.pressed(ins) == MyGrid.__dict_['pressed'].__get(self, MyGrid)(self, ins)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-19
      • 2022-11-04
      • 2010-09-06
      • 2022-01-16
      • 1970-01-01
      • 2013-01-01
      相关资源
      最近更新 更多