質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.46%

  • Python 3.x

    2184questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Tkinter

    49questions

    Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

pythonのTkinterでクライアントGUIを作ったのですが、エラーが出てしまいます。

解決済

回答 1

投稿 2016/11/12 14:44 ・編集 2016/11/13 04:11

  • 評価
  • クリップ 0
  • VIEW 762

0chihiro0

score 1

前提・実現したいこと

参考書を読みながら、Echoアプリケーションを作成中です。
言語はPythonで、Tkinter,syncore,functoolsライブラリを使っています。
今回のコードはクライアント側なのですが、実行しようとしてもエラーが出てしまい、GUIの画面もうまく表示されません。
こういう場で質問することが初めてなので、至らないところがあるかもしれないので、その時はご指摘ください。

発生している問題・エラーメッセージ

Traceback (most recent call last):
  File "/Users/CHIHIRO/Downloads/Python/Part3/11/client.py", line 76, in <module>
    main()
  File "/Users/CHIHIRO/Downloads/Python/Part3/11/client.py", line 68, in main
    root.after(200, functools.partial(idle_task, root))
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/tkinter/__init__.py", line 593, in after
    callit.__name__ = func.__name__
AttributeError: 'functools.partial' object has no attribute '__name__'

該当のソースコード

# -*- coding::utf-8 -*-

import tkinter
import asyncore
import functools

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()

試したこと

エラーメッセージにmain関数のfunctools.partailの部分が出ているので、functorsのドキュメントを読んだのですが、自分では原因がわかりませんでした。
ですので、助けて頂けるとありがたいです。
よろしくお願いします。

補足情報(言語/FW/ツール等のバージョンなど)

Python3.4.4

『パーフェクトPython』:
著 Pythonサポーターズ:
発行 技術評論社:
11章チャットアプリケーションのP230~P235の部分です

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • ikedas

    2016/11/12 15:44

    Pythonのバージョンを明記してください。また、参考にしている書籍 (著者・標題・出版社と、参考にした箇所のページ数) も教えてもらえますか。

    キャンセル

  • 0chihiro0

    2016/11/13 06:09

    ご指摘ありがとうございます。編集しておきました。次からは載せるようにします。

    キャンセル

回答 1

checkベストアンサー

+1

tinter,syncope,functorsライブラリを使っています。 

見事に全部に typo が・・・閑話休題

エラーの原因ですが tkinter の内部の変更によるものの様です。

詳細なバージョンは解りませんが、おそらく 3.4.x の途中からの変更で、
3.4.0 ではエラーは出ませんでした。

 修正方法

エラーログより、functools.partial で生成したオブジェクトには __name__ 属性がないようなので、
通常のように関数を定義して渡す、もしくは lambda 式 でコールバックを渡すことで回避します。

functools.partail(idle_task, root) 

となっている2箇所を

lambda:idle_task(root)

と変更し試してみて下さい。
エラー無しでウィンドウが出るところまでは確認しました。@ win10 / 3.5.0, 3.6.0a2

投稿 2016/11/12 16:58

編集 2016/11/12 17:01

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/13 06:06

    GUIが無事に表示されました。
    lambdaについてももっと勉強します。
    ありがとうございました。

    キャンセル

  • 2016/11/14 00:35

    すいません。説明不足だったので少し補足させてください。
    lambda の利用は、このコードでの 一時的な回避策の為 でした。

    実際の Python のプログラムでは、コールバックを引数に渡すようなところでは、
    partial の利用が推奨されてます。例えば、asyncio というモジュールのコールバックの説明では
    http://docs.python.jp/3.5/library/asyncio-eventloop.html#calls

    > 注釈 lambda 関数よりも functools.partial() を使用しましょう。 asyncio はデバッグモードで引数を表示するよう functools.partial() オブジェクトを精査することが出来ますが、lambda 関数の表現は貧弱です。

    他の局面でも、lambda を使うところでは、
    極力lambdaを使わないで代替手段を取るのが推奨されてます。

    今回のコードでは、idle_task を main関数内 root を生成した後に定義すれば
    rootを引数に渡すために functools.partial や lambda を使うことなく記述できます。

    ‘‘‘python
    def main():
    root = tkinter.Tk()

    def idle_task():
    try:
    asyncore.loop(count=1, timeout=1)
    finally:
    root.after(200, idle_task)
    root.after(200, idle_task)
    ‘‘‘

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.46%

関連した質問

同じタグがついた質問を見る

  • Python 3.x

    2184questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Tkinter

    49questions

    Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。