本日は投プロ会(投資家のためのプログラミング勉強会)「初級編」の締めくくりです。
第1回から第7回までに、投資活動のお便利アプリ開発を通して、これらのことを学びました。
- 第1回 複数の株情報サイトを一度に表示してみよう 「変数とは?」
- 第2回 指定した証券コードの関連サイトを表示する 「文字列の結合」
- 第3回 入力した証券コードの妥当性をチェックスする 「if文による条件分岐」
- 第4回 入力したコードが東証銘柄かチェックする 「リストとforループ」
- 第5回 米国株の関連ニュースを取得する 「辞書型と関数」
- 第6回 ループを使って対話式アプリを作る 「whileループ」
- 第7回米国の株式ニュース中に「配当」の文字があったら装飾して表示する 「文字列検索」
ここまで理解できればプログラミングの初級者としては十分な力を持っていると考えてよいでしょう。
次回からの中級編に進めば、ウェブサイトから自分が欲しい情報を自在に取ってきたり、それらのデータを集計、分析した結果をエクセルに一発で保存したり、といったことができるようになります。
これにより投資情報の取得/整理/分析に労力を割く必要がなくなり、自己の投資判断にのみ集中できる環境を実現できるようになります。
さて、本日は前回作製したアメカブくんを例にして、今一度「関数」について理解を深め初級編の締めくくりとします。
関数の考え方はプログラミングをしていく上で非常に重要なものとなります。関数の定義方法はもちろんのこと、そのメリットをしっかり理解していきましょう。
第5回で学習した通り、関数とはあらかじめ決められた処理を一つの塊として定義しておくことです。
例えばprint()という関数は、括弧内に値(パラメータ)を入れると、その値をディスプレイに表示する関数でした。またlen()は文字列やリスト型のパラメータを入れるとその長さを返す関数です。
1 2 |
print("投プロ会で丸儲け") print(len("投プロ会で丸儲け")) |
これらの関数はPythonにあらかじめ用意されている「組み込み関数」でしたが、独自の関数を定義させることもできます。
たとえばパラメータに指定された文字列に!をつけて表示した後にその文字列長を表示する関数を作ってみましょう。
1 2 3 4 5 6 7 |
def print_bikkuri(message): print(message + "!") print(len(message)) print_bikkuri("投プロ会で丸儲け") print_bikkuri("夢の配当金生活") print_bikkuri("下手なナンピンスカンピン") |
上記の結果を確認してみてください。
このように、あらかじめ決まった処理(今回の場合は「パラメータの最後に!をつけて表示した次にパラメータの文字列長を表示する」)を関数として定義することで、それを呼び出すことができます。
独自関数の定義の仕方は次の通りです。(詳細は教本の3.1も参照してみてください)
1 2 3 |
def 関数名(パラメータ): パラメータを使った独自の処理 return 戻り値(戻り値を返したいときのみ) |
では独自関数を定義するメリットはなんでしょうか。大きく2つあります。
- ソースの可読性をあげる
- メンテナンス性の向上
例えば前回のコードを関数を使わずに書いてみます。
1 2 3 4 5 6 |
print("投プロ会で丸儲け" + "!") print(len("投プロ会で丸儲け")) print("夢の配当金生活" + "!") print(len("夢の配当金生活")) print("下手なナンピンスカンピン" + "!") print(len("下手なナンピンスカンピン")) |
ごちゃごちゃとかなり読みにくくなりましたね。。。
書いた直後であればそんなに気にならないかもしれませんが、1ヶ月、1年後に見返すとなると、最初から最後まで処理内容を確認する必要があります。
最初のコードのように、共通の処理部分を関数にしておくことでprint_bikkuri()の処理内容を把握するだけで、その後はパラメータのみに集中してソースを読むことができます。
2つ目の「メンテナンスの向上」はどうでしょうか。
一度書いたソースを「やっぱり”!”ではなくて”?”にしたいな」とか「文字列の長さは表示しなくていいや」となった場合に、独自関数を使ったケースとそうでない場合の修正箇所を比較してみましょう。
いかがでしたか?
前者は2箇所のみ、後者はその3倍の6箇所も修正する必要がありました。
まとまった処理を関数にすることにより、変更したい部分ができても、関数内だけを直せば、全てを修正できるのがメリットの一つ目です。
変更箇所が複雑になったり繰り返す処理が多くなったりするほど関数化の恩恵を受けることが分かりますね。
プログラミングの世界では「同じことを二度書かない」という不文律があります。英語ではDRY:Don’t Repeat Yourselfといったりします。この考え方は非常に重要なことですのでぜひ頭に入れておいてください。
気がつけば同じ処理をいろいろなところで書いているな、とか、コードをコピペしたくなったら、それを関数にできないかを必ず確認しましょう。関数化によりメンテナンス性と可読性があがりますので効率的にアプリを作製することができるからです。
関数化=未来の自分への投資とも言えますね(^^)
それでは最後に前回作ったアメカブくんを「関数視点」でもう一度眺めてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
#------- ここからコピペする ----------# import urllib import urllib.parse from bs4 import BeautifulSoup import requests from time import sleep def get_stock_news(company): ret = [] googlenews = "https://news.google.com/search?q={}&hl=en-US&gl=US&ceid=US:en".format(urllib.parse.quote(company)) print(googlenews) r = urllib.request.urlopen(googlenews) html = r.read() sp = BeautifulSoup(html, "html.parser") for tag in sp.find_all("article"): url = tag.find("a").get("href") title = tag.find("span").getText() if url is None or title is "": continue if "article" in url: ret.append(title) if len(ret) == 10: break return ret def translate_en_jp(en): sleep(1) url = "https://translate.google.com/translate_a/single" headers = { "User-Agent": "GoogleTranslate/5.9.59004 (iPhone; iOS 10.2; ja; iPhone9,1)" } params = { "client": "it", "dt": ["t", "rmt", "bd", "rms", "qca", "ss", "md", "ld", "ex"], "dj": "1", "q": en, "tl": "ja" } res = requests.get(url=url, headers=headers, params=params) res = res.json() return f'{res["sentences"][0]["trans"]}' #------- ここまでコピペする ----------# us_stocks = {"PEP": "PepsiCo","JNJ": "Johnson & Johnson","PG": "Procter & Gamble","GIS": "General Mills", "KO": "The Coca-Cola Co", "MO": "Altria Group", "PM": "Philip Morris International", "BUD": "Anheuser Busch Inbev NV", "CL": "Colgate-Palmolive Company", "UL": "UNILEVER N.V. Common Stock", "XOM": "Exxon Mobil Corporation","GILD": "Gilead Sciences","T": "AT&T","HRL": "Hormel Foods", "V": "Visa","OKTA": "Okta","TEAM": "Atlassian"} while True: print("--- 検索したいニュースのティッカーコードを入れて下さい:") ticker = input() if ticker == "end": print("終了します") break flag = ticker in us_stocks.keys() if flag: print("ニュースを検索しています...") company = us_stocks.get(ticker) news = get_stock_news(company) for n in news: trans = translate_en_jp(n) index = trans.find("配当") if index != -1: str1 = trans[:index] str2 = trans[index+len("配当"):] print(str1 + "【" + "配当" + "】" + str2) else: print(trans) else: print("有効なティッカーをいれてください") |
ここでは次の2つの関数を使ってアプリを作りました。
- get_stock_news() :銘柄名を入れると、それに関連する英語のニュースをリストで返す関数
- translate_en_jp() :英文を入れると、それを日本語に翻訳して返す関数
アメカブくんの作製にあたって、われわれはこれらの関数のパラメータと戻り値のみに意識を向ければよく、中身の処理内容は理解の必要なくアメカブくんを実装できました。これが「可読性」です。
またこのアプリを、ニュースではなく指定した企業のIR情報を返したり、日本語訳ではなく英語のまま返すように変更したい場合は、それぞれの関数を変更することで我々が実装した部分は変更することなく(メンテナンス性高く)、アプリを改造することができます。
関数化することで複雑な処理を読みやすく、メンテナンスしやすくなることを感じていただけたでしょうか?
次回からの中級編ではより実践的な内容を学んでいき、世界の株式情報をより効率的に処理できるようなアプリを作っていきましょう!