Pythonで簡易HTTPサーバー

Pythonで簡易HTTPサーバー

この方法はPython3でのやり方。
今更Python2は無いだろうけど。

HTTPサーバー起動

$ python -m http.server 8000

これでカレントディレクトリが公開されている。
ポート番号を8000にしているのは、80は管理者権限が必要なため。

CGIを動かしたいとき

オプションを指定する。

$ python -m http.server 8000 --cgi

CGIプログラムは./cgi-binに必ず置く。

このHTTPサーバは指定ファイルをそのまま素直に走らせているようなので、
Windowsの場合は.exeや.batなど、ダブルクリックで直接実行できるプログラムにする。
(標準出力を得て、標準出力するような)

WindowsのApacheは、shebangを読んでそのスクリプトエンジンで実行してくれるのに。

おまけ Windowsのexe作成

たとえばC#なら

Test1.cs

using System;
namespace Test1
{
        public class Test1
        {
                static void Main()
                {
                        Console.WriteLine("Context/type: text/html");
                        Console.WriteLine("");
                        Console.WriteLine("Hello, C#!");
                }
        }
}

コンパイルは下記の通り

D:\> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe Test1.cs

Test1.exeの出来上がり。

VB.netなら

Test2.vb

Module Test2
        Sub Main()
                Console.WriteLine("Context/type: text/html")
                Console.WriteLine("")
                Console.WriteLine("Hello, VB.net!")
        End Sub
End Module

コンパイルは下記の通り

D:\> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\vbc.exe Test2.vb

Test2.exeの出来上がり。

まとめ

ローカルのHTMLをhttpで表示したいだけで始めたのに、いろいろ試す事ができた。
たまにはC#やVB.netも楽しい。

同じタグの記事
同じカテゴリの記事

PythonとBottomでWeb API作成

PythonとBottleでWeb API作成

ちょっとしたWeb APIを作る必要があった。
Web APIといえば、node.jsで簡単に作れそうだけど、
慣れ親しんだPythonならもっと簡単にできてしまう。
PythonとBottleを使って作ってみる。

Bottleのインストール

Bottleはpipでインストールしても良いし、単純にダウンロードしてAPIと同じディレクトリに置くだけでも動作する。

実装

from bottle import run, route, request, response
import json

@route('/echo/<msg1>/<msg2>')
def echo(msg1, msg2):
    # CORS
    if 'Origin' in request.headers:
        origin = request.headers['Origin']
        response.headers['Access-Control-Allow-Origin'] = origin
        response.headers['Access-Control-Allow-Methods'] = (
            'PUT, GET, POST, DELETE, OPTIONS')
        response.headers['Access-Control-Allow-Headers'] = (
            'Origin, Accept, Content-Type, X-Requested-With'
            ', X-CSRF-Token, Authorization')
    # ECHO
    return json.dumps({
        'msg1': msg1,
        'msg2': msg2,
    })

run(host='localhost', port=8080)

とりあえず、ブラウザからアセスしてみる

http://localhost:8080/echo/test11/test22

画面にJSONらしきテキストが表示された。

javascriptでfetchしてみる

fetch('http://localhost:8080/echo/js11/js22', {
    method: 'GET',
    mode: 'cors',
    cache: 'no-cache'
}).then(function(res) {
    res.json().then(function(data) {
        console.log(data);
    });
});

chromeで実行したところ、開発者コンソールにJSONが出力された。

まとめ

Pythonで簡単にWeb APIが作れた。
とりあえず、サーバに応答して欲しくて作ったが、クライアントがjavascriptなので、そのうちサーバー側もnode.jsで作って言語を統一しよう。

同じタグの記事
同じカテゴリの記事

Pythonでマルチスレッド再び

以前、Pythonでマルチスレッド処理を行うプログラムを書いた。そのときはthreading.ThreadとQueue.Queueを使っていた。それはPython2.7を使っていたから。
しかし、今はPython3がメインだ。concurrent.futures.ThreadPoolExecutorを使えばもっとスマートに実装できる。

Python3

from concurrent.futures import ThreadPoolExecutor

def download(name, url):
    pass

target_url_list = []  # URL List
tp = ThreadPoolExecutor(max_workers=4)
for url in target_url_list:
    tp.submit(download, url.name, url.url)
tp.shutdown()
print('End')

とても簡単に書くことができる。max_workersに応じて多重度を調整してくれる。ThreadPoolExecutorのshutdown()メソッドで、すべてのスレッドの終了を待ち合わせてくれる。
これは便利。

Python2(参考)

import threading
import Queue

