pythonのtkinterを使ったEchoアプリでエラーがでる。(AttributeError 'functors.partial' obj has no attribute '__name__')
"パーフェクトpython"を見て、Echoアプリケーションを作っていましたが、「python3 client.py」と実行すると、以下のエラーが発生します。どういう意味でしょうか?もちろん、server側のプログラムも立ち上げています。
なお、client側とserver側のコードも示しています。(教材に書いているコードそのままなんですけど。。。)
解決策も教えていただけませんでしょうか?
【エラー内容】
Traceback (most recent call last):
File "client.py", line 76, in <module>
main()
File "client.py", line 68, in main
root.after(200, functools.partial(idle_task, root))
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 752, in after
callit.__name__ = func.__name__
AttributeError: 'functools.partial' object has no attribute '__name__'
client側コード
# -*- coding::utf-8 -*-
import tkinter
import asyncore
import functools
import sys
class EchoView(tkinter.Frame):
""" Echo User Interface """
def __init__(self, master):
super(EchoView, self).__init__(master)
self.listcontainer = tkinter.Frame(self)
self.listbox = tkinter.Listbox(self.listcontainer)
self.yscroll = tkinter.Scrollbar(self.listcontainer)
self.listbox.pack(side=tkinter.LEFT, expand=True, fill=tkinter.BOTH)
self.yscroll.pack(side=tkinter.LEFT, expand=True, fill=tkinter.Y)
self.listcontainer.pack(expand=True, fill=tkinter.BOTH)
self.entry = tkinter.Entry(self)
self.entry.pack(side=tkinter.BOTTOM, expand=True, fill=tkinter.X)
def get_submit_messegae(self):
data = self.entry.get()
self.entry.delete(0, tkinter.END)
return data
def show_message(self, message):
self.listbox.insert(tkinter.END, message)
self.listbox.see(tkinter.END)
class EchoClient(asyncore.dispatcher_with_send):
def __init__(self, view):
super(EchoClient, self).__init__()
self.create_socket()
self.buffers = []
self.view = view
self.bind_all()
def bind_all(self):
self.view.entry.bind('<Return>', self.on_submit)
def on_submit(self, event):
message = self.view.get_submit_messegae()
self.buffers.append(message.encode('utf-8'))
def handle_write(self):
if not self.buffers:
return
buffer, self.buffers = self.buffers[0],self.buffers[1:]
self.send(buffer)
def writable(self):
return self.buffers
def handle_read(self):
message = self.recv(8192)
self.view.show_message(message.decode('utf-8'))
def idle_task(root):
try:
asyncore.loop(count=1, timeout=1)
finally:
root.after(200, functools.partial(idle_task, root))
def main():
root = tkinter.Tk()
root.after(200, functools.partial(idle_task, root))
view = EchoView(root)
view.pack(expand=True, fill=tkinter.BOTH)
client = EchoClient(view)
client.connect(('localhost', 8080))
root.mainloop()
if __name__ == '__main__':
main()
server側コード
import asyncore
class EchoHandler(asyncore.dispatcher_with_send):
def __init__(self, socket, parent):
super(EchoHandler, self).__init__(socket)
self.parent = parent
def handle_read(self):
data = self.recv(8192)
if data:
self.parent.send(data)
class EchoServer(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.handlers = []
self.create_socket()
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
def handle_accepted(self, sock, addr):
print('Incoming connection from %s' % repr(addr))
handler = EchoHandler(sock)
self.handlers.append(handler)
def send(self, data):
for handler in self.handlers:
handler.send(data)
server = EchoServer('localhost', 8080)
syncore.loop()
※lambda関数を使用した際のエラーメッセージ
Incoming connection from ('127.0.0.1', 51076)
error: uncaptured python exception, closing channel
<main.EchoServer listening localhost:8080 at 0x107e18f28> (:init() missing 1 required positional argument: 'parent'
[/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncore.py|read|83]
[/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncore.p
y|handle_read_event|416]
[/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncore.p
y|handle_accept|493] [server.py|handle_accepted|27])