TomoProgの技術書

底辺プログラマーが達人プログラマーになるまで

Pythonでは関数の引数はすべて参照渡し?

皆さん
こんにちは、こんばんは
TomoProgです。

Pythonの関数の引数がすべて参照渡しということを知っていますか?
私はPythonを趣味で使い始めてそろそろ一年ぐらいだと思いますが、知らなかったです・・・。

ということで、
今日はPythonの関数の引数について少し調べてみたことをここに書いていこうと思います。

それでは頑張っていきましょう。

ほんとに参照渡しなの!?

関数の引数がすべて参照渡しらしいので、こんなコードを書いてみました。

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

def calc(y):
    y += 10

def main():
    x = 10
    calc(x)
    print(x)

if __name__ == "__main__":
    main()

すべて参照渡しならば結果は20になるはずだ!!

実行結果:
10

あれ?
参照渡しなのに20になっていないんですけど、どうゆうことなんでしょう・・・。

変数の識別値を調べてみる

Pythonには組み込み関数としてid()という関数が準備されています。

id(object)
オブジェクトの “識別値” を返します。この値は整数で、このオブジェクトの有効期間中は一意かつ定数であることが保証されています。有効期間が重ならない 2 つのオブジェクトは同じ id() 値を持つかもしれません。
引用元:2. 組み込み関数 — Python 3.4.3 ドキュメント

この組み込み関数を使用して先ほどのプログラムの変数の識別値を調べてみます。

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

def calc(y):
    print("id(y):" + str(id(y)))
    y += 10

def main():
    x = 10
    print("id(x):" + str(id(x)))
    calc(x)
    print(x)

if __name__ == "__main__":
    main()
実行結果:
id(x):10106112
id(y):10106112
10

確かに識別値は一緒なので、参照渡しであることは間違いないみたいです。
参照渡しなのになぜ値が変わらないのかgoogle先生に聞いてみることにします。

ミュータブルとイミュータブル

先生が教えてくれたのは以下のサイトでした。
rcmdnk.github.io

なるほど。
Pythonで使用できるオブジェクトにはミュータブル(変更可能)とイミュータブル(変更不可)のオブジェクトがあるみたいです。

# ミュータブルオブジェクト
list, set, dict など

# イミュータブルオブジェクト
int, float, str, tuple など

先ほど私が作ったプログラムの引数はintでイミュータブルなので変わらなかったようです。

ミュータブルなオブジェクトを引数にしてみる

ミュータブルオブジェクトなら値が書き変わるのか見てみます。
今回はリスト型で試してみました。

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

def func(dist):
    dist[0] = 2
    dist[1] = "apple"
    dist[2] = False

def main():
    src = [1, "banana", True] 
    print(src)

    func(src)
    print(src)

if __name__ == "__main__":
    main()
実行結果:
[1, 'banana', True]
[2, 'apple', False]

おぉ!!
確かにミュータブルオブジェクトであれば値が書き変わりました!!

まとめ

  • Pythonでは関数の引数はすべて参照渡しである。
  • 参照渡しでも書き換え可能なオブジェクトと書き換え不可能なオブジェクトが存在する。

今日はPythonの関数の引数について調べてみました。
1年使っても知らないことは多いものです。
それではまた。

TomoProg

GitHub
TomoProg (TomoProg) · GitHub

Twitter
TomoProg (@tomoprog_xxx) | Twitter

Pythonで百人一首ボットを作ってみる!! パート1

皆さん
こんにちは、こんばんは
TomoProgです。

前々回のブログ「Python使ってつぶやいてみた」でTwitterへ投稿するやり方を学びました。
これを応用して百人一首ボットを作ってみたいと思います。

それでは頑張っていきましょう!!

百人一首ボットの仕様

まずは仕様を考えるところからスタートです。
とりあえず、考えてみた仕様はこんな感じ。

  • 何分か毎に百首の中から一首ランダムに選びTwitterに投稿する。
  • 投稿する内容はランダムに選ばれた歌の上の句、下の句、歌人名、現代語訳、絵札の画像とする。

何分毎にするかは後々決めていきます。
また、投稿する内容が多いので、投稿を分割するかもしれません。
その辺りは作りながら決めていきましょう!!

絵札の画像を集めてみる