def download(q):
    while True:
        item = q.get()
        if item is None:
            break
        name = item.name
        url = item.url
        pass

target_url_list = []  # URL List
q = Queue.Queue()

thread_list = []
for i in range(4):
    thread = threading.Thread(target=download, args=(q,))
    thread.start()
    thread_list.append(thread)

for item in target_url_list:
    q.put(item)

for i in range(len(thread_list)):
    q.put(None)

for thread in thread_list):
    thread.join()

print('End')

以前はこれが普通だったけれど、今見るととても冗長だ。

まとめ

もうPython2のことは忘れてPython3でどんどん作ろう。
(はやくJythonがPython3系になってくれると良いのだが・・・)

同じタグの記事
同じカテゴリの記事

Pythonでファイルの更新日時変更

メーカーの分からないフォトフレームがある。SDカードに写真を入れて、それを差し込めば表示されるのだが、並び順が全くわからない。ディレクトリも無視しているようだ。しかしよく見ると、写真を撮った順番に並んでいるようにも見える。どうやら、撮影日ではなく、ファイルの最終更新日時順で表示されているようだ。たまに順番がおかしいのは編集したファイルだ。
ファイルの更新日を希望の順番で更新してしまおう。

os.utimeで更新

import os
import datetime

target_file = 'test.jpg'
utime = datetime.datetime.strptime('20191109_080322', '%Y%m%d_%H%M%S')
os.utime(target_file, (utime.timestamp(), utime.timestamp()))

まとめ

写真のファイル名が連番だったので、その名前で並べ替えてから、先頭のファイルをシステム日時にして、残りを1秒ずつずらしなら設定したらキレイに並びました。

同じタグの記事
同じカテゴリの記事

Pythonクラスの雛型

Pythonでクラスを作成するとき、コメントの場所、スーパークラスのコンストラクタ呼び出し、デストラクタの名前、withに対応させるメソッド名など、いろいろ忘れてしまう。
雛型を作ろう。

Pythonクラス雛形

class MyClass(object):
    '''私の作るクラス。ここにクラスのコメントを記述する。
       このコメントがクラスの説明として表示される。
       objectを継承しているが、この記述は省略可能。
    '''

    def __init__(self, x, y):
        ''' コンストラクタ。ここにメソッドのコメントを記述する。

            Args:
                x (str): xxxx
                y (str): yyyy
        '''
        self.x = x
        self.y = y
        self.file1 = self.__open('file1.txt', 'a')
        self.file2 = None

    def __del__(self):
        '''デストラクタ。終了処理を書く。
           ただしクラス開放のタイミングはPython任せになる。
        '''
        self.file1.close()

    def __enter__(self):
        '''withブロックが開始した時に呼び出されるメソッド。
           ここでオープン処理を行う。
           selfをreturnする必要がある。
        '''
        self.file2 = self.__open('file2.txt', 'a')
        return self

    def __exit__(self, exc_type, exc_val, exc_th):
        '''withブロックが終了した時に呼び出されるメソッド。
           ここでクローズ処理を行う。
           引数を4つ取る必要がある。
        '''
        self.file2.close()

    def __open(self, filename, open_mode):
        ''' アンダースコア2つのメソッドは、外から呼べなくなる。
            プライベートメソッドを定義したいときはこうする。

            Args:
                filename (str): file nema.
                open_mode (str): file open mode.
            Returns:
                stream: file stream
        '''
        return open(filename, open_mode)

    def write(self, msg):
        ''' 通常の公開メソッド。引数の説明を書くと親切。

            Args:
                msg (str): メッセージ
        '''
        self.file1.write(msg + '\n')
        if self.file2:
            self.file2.write(msg + '\n')

    def __str__(self):
        '''str()したときに呼ばれるメソッド。
           インスタンスを単純にプリントした時に表示されるので、
           デバッグ時に役立つ。
        '''
        return 'X[{}] Y[{}]'.format(self.x, self.y)

    def __repr__(self):
        '''repr()したときや、インタラクティブシェルで書き出した時に
           呼び出されるメソッド。
           eval()でオブジェクトになるように記述する。
           定義しておくとデバッグ時に役立つ。
        '''
        return '''MyClass('{}', '{}')'''.format(self.x, self.y)


class MyClassClass(MyClass):
    '''MyClassを継承したクラス
    '''

    def __init__(self, x, y, z):
        '''コンストラクタ。
        '''
        # スーパークラスのコンストラクタを呼び出す方法
        super(MyClassClass, self).__init__(x, y)
        self.z = z
    
    def __str__(self):
        return 'X[{}] Y[{}] Z[{}]'.format(self.x, self.y, self.z)
    
    def __repr__(self):
        return '''MyClassClass('{}', '{}', '{}')'''.format(
            self.x, self.y, self.z)

