TonamiLog

ゆるキャン△とスノーボードとオタク

ABC131(3完)と今後の方針

hayトナミです


ABC131をやって3完でした。

まとめを書こうと思ったんですが毎回まとめしてもつまらないので概要と考えてる事を書こうと思います。

概要

A

省略

B

省略

C

あれ?通らんぞ?あれ?ンン?をやっていたら終わり。
CでもDでも割り切れる数の扱いが上手く行かなくて通せませんでした。
なんでかなー、算数の脳みそが動かなかったとしか言えず、辛い気持ちになりました。

D

Cが通らなかったので気晴らしにやったら一瞬で通せました。
解説どおりのソースなので想定解だと思うんですけど、いまいち証明に自信がありません。
これ証明するのやや難しくないですか?

E

Dが通せたし今更C通してもたいして順位上がらんなという状態だったので着手。
解説どおりの解法にはたどり着いており、実装が間に合わなくて終わりました。


f:id:Thiroyuki:20190623024949p:plain
結果としては大惨事です。

今後について

現在のABCは参加者が多く、早解き勝負のハードルが上がってるような気がします。
旧ABC時代はCまでの早解きでレートを稼ごうという方針だったのですが、これが通用しなくなってしまいました。
そこで、これからは400~600点問題の精進を真面目にやろうと思います。
これ言うと今までやってなかったんですか!???!?wwwwとか言われそうですけど
今までは基本的に300点以下の早解きを主軸に精進をしてたのでした。
f:id:Thiroyuki:20190623025417p:plain
こんな感じです。
なぜかというとまあ、400以上の問題は解けなくて面白くないからというのが理由だったんですけど。
最近はDまでは割と解けるようになってきているし、多分自分にとってのレートを上げに関して
早解きでは限界というところまできたんだと思います。
dpやるぞーとかTwitterで言ってたんですけど、dpをやるというよりは今より少し上の問題を解くというのが正しいです。

レートがモリモリ下がってやる気を失いそうになっていたんですが
少し前に公式解説放送で言っていた
「それっぽい貪欲だけ書くより、ちゃんと考察して証明出来る解法を出した方が、長期的にはレートが上がる。」
というのを信じて頑張っていこうと思います。


まずは蟻本を全部理解するのと毎日過去問に戻ります。
やっていきましょう。
おわり

python:requestsを使ってリクエストボディのついたGETリクエストを送出する

トナミです。表題通りの事します。


GETリクエストにリクエストボディつけて送ってくれと言われてンェー何それという気持ちが発生しました。

調べてみるとGETリクエストにおけるリクエストボディの取扱はRFCに記述がありません(=未定義です)。

なんでまー、クライアントにしろサーバにしろ、好きに実装してねという状態のようです。

ソースコードの組み合わせで君だけの最強のGETリクエストにおけるリクエストボディの取扱を実装しろ!


というわけでやります。とは言え一般的でないため、簡単に調べても出てきません。

この手の話題「pythonでHTTP通信!」みたいなエントリーがヒットしまくりググラビリティが低すぎで涙出ます。


とりあえず普段使ってるrequestsさんで出来ないか考えましょう。requestsの基本的な使い方は省略します。
postの時はリクエストボディを付与出来て、getの時は普通にやると付与されないという認識があります。
まず両者の違いですが

def get(url, params=None, **kwargs):
    r"""docstring長いので省略
    """

    kwargs.setdefault('allow_redirects', True)
    return request('get', url, params=params, **kwargs)

これがget

def post(url, data=None, json=None, **kwargs):
    r"""docstring長いので省略
    """

    return request('post', url, data=data, json=json, **kwargs)

これがpost

という感じです。
キーワード引数が違うだけで、最終的に全部突っ込んでrequest()している事が分かります。

ここでrequestが何かと言うと

def request(method, url, **kwargs):
    """
    (docstringには他にも色々と大事な事が書いてあるんですが、長かったので抜粋)

    :param params: (optional) Dictionary, list of tuples or bytes to send
        in the query string for the :class:`Request`.
    :param data: (optional) Dictionary, list of tuples, bytes, or file-like
        object to send in the body of the :class:`Request`.
    """

    # By using the 'with' statement we are sure the session is closed, thus we
    # avoid leaving sockets open which can trigger a ResourceWarning in some
    # cases, and look like a memory leak in others.
    with sessions.Session() as session:
        return session.request(method=method, url=url, **kwargs)

という感じになってます。
結局mthodの種類とrequest投げる先の情報以外は全部突っ込まれているということです。
んでdocstringを見ると、paramsはquery stringへ、dataはbodyへ行くぜ!という事が書いてあります。わかりやすい
(余談:docstringにコピペミスがあってoss貢献チャンスかと思いきや、自分のrequsetsがちょっと古かっただけで修正済みでした。)

つまり考えはこうです。
postの時にリクエストボディが設定されてるのは、dataに要素を渡しているから。
getの時にリクエストボディが生まれないのは、paramsにしか要素を渡していないから。
kwargsのところに入れてしまえば、どんなパラメータも最後は同じ出口から送出されていく。
んじゃgetリクエスト打つ時にdataを定義すればリクエストボディにしてもらえるんじゃねえの?

実際にやってみます

from flask import Flask, request
import json

app = Flask(__name__)

@app.route('/test', methods=['GET'])
def test():
    body = json.loads(request.data)
    print(body)

    return body['test']

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8080, debug=True)

こんな感じに適当に立てたflaskサーバにリクエストを投げ、'bodydata'が取り出せるか確認します。
※flaskにおいてリクエストボディの内容はrequset.dataで取り出せるということになっています。
私は甘いのでここの検証をしていません

投げるソースはこんな

import requests
import json

url = 'http://localhost:8080/test'
data = {'test': 'bodydata'}
response = requests.get(url, data=json.dumps(data))
print(response.text)

サーバ側のソースを実行するとlocalhost:8080にFlaskくんが立つので、投げるソースを実行して似非通信をしてます。
localhostに立ってるサーバに同一ホストからリクエスト投げた、というのが検証として妥当なのか検証していません。

上記ソースをアレするとサーバ側でもクライアント側でもいい感じの値が取れてる事を確認出来ます。
これでGETリクエストにリクエストボディをつける事が出来、この問題を解く事が出来ました。よかったですね

マサカリお待ちしております。
おわり