一番時間がかかりそうな絵札画像の収集からやっていきます。
百人一首の絵札の画像は探せば沢山の種類がネット上にありますが、今回は下記のサイトの絵札画像を収集していきます。
Ogura Hyakunin Isshu - Wikimedia Commons

このサイトに表示されている画像はサムネイル用なので、前回の画像収集プログラムの時にもやったようにaタグのhref属性のURLから取得していきます。

<!-- imgタグのsrc属性はサムネイル用なので、aタグのhref属性のURLからオリジナルを取得していく -->
<a href="/wiki/File:Hyakuninisshu_003.jpg" class="image">
<img alt="" src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Hyakuninisshu_003.jpg/86px-Hyakuninisshu_003.jpg" width="86" height="120" ・・・ />

そしてここで気づいたのです。
そう。このhref属性はルート記号("/")から始まってるのです。

普通にhref属性の内容でURLを開こうとすると「404 Not Found」でオリジナルの画像のURLまで辿りつけないのです・・・。

というわけで、href属性の前方にルートディレクトリのパス(https://commons.wikimedia.org/)をつけて、そのURLにアクセスし、画像を集めることにしました。

これでなんとか画像はすべて全部ゲット出来ました!!

f:id:TomoProg:20160217232156j:plain

とりあえず画像付きでつぶやいてみる

画像をTwitter上に投稿するコードを公式のサンプルプログラムを参考に書いてみることにします。
twitterモジュールのドキュメントにアップロードのやり方が書いてあったので、参考に書いてみました。
twitter · PyPI

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

from twitter import *
import json

# global変数
conf_file_name = "conf.json"

def main():
    """
        Content:
            エントリーポイント
    """
    # 設定ファイル読み込み
    with open(conf_file_name) as f:
        conf_data = json.loads(f.read())

    # Twitterアプリ認証
    app_auth = OAuth(conf_data["access_token"],
                conf_data["access_token_secret"],
                conf_data["consumer_key"],
                conf_data["consumer_secret"])
    app = Twitter(auth=app_auth)

    # 画像をつぶやく
    with open("001.jpg", "rb") as image_f:
        image_data = image_f.read()

    t_up = Twitter(domain="upload.twitter.com", auth=app_auth)
    id_img = t_up.media.upload(media=image_data)["media_id_string"]

    app.statuses.update(status="画像アップロードテスト", media_ids=id_img)

    print("Success!!")

if __name__ == "__main__":
    main()

Twitterクラスのdomain引数に"upload.twitter.com"を指定して新しく画像アップロード用のインスタンスを作成するみたいです。

さて、実行してみると・・・
f:id:TomoProg:20160218002434j:plain

画像が投稿できました!!

今日の成果

  • 百人一首の画像ファイルは全部ゲット出来た!!
  • Twitterに画像を投稿することが出来た!!


さて、今日はこの辺で終わりにします。
パート2を乞うご期待!!
それではまた。

TomoProg

GitHub
TomoProg (TomoProg) · GitHub

Twitter
TomoProg (@tomoprog_xxx) | Twitter

COMポートって何!?

皆さん
こんにちは、こんばんは
TomoProgです。

このブログのPVが今月100を超えたという嬉しいお知らせが来ました!!
これって自分が見た回数とかも数えられるんですかね?

何はともあれ嬉しいことです!!
見ていただいた方ありがとうございます!!
これを糧に今後も頑張って書いていこうと思います!!

さてさて、今日は仕事中にCOMポートと言う言葉が出てきたので「COMポート」について調べてみました。

COMポートって何!?

早速google先生に聞いてみるとIT用語辞典を勧めてくれました。
e-words.jp

「〜など。」や「〜を指すこともある。」など、IT用語って結構あやふやなのが多いと思うんです!!

IT用語辞典では私にはよく分からない!!

ということで、他に調べてみると以下のサイトにこんなことが書いてありました。

ウィンドウズパソコンの場合、普通はシリアルポート(RS-232C)のことだと思っていい。以前のマッキントッシュでは、モデムポートやプリンタポートがCOMポート(コムポート)になることもあった。
引用元:http://www.nttpc.co.jp/yougo/COM%E3%83%9D%E3%83%BC%E3%83%88.html

COMポートはWindowsパソコンの場合シリアルポートのことだと思っていいみたいです。

じゃあシリアルポートって何!?

シリアルポートと思っていいみたいなので、シリアルポートについて調べてみました。
Wikipediaによると

シリアルポートとは、情報を(パラレルポートとは異なり)1度に1ビットずつ送受信するシリアル通信物理インタフェースである[1]。パーソナルコンピュータの歴史の大半において、データはシリアルポートを通じてモデム、端末、その他様々な周辺装置のデバイスに伝送された。
引用元:シリアルポート - Wikipedia

シリアルポートはモデムや端末などと通信するために使われているんですね。

調べてみると結構古い規格のようで、今では過去の遺産と書いているページも見つけました。
普通のPC同士の通信には今はほぼ使われていないみたいです。
シリアルポートに変わるUSBなどの規格が出てきてから、そちらに置き換わっていったみたいですね。

PLC(シーケンサ)などの制御機器との通信ではまだまだ現役みたいです。

正直、通信すると言われればLANケーブルをハブに挿して通信するんじゃないの?と思ってしまうんですよね・・・
シリアルポートにケーブル挿して通信したという記憶がないです。

まとめ

  • COMポートと言われればシリアルポートのこと!!
  • シリアルポートは制御機器との通信ではまだまだ一般的に使用されている!!


今日はCOMポートを自分なりに調べてみました。
それではまた。

TomoProg

GitHub
TomoProg (TomoProg) · GitHub


Twitter
TomoProg (@tomoprog_xxx) | Twitter

Python使ってつぶやいてみた

皆さん
こんにちは、こんばんは
TomoProgです。

今日はPythonを使ってツイッターにつぶやいてみたので、やり方など書いていこうと思います。
(ここではPython3を使用することを前提として書きます。)

Twitterアプリを作成する

まずはPythonからつぶやくアカウントを作成します。
アカウントの作成方法は普通にアカウントを作るのと何も変わらないのでここでは省略です。

アカウントを作成し終わったら、下記のTwitter開発者用ページにアクセスし、先ほど作成したアカウントでログインします。
https://dev.twitter.com/

開発者用ページの一番下にある「Manage Your Apps」からアプリ管理画面に移動し、アプリを作成します。

アプリを作成すると、以下の4つのキーが生成されるので、メモしておきましょう。

  • Consumer Key
  • Consumer Secret
  • Access Token
  • Access Token Secret

ここまで出来れば準備完了です。

Pythonでつぶやくコードを書く

それではPythonのコードを書いていきましょう。
まず、pipを使ってtwitterモジュールをインストールします。

$ pip install twitter

インストールが出来たらコードを書いていきましょう!!

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

from twitter import *

api = Twitter(
    auth = OAuth(
        Access Token, 
        Access Token Secret,
        Consumer Key, 
        Consumer Secret))

api.statuses.update(status="Hello World!!")

OAuthに渡す引数はアプリを作成したときに生成された4つのキーをそれぞれ書き込みます。
api.statuses.updateのstatus引数に渡した文字列がTwitterTweetされます。
たったこれだけです。

実際に実行してみる

さてそれでは実行してみましょう!!
実行すると...
f:id:TomoProg:20160214170521j:plain
Hello World!!」がつぶやけました!!

というわけで、今日はPythonプログラムからTweetしてみました。
せっかくPython使ってつぶやけたのでボットでも作ってみようかなと思います。
それではまた。

TomoProg

GitHub
https://github.com/TomoProg

Twitter
TomoProg (@tomoprog_xxx) | Twitter

C言語のstruct型を使ってたら謎の現象に遭遇した

皆さん
こんにちは、こんばんは
TomoProgです。

前の記事に星をつけてくださった方ありがとうございます!!
次は20記事を目標に頑張っていきます!!

今回はPythonを離れて、C言語のstruct型で疑問に思ったことを書いていこうと思います。

謎の現象に遭遇

C言語で以下のようなコードを書いてみると、謎の現象に遭遇しました。

#include <stdio.h>

typedef struct st_a
{
    int num_a;
    char char_a;
    int num_b;
}ST_A;

int main(void)
{
    printf("sizeof(int):%lu\n", sizeof(int));
    printf("sizeof(char):%lu\n", sizeof(char));
    printf("sizeof(ST_A):%lu\n", sizeof(ST_A));
    return 0;
}
実行結果:
sizeof(int):4
sizeof(char):1
sizeof(ST_A):12

あれ?
構造体の大きさが12バイト?
定義した構造体のメンバはint型2つとchar型1つだから合計で「9」バイトになるんじゃないの?

というわけで今日は構造体の大きさの謎に迫ってみようと思います。

バイト境界、アライメント、パディング

とりあえずgoogle先生に聞いてみたらこのサイトを教えてくれたので、勉強させていただきました。
C言語編 - 構造体のサイズとアライメント

  • メモリに変数が配置される時は「バイト境界」と言われる区切りに合わせて配置される。
  • メンバ間に空間が出来ることを構造体の「アライメント(整列)」と呼ぶ。
  • メンバ間の空白を「パディング」という。

なるほど。
今回の内容もメモリに配置されるときにアライメントされているので、メンバ間に空白があるということか。

メンバ間のパディングを確かめる

メンバのそれぞれの先頭アドレスを調べてパディングを確かめてみます。

#include <stdio.h>

typedef struct st_a
{
    int num_a;
    char char_a;
    int num_b;
}ST_A;

int main(void)
{
    ST_A st_a;

    printf("num_a  address:[%p]\n", &st_a.num_a);
    printf("char_a address:[%p]\n", &st_a.char_a);
    printf("num_b  address:[%p]\n", &st_a.num_b);

    return 0;
}
実行結果(実行毎に異なります):
num_a  address:[0x7fffc215c060]
char_a address:[0x7fffc215c064]
num_b  address:[0x7fffc215c068]

メンバが4バイトずつ配置されていることが確認出来ました!!

また、char型は1バイト、int型は4バイトだったので、定義した構造体はメモリ上では下記のように配置されてそうです!!

メモリ配置:
[0x7fffc215c060] → num_a(先頭アドレス)
[0x7fffc215c061] → num_a
[0x7fffc215c062] → num_a
[0x7fffc215c063] → num_a
[0x7fffc215c064] → char_a(先頭アドレス)
[0x7fffc215c065] → パディング
[0x7fffc215c066] → パディング
[0x7fffc215c067] → パディング
[0x7fffc215c068] → num_b(先頭アドレス)
[0x7fffc215c069] → num_b
[0x7fffc215c06A] → num_b
[0x7fffc215c06B] → num_b

まとめ

構造体のメンバはバイト境界に応じてメモリ上に配置される。
そのため、単純に定義したメンバの型の数で計算した結果になるとは限らない。

これからはstructを使うときはバイト境界に気をつけて定義しようと思います。
それではまた。

GitHub
https://github.com/TomoProg

Twitter
TomoProg (@tomoprog_xxx) | Twitter

Python使ってYahoo画像検索の画像を自動で収集してみた

皆さん
こんにちは、こんばんは
TomoProgです。

記念すべき10記事目!!
頑張っていきましょう!!

今回はPythonを使ってYahoo画像検索の画像を自動で画像を収集してみようと思います。

指定したWebサイトのhtmlを取得する

まずはWebサイトのhtmlを取得してみたいと思います。
Pythonにはurllibという指定したURLに簡単にアクセスできるモジュールが備わっています。

import urllib.request

request = urllib.request.urlopen(url)
html = request.read()

urllib.request.urlopenを使うと引数に指定したURLを開きます。
あとは開いたURLの情報をreadで読み取るだけです。

実際にgoogle検索のトップページのhtmlを取得してみます。

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

import urllib.request

url = "https://www.google.co.jp"
request = urllib.request.urlopen(url)
html = request.read()

print(html)
実行結果:
b'<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="\x90\xa2\x8aE\x92\・・・
(長いので省略)

こんな感じで指定したURLのhtmlを簡単に取得出来ます。

htmlを読めるようにデコードする

htmlを取得したのは良いものの、request.readの戻り値をそのまま出力すると何らかの文字コードエンコーディングされたまま取得してしまうので、謎の文字(上の実行結果の\x90\xa2\x8aEなど)が出力されてしまいます。

これでは何が書いてあるのかわからないので、取得したhtmlの文字コードを特定してデコードしましょう。

文字コードを特定するには様々な文字コードで片っ端からデコードしていきます。

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

import urllib.request

url = "https://www.google.co.jp"
request = urllib.request.urlopen(url)
html = request.read()

encoding_list = ["utf-8", "utf_8", "euc_jp", 
                    "euc_jis_2004", "euc_jisx0213", "shift_jis",
                    "shift_jis_2004","shift_jisx0213", "iso2022jp",
                     "iso2022_jp_1", "iso2022_jp_2", "iso2022_jp_3",
                    "iso2022_jp_ext","latin_1", "ascii"]

for enc in encoding_list:
    try:
        html.decode(enc)
        break
    except:
        enc = None

print(enc)
if enc != None:
    print(html.decode(enc))
実行結果:
shift_jis
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="世界中のあらゆる・・・
(長いので省略)

先ほどの謎の文字が日本語になりましたね!!
(これ以外のやり方を知っている人がいたら是非教えて下さい!!)

Yahoo画像検索のhtmlを見てみる

ここまでで指定したサイトのhtmlを手に入れる術を身につけたので、実際にYahoo画像検索で欲しい画像を検索します。
CodeIQさんのプログラミング漫画「走れ! コード学園」で検索!!
f:id:TomoProg:20160212235220j:plain

可愛い女の子がいっぱいですね!!

それはさておき、このサイトのhtmlをじっくり見てみるとどうやら画像がaタグのhref属性に書かれたURLに存在するようです。

<a href="http://ord.yahoo.co.jp/o/image/.../sample.jpg" target="imagewin">
(長いので途中省略)

このaタグのhref属性の中身だけを抽出できれば画像が取得出来そうです。

htmlからaタグのhref属性だけを抽出する

htmlを解析するモジュールはPythonにはいくつかありますが、今回はBeautifulSoupというモジュールを使用します。

BeautifulSoupは標準モジュールではないので、pipコマンドでインストールします。

$ pip install beautifulsoup4

これだけでBeautifulSoupを使用する準備は完了です。

実際にBeautifulSoupを使ってみます。

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

import bs4

html = """
        <html>
            <head>
                <body>
                    <a href="http://www.yahoo.co.jp">Yahoo!!</a>
                    <a href="https://www.google.co.jp">Google</a>
                    <p>こんにちは</p>
                </body>
            </head>
        </html>
        """

resources = []

# BeautifulSoupオブジェクトを作成
soup = bs4.BeautifulSoup(html)

# htmlのすべてのaタグの中のhref属性の内容を取得
for a_tag in soup.find_all("a"):
    href_str = a_tag.get("href")
    resources.append(href_str)

# hrefの内容を表示
for resource in resources:
    print(resource)
実行結果:
http://www.yahoo.co.jp
https://www.google.co.jp

BeautifulSoupを使う際はimport bs4を最初に書きます。
find_all("a")ですべてのaタグの内容を取得、get("href")でaタグの中のhrefの内容だけを取得出来ます。

これで画像ファイルのURLをすべて取得出来ました!!

URLからダウンロードする

あとは取得した画像ファイルのURLを開き、バイナリ形式でファイルに書き出すだけです。

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

import urllib.request

# 画像ファイルのURLを開く
# (urlに画像ファイルのURLを指定)
request = urllib.request.urlopen(url)

# ファイルをバイナリモードで開き、URLの内容を書き込み
# (file_nameに保存時のファイル名を指定)
f = open(file_name, "wb")
f.write(request.read())

# ファイルを閉じる
f.close()

実際に自動収集してみる

ここまで長い道のりでしたが、なんとか完成しました!!
実際に自動収集してみます!!
youtu.be

これでWebの画像も集め放題です!!
ソースはGitHubで公開しておきます。
それではまた。

GitHub
https://github.com/TomoProg/HatenaBlog/blob/master/python/web_crawler.py

Twitter
TomoProg (@tomoprog_xxx) | Twitter

GitHubのプレビュー時のタブ幅を設定する

皆さん
こんにちは、こんばんは
TomoProgです。

2日ぶりの更新!!
頑張っていきましょう!!

今日はGitHubのプレビュー時のタブ幅の設定方法を書き記しておこうと思います。

GitHubのタブ幅は8!!

GitHubで普通にソースをプレビューするとタブ幅が8に設定されてしまいます。
https://github.com/TomoProg/HatenaBlog/blob/master/python/logger.py

8だとちょっと広がりすぎで見辛いですよね・・・。

タブ幅を変えてみる

タブ幅を変えて表示するにはURLの最後に

?ts=2

を書き加えるだけです!!
数字の部分は好みのタブ幅に変えてください。

先ほどのURLに?ts=2を追記したURLがコチラ
https://github.com/TomoProg/HatenaBlog/blob/master/python/logger.py?ts=2

まとめ

GitHubのプレビューが見やすくなります!!
それではまた。

TomoProg