まとめ

これで次からクラスを作る度に調べる必要がなくなる。

同じタグの記事
同じカテゴリの記事

Python自前のクラスをWithに対応させる

自前のクラス、使い終わったらclose()して欲しい。
将来の自分は、ちゃんとclose()を呼び出してくれるだろうか?
例外が発生した場合も、ちゃんとclose()を呼び出してくれるだろうか?

自前のクラスもwithでクローズ出来たら構文がスッキリする。
Javaならjava.lang.AutoCloseableインターフェースを継承してclose()メソッドを実装すれば、try-with-resource構文が使えるようになりスッキリする。
では、Pythonではどうするのだろうか。

__enter__、__exit__メソッド

自前のクラスに__enter__と__exit__を実装すればよいようだ。

__enter__は__init__の後に呼ばれる。
__enter__は戻り値としてselfを返却すればよい。

__exit__はwithが終わったところで呼び出される。
引き数は必ず4つ受け取る必要がある。withから渡される。
with内で例外が発生したとき、その情報が入っているらしい。

class MyClass:
    def __init__(self, init_value):
        self.xxx = Xxx(init_value)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.xxx.close()

    def proc(self, proc_value):
        self.xxx.yyy(proc_value)

with MyClass('ABC') as m:
    m.proc('LMN')

このような実装で、withから抜けた時にMyClassがちゃんと閉じられる。

まとめ

FTP接続し複数ファイルを転送したらcloseするとか、
DB接続し処理が完了したらcloseとかいろいろ使えそうだ。
キレイにまとまってよかった。

同じタグの記事
同じカテゴリの記事

Pythonで正規表現

相変わらず、ログの集計。
今回は、ログファイルより特定のキーワードが含まれる行を取得したい。
特定のキーワードは2種類。
ログファイルなので、お決まりのフォーマットで出力されている。
キーワードが2つなので、正規表現を利用してみる。

正規表現モジュール

Pythonで正規表現を利用するためにはreをインポートする。

import re

単純に部分一致する行を見つけたいのであれば以下の様で良い。

text = 'test X start'
if re.search('(X start|X end)', text) is not None:
    print(text)

ファイルの内容を行単位で繰り返し評価する場合は、正規表現オブジェクトをあらかじめ作成しておいた方が良いかも。

r = re.compile('(X start|X end)')
with open('log.log', 'r') as r:
    for line in r:
        if r.search(line) is not None:
            print(line.strip())

re.searchの戻り値を利用する

単純に存在するかどうかを判定するだけであれば、is not Noneで評価すればよいが、matchオブジェクトが返ってきているので、それを使うのも良い。

text = '----+----1----+----2----+----3'
m = re.search('1.*2', text)
print(m.group())
print(m.start())
print(m.end())
print(m.span())
# 1----+----2
# 9
# 20
# (9, 20)

m.start()やm.end()は、文字の切り出しに便利かもしれない。

まとめ

正規表現は書き方がわかるといろいろ便利。

同じタグの記事
同じカテゴリの記事

Pythonで昨日

FTPで昨日のログファイルを取得したい。
FTP取得自体は、以前から行っていたが昨日を求める必要がある。

Pythonで昨日を取得する

datetime.timedeltaで一日を表現して、それをマイナスすればよいようだ

import datetime
now = datetime.datetime.now()

# 今
print(now)
# 一日前
print(now - datetime.timedelta(days=1))

すばらしい。1日はdays=1で表現できて、それを減算すると一日前のようだ。

ならば、7日前は1週間前だ。

print(now - datetime.timedelta(days=7))

7日前は1週間前という表現もできるようだ。

print(now - datetime.timedelta(weeks=1))

1時間前も取得できる。

print(now - datetime.timedelta(hours=1))

プラスすれば1時間後

print(now + datetime.timedelta(hours=1))

datetimeの引き算の結果もtimedelta

そういえば、datetimeとdatetimeの引き算の結果もtimedeltaだった。

before = datetime.datetime.strptime('2019/4/16 16:30', '%Y/%m/%d %H:%M')
after = datetime.datetime.strptime('2019/4/17 17:15', '%Y/%m/%d %H:%M')
delta = after - before
print(delta.days)
print(delta.seconds)

daysは経過日数、secoundsは経過秒数が得られる。

まとめ

Pythonの日付時刻は一貫性があって美しい。

同じタグの記事
同じカテゴリの記事

Ruby公式サイトの他言語とRubyの違いを眺めてみて

Ruby公式サイトの他の言語とRubyの違いを眺めてみて

www.ruby-lang.orgの多言語からのRuby入門が面白かった。
他の言語と同じところ、違うところがまとめられている。
個人的にPythonとJavaが得意で、そこを眺めてみたが、こういう風にまとめられていると導入しやすいと思う。
気になったところを書き出してみる。

irbと言われる対話型の実行環境がある

この環境はとても便利。使ったことのないクラスを使う必要がある場合や、普段から使っているけどなかなか覚えられないsubstringの区切り位置を確認するときに重宝する。
文字列の2バイト目から5バイト欲しいときはどう指定するのか。対話画面があるとすぐに試せる。

今でこそ、Javaにもjshellができたが、それまでは小さなプログラムを作って、コンパイルして実行する必要があった。Eclipse 2の頃はスクラッチパットがあったが、今はどうなのだろう。
irbでいろいろ試しながら、スクリプトを作ることにしよう。

三重引用符で複数行リテラル

これは、Pythonでも好きなところ。Rubyでも使えるのは良いことだ。
Javaだったら、StringBuilder使うのも面倒なので、Propertiesにでも書き出しておくだろうか。

リストは[]、辞書は{}

PythonのTupleは無いようだ。あまり使わないから、どっちらでもよいが。

メソッド呼び出しの括弧はオプション

さすがPerlの次の言語だ。メソッドの呼び出しに括弧がいらない。Perlもそうであった。
昔のVBの様に戻り値の無いときの利用なら許容範囲かと思う。

True、Falseはtrueとfalse。Noneの変わりはnil。

PythonもTrue、Falseはtrueとfalseになってくれれば良いのに。
Noneとnilはnullになってしまえば良いのに。

importの代わりにrequireを使う

JRubyから始めたので、requireとimportの違いがいまだによくわからない。

MyClass.new()

インスタンスの作成が独特。new()もメソッドの扱いなのだろうか。
PythonならMyClass()。Javaならnew MyClass()。知ってしまえば、どれでも大した差はないか。

==とequals()

Rubyで文字列の比較は==。Javaならequals。
Rubyにはequalsは無く、equal?がある。しかしRubyのequal?はオブジェクトの比較用。Javaとは逆の動きだ。

まとめ

RubyもPythonもJavaも違いがあって面白い。
本当は何か1つの言語を極めるべきなのかもしれないけど、同じ言語ばかりだと飽きてしまうので、あれもこれも使っていきたいと思っている。

同じタグの記事
同じカテゴリの記事

Pythonでデータクラス。その後。

Pythonでデータクラス。その後。

Python3.6でデータクラスの使用方法を知ってから、typing.NamedTupleを使ってPythonツールを作ってきた。しかし、今更ながらPython2.7(Jython)のツールを作る必要がでてきた。データクラスが使えない。
と思って、ドキュメントを見ていたら、collections.namedtupleはPython2.6から使えた。じゃあ、これを使えばいいか。

collections.namedtuple

1
2
3
4
5
from collections import namedtuple

Point = namedtuple('Point', 'x,y')
pos = Point(10, 20)
print(pos)

便利だ。__init__や__str__、__repr__まで実装されている。
それにVisual Studio Codeがプロパティを認識してくれている。

しかしtupleなので、プロパティの変更ができない。

1
2
3
4
>>> pos.x = 15
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

けど方法がないわけではない。

_replace

1
2
pos = pos._replace(x=15)
print(pos)

tupleなので変更はできない。しかし、プロパティを変更した新しいtupleを返してくれる。
これで、プロパティの変更のようなことができた。

namedtupleはクラスだ。したがって継承できる。
初期値として渡すような項目はnamedtupleとして定義し、変更する必要があったり、後から設定するようなプロパティは、そのnamedtupleを継承したクラスの方で定義してもよい。

namedtupleの継承(拡張)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from collections import namedtuple

Point = namedtuple('Point', 'x,y')
class MyPoint(Point):
    z = 0

    def move_z(self):
        self.z += 1

    def __str__(self):
        return 'X:{} Y:{} Z:{}'.format(
            self.x, self.y, self.z)

pos = MyPoint(10, 20)
pos.z = 30
pos.move_z()
print(pos)

これで不足ないデータクラスが作成できた。
この例では__str__を書き換えているが、本当は__repr__も書き換えておかないといけない。
__repr__を書き換えるなら、__init__も書き換える必要があるが・・・

まとめ

Python2.7でも、ここまでできるとは。
まだまだJythonも使えそうだ。

同じタグの記事
同じカテゴリの記事