Python 装饰函数无法更新另一个函数的属性 Class
Python Decorated Function Can't Update Attribute from Another Class
我在使用我创建的 class 中的导入包中的装饰器时遇到问题。我创建了两个 classes 和一个 main()
。 class A
的实例在 main()
中创建,class B
的实例在 class A
中创建。 Class B
需要更新在 main()
中创建的实例的属性。此外,我需要使用导入包中的装饰器。
我不知道如何解决无法从 class B
实例中的修饰 confirm_connect
函数引用 main()
中创建实例的属性的问题。我让它工作的唯一方法是将 main()
中创建的实例声明为 global
并删除 class B
中的所有 self
引用。但是,将其设置为 global
会导致我的应用程序出现其他问题。 (将 socketio
的实例设为 class B
中的 global
是可以容忍的,但我也不希望有它。)
函数confirm_connect
从服务器接收消息。如果我将函数定义为 def conform_connect(self, data)
,我会收到错误消息 connect_confirm() missing 1 required positional argument: 'data'/
。如果我从声明中删除 self
,则会收到错误 NameError: name 'self' is not defined
.
这是我的脚本。我怎样才能让我的脚本做我需要它做的事情?
import socketio
class A():
def __init__(self):
self.pin = None
def connect_to_server(self):
self.io = B()
self.io.connect_to_server()
def start_the_process(self):
self.b = B(self)
self.b.connect_to_server()
def do_something_with_pin(self):
print(self.pin)
class B():
global sio
sio = socketio.Client()
def __init__(self, a):
self.a = a
def connect_to_server(self):
sio.connect('http://my_url_is_this.org')
sio.emit('manual_connection_parameter', {'foo': 'bar'})
@sio.event
def connect_confirm(data):
self.a.pin = data
self.a.do_something_with_pin()
def main():
a = A()
a.start_the_process()
if __name__ == '__main__':
main()
如果你了解装饰器的工作原理,那么你就会明白
@sio.event
def connect_confirm(self, data):
self.a.pin = data
self.a.do_something_with_pin()
只是
的语法糖
def connect_confirm(self, data):
self.a.pin = data
self.a.do_something_with_pin()
connect_confirm = sio.event(connect_confirm)
报告的问题是 sio.event
需要一个 1 参数的普通回调函数,它将接收 data
;所以使用 self
参数它不符合这些期望(没有 self
参数,方法 的期望 不满足)。
洞察力是(因为 3.x;2.x 在幕后做了不同的事情)在 class 中定义的方法 只是一个函数 ;正是 从实例中查找该方法的过程 使方法用 self
完成它们所做的特殊事情。
所以当你修饰这个方法时,你最终注册了一个完全错误的回调。 socketio.Client
对您的 B 实例一无所知,也无法使用它,无论您做什么。
解决方案是使用你实例的绑定实例方法回调,这需要我们手动调用装饰器,如开头所述。
在__init__
中,我们可以这样做:
def __init__(self, a):
self.a = a
sio.event(self.connect_confirm)
然后我们就可以正常定义那个方法了:
def connect_confirm(self, data):
self.a.pin = data
self.a.do_something_with_pin()
请注意,在 __init__
上下文中,我们现在如何在进行“装饰”时编写 self.
,因此我们告诉 socketio.Client
使用 connect_confirm
此实例的 作为回调。我们不需要对“装饰”的结果做任何事情,所以我们不会在任何地方分配它。
从API的角度来看,这种事情是什么样的值得考虑。 socketio.Client
class 实现可能包括如下内容:
class Client:
# ... lots of other stuff...
def event(self, callback):
self._event_callback = callback
return callback
def _some_internal_logic(self):
if _special_situation_occurs():
self._event_callback(self._get_data_for_callback())
如果实现没有 return callback
,那么在您的情况下您需要做什么就很明显了,因为装饰器语法将不可用。 (好吧,你 可以 使用任何东西作为装饰器;但是返回 None
或其他非函数在大多数时候并不是很有用。)
我在使用我创建的 class 中的导入包中的装饰器时遇到问题。我创建了两个 classes 和一个 main()
。 class A
的实例在 main()
中创建,class B
的实例在 class A
中创建。 Class B
需要更新在 main()
中创建的实例的属性。此外,我需要使用导入包中的装饰器。
我不知道如何解决无法从 class B
实例中的修饰 confirm_connect
函数引用 main()
中创建实例的属性的问题。我让它工作的唯一方法是将 main()
中创建的实例声明为 global
并删除 class B
中的所有 self
引用。但是,将其设置为 global
会导致我的应用程序出现其他问题。 (将 socketio
的实例设为 class B
中的 global
是可以容忍的,但我也不希望有它。)
函数confirm_connect
从服务器接收消息。如果我将函数定义为 def conform_connect(self, data)
,我会收到错误消息 connect_confirm() missing 1 required positional argument: 'data'/
。如果我从声明中删除 self
,则会收到错误 NameError: name 'self' is not defined
.
这是我的脚本。我怎样才能让我的脚本做我需要它做的事情?
import socketio
class A():
def __init__(self):
self.pin = None
def connect_to_server(self):
self.io = B()
self.io.connect_to_server()
def start_the_process(self):
self.b = B(self)
self.b.connect_to_server()
def do_something_with_pin(self):
print(self.pin)
class B():
global sio
sio = socketio.Client()
def __init__(self, a):
self.a = a
def connect_to_server(self):
sio.connect('http://my_url_is_this.org')
sio.emit('manual_connection_parameter', {'foo': 'bar'})
@sio.event
def connect_confirm(data):
self.a.pin = data
self.a.do_something_with_pin()
def main():
a = A()
a.start_the_process()
if __name__ == '__main__':
main()
如果你了解装饰器的工作原理,那么你就会明白
@sio.event
def connect_confirm(self, data):
self.a.pin = data
self.a.do_something_with_pin()
只是
的语法糖def connect_confirm(self, data):
self.a.pin = data
self.a.do_something_with_pin()
connect_confirm = sio.event(connect_confirm)
报告的问题是 sio.event
需要一个 1 参数的普通回调函数,它将接收 data
;所以使用 self
参数它不符合这些期望(没有 self
参数,方法 的期望 不满足)。
洞察力是(因为 3.x;2.x 在幕后做了不同的事情)在 class 中定义的方法 只是一个函数 ;正是 从实例中查找该方法的过程 使方法用 self
完成它们所做的特殊事情。
所以当你修饰这个方法时,你最终注册了一个完全错误的回调。 socketio.Client
对您的 B 实例一无所知,也无法使用它,无论您做什么。
解决方案是使用你实例的绑定实例方法回调,这需要我们手动调用装饰器,如开头所述。
在__init__
中,我们可以这样做:
def __init__(self, a):
self.a = a
sio.event(self.connect_confirm)
然后我们就可以正常定义那个方法了:
def connect_confirm(self, data):
self.a.pin = data
self.a.do_something_with_pin()
请注意,在 __init__
上下文中,我们现在如何在进行“装饰”时编写 self.
,因此我们告诉 socketio.Client
使用 connect_confirm
此实例的 作为回调。我们不需要对“装饰”的结果做任何事情,所以我们不会在任何地方分配它。
从API的角度来看,这种事情是什么样的值得考虑。 socketio.Client
class 实现可能包括如下内容:
class Client:
# ... lots of other stuff...
def event(self, callback):
self._event_callback = callback
return callback
def _some_internal_logic(self):
if _special_situation_occurs():
self._event_callback(self._get_data_for_callback())
如果实现没有 return callback
,那么在您的情况下您需要做什么就很明显了,因为装饰器语法将不可用。 (好吧,你 可以 使用任何东西作为装饰器;但是返回 None
或其他非函数在大多数时候并不是很有用。)