如何绑定未绑定的方法而不调用它?
- 2025-01-10 08:46:00
- admin 原创
- 13
问题描述:
在 Python 中,有没有办法绑定未绑定的方法而不调用它?
我正在编写一个 wxPython 程序,对于某个类,我决定将所有按钮的数据组合在一起作为类级别的元组列表,如下所示:
class MyWidget(wx.Window):
buttons = [
("OK", OnOK),
("Cancel", OnCancel)
]
...
def setup(self):
for text, handler in MyWidget.buttons:
# This following line is the problem line.
b = wx.Button(parent, label=text).bind(wx.EVT_BUTTON, handler)
问题是,由于所有的值都是handler
未绑定的方法,我的程序在一场壮观的火焰中爆炸,我哭泣。
我在网上寻找一个解决方案,以解决一个看似相对简单、可解决的问题。不幸的是,我什么也没找到。现在,我正在解决functools.partial
这个问题,但有人知道是否有一种干净、健康、符合 Python 的方式将未绑定的方法绑定到实例并继续传递它而不调用它?
解决方案 1:
所有函数也是描述符,因此你可以通过调用它们的方法绑定它们__get__
:
bound_handler = handler.__get__(self, MyWidget)
这是 R. Hettinger 的描述符的优秀指南。
作为从Keith 的 评论中抽取的一个独立的例子:
def bind(instance, func, as_name=None):
"""
Bind the function *func* to *instance*, with either provided name *as_name*
or the existing name of *func*. The provided *func* should accept the
instance as the first argument, i.e. "self".
"""
if as_name is None:
as_name = func.__name__
bound_method = func.__get__(instance, instance.__class__)
setattr(instance, as_name, bound_method)
return bound_method
class Thing:
def __init__(self, val):
self.val = val
something = Thing(21)
def double(self):
return 2 * self.val
bind(something, double)
something.double() # returns 42
解决方案 2:
可以通过以下方式完成types.MethodType
:
import types
bound_handler = types.MethodType(handler, self)
解决方案 3:
闭包,也称为封闭表达式(与开放表达式相反),它是没有自由变量的表达式:
bound_handler = (lambda handler, self:
lambda *args, **kwargs: handler(self, *args, **kwargs)
)(handler, self)
这里handler
和self
是内层 lambda 表达式中的自由变量,也是外层 lambda 表达式中的绑定变量args
,而和kwargs
在内层和外层 lambda 表达式中都是绑定变量,所以外层 lambda 表达式是一个闭包。
解决方案 4:
这将绑定self
到handler
:
bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)
它通过将其self
作为第一个参数传递给函数来实现。obj.f()
只是的语法糖f(obj)
。
解决方案 5:
虽然迟到了,但是我带着类似的问题来到这里:我有一个类方法和一个实例,并且想将实例应用到该方法中。
冒着过度简化 OP 问题的风险,我最终做了一些不那么神秘的事情,可能对到达这里的其他人有用(警告:我在 Python 3 中工作 - YMMV)。
考虑这个简单的类:
class Foo(object):
def __init__(self, value):
self._value = value
def value(self):
return self._value
def set_value(self, value):
self._value = value
你可以用它做以下事情:
>>> meth = Foo.set_value # the method
>>> a = Foo(12) # a is an instance with value 12
>>> meth(a, 33) # apply instance and method
>>> a.value() # voila - the method was called
33
解决方案 6:
扩展@Keith Pinson使用闭包的答案和@brian-brazil没有使用的答案,以下是前者正确的原因。
闭包示例:
def handler(self, *args, **kwargs):
return self
self = True
bound_handler = (lambda handler, self:
lambda *args, **kwargs: handler(self, *args, **kwargs)
)(handler, self)
bound_handler() # returns True
self = False
bound_handler() # returns True
handler = print
bound_handler() # returns True
外部 lambda 表达式是封闭的,因此其绑定变量handler
和self
不能被重新绑定。__get__
,types.MethodType
和functools.partial
具有相同的行为。
没有闭包的示例:
def handler(self, *args, **kwargs):
return self
self = True
bound_handler = lambda *args, **kwargs: handler(self, *args, **kwargs)
bound_handler() # returns True
self = False
bound_handler() # returns False
handler = print
bound_handler() # prints False
Lambda 表达式是开放的,因此它是自由变量handler
,self
可以被重新绑定。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理必备:盘点2024年13款好用的项目管理软件