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

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

ただいまの
回答率

88.23%

TypeError: __init__() missing 3 required positional arguments: 'request', になるのはなぜでしょうか

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,021

eisaku123

score 53

Pyhonのクラスに関することで細かいことになるのですが

server = HTTPServer((host, port), Handler)

正常に動作しますが

hand=Handler() にして
server = HTTPServer((host, port),hand )

に変更すると以下のようなエラー(標記)になってしまいます。

インスタンスにしてから引数にセットするとなぜエラーになるのかわかりませんので
ご教授よろしくお願いいたします。

ソースはさらに下にあります。

(python3-toku) pi@raspberrypi:~/toku1/01-04-a1/package_parts $ python app_server.py 
__main__
Traceback (most recent call last):
  File "app_server.py", line 147, in <module>
    run(app)
  File "app_server.py", line 85, in run
    hand=Handler()
TypeError: __init__() missing 3 required positional arguments: 'request', 'client_address', and 'server

ソース
※の部分3点を変更

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from http.server import BaseHTTPRequestHandler, HTTPServer
import os, time

import wiringpi
from parts import Led

# グローバル変数
_application = None
_server = None


class Handler(BaseHTTPRequestHandler):
    """ HTTPリクエストを処理するクラス """

    def do_GET(self):
        """ GETメソッドによるHTTPリクエストを処理する関数 """
        global _application
        if self.path == '/shutdown':
            self._do_response('shutdown')
            global _server
            if _server is not None and _server.socket is not None:
                _server.socket.close()
                _server = None
                return
        if _application is not None:
            result, response_body = _application.exec(self.path)
        if result:
            self._do_response(response_body)
        else:
            result = self._do_file_response(self.path)
            if not result: # 上記にあてはまらない場合は対応するパスがない
                self.send_error(404, 'File Not Found: {0}'.format(self.path))
        return

    def _do_response(self, s):
       """ 省略 """

    def _do_file_response(self, url_path):
       """ 省略"""

def run(app=None, host='0.0.0.0', port=8080, cam=None):
    """ サーバー起動用関数
    app: アプリケーション機能拡張用オブジェクト exec()メソッドが必要
    host: 待機するIPアドレス
    port: 待機するポート
    cam: mjpeg_server用カメラオブジェクト start(), stop(), capture() メソッドが必要
    """
    global _application
    global _server
    _application = app
    hand=Handler() ※-----ここを追加
    server = HTTPServer((host, port),hand )※-------これに変更 エラーになる
    #server = HTTPServer((host, port), Handler)※---これをこコメントアウト 正常
    print(time.asctime(), 'Server start - {0}:{1}'.format(host, port))
    try:
        _server.serve_forever()
    except ValueError:
        print('remote shutdown')
    except KeyboardInterrupt:
        print('KeyboardInterrupt')
    finally:
        if _server is not None and _server.socket is not None:
            _server.socket.close()
    print(time.asctime(), 'Server stop - {0}:{1}'.format(host, port))


if __name__ == '__main__':  # このファイルがスクリプトとして実行される時だけ処理を実行

    print(__name__)
    #run()
    # -- 定数宣言 -- #
    # LEDのGPIO番号
    LED_PIN = 4
    # HTTPレスポンス用HTMLデータ
    HTML_TEXT = """
    <!doctype html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>toku1/01</title>
    </head>
    <body>
    <p><input type="button" value="点灯" onclick="location.href='/led/1'"></p>
    <p><input type="button" value="消灯" onclick="location.href='/led/0'"></p>
    <p><input type="button" value="停止" onclick="location.href='/shutdown'"></p>
    </body>
    </html>
    """


    class Led01(Led):
        """ app_server対応版parts.LEDクラス """

        def exec(self, path):
            """ ルーティング処理を記述 """
            if path == '/led/0':
                self.set_status(0)  # LED消灯
            elif path == '/led/1':
                self.set_status(1)  # LED点灯
            else:
                return False, ''
            result_body = self.render_template()
            return True, result_body

        def render_template(self):
            """ レンダリング処理を記述 """
            return HTML_TEXT

    # 自作のLED01を使ったWebアプリの実行
    wiringpi.wiringPiSetup()
    app = Led01(LED_PIN)
    run(app)
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

なぜか、というより、そもそもクラスを取る仕様なのでインスタンス化して渡すのは明確な間違いなのです。

class http.server.HTTPServer(server_address, RequestHandlerClass)¶
このクラスは TCPServer クラスの上に構築されており、サーバのアドレスをインスタンス変数 server_name および server_port に記憶します。 サーバはハンドラからアクセス可能で、通常ハンドラの server インスタンス変数からアクセスします。
http.server --- HTTP サーバ — Python 3.8.2 ドキュメント

受け取ったハンドラは内部で適切な引数でインスタンス化されます。


エラー自体は、Handlerクラスの親クラスの__init__の定義に起因します。__init__をオーバーライドしていないので、親クラスの定義のままです。
(オーバーライドすればいい、という意味ではありません。念の為)

class http.server.BaseHTTPRequestHandler(request, client_address, server)
http.server --- HTTP サーバ — Python 3.8.2 ドキュメント

コンストラクタは3つの引数を要求するので、hand=Handler()を追加した時点でエラーに鳴ります。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/03/11 20:52

    hayataka2049さん
    ありがとうございます!
    ここまでの解決にいたるには私の知識ではたどりつけなかったです。
    ドキュメントをよめるようにしたいです

    キャンセル

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

  • ただいまの回答率 88.23%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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