tag:crieit.net,2005:https://crieit.net/tags/Python3/feed 「Python3」の記事 - Crieit Crieitでタグ「Python3」に投稿された最近の記事 2020-10-07T16:56:56+09:00 https://crieit.net/tags/Python3/feed tag:crieit.net,2005:PublicArticle/16118 2020-10-07T16:56:24+09:00 2020-10-07T16:56:56+09:00 https://crieit.net/posts/Chrome-ChromeDriver ChromeとChromeDriverのバージョン違いによるエラー <p>初めての記事投稿(ポエム以外で)です</p> <h5 id="概要"><a href="#%E6%A6%82%E8%A6%81">概要</a></h5> <p>Seleniumを使ってスクレイピングをしています。<br /> プログラムが動いてない…と思ったらChromeが自動更新されていてCromeDriverとバージョンが合わなくなっていたからだったという話です(つい1時間前までは動いてたのに…)コードはお見せできませんが、備忘録的に記しておきます。</p> <pre><code class="python">$ python3 sc.py (中略) selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 84 # バイナリでインストールしたChromeDriver $ chromedriver --version ChromeDriver 84.0.4147.30 # 現在のChrome $ google-chrome --version Google Chrome 86.0.4240.75 # ChromeDriverのインストール $ pip install chromedriver-binary==86.0.4240.22 Successfully installed chromedriver-binary-86.0.4240.22.0 </code></pre> <p>今回はChromeDriverをpipでインストールしたので、プログラム(scr.py)に<br /> <code>import chromedriver_binary</code>を追記</p> <p><code>driver = webdriver.Chrome(options=options, executable_path=r'/usr/local/bin/chromedriver')</code><br /> の<code>executable_path</code>以降を削除</p> <h5 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h5> <ul> <li><p>ChromeDriverのインストール</p> <p><a target="_blank" rel="nofollow noopener" href="https://qiita.com/hanzawak/items/2ab4d2a333d6be6ac760">[selenium向け] ChromeDriverをpipでインストールする方法(パス通し不要、バージョン指定可能) </a></p></li> <li><p>ChromeDriver</p> <p><a target="_blank" rel="nofollow noopener" href="http://chromedriver.chromium.org/downloads">Downloads - ChromeDriver - WebDriver for Chrome </a></p></li> </ul> 橘 lah tag:crieit.net,2005:PublicArticle/15733 2020-02-25T01:17:50+09:00 2020-02-25T01:17:50+09:00 https://crieit.net/posts/auto-generate-requirements-with-dephell requirements.txtの自動生成 〜Pythonスクリプトから依存パッケージを抽出する〜 <h1 id="この記事の概要"><a href="#%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%81%AE%E6%A6%82%E8%A6%81">この記事の概要</a></h1> <ul> <li><code>dephell</code> コマンドを使うと Python パッケージの依存関係記述ファイルの相互変換ができる <ul> <li>setup.py から requirements.txt を作るとか</li> </ul></li> <li>プロジェクトの Python パッケージの <code>import</code> を読み取って適切なフォーマットに変換できる</li> <li>依存関係が掲載されていないプロジェクトでも使えるのでオススメ</li> </ul> <h1 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h1> <p>データの前処理や可視化はどうやったの?みたいな話で Jupyter Notebook が残っているけど、特に requirements.txt とか setup.py が残ってない、みたいなケースがままあると思います。</p> <p>もはや依存関係のバージョンの同定は不可能ですし、ほとんどの場合システムに組み込むとかしないので「動けばいい(再現すればいい)」のですが、そもそも動かすために依存するライブラリの一覧を作るのが一苦労です。ノートブックを開いて<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>、import 文からサードパーティのライブラリを特定して、requirements.txt を作る単純作業になります。</p> <p>そんなつまらない作業、自動化したいよな〜思うことでしょう。そんなときに使えるのが<a target="_blank" rel="nofollow noopener" href="https://github.com/dephell/dephell">DepHell</a>です。下記 1 コマンドだけで、スクリプトの import 文から requirements.txt を作ってくれます。</p> <pre><code>$ dephell deps convert --from=imports --to=requirements.txt </code></pre> <h1 id="実施手順"><a href="#%E5%AE%9F%E6%96%BD%E6%89%8B%E9%A0%86">実施手順</a></h1> <p>下記プロジェクトを例に説明します。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/515hikaru/create-requirement-from-imports">515hikaru/create-requirement-from-imports</a></p> <p>上記リポジトリにはサンプルとして<a target="_blank" rel="nofollow noopener" href="https://github.com/515hikaru/create-requirement-from-imports/blob/master/notebook/load_data.ipynb">僕がなんとなく書いた</a>ノートブックが置いてあります。このサンプルでは下記のように import をしています。</p> <ul> <li>先頭のセルで pandas の import</li> <li>関数内で matplotlib の import(動的インポート)</li> <li>ノートの後半で PyTorch(torch)と sklearn の import</li> </ul> <p>もちろん(?)プロジェクトには requirements.txt もなんにもありません。この状態から、requirements.txt を作ります。</p> <h2 id="DepHell のインストール"><a href="#DepHell+%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">DepHell のインストール</a></h2> <p>まずはコマンドをインストールしましょう。Python3.6 以上が必要です。公式のインストール方法に従います。</p> <pre><code>curl -L dephell.org/install | python3 </code></pre> <p>ちなみに現時点では Windows はサポートできていないようです<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>。</p> <h2 id="Jupyter Notebook をスクリプトに変換"><a href="#Jupyter+Notebook+%E3%82%92%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%AB%E5%A4%89%E6%8F%9B">Jupyter Notebook をスクリプトに変換</a></h2> <p>.ipynb ファイルは <code>jupyter nbconvert</code> コマンドで Python スクリプト形式に変換できます。もちろん、ブラウザでダウンロードする方法もありますが、たくさんノートブックがあるときはコマンドの方が楽に変換できるでしょう。</p> <pre><code>$ jupyter nbconvert --to script notebook/load_data.ipynb </code></pre> <p>これで notebook/load_data.py ができるはずです。</p> <h2 id="いざ変換"><a href="#%E3%81%84%E3%81%96%E5%A4%89%E6%8F%9B">いざ変換</a></h2> <p>変換する前に、Python のパッケージであることを示すために <code>__init__.py</code> を置く必要があります。</p> <pre><code>$ touch notebook/__init__.py </code></pre> <p>あとは変換コマンドを実行するだけです。</p> <pre><code>$ dephell deps convert --from imports --to requirements.txt $ cat requirements.txt matplotlib pandas scikit-learn torch </code></pre> <p>ノートブックに登場していたすべての外部パッケージがリストアップされました。</p> <p>あとはバージョンを固定するなり、このままリポジトリに add するなり、好きにしましょう。</p> <h1 id="終わりに"><a href="#%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%AB">終わりに</a></h1> <p>サンプルはたった 4 つだったので手動でやってもたかが知れていますが、実際の現場では複数のモジュールを使っていたりしてあとから全容を把握するのは結構大変ということはあると思います。</p> <p>DepHell が依存関係の記述の一助になれば幸いです。</p> <div class="footnotes" role="doc-endnotes"> <hr /> <ol> <li id="fn:1" role="doc-endnote"> <p>ほとんどの場合、ノートは 1 つではなく複数でしょう。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p> </li> <li id="fn:2" role="doc-endnote"> <p>https://github.com/dephell/dephell/issues/343 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">↩︎</a></p> </li> </ol> </div> 515hikaru tag:crieit.net,2005:PublicArticle/15509 2019-10-26T22:52:42+09:00 2019-10-27T14:20:12+09:00 https://crieit.net/posts/CLI CLIツールを簡単に作れるフレームワークを作ったよ! <p>PythonでCLIツールを簡単に作れるようになるフレームワークを作ってみました!</p> <p>argparseって正直使いにくくないですか?<br /> groomなら、実質関数を1つ定義するだけでコマンドラインツールを作成できます。</p> <h2 id="インストール"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">インストール</a></h2> <p>pypiに登録してあるので簡単!</p> <pre><code class="sh">$ pip install groom </code></pre> <p>これで終わりです。早速使ってみましょう!</p> <h2 id="簡単に使ってみる"><a href="#%E7%B0%A1%E5%8D%98%E3%81%AB%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B">簡単に使ってみる</a></h2> <p>さて、早速使ってみましょう。<br /> 2つの数を取って、四則演算するコマンドラインツールを作ってみます。</p> <pre><code class="python">import sys from groom import positional, optional, Dispatcher __version__ = '1.0' def calculate( num1: positional(float, "former number", required=True, var_name='N1'), num2: positional(float, "latter number", required=True, var_name='N2'), operator: optional(str, "operator name", short_name='op')='add'): if operator == 'add': print(num1 + num2) return if operator == 'sub': print(num1 - num2) return if operator == 'mul': print(num1 * num2) return if operator == 'div': print(num1 / num2) return print("unknown operator:", operator, file=sys.stderr) if __name__ == '__main__': Dispatcher( calculate, "calculate one of four arithmetic operations" ).dispatch() </code></pre> <p>これだけで、ヘルプの表示やコマンドライン引数の処理までができます。<br /> 生成されたヘルプメッセージはこんな感じ。</p> <pre><code class="text">calc.py: 1.0 calculate one of four arithmetic operations Usage: calc.py [-v | --version | -h | --help] calc.py params... positional parameters: N1: former number type: float required: True N1: latter number type: float required: True parameters: --operator, -op: operator name type: str required: False multiple values: False default: add </code></pre> <p>どうでしょうか? かなり簡単になっているのではないかと思います。<br /> ヘルプメッセージの改善に関しては鋭意取り組み中ですので、少々お待ち頂けたらw</p> <hr /> <p>追記 2019/10/27</p> <p>groom==0.0.3a1で、ヘルプメッセージを少し改善しました。現在はこのようになります。</p> <pre><code class="text">calc.py: 1.0 calculate one of four arithmetic operations Usage: calc.py [-v | --version | -h | --help] calc.py <N1> <N2> [--operator <OPERATOR> | -op <OPERATOR>] positional parameters: N1: former number type: float required: True N2: latter number type: float required: True parameters: --operator, -op: operator name type: str required: False multiple values: False default: add </code></pre> <hr /> <p>一応サブコマンドにも対応していまして、以下のようにすれば可能です。が、こちらも鋭意改善中です。</p> <pre><code class="python">d = Dispatcher(func, "desc") d.add_subcommand( "sub-command", Dispatcher(subfunc, "subdesc")) </code></pre> <p>このプロジェクトのGitHubのリポジトリは<a target="_blank" rel="nofollow noopener" href="https://github.com/frodo821/groom">https://github.com/frodo821/groom</a>です。issueやpull requestなど、どんどんお寄せいただけたら凄く嬉しいです。よろしくお願いします。</p> frodo821 tag:crieit.net,2005:PublicArticle/15387 2019-09-10T20:49:01+09:00 2019-09-10T20:49:01+09:00 https://crieit.net/posts/TSV-Markdown TSVで定義した辞書をMarkdownで出力するツールを作った話 <h2 id="TL;DR"><a href="#TL%3BDR">TL;DR</a></h2> <p>電子辞書が欲しくなったので作ることにしました。今回の要件は、品詞別の索引と全単語の索引、先頭の文字ごとの詳細解説があることです。</p> <p>そこで辞書本体をmarkdownで書くことにしたのですが、ちまちま手で書くのは面倒くさい。なのでTSVを読み込んでmarkdownを吐くジェネレータを簡単に書いてみることにしました。</p> <h2 id="TSVに格納する辞書の形式を考えてみた"><a href="#TSV%E3%81%AB%E6%A0%BC%E7%B4%8D%E3%81%99%E3%82%8B%E8%BE%9E%E6%9B%B8%E3%81%AE%E5%BD%A2%E5%BC%8F%E3%82%92%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%81%9F">TSVに格納する辞書の形式を考えてみた</a></h2> <p>TSVとは言いつつ、純粋なTSVは使っていません。まずは辞書のヘッダ部分です。</p> <pre><code>BEGIN_HEADER LANGUAGE_LONG Language Name LANGUAGE_CODE LC(注1) PHONETICAL_CHARS 頭文字になりうる文字の列挙(注2) END_HEADER </code></pre> <ul> <li>注1 これは2~3文字の言語コードです。<code>ja</code>, <code>en</code>など</li> <li>注2 スペース区切りで列挙します。<code>a b c d e f g h i j k l m n o p q r s t u v w x y z</code>のように</li> </ul> <p>続いて、辞書の本体を考えてみました。</p> <pre><code>BEGIN_DICTIONARY 単語 品詞ID(注1) 意味 関連語(注2) END_DICTIONARY </code></pre> <ul> <li>注1 品詞IDは任意の文字列です。</li> <li>注2 関連語はスペース区切りで列挙します。<code>study learn</code>のように</li> <li>単語は任意個この形式で列挙します。</li> </ul> <p>最後に、品詞の定義です。</p> <pre><code>BEGIN_DEFINITION 品詞ID 品詞の名称 END_DEFINITION </code></pre> <p>このフィールドでは、DICTIONARYフィールド内で使用した品詞IDとその名称の対応(<code>NOUN</code>と名詞のような)を定義します。</p> <h2 id="パーサーをざっくり書いてみる"><a href="#%E3%83%91%E3%83%BC%E3%82%B5%E3%83%BC%E3%82%92%E3%81%96%E3%81%A3%E3%81%8F%E3%82%8A%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%8B">パーサーをざっくり書いてみる</a></h2> <p>さて、このパーサーをざっくり書いてみました。</p> <pre><code class="python">import csv class ParseError(SyntaxError): pass def open_dict(dic_path: str) -> list: with open(dic_path, encoding='utf-8') as f: reader = csv.reader(f, delimiter='\t') return list(reader) def parse_dict(dic: list) -> dict: ret = {} state = 'none' for i in dic: if i[0] == 'BEGIN_HEADER': if state != 'none': raise ParseError('Unexpected BEGIN_HEADER tag.') state = 'header' ret['header'] = {} continue if i[0] == 'END_HEADER': if state != 'header': raise ParseError('Unexpected END_HEADER tag.') state = 'none' continue if i[0] == 'BEGIN_DICTIONARY': if state != 'none': raise ParseError('Unexpected BEGIN_DICTIONARY tag.') state = 'dictionary' ret['dict'] = {} continue if i[0] == 'END_DICTIONARY': if state != 'dictionary': raise ParseError('Unexpected END_DICTIONARY tag.') state = 'none' continue if i[0] == 'BEGIN_DEFINITION': if state != 'none': raise ParseError('Unexpected BEGIN_DEFINITION tag.') state = 'definition' ret['defs'] = {} continue if i[0] == 'END_DEFINITION': if state != 'definition': raise ParseError('Unexpected END_DEFINITION tag.') state = 'none' continue if state == 'none': continue if state == 'header': ret['header'][i[0]] = i[1] continue if state == 'dictionary': if i[0] not in ret['dict']: ret['dict'][i[0]] = {} ret['dict'][i[0]][i[1]] = { 'meaning': i[2], 'reference': i[3].split(' ') } continue if state == 'definition': ret['defs'][i[0]] = i[1] if state != 'none': raise ParseError(f'A match pair tag of END_{state.upper()} not found.') return ret </code></pre> <p>まぁ、本当に簡単に書いているので、解説することもほとんどないんですけれど……。ざっくり説明すると、tsvを読み込んで2次元配列に格納し、それを先ほど定義したフォーマットに従って辞書に格納しなおしているだけです。</p> <p>次に、この生成した辞書から索引情報を抽出する関数を定義してみます。</p> <pre><code class="python">def get_comparator(_order): class _Comparator(str): def __gt__(self, other): order = list(_order) for s, o in zip(self, other): oi = order.index(o) si = order.index(s) if oi > si: return True if si > oi: return False return len(self) > len(other) def __lt__(self, other): order = list(_order) for s, o in zip(self, other): oi = order.index(o) si = order.index(s) if oi < si: return True if si < oi: return False return len(self) < len(other) return _Comparator def generate_indices(dic: dict): chars = dic['header'].get( 'PHONETICAL_CHARS', 'a b c d e f g h i j k l m n o p q r s t u v w x y z').split(' ') nodes = {i: {c: [] for c in chars} for i in dic['defs']} nodes['ALPHABETICAL'] = {c: [] for c in chars} comp = get_comparator(''.join(chars)) for word, data in dic['dict'].items(): nodes['ALPHABETICAL'][word[0]].append(word) for kind in data: nodes[kind][word[0]].append(word) for i in nodes.values(): for j in i.values(): j.sort(key=comp) return nodes </code></pre> <p><code>get_comparator</code>関数は、<code>PHONETICAL_CHARS</code>ヘッダフィールドで定義された辞書順に従って文字列を比較できるようにするラッパークラスを返す関数です。品詞ごとに単語の頭の文字の配列を作り、そこに単語のみを格納しているだけですね。<code>ALPHABETICAL</code>は全単語索引の情報で、定義されたすべての単語が登録されています。</p> <p>次に意味情報と関連語情報を抽出する関数を定義します。</p> <pre><code class="python">def generate_dict_content(dic: dict): chars = dic['header'].get( 'PHONETICAL_CHARS', 'a b c d e f g h i j k l m n o p q r s t u v w x y z').split(' ') defs = dic['defs'] contents = {i: [] for i in chars} comp = get_comparator(''.join(chars)) for word, data in dic['dict'].items(): contents[word[0]].append({ 'surface': word, 'meaning': [ (kind, meta['meaning'].split(' ')) for kind, meta in data.items() ], 'reference': [ref for d in data.values() for ref in d['reference']] }) for c in contents.values(): c.sort(key=lambda x: comp(x['surface'])) return contents </code></pre> <p>この関数についての解説は、<code>generate_indices</code>関数とほぼ同じ動作のため割愛します。</p> <p>これでTSVから単語情報を抽出する関数がそろいました。次はこれをmarkdownとして出力する関数を作っていきます。</p> <h2 id="抽出した情報をMarkdownにしてみる"><a href="#%E6%8A%BD%E5%87%BA%E3%81%97%E3%81%9F%E6%83%85%E5%A0%B1%E3%82%92Markdown%E3%81%AB%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">抽出した情報をMarkdownにしてみる</a></h2> <p>索引を生成する関数を考えてみました。こんな感じです。</p> <pre><code class="python">def generate_index_file(kind: str, defs: dict, index: list): ret = f"# {defs[kind]}\n" if kind == 'ALPHABETICAL': ret += "\n## 品詞別インデックス\n" for fp, kd in defs.items(): if fp != 'ALPHABETICAL': ret += f"* [{kd}](./{fp.lower()}.md)\n" for representative, content in index.items(): ret += f"\n## {representative.upper()}\n" for word in content: ret += f"* [{word}](./content/{word[0].upper()}.md#{word})\n" return ret </code></pre> <p>すごいシンプルにかけて満足しています。あまりPythnoicではないと思いますが、そこは気にしないことにします。あと、<code>ALPHABETICAL</code>のページに品詞別インデックスへのリンクを表示することにしました。引数の意味ですが、<code>kind</code>は品詞ID、<code>defs</code>は品詞の定義、<code>index</code>には単語のリストを渡します。</p> <p>続いて、単語の解説ページを生成する関数を考えてみました。</p> <pre><code class="python">def generate_content_file(representative: str, words: list, defs: dict): ret = f"# {representative.upper()}\n" for word in words: ret += f"\n## {word['surface']}\n" ret += "意味: \n" for i, (k, m) in enumerate(word['meaning']): ret += f"{i + 1}. <{defs[k]}> \n" for ml in m: ret += f" {ml} \n" refs = [i for i in word['reference'] if i] if refs: ret += "\n関連語: \n" for ref in refs: ret += f"* [{ref}](./{ref[0].upper()}.md#{ref})\n" return ret </code></pre> <p>引数の意味ですが、<code>representative</code>は代表の文字(ようするにそのページの単語に共通の頭文字)、<code>words</code>は単語とそのメタ情報、<code>defs</code>は品詞の定義をとります。</p> <p>さて、最後にこれらの関数の動作を連結する関数を書きましょう。それで完成です。</p> <pre><code class="python">def generate_markdown_files(dic: dict): indices = generate_indices(dic) content = generate_dict_content(dic) chars = dic['header'].get( 'PHONETICAL_CHARS', 'a b c d e f g h i j k l m n o p q r s t u v w x y z').split(' ') defs = dic['defs'].copy() defs['ALPHABETICAL'] = "全単語索引" return { 'content': { i: generate_content_file(i, content[i], defs) for i in chars }, 'indices': { ('index' if i == 'ALPHABETICAL' else i.lower()): generate_index_file(i, defs, content) for i, content in indices.items() } } </code></pre> <p>この関数はparseされたTSVをmarkdown形式の文字列に変換する関数です。ここまでに定義した関数を連結して整形された形にするのが役割ですね。</p> <p>さて、これをファイルにdumpする関数を書いて、それで本当に完成です。</p> <pre><code class="python">def dump_markdown(dic_path: str, dump_dir: dir): dic_path = abspath(dic_path) dump_dir = abspath(dump_dir) files = generate_markdown_files(parse_dict(open_dict(dic_path))) print('generating indices...') for rep, con in files['indices'].items(): path = join(dump_dir, f'{rep}.md') d = dirname(path) if not exists(d): md(d) print(f'writing file: {path}') with open(path, 'w', encoding='utf-8') as f: f.write(con) print('generating content...') for rep, con in files['content'].items(): path = join(dump_dir, 'content', f'{rep.upper()}.md') d = dirname(path) if not exists(d): md(d) print(f'writing file: {path}') with open(path, 'w', encoding='utf-8') as f: f.write(con) print('done.') </code></pre> <p>この関数は、コンソールコマンドとして実行されることを想定したものになっています。</p> <p>最後に、ここまで書いたスクリプトの全体を示しておきます。</p> <pre><code class="python">#-*- coding: utf-8;-*- from os import makedirs as md from os.path import join, exists, dirname, abspath import csv class ParseError(SyntaxError): pass def get_comparator(_order): class _Comparator(str): def __gt__(self, other): order = list(_order) for s, o in zip(self, other): oi = order.index(o) si = order.index(s) if oi > si: return True if si > oi: return False return len(self) > len(other) def __lt__(self, other): order = list(_order) for s, o in zip(self, other): oi = order.index(o) si = order.index(s) if oi < si: return True if si < oi: return False return len(self) < len(other) return _Comparator def open_dict(dic_path: str) -> list: with open(dic_path, encoding='utf-8') as f: reader = csv.reader(f, delimiter='\t') return list(reader) def parse_dict(dic: list) -> dict: ret = {} state = 'none' for i in dic: if i[0] == 'BEGIN_HEADER': if state != 'none': raise ParseError('Unexpected BEGIN_HEADER tag.') state = 'header' ret['header'] = {} continue if i[0] == 'END_HEADER': if state != 'header': raise ParseError('Unexpected END_HEADER tag.') state = 'none' continue if i[0] == 'BEGIN_DICTIONARY': if state != 'none': raise ParseError('Unexpected BEGIN_DICTIONARY tag.') state = 'dictionary' ret['dict'] = {} continue if i[0] == 'END_DICTIONARY': if state != 'dictionary': raise ParseError('Unexpected END_DICTIONARY tag.') state = 'none' continue if i[0] == 'BEGIN_DEFINITION': if state != 'none': raise ParseError('Unexpected BEGIN_DEFINITION tag.') state = 'definition' ret['defs'] = {} continue if i[0] == 'END_DEFINITION': if state != 'definition': raise ParseError('Unexpected END_DEFINITION tag.') state = 'none' continue if state == 'none': continue if state == 'header': ret['header'][i[0]] = i[1] continue if state == 'dictionary': if i[0] not in ret['dict']: ret['dict'][i[0]] = {} ret['dict'][i[0]][i[1]] = { 'meaning': i[2], 'reference': i[3].split(' ') } continue if state == 'definition': ret['defs'][i[0]] = i[1] if state != 'none': raise ParseError(f'A match pair tag of END_{state.upper()} not found.') return ret def generate_indices(dic: dict): chars = dic['header'].get( 'PHONETICAL_CHARS', 'a b c d e f g h i j k l m n o p q r s t u v w x y z').split(' ') nodes = {i: {c: [] for c in chars} for i in dic['defs']} nodes['ALPHABETICAL'] = {c: [] for c in chars} comp = get_comparator(''.join(chars)) for word, data in dic['dict'].items(): nodes['ALPHABETICAL'][word[0]].append(word) for kind in data: nodes[kind][word[0]].append(word) for i in nodes.values(): for j in i.values(): j.sort(key=comp) return nodes def generate_dict_content(dic: dict): chars = dic['header'].get( 'PHONETICAL_CHARS', 'a b c d e f g h i j k l m n o p q r s t u v w x y z').split(' ') defs = dic['defs'] contents = {i: [] for i in chars} comp = get_comparator(''.join(chars)) for word, data in dic['dict'].items(): contents[word[0]].append({ 'surface': word, 'meaning': [ (kind, meta['meaning'].split(' ')) for kind, meta in data.items() ], 'reference': [ref for d in data.values() for ref in d['reference']] }) for c in contents.values(): c.sort(key=lambda x: comp(x['surface'])) return contents def generate_content_file(representative: str, words: list, defs: dict): ret = f"# {representative.upper()}\n" for word in words: ret += f"\n## {word['surface']}\n" ret += "意味: \n" for i, (k, m) in enumerate(word['meaning']): ret += f"{i + 1}. <{defs[k]}> \n" for ml in m: ret += f" {ml} \n" refs = [i for i in word['reference'] if i] if refs: ret += "\n関連語: \n" for ref in refs: ret += f"* [{ref}](./{ref[0].upper()}.md#{ref})\n" return ret def generate_index_file(kind: str, defs: dict, index: list): ret = f"# {defs[kind]}\n" if kind == 'ALPHABETICAL': ret += "\n## 品詞別インデックス\n" for fp, kd in defs.items(): if fp != 'ALPHABETICAL': ret += f"* [{kd}](./{fp.lower()}.md)\n" for representative, content in index.items(): ret += f"\n## {representative.upper()}\n" for word in content: ret += f"* [{word}](./content/{word[0].upper()}.md#{word})\n" return ret def generate_markdown_files(dic: dict): indices = generate_indices(dic) content = generate_dict_content(dic) chars = dic['header'].get( 'PHONETICAL_CHARS', 'a b c d e f g h i j k l m n o p q r s t u v w x y z').split(' ') defs = dic['defs'].copy() defs['ALPHABETICAL'] = "全単語索引" return { 'content': { i: generate_content_file(i, content[i], defs) for i in chars }, 'indices': { ('index' if i == 'ALPHABETICAL' else i.lower()): generate_index_file(i, defs, content) for i, content in indices.items() } } def dump_markdown(dic_path: str, dump_dir: dir): dic_path = abspath(dic_path) dump_dir = abspath(dump_dir) files = generate_markdown_files(parse_dict(open_dict(dic_path))) print('generating indices...') for rep, con in files['indices'].items(): path = join(dump_dir, f'{rep}.md') d = dirname(path) if not exists(d): md(d) print(f'writing file: {path}') with open(path, 'w', encoding='utf-8') as f: f.write(con) print('generating content...') for rep, con in files['content'].items(): path = join(dump_dir, 'content', f'{rep.upper()}.md') d = dirname(path) if not exists(d): md(d) print(f'writing file: {path}') with open(path, 'w', encoding='utf-8') as f: f.write(con) print('done.') if __name__ == '__main__': from sys import argv dump_markdown(argv[1], argv[2]) </code></pre> <p>はー。疲れました。はい、これでおそらくどの方面にも需要がないツールの完成です。「欲しかったから作った」の真骨頂ですね。最後までお付き合いいただき、ありがとうございました。</p> frodo821 tag:crieit.net,2005:PublicArticle/15081 2019-06-10T07:45:51+09:00 2019-06-10T07:45:51+09:00 https://crieit.net/posts/Python-ABC129A Pythonで競プロ|ABC129A| <p>今回は、<a target="_blank" rel="nofollow noopener" href="https://atcoder.jp/contests/abc129/tasks/abc129_a">AtCoder Beginner Contest 129A</a><br /> を解いていきたいと思います。</p> <h2 id="問題文"><a href="#%E5%95%8F%E9%A1%8C%E6%96%87">問題文</a></h2> <blockquote> <p>空港 A, B, C があり、それぞれの空港の間では、双方向に飛行機が運航しています。<br /> 空港 A, B 間の飛行時間は片道P時間、空港 B, C 間の飛行時間は片道Q時間、空港 C, A 間の飛行時間は、片道 R時間です。<br /> いずれかの空港からスタートして他の空港に飛行機で移動し、さらにそのどちらでもない空港に飛行機で移動するような経路を考えます。<br /> 飛行時間の和は最短で何時間になるでしょうか。</p> </blockquote> <h2 id="こう考えた"><a href="#%E3%81%93%E3%81%86%E8%80%83%E3%81%88%E3%81%9F">こう考えた</a></h2> <ul> <li>P、Q、Rをから2つを選択しそれぞれを加算する。</li> <li>それらをリストに格納し<code>min()</code>で出力する。</li> </ul> <h2 id="実装したコード"><a href="#%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%9F%E3%82%B3%E3%83%BC%E3%83%89">実装したコード</a></h2> <pre><code class="python">P,Q,R=map(int,input().split()) print(min(P+Q,Q+R,P+R)) </code></pre> <h2 id="結果"><a href="#%E7%B5%90%E6%9E%9C">結果</a></h2> <p><code>AC</code>でした。</p> <blockquote> <p>🐍やったで!</p> </blockquote> <h2 id="勉強になったコード"><a href="#%E5%8B%89%E5%BC%B7%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%82%B3%E3%83%BC%E3%83%89">勉強になったコード</a></h2> <pre><code class="python">print(sum(sorted(map(int,input().split()))[:2])) </code></pre> <ul> <li><p><code>map(int,input().split()</code>ですべての入力を受けて</p></li> <li><p><code>sorted()</code>で小さい順番に並べ替えます。</p></li> <li><p><code>[:2]</code>で小さい順番から2つを引っ張ってきて</p></li> <li><p><code>sum()</code>で合計をだして<code>print()</code>で出力します。</p></li> </ul> <h2 id="sort()とsorted()の違い"><a href="#sort%28%29%E3%81%A8sorted%28%29%E3%81%AE%E9%81%95%E3%81%84">sort()とsorted()の違い</a></h2> <ul> <li>リスト型のメソッドsort(): 元のリストをソート</li> <li>組み込み関数sorted(): ソートした新たなリストを生成</li> </ul> <blockquote> <p>🐍いきなり<code>sorted</code>で並び替える発想無かった。</p> </blockquote> aocory tag:crieit.net,2005:PublicArticle/15015 2019-05-23T17:55:31+09:00 2019-05-27T11:36:40+09:00 https://crieit.net/posts/Discord-Splatoon2-bot DiscordからSplatoon2の情報を取得できるbotを作った <h1 id="DiscordからSplatoon2の情報を取得できるbotを作った"><a href="#Discord%E3%81%8B%E3%82%89Splatoon2%E3%81%AE%E6%83%85%E5%A0%B1%E3%82%92%E5%8F%96%E5%BE%97%E3%81%A7%E3%81%8D%E3%82%8Bbot%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%9F">DiscordからSplatoon2の情報を取得できるbotを作った</a></h1> <h2 id="どんなbot?"><a href="#%E3%81%A9%E3%82%93%E3%81%AAbot%EF%BC%9F">どんなbot?</a></h2> <p>botがいるサーバーで<br /> 「ナワバリ」とコメントすると現在のステージ2つが返ってきます。<br /> 「ガチ」or 「リーグ」とコメントすると現在のステージ2つとルールが返って来ます。<br /> 「サーモンラン」とコメントすると現在のステージと使用可能な武器が返ってきます。</p> <p>他にも機能があるのですが長くなるので気になる方は下記リンク先の説明を読んでください。<br /> <a target="_blank" rel="nofollow noopener" href="https://cube-library.net/works/co-production-works/splatoon2-bot-discord/">イカボット</a></p> <h2 id="なんで作ったの?"><a href="#%E3%81%AA%E3%82%93%E3%81%A7%E4%BD%9C%E3%81%A3%E3%81%9F%E3%81%AE%EF%BC%9F">なんで作ったの?</a></h2> <p>友人との会話の流れで作ることになった。<br /> 他の方が作ったbotが既にあったが対応しているコマンドが覚えにくかったらしい。<br /> - 「ガチ」「リーグ」「ガチマ」「リグマ」「バイト」とかいろんな表現で情報を取得したい<br /> - 他にも情報を取得したい</p> <p>とかそんな理由で開発がスタートした。</p> <h2 id="開発・実行環境"><a href="#%E9%96%8B%E7%99%BA%E3%83%BB%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83">開発・実行環境</a></h2> <h3 id="言語とライブラリ"><a href="#%E8%A8%80%E8%AA%9E%E3%81%A8%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA">言語とライブラリ</a></h3> <p>PythonからDiscordにアクセスできる<a target="_blank" rel="nofollow noopener" href="https://github.com/Rapptz/discord.py">discord.py</a>というライブラリが既に公開されていたのでそれを使用した。<br /> 開発当時はPython3.7に対応していなかったのでPythonのバージョンは3.6で開発した。</p> <h3 id="Splatoon2の情報の取得元"><a href="#Splatoon2%E3%81%AE%E6%83%85%E5%A0%B1%E3%81%AE%E5%8F%96%E5%BE%97%E5%85%83">Splatoon2の情報の取得元</a></h3> <p>下記サイトでSplatoon2のステージ情報を取得できるAPIを公開している方がいたため、ありがたく使わせていただきました。<br /> <a target="_blank" rel="nofollow noopener" href="https://spla2.yuu26.com/">Spla2 API</a></p> <p>大量のアクセスを行わないように + 高速化のためスケジュール更新があるまではキャッシュしたデータをもとにステージ情報などを返すようにしている。</p> <h3 id="実行環境"><a href="#%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83">実行環境</a></h3> <p>GCPで仮想サーバーを立ててSupervisorでデーモン化した。</p> <p>参考にした記事↓<br /> <a target="_blank" rel="nofollow noopener" href="https://qiita.com/shiraco/items/70c5d48a1b4f43fb4aa7">SupervisorでPythonのWebアプリをデーモン化する</a></p> <h2 id="開発中の苦労"><a href="#%E9%96%8B%E7%99%BA%E4%B8%AD%E3%81%AE%E8%8B%A6%E5%8A%B4">開発中の苦労</a></h2> <p>Pythonをまともに書いたことがなかったので慣れるまでは開発スピードが遅かった。<br /> 特に普段は型ありの言語しか書かないので、型が違うエラーが実行時にしかわからないのが苦労した。</p> <h2 id="今後"><a href="#%E4%BB%8A%E5%BE%8C">今後</a></h2> <ul> <li>機能追加(要望があれば)</li> <li>Python 3.7対応</li> </ul> <h2 id="リンク"><a href="#%E3%83%AA%E3%83%B3%E3%82%AF">リンク</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://discordapp.com/api/oauth2/authorize?client_id=547404858135805992&permissions=2048&scope=bot">botをサーバーに登録するためのリンク</a></p> block tag:crieit.net,2005:PublicArticle/14904 2019-04-05T22:33:52+09:00 2019-04-05T22:36:21+09:00 https://crieit.net/posts/SQLAlchemy-Declarative-API SQLAlchemy の Declarative API を使ってハマった事 <p>Python3 + Bottle + Jinja2 + SQLAlchemy で Web サービスを作っているのですが、SQLAlchemy の Declarative API を使い始めた時にちょっとした失敗をやらかしましたので、この辺りで供養しておきます。</p> <p>以下は SQLAlchemy の Declarative API を使って User クラス(users テーブル) を定義し、テーブルを生成するコードです。コードが膨れ上がるのが嫌いなので、User クラスは user.py に、テーブル生成は database.py に書いています。しかし、database.py の <code>create_all()</code> を読んでもテーブルが生成されない、という問題にぶつかりました。</p> <pre><code class="py"># user.py from sqlalchemy import Column from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.types import String Base = declarative_base() class User(Base): __tablename__ = "users" user_id = Column(UUID, primary_key=True) name = Column(String) : </code></pre> <pre><code class="py"># database.py from sqlalchemy.ext.declarative import declarative_base from .user import User Base = declarative_base() Base.metadata.create_all(bind=self.engine) # ここで users テーブルが作られているはずが、作られない </code></pre> <p>何が問題なのかというと、複数のソースに分けて書いた時の対応がまずかったのです。<br /> ネットでよく見かける Delcarative API の サンプルは同じ py ファイルの中に書いてあるので問題はありません。<br /> 上の例の場合、user.py と database.py の双方で declarative_base() を呼び出して基底クラス Base を使用していますが、互いに独立したメタクラスを触っているので、テーブル生成しようにも Users クラスで定義した内容が引き渡されていませんでした。</p> <p>解決方法としては以下のようになります。declarative_base(0 で生成した Base を引き回すため、独立した base.py を生成し、user.py を database.py の双方から参照するように修正しました。</p> <pre><code class="py"># base.py from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() </code></pre> <pre><code class="py"># user.py from .base import Base from sqlalchemy import Column from sqlalchemy.types import String class User(Base): __tablename__ = "users" : </code></pre> <pre><code class="py"># database.py from .base import Base from .user import User Base.metadata.create_all(bind=self.engine) # ここで users テーブルが作られる </code></pre> <p>以上の対応で、無事 users テーブルが生成されるようになりました。よかったよかった。</p> <p>しかしこの Declarative API 、実に ORM らしい使い方になるのでとても快適ですね。<br /> 当初 SQLAlchemy のリファレンスを適当に見ながら書いたものは Reflective Table Object という方法だったようで<br /> クエリの結果がdict(連想配列)で帰ってくるので PHP の MDB を使っていた頃とあまり使い勝手が変わらない感じでしたが、Declarative API だとちゃんとオブジェクトで帰ってくるのでとても良いです。</p> ともたこ tag:crieit.net,2005:PublicArticle/14851 2019-03-03T08:30:14+09:00 2019-03-03T08:30:14+09:00 https://crieit.net/posts/pandas-head pandas入門 .head()で先頭から要素を抜き出す <h2 id="データをいろいろ扱いたい"><a href="#%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E3%81%84%E3%82%8D%E3%81%84%E3%82%8D%E6%89%B1%E3%81%84%E3%81%9F%E3%81%84">データをいろいろ扱いたい</a></h2> <p>google Colaboratoryは、環境構築不要で色々できるのが魅力です。<br /> スクレイピングで得たデータもPythonでごにょごにょしたい。そういう時はpandasを使うようです。<br /> 今回はスクレイピングデータから最初から任意の要素を抜き出します。</p> <h2 id="元となるデータ"><a href="#%E5%85%83%E3%81%A8%E3%81%AA%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF">元となるデータ</a></h2> <p>元となるデータはCrieitさんのタイトル一覧です。</p> <pre><code>from bs4 import BeautifulSoup import requests import pandas as pd columns = ['title'] df = pd.DataFrame(columns=columns) base_url = "https://crieit.net/posts?page=" num = 1 while num <= 1: url=base_url+ str(num) r = requests.get(url) soup = BeautifulSoup(r.text) titles =soup.select("h5 a") if len(titles) == 0: print("これ以上記事はありません") break num += 1 for title in titles: se= pd.Series(title.text, columns) df = df.append(se, ignore_index=True) df </code></pre> <h2 id=".head"><a href="#.head">.head</a></h2> <p>.head()を使うことで先頭から5つの要素を抜き出すことが可能です。<br /> 任意の数を表示させる場合はdf.head(10)などのように引数を渡します。</p> <h2 id="出来たコード"><a href="#%E5%87%BA%E6%9D%A5%E3%81%9F%E3%82%B3%E3%83%BC%E3%83%89">出来たコード</a></h2> <p>試しに6つまで取得するコードを書いています。</p> <pre><code>from bs4 import BeautifulSoup import requests import pandas as pd columns = ['title'] df = pd.DataFrame(columns=columns) base_url = "https://crieit.net/posts?page=" num = 1 while num <= 1: url=base_url+ str(num) r = requests.get(url) soup = BeautifulSoup(r.text) titles =soup.select("h5 a") if len(titles) == 0: print("これ以上記事はありません") break num += 1 for title in titles: se= pd.Series(title.text, columns) df = df.append(se, ignore_index=True) df.head(6) </code></pre> <h2 id="動くサンプル"><a href="#%E5%8B%95%E3%81%8F%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB">動くサンプル</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://colab.research.google.com/drive/1slyp9ssiahsR9TSiOGr7i8KPUxTXcU_z">Python3</a></p> aocory tag:crieit.net,2005:PublicArticle/14812 2019-02-18T22:33:44+09:00 2019-02-18T22:33:44+09:00 https://crieit.net/posts/Python-5c6ab437f2316 Pythonで文字列を分割したい <h2 id="Pythonで文字列を分割したい"><a href="#Python%E3%81%A7%E6%96%87%E5%AD%97%E5%88%97%E3%82%92%E5%88%86%E5%89%B2%E3%81%97%E3%81%9F%E3%81%84">Pythonで文字列を分割したい</a></h2> <p>Pythonでスクレイピングをしていると?q=python&lang=jaとかややこしい文字列に出くわします。<br /> そんな時、文字列を分割したい!と思うことが多々あります。<br /> そこで今回はPythonで文字列を分割するにはそうすればいいかを勉強しました。</p> <h2 id="Pythonで文字列に数字を変換する方法"><a href="#Python%E3%81%A7%E6%96%87%E5%AD%97%E5%88%97%E3%81%AB%E6%95%B0%E5%AD%97%E3%82%92%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95">Pythonで文字列に数字を変換する方法</a></h2> <p>split(文字列)を使えば解決!</p> <h2 id="実際のコード"><a href="#%E5%AE%9F%E9%9A%9B%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89">実際のコード</a></h2> <p>Pythonのsplit()を行ったサンプルになります。</p> <pre><code class="Python">colors = 'blue-red-yellow' print(colors.split('-')) colors = 'blue-red--yellow' print(colors.split('-')) colors = 'blue-red--yellow' print(colors.split('red')) </code></pre> <h3 id="出力結果"><a href="#%E5%87%BA%E5%8A%9B%E7%B5%90%E6%9E%9C">出力結果</a></h3> <pre><code class="Python">['blue', 'red', 'yellow'] ['blue', 'red', '', 'yellow'] ['blue-', '--yellow'] </code></pre> <p>--などの場合は空の配列が出来たりします。</p> <h2 id="動くサンプル"><a href="#%E5%8B%95%E3%81%8F%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB">動くサンプル</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://colab.research.google.com/drive/191wx5C3_48NBPY62dSrhYtUMertqF2sY">Python3</a></p> aocory tag:crieit.net,2005:PublicArticle/14705 2019-01-01T00:00:27+09:00 2019-01-01T10:42:41+09:00 https://crieit.net/posts/Python-5c2a2f0bb5a45 あけおめからPython <h1 id="皆さんへのメッセージです。"><a href="#%E7%9A%86%E3%81%95%E3%82%93%E3%81%B8%E3%81%AE%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%81%A7%E3%81%99%E3%80%82">皆さんへのメッセージです。</a></h1> <pre><code class="python">謹賀, 新年=(lambda x:(not x,x))([]) 新年.append((謹賀+謹賀)**((謹賀+謹賀)**(謹賀+謹賀+謹賀))-(謹賀+謹賀+謹賀)**(謹賀+謹賀+謹賀)-(謹賀+謹賀)) 新年.append((謹賀+謹賀)**((謹賀+謹賀)**(謹賀+謹賀+謹賀)-謹賀)+謹賀) 新年.append(新年[-謹賀]+謹賀) 新年.append(新年[謹賀-謹賀]) 新年.append(新年[謹賀]) 新年.append(新年[謹賀+謹賀]+((謹賀+謹賀)*(謹賀+謹賀))**(謹賀+謹賀)-謹賀) 新年.append(新年[謹賀-謹賀]) 新年.append(新年[謹賀]) 新年.append(新年[謹賀+謹賀]+(謹賀+謹賀)**(謹賀+謹賀+謹賀)) 新年.append(新年[謹賀-謹賀]) 新年.append(新年[謹賀+謹賀]) 新年.append(新年[謹賀]) print(bytes(新年).decode('utf-8')) </code></pre> <p>実行してみましょう。</p> <h1 id="小ネタは置いといて。"><a href="#%E5%B0%8F%E3%83%8D%E3%82%BF%E3%81%AF%E7%BD%AE%E3%81%84%E3%81%A8%E3%81%84%E3%81%A6%E3%80%82">小ネタは置いといて。</a></h1> <p>この前、ふとリスト内包表記の中身(ローカル変数空間)が気になったので以下のコードを実行してみました。</p> <pre><code class="python">[i for i in [0] if print(locals()) or 1] </code></pre> <p>結果はこうなりました。</p> <pre><code class="python">{'i': 0, '.0': <tuple_iterator object at 0x0000018E8BDDE518>} </code></pre> <p>はい、コードの実行フレームが分かれていますね。ところで表示された辞書オブジェクトのキー<code>'.0'</code>って何でしょう?気になったので以下のコードを実行してみました。もし、私の予想が正しければ実行は終了しないはずです。</p> <pre><code class="python">[i for i in [0] if locals().__setitem__('.0', range(2).__iter__()) or 1] </code></pre> <p>実際にやってみた結果、<code>[0]</code>が出力されました。どういうことなんでしょう…?<br /> <code>__setitem__</code>をした後に<code>print(locals())</code>で中身を調べてみます。</p> <pre><code class="python">[i for i in [0] if locals().__setitem__('.0', range(2).__iter__()) or print(locals()) or 1] </code></pre> <p>結果はこのようになりました。</p> <pre><code class="python">{'i': 0, '.0': <tuple_iterator object at 0x0000018E8BDDE518>} </code></pre> <p>要素を変えることができていません。なぜでしょう? 残念なことにいくつか仮説を立ててみたのですが、そのどれもが間違っていました。</p> <h2 id="仮説1. ローカル変数空間はループごとに新しく作られている"><a href="#%E4%BB%AE%E8%AA%AC%EF%BC%91.+%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E5%A4%89%E6%95%B0%E7%A9%BA%E9%96%93%E3%81%AF%E3%83%AB%E3%83%BC%E3%83%97%E3%81%94%E3%81%A8%E3%81%AB%E6%96%B0%E3%81%97%E3%81%8F%E4%BD%9C%E3%82%89%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B">仮説1. ローカル変数空間はループごとに新しく作られている</a></h2> <p>これは簡単に確かめることができます。</p> <pre><code class="python">[i for i in [0,1] if print(id(locals())) or 1] </code></pre> <p>これで表示される数が2つとも等しければ使いまわされていることが証明できます。私が実行した結果はこうなりました。</p> <pre><code class="python">1711743637328 1711743637328 [0, 1] </code></pre> <p>はい、一致していますね。異なるオブジェクトのIDが一致することはまずありえませんので、ローカル変数空間は使いまわされていることがわかりました。</p> <h2 id="仮説 2. '.0'というキーは例外的に書き換えできない"><a href="#%E4%BB%AE%E8%AA%AC+2.+%27.0%27%E3%81%A8%E3%81%84%E3%81%86%E3%82%AD%E3%83%BC%E3%81%AF%E4%BE%8B%E5%A4%96%E7%9A%84%E3%81%AB%E6%9B%B8%E3%81%8D%E6%8F%9B%E3%81%88%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84">仮説 2. '.0'というキーは例外的に書き換えできない</a></h2> <p>当然なんてことはありませんでした。</p> <pre><code class="python">>>> x = {} >>> x['.0'] = 12 >>> x {'.0': 12} >>> x['.0'] = 4 >>> x {'.0': 4} </code></pre> <h2 id="仮説 3. ローカル名前空間のオブジェクトがdictではない"><a href="#%E4%BB%AE%E8%AA%AC+3.+%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E5%90%8D%E5%89%8D%E7%A9%BA%E9%96%93%E3%81%AE%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%8Cdict%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84">仮説 3. ローカル名前空間のオブジェクトがdictではない</a></h2> <p>だんだん投げやりになってきましたね。当然そんなわけなく、<code>dict</code>でした…。</p> <pre><code class="python">>>> [i for i in [0] if print(type(locals())) or 1] <class 'dict'> [0] </code></pre> <p>とまぁ、こんな感じで<code>Python</code>サイドからの解明は終ぞできませんでした…。今年はPythonのコードリーディングをしようかと考えています。</p> <h1 id="リスト内包表記は単体でチューリング完全と聞いたので"><a href="#%E3%83%AA%E3%82%B9%E3%83%88%E5%86%85%E5%8C%85%E8%A1%A8%E8%A8%98%E3%81%AF%E5%8D%98%E4%BD%93%E3%81%A7%E3%83%81%E3%83%A5%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E5%AE%8C%E5%85%A8%E3%81%A8%E8%81%9E%E3%81%84%E3%81%9F%E3%81%AE%E3%81%A7">リスト内包表記は単体でチューリング完全と聞いたので</a></h1> <p>リスト内包表記だけでいくつか書いてみました。まずは普通にFizzBuzzから。</p> <pre><code class="python"># FizzBuzz in list comprehension [('Fizz' if not i%3 else '')+('Buzz' if not i%5 else '')+(str(i) if i%3 and i%5 else '') for i in range(20)] </code></pre> <p>続いてはAtCoder Beginners Selectionより<a target="_blank" rel="nofollow noopener" href="https://atcoder.jp/contests/abs/tasks/abc088_b">Card Game for Two</a>を解くプログラム。結構強引ですね。</p> <pre><code class="python">print(sum(x-y for x, y in zip(*(lambda x:((x.append(0) if len(x)%2 else None),x.sort(reverse=True),(x[::2],x[1::2]))[2])((input(), [int(i) for i in input().split()])[1])))) </code></pre> <p>正直言うと、自分も難読化以上の意味はないと思いました…。</p> <p>ですが、いろいろやっているとやはり内包表記のポテンシャルは高いと感じました。あなたもやってみてはいかが?</p> <h1 id="for文で遊ぶ"><a href="#for%E6%96%87%E3%81%A7%E9%81%8A%E3%81%B6">for文で遊ぶ</a></h1> <pre><code class="python">for i in range(20): print(i) </code></pre> <p>と同じプログラムを<code>range</code>関数なしで黒魔術っぽくやってみたいと思います。</p> <pre><code class="python">for i in (lambda x: (x, x.append(x))[0])([]): print(len(i)-1) i.append(i) if i[20:]: i.clear() </code></pre> <p>循環参照をうまく使ってみました。難読化以上の意味はないです</p> <p>私からは以上です。皆さん、今年も元気に行きましょう!</p> frodo821 tag:crieit.net,2005:PublicArticle/14600 2018-11-12T21:28:55+09:00 2018-11-12T21:28:55+09:00 https://crieit.net/posts/Python 【保存版・初心者向け】Python 目的別チュートリアル <p><img width="644" alt="スクリーンショット 2018-11-09 14.34.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/195675/5bce4631-3d40-d75e-67af-ecfa17679491.png"></p> <h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://aiacademy.jp">AI Academy</a>を開発・運営しています、<a target="_blank" rel="nofollow noopener" href="https://twitter.com/tankazunori0914">サイバーブレイン株式会社代表の谷</a>です。</p> <p>近年機械学習等で人気のPythonですが、Pythonで出来ることは機械学習以外にも多くあります。<br /> そこで、初学者の方は<strong>機械学習以外でPythonで何が出来るのか?</strong>また、<strong>何から手をつけて行けば目的を達成できるのか?</strong>など疑問を持つかと思います。<br /> この記事が多くの方々のお役に立てれば幸いです。</p> <h2 id="この記事の対象者"><a href="#%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%81%AE%E5%AF%BE%E8%B1%A1%E8%80%85">この記事の対象者</a></h2> <p>・Pythonで何ができるのか知りたい方<br /> ・Pythonを使って自身のしたいことを最短ルートで実現したい方</p> <h2 id="対象ではない方"><a href="#%E5%AF%BE%E8%B1%A1%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%84%E6%96%B9">対象ではない方</a></h2> <p>・普段仕事でPythonを使われている方<br /> ・Pythonに興味のない方</p> <h2 id="なぜPythonなのか"><a href="#%E3%81%AA%E3%81%9CPython%E3%81%AA%E3%81%AE%E3%81%8B">なぜPythonなのか</a></h2> <p>なぜ複数あるプログラミング言語の中で、Pythonをお勧めしているかと言いますと、2つ挙げられます。</p> <p>まず、<strong>PythonはC言語などに比べ、比較的容易に習得しやすく、多くのことができること。</strong></p> <p>次に、<strong>機械学習のライブラリの充実に加え、様々なライブラリが豊富です。</strong><br /> Web開発もできますし、Webスクレイピング、データ分析などなどです。</p> <h2 id="Pythonでできること"><a href="#Python%E3%81%A7%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%93%E3%81%A8">Pythonでできること</a></h2> <p>Pythonでできることは、次のようなことが出来ます。</p> <pre><code>1. Webスクレイピング 2. 機械学習・ディープラーニング・最適化 3. テキストマイニング 4. データ分析 5. 画像認識・画像処理 6. 業務効率化プログラム 7. Webアプリケーション開発 8. ネットワーク・サイバーセキュリティプログラミング 9. ゲーム開発 10. Androidアプリ開発 11. デスクトップアプリ制作 12. データベース操作 13. 並列化 14. インフラ構築自動化 15. グラフィックス 16. 非同期処理 </code></pre> <p>『11. デスクトップアプリ制作』以降は他のプログラミング言語でもできる事が多いですが、それらを除いてもPython言語1つで、非常に多くのことができることがわかるかと思います。この記事では主に1~10までに関して記述していきます。</p> <h2 id="Pythonが学べるサイトは?"><a href="#Python%E3%81%8C%E5%AD%A6%E3%81%B9%E3%82%8B%E3%82%B5%E3%82%A4%E3%83%88%E3%81%AF%EF%BC%9F">Pythonが学べるサイトは?</a></h2> <p>全くのプログラミング初心者は、<a target="_blank" rel="nofollow noopener" href="https://prog-8.com/">Progate(プロゲート)</a>をお勧めします。</p> <p>既に、Pythonの基本文法が既知であり、Pythonで多くの事を実現できるようになりたい方は次の動画の購入を強くお勧めいたします。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.udemy.com/python-beginner/">Python 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイルを学び、実践的なアプリ開発の準備をする</a></p> <p>最初に挙げた多くのことが網羅されており、大変わかりやすく非常にお勧めです。</p> <p>また手前味噌ですが、<a target="_blank" rel="nofollow noopener" href="https://aiacademy.jp">AI Academy</a>も合わせてご利用頂けますと幸いです。他のプログラミング学習サービスとの違いは、受講者の目的に応じてカリキュラムを最適化している点です。</p> <p>他にも有料サービスとして、PyQやAidemy、動画サービスですと先ほど紹介したUdemyやドットインストールなどがありますので、ご自身にあうサービスを選んで学んで頂けたらと思います。</p> <h1 id="どのようにPythonを学べば良いか?"><a href="#%E3%81%A9%E3%81%AE%E3%82%88%E3%81%86%E3%81%ABPython%E3%82%92%E5%AD%A6%E3%81%B9%E3%81%B0%E8%89%AF%E3%81%84%E3%81%8B%EF%BC%9F">どのようにPythonを学べば良いか?</a></h1> <p>先ほど紹介したProgateに加え、AI Academyで、自身の目的にあったコースを選んで頂き進めて頂けたらと思います。<br /> そして、より詳細に学んでいきたい方はこれから紹介する項目からやりたい内容を選び参考にして頂けたらと思います。<br /> それではPythonでできることを1つ1つ詳細に見ていきましょう。</p> <h1 id="Webスクレイピング"><a href="#Web%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0">Webスクレイピング</a></h1> <p>Webスクレイピングとは、Web上からデータを取得することができる技術です。</p> <p>・毎日発信されるAIに関するニュースをスクレピング<br /> ・会員制ECサイトに自動的にログインして、そのサイトでの直近の購入履歴を取得する</p> <p>これらのことは、Webスクレイピングで実現できます。<br /> PythonでWebスクレイピングするには、<strong>selenium</strong>や<strong>beautifulSoup</strong>といったライブラリを利用します。</p> <p><a target="_blank" rel="nofollow noopener" href="https://aiacademy.jp/texts/#web">AI Academy Webスクレイピング</a></p> <p>・オススメ書籍<br /> Pythonクローリング&スクレイピング -データ収集・解析のための実践開発ガイド-</p> <p><img src="https://qiita-image-store.s3.amazonaws.com/0/195675/fd5b17e8-0cc0-d854-536c-f817627f7538.jpeg" alt="51IiWeYB-7L._SX399_BO1,204,203,200_.jpg" /><br /> <a target="_blank" rel="nofollow noopener" href="http://amzn.asia/d/6dB1o9K">http://amzn.asia/d/6dB1o9K</a></p> <h1 id="機械学習"><a href="#%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92">機械学習</a></h1> <p>scikit-learnやTensorFlowなどを扱うことで機械学習の主要なアルゴリズムを扱うことが出来ます。<br /> 機械学習における必須のライブラリは、NumPy,Pandas,Matplotlib/seaborn/scikit-learnなどがあります。<br /> 他にも画像領域ですと、keras,OpenCV,Pillow、テキスト領域ですと、mecabやGensimなども使えるようになると良いです。</p> <p>AI Academyでは、下記リンクから機械学習のアルゴリズムをscikit-learnを使って、手を動かしながら学ぶことができます。<br /> <a target="_blank" rel="nofollow noopener" href="https://aiacademy.jp/texts/#ml">AI Academy機械学習</a></p> <p>勉強方法など詳しくは下記記事をご参考ください。</p> <p><a target="_blank" rel="nofollow noopener" href="https://qiita.com/tani_AI_Academy/items/4da02cb056646ba43b9d">【保存版・初心者向け】独学でAIエンジニアになりたい人向けのオススメの勉強方法</a></p> <h1 id="テキストマイニング"><a href="#%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%83%9E%E3%82%A4%E3%83%8B%E3%83%B3%E3%82%B0">テキストマイニング</a></h1> <p>テキストマイニングとは文字列を対象にしたデータマイニングのことで、文章などの大量のテキストデータから言語解析や統計解析などを活用し、『意味のある情報』を取り出すことでテキストデータの分析手法です。</p> <p>Pythonのライブラリでは、<strong>mecab</strong>や<strong>gensim</strong>などを使うと実現できます。</p> <p>SNSの投稿(Twitterのツイートなど)を分析したり、アンケートの分析が可能です。</p> <h1 id="データ分析"><a href="#%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90">データ分析</a></h1> <p>Pythonでデータ分析をしたい場合は、<strong>Pandas</strong>というライブラリを使います。<br /> また、matplotlibやseabornというライブラリも合わせて使えるとグラフを描画することもできます。</p> <p>・オススメ書籍<br /> Pythonによるデータ分析入門 第2版 ―NumPy、pandasを使ったデータ処理<br /> <img src="https://qiita-image-store.s3.amazonaws.com/0/195675/db0d2056-5cd7-5567-46fd-359543e738ce.jpeg" alt="download.jpg" /><br /> <a target="_blank" rel="nofollow noopener" href="http://amzn.asia/d/3jlYXKd">http://amzn.asia/d/3jlYXKd</a></p> <h1 id="画像認識・画像処理"><a href="#%E7%94%BB%E5%83%8F%E8%AA%8D%E8%AD%98%E3%83%BB%E7%94%BB%E5%83%8F%E5%87%A6%E7%90%86">画像認識・画像処理</a></h1> <p>画像認識では、ディープラーニングが扱えるライブラリ(kerasやTensorFlowなど)を使って写真に写っている画像が何かを検出することができます。<br /> <a target="_blank" rel="nofollow noopener" href="https://aiacademy.jp/texts/#dl_experience">AI Academy 画像認識</a></p> <p>画像処理をしたい場合は、OpenCVやPillowなどの画像処理ライブラリを使うと実現できます。</p> <h1 id="業務効率化プログラム"><a href="#%E6%A5%AD%E5%8B%99%E5%8A%B9%E7%8E%87%E5%8C%96%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0">業務効率化プログラム</a></h1> <p>Pythonを使うと、先ほどのスクレイピングを使って、データを自動で収集したり、Excel処理ができたり、たくさんのフォルダを一瞬で作成したり、Twitterのユーザーを自動でフォローしたり、1000人に一括メールを送ったりなど様々なことが出来ます。</p> <p>これらの内容の一部は、下記書籍で学ぶことが出来ます。</p> <p>・オススメ書籍<br /> 退屈なことはPythonにやらせよう ―ノンプログラマーにもできる自動化処理プログラミング<br /> <img src="https://qiita-image-store.s3.amazonaws.com/0/195675/93468749-ae32-daa2-f72f-476e81799e51.jpeg" alt="51hk+5bKNrL._SX352_BO1,204,203,200_.jpg" /></p> <p><a target="_blank" rel="nofollow noopener" href="http://amzn.asia/d/3besjKA">http://amzn.asia/d/3besjKA</a></p> <p>チャトボットで問い合わせ自動化したい場合は、次の動画を購入するのを強くオススメ致します。</p> <p><a target="_blank" rel="nofollow noopener" href="https://www.udemy.com/ai-ytxof/">挨拶から店舗予約まで!手を動かして学ぶAIチャットボット開発入門</a></p> <h1 id="Webアプリケーション開発"><a href="#Web%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA">Webアプリケーション開発</a></h1> <p>Pythonでは、FlaskやDjangoといったライブラリを使うことで、Webアプリケーション開発ができます。</p> <p>具体的には次のようなことが出来ます。</p> <pre><code>Djangoを使ったTwitterクローン作成 FlaskとMySQLでToDoアプリを実装しよう 機械学習で花を判定するWebアプリケーションを作ろう! </code></pre> <p>これら全ては、<a target="_blank" rel="nofollow noopener" href="https://aiacademy.jp/texts/#api">AI Academy Web開発</a>を元に進めると作ることが出来るようになります。</p> <p>・オススメ書籍<br /> 現場で使える Django の教科書《基礎編》<br /> <img src="https://qiita-image-store.s3.amazonaws.com/0/195675/db989ea7-cff9-926b-4715-f71e3a94cc5b.jpeg" alt="41vG221V8dL._SX352_BO1,204,203,200_.jpg" /></p> <p><a target="_blank" rel="nofollow noopener" href="http://amzn.asia/d/cygNnDN">http://amzn.asia/d/cygNnDN</a></p> <h1 id="Androidアプリ開発"><a href="#Android%E3%82%A2%E3%83%97%E3%83%AA%E9%96%8B%E7%99%BA">Androidアプリ開発</a></h1> <p>Pythonでは、<a target="_blank" rel="nofollow noopener" href="https://www.qpython.com">QPython</a>や<a target="_blank" rel="nofollow noopener" href="https://kivy.org/#home">Kivy</a>を用いることでAndroidのアプリケーションを開発することが可能です。</p> <p>ですが、本格的なAndroidアプリ開発をされる場合は、<strong>Java</strong>や<strong>Kotlin</strong>を使う方が、ネット上に情報量多かったり、多くのAndroidアプリはJavaで開発されているのでPythonではない方が良かったりします。</p> <h1 id="ゲーム開発"><a href="#%E3%82%B2%E3%83%BC%E3%83%A0%E9%96%8B%E7%99%BA">ゲーム開発</a></h1> <p>Pythonでゲームを作るライブラリは<a target="_blank" rel="nofollow noopener" href="https://www.pygame.org/news">Pygame</a>、<a target="_blank" rel="nofollow noopener" href="https://kivy.org/#home">Kivy</a>や<a target="_blank" rel="nofollow noopener" href="https://docs.python.jp/3/library/tkinter.html">Tkinter</a>などあります。</p> <p>・オススメ書籍<br /> ゲームを作りながら楽しく学べるPythonプログラミング<br /> <img src="https://qiita-image-store.s3.amazonaws.com/0/195675/3d083724-3314-6d5f-999b-0c13667d6333.jpeg" alt="51vd-anoLyL._SX351_BO1,204,203,200_.jpg" /><br /> <a target="_blank" rel="nofollow noopener" href="http://amzn.asia/d/gni454S">http://amzn.asia/d/gni454S</a></p> <h1 id="ネットワーク・サイバーセキュリティプログラミング"><a href="#%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%BB%E3%82%B5%E3%82%A4%E3%83%90%E3%83%BC%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0">ネットワーク・サイバーセキュリティプログラミング</a></h1> <p><a target="_blank" rel="nofollow noopener" href="https://scapy.net">Scapy</a>を使う事で、パケット生成や送受信が可能です。<br /> (セキュリティ脆弱性診断に特化したKali Linux(カーリーリナックス)にはデフォルトでインストールされていたりします。)</p> <p><a target="_blank" rel="nofollow noopener" href="https://docs.python.jp/3/library/urllib.request.html">urrlib</a>などを使う事でGETリクエストなどが可能です。</p> <p>・オススメ書籍<br /> サイバーセキュリティプログラミング ―Pythonで学ぶハッカーの思考<br /> <img src="https://qiita-image-store.s3.amazonaws.com/0/195675/97024567-5798-2775-85dd-7dca4b141985.jpeg" alt="518ZyCCEKGL._SX350_BO1,204,203,200_.jpg" /></p> <p><a target="_blank" rel="nofollow noopener" href="http://amzn.asia/d/4x7OMN3">http://amzn.asia/d/4x7OMN3</a></p> <h1 id="その他(人工生命)"><a href="#%E3%81%9D%E3%81%AE%E4%BB%96%EF%BC%88%E4%BA%BA%E5%B7%A5%E7%94%9F%E5%91%BD%EF%BC%89">その他(人工生命)</a></h1> <p>ALife(人工生命)」は、「AI(人工知能)」の発展系として、近年改めて注目されつつある分野ですがこの分野の内容は次の書籍などが丁寧です。</p> <p>・オススメ書籍<br /> 作って動かすALife ―実装を通した人工生命モデル理論入門<br /> <img src="https://qiita-image-store.s3.amazonaws.com/0/195675/f2cfcbfe-2d68-3e74-853d-2883881f4307.jpeg" alt="516dQmDuT3L._SX350_BO1,204,203,200_.jpg" /></p> <p><a target="_blank" rel="nofollow noopener" href="http://amzn.asia/d/6v46F2O">http://amzn.asia/d/6v46F2O</a></p> <h1 id="学習ロードマップ"><a href="#%E5%AD%A6%E7%BF%92%E3%83%AD%E3%83%BC%E3%83%89%E3%83%9E%E3%83%83%E3%83%97">学習ロードマップ</a></h1> <p>次の図で、自身がどれに適しているか確認してみてください。</p> <p><img width="644" alt="スクリーンショット 2018-11-09 14.34.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/195675/5bce4631-3d40-d75e-67af-ecfa17679491.png"></p> <p>右向き矢印の名称は各ライブラリ名になります。<br /> ライブラリはpipなどのコマンドを使うことでインストールができます。</p> <h1 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h1> <p>この記事ではこれからPythonを学びたい初学者に向けて、<br /> ・Pythonをこれから勉強しようと考えているが、何から手をつければ良いのか?<br /> ・何から学ぶと自分の目的を達成できるのだろう?<br /> などの悩みを解消できればと思い執筆しました。</p> <p>Pythonでは多くの事ができるプログラミング言語だという事がお分かり頂けたかと思います。是非Pythonを学んで、読まれている方々の目的が最短で実現できれば幸いです。</p> <h1 id="この記事を書いた人"><a href="#%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%82%92%E6%9B%B8%E3%81%84%E3%81%9F%E4%BA%BA">この記事を書いた人</a></h1> <p><img src="https://qiita-image-store.s3.amazonaws.com/0/195675/a4bad386-6700-4b9e-6a33-368a92c7ae6c.jpeg" alt="37741205_1003841679788059_2705403151040643072_n.jpg" /></p> <p>サイバーブレイン株式会社<br /> 代表取締役CEO 谷 一徳</p> <p>フォローお待ちしております!<br /> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/tankazunori0914">Twitter</a><br /> <a target="_blank" rel="nofollow noopener" href="https://www.facebook.com/takazunori">Facebook</a></p> <p>2000名以上が参加しいてるAIコミュニティも運営しております。<br /> 毎日AIに関する情報を提供しておりますので、こちらのご参加もお待ちしております!<br /> <a target="_blank" rel="nofollow noopener" href="https://www.facebook.com/groups/1892746874314837/">人工知能研究コミュニティ</a></p> kazu (AI Academy今なら無料)