pikesaku’s blog

個人的なプログラム勉強メモです。記載内容について一切の責任は持ちません。

Pythonのlambda式について

lambda式とは?


無名関数を記述する方法

無名関数とは?


・関数宣言をせずに使える関数
・一度だけしか使われない使い捨ての関数。名前をつける必要がないため無名関数と呼ばれる

使い方

lambda 引数:返り値

コロンの左側に記述されたオブジェクトは引数。
式の中のオブジェクト名はxがよく使われているが、aでもhogeでもOK

例) lambda式を使わない場合


コード

def test(a):
    return a * 2

b = test(3)
print(b)

実行結果

6

例) lambda式を使う場合


コード

b = lambda a: a * 2
print(b(3))
print(type(b))

実行結果

6
<class 'function'>

よく見る使われ方


高階関数と一緒に利用される。

高階関数は、関数を引数にしたり戻り値にする関数

例) map関数と使うケース


map関数は、引数に関数とリストを取る。
リストの各要素に対し指定された関数処理をするgeneratorオブジェクトを返す。

コード

l = map(lambda x: x ** 2, [1, 2, 3])
print(l.__next__())
print(l.__next__())
print(l.__next__())

実行結果

1
4
9

例) sorted関数のkeyパラメータとの使われ方1


sorted関数のkeyパラメータは比較を行う前にリストの各要素に対して呼び出される★関数★を指定するパラメータ
並べ替えは、関数の実行結果を使って行われる。

ソート HOW TO — Python 3.6.1 ドキュメント

コード

a = [1,2,3]
b = sorted(a)
print(b)
b = sorted(a, key=lambda x: x * -1)
print(b)

実行結果

[1, 2, 3]
[3, 2, 1]

各要素に対してlambda式で指定した無名関数(-1で掛け算)を実行した結果を使ってソートする。

例) sorted関数のkeyパラメータとの使われ方2

コード

a = [[0,10], [1,9], [2,8]]
b = sorted(a)
print(b)
b = sorted(a, key=lambda x: x[1])
print(b)

実行結果

[[0, 10], [1, 9], [2, 8]]
[[2, 8], [1, 9], [0, 10]]

各要素がリストの場合、その2個目の要素の値を使ってソートする。

Pycharm使い方メモ

他便利な使い方

最強のPython統合開発環境PyCharm - Qiita

検索機能

指定したキーワードにマッチするclass、ファイル、symbolを検索してくれる

コード実行

control + r

コード解析(超便利!)

①CMDキー+クリックで定義元にジャンプする。

②View → Tool Window → Structure選択で左部にプログラム構造が表示される。

Pythonネットワークプログラミング勉強コード

簡易tcpサーバ

動作

・受信データを16進数でクライアントに返す。
・接続開始、終了情報をサーバ側コンソールに出力する。

コード

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

import sys
import socket
import threading

CS          = 'utf-8'
PORT = sys.argv[1]

# PORTはstr型(Python3)
# isdigitメソッドで数字が判定
if not PORT.isdigit():
    print('invaild argment')
    exit(1)


def do_server():
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('0.0.0.0', int(PORT)))
    server.listen(5)
    while True:
        client_socket, addr = server.accept()
        # targetに受信データを処理する関数オブジェクト(client_hander)を指定。
        # 実行結果を引数にするわけではない為、client_handerの後に()はつけない。
        client_addr = str(addr[0]) + ':' + str(addr[1])
        print('Connected from: ' + client_addr)
        client_thread = threading.Thread(target=client_handler, args=(client_socket,client_addr))
        client_thread.start()


def client_handler(client_socket,client_addr):
    while True:
        # dataにクライアント送信データが格納(byte型)される。
        data = client_socket.recv(1024)

        if not data:
            # 切断時処理
            # ncコマンドで接続しCTRL+Cを送信するとクライアントはFINパケット
            # を送信しTCP接続は切れる。dataにはbyte型の空データ(0x00)が格納される。
            # TCP1接続が切れた状態で、client_socket.recvが実行されるとdataに
            # 空データが格納される。その為、LOOPを抜ける必要がある。
            print('Dosconnected from: ' + client_addr)
            break
        else:
            # 受信データを16進数にしたものをクライアントに返す
            r = 'You send following data: '
            for i in data:
                # byte型にイテレータ処理をするとint型になる。 
                # int型のiを、formatメソッドでstr型に変換
                r += 'x{0:02x}'.format(i)
             # クライアントにデータを返す時は、byte型にして送る。
            r += '\n'
            client_socket.send(r.encode(CS))

    client_socket.close()


def main():
    do_server() 


if __name__ == '__main__':
    main()

実行例

クライアント側操作
①ncコマンドでサーバに接続
②"abc"を入力してEnter
③何も入力せずEnter
④CTRL+C

サーバ側出力

$ python ./tcp_srv.py 10001
Connected from: 127.0.0.1:59653
Dosconnected from: 127.0.0.1:59653

クライアント側出力

$ nc 127.0.0.1 10001
abc
You send following data: x61x62x63x0a

You send following data: x0a
^C
$ 

ファイルを指定した行数で分割するコマンド

splitってコマンドがある

動きはこんな感じ

$ seq 100 > ./all.txt && split -l 30 -d ./all.txt bunkatsu_
$ wc -l  ./bunkatsu*
 30 ./bunkatsu_00
 30 ./bunkatsu_01
 30 ./bunkatsu_02
 10 ./bunkatsu_03
100 合計
$ 


・第一引数は入力ファイル
・第二引数は出力ファイルのファイル名のsuffix
・-lで分割する行数を指定
・-dで生成ファイルのシーケンスを数字にする。(-dなしの場合、a-z)

muttでメール送信

使い方

echo "MESSAGE" | mutt [OPTION] 宛先アドレス
mailコマンドと似た感じで使える

参考

man mutt(1)
man muttrc(5)


件名設定

$ echo test | mutt -s 'test' root@example.com


MTA指定

$ echo test | mutt -e 'set smtp_url="smtp://127.0.0.1:25"' root@example.com


送信元(Envelope from)指定

$ echo test | mutt -e 'set smtp_url="smtp://127.0.0.1:25"' -e 'set envelope_from_address="hoge@example.com"' root@example.com


添付ファイル送信

$ echo test | mutt -a /etc/hosts /bin/cp -- root@example.com

複数ファイル指定可能、MIMEエンコーディングされる。
テキストデータはcontent-typeがtext/plain、バイナリファイルはapplication/octet-stream
添付ファイルと宛先アドレスの間に、--を入れる必要あり


任意ヘッダ設定

$ echo test | mutt -e 'my_hdr x-hoge1: hoge1' -e 'my_hdr x-hoge2: hoge2'  root@example.com


指定ファイルのデータを本文に利用

$ mutt -s   "test" both@example.com < /etc/hosts

Pythonのネットワークプラグラミング

netcatもどき(作成中)

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

import sys
import socket
import getopt
import threading
import subprocess
import argparse
import re
import time

CS          = 'utf-8'

# Client Mode Option
HOST        = None
PORT        = 0
SRC_PORT    = 0

# Server Mode Option
LISTEN      = False
LISTEN_PORT = 0
WRITE_FILE  = None
EXEC_FILE   = None
COMMAND     = None


def do_server():
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('0.0.0.0', LISTEN_PORT))
    server.listen(5)
    while True:
        client_socket, addr = server.accept()
        client_thread = threading.Thread(target=client_handler, args=(client_socket,))
        client_thread.start()


def client_handler(client_socket):
    if WRITE_FILE:
        file_buffer = b''

        while True:
            data = client_socket.recv(1024)
            # terminates session if OS X Client send Ctrl + D
            if data == b'\x04':
                break
            else:
                file_buffer += data

        try:
            # must open file with wb mode. Because data is Byte data.
            fd = open(WRITE_FILE, 'wb')
            fd.write(file_buffer)
            fd.close()
            m = 'Success: saved data to ' + WRITE_FILE + '\r\n'
        except:
            m = 'Failed: failed to save data to ' + WRITE_FILE + '\r\n'

        # Unicode(Str) -> Byte Data(UTF-8)
        client_socket.send(m.encode(CS))
        client_socket.close()
        



#    if EXECUTE:
#        output = run_command(EXECUTE)
#        client_socket.send(output)
#
#    if SHELL:
#        prompt = '(SHELL): '
#        client_socket.send(prompt)
#
#        while True:
#           cmd_buffer = None
#           while '\n' not in cmd_buffer:
#              cmd_budder += client_socket.recv(1024)


def do_client():
    print('making')
 

def get_opt():
    def valid_target(s):
        if not re.search('^\S+:[1-65536]$', s):
           raise argparse.ArgumentTypeError('Invalid value. Value must be HOST:PORT')
        return s

    parser = argparse.ArgumentParser(description='This is tool similar to netcat by python. -l or -t option is required')

    cl_mode = parser.add_argument_group('Run on Client Mode')
    cl_mode.add_argument('-t', dest='target',      help='host:port(REQUIRED)',   type=valid_target)
    cl_mode.add_argument('-p', dest='source_port', help='source port',           type=int)

    sv_mode = parser.add_argument_group('Run on Server Mode. -w, -e, -c options is exclusive')
    sv_mode.add_argument('-l', dest='listen_port', help='listen port(REQUIRED)', type=int)
    sv_mode.add_argument('-w', dest='write_file',  help='write data to file')
    cl_mode.add_argument('-e', dest='exec_file',   help='execute file')
    cl_mode.add_argument('-c', dest='command',     help='execute command')

    args = parser.parse_args()

    if args.target:
        #---------------------------------------------------------
        # Client Mode Option Set
        #---------------------------------------------------------
        if args.listen_port or args.write_file or args.exec_file or args.command:
            parser.print_help()
        global HOST
        global PORT
        global SRC_PORT
    
        HOST     = args.target.split(':')[0]
        PORT     = int(args.target.split(':')[1])
        SRC_PORT = args.source_port
    else:
        #---------------------------------------------------------
        # Server Mode Option Set
        #---------------------------------------------------------
        if args.source_port:
            parser.print_help()
        if not args.listen_port:
            parser.print_help()

        global LISTEN
        global LISTEN_PORT
        global WRITE_FILE
        global COMMAND
        global EXEC_FILE

        LISTEN = True
        LISTEN_PORT = args.listen_port
        WRITE_FILE  = args.write_file
        EXEC_FILE   = args.exec_file
        COMMAND     = args.command


def main():
    get_opt()
    if LISTEN:
        print('Server Mode Start')
        do_server() 
    else:
        print('Client Mode Start')
        do_client() 


if __name__ == '__main__':
    main()

Pythonのジェネレータ関数

ジェネレータ関数とは?

 

  • ジェネレータオブジェクトを生成する関数
  • ジェネレータオブジェクトはイテレータ処理(データを順番に処理)をする機能を持つ
  • オブジェクト生成時にデータを全て読み込まない。__next__メソッド実行時に、1つづつ読み込む。大きなデータ、ネットワーク通信処理時に省メモリの効果あり。
  • yield式を含む。yield実行時に、呼び出し元にデータと制御を戻す

 

動作確認

 

  • データ生成
$ seq 10000 | xargs -I {} echo "line {}" > ./data
$ head -3 ./data 
line 1
line 2
line 3
$ tail -3 ./data 
line 9998
line 9999
line 10000
  • サンプルコード
def gen():
  for l in open('./data'):
    l = l.strip()
    yield l

a = gen()

for i in range(3):
  print(a.__next__())
  • 実行結果
line 1
line 2
line 3
  • 考察

__next__メソッドを呼び出す度にforループが1回回る。
__next__メソッド呼び出される迄は、処理待ち状態。
  
 

sendメソッド

 
処理待ち状態のジェネレータオブジェクトにデータを渡す。
 

  • サンプルコード
def gen():
  for l in open('./data'):
    l = l.strip()
    v = yield l
    if v is None:
      print('moge')
    else:
      yield l + ' ' + v

a = gen()

print('1 回目nextメソッド実行 ========================')
print(a.__next__())
print()

print('2 回目nextメソッド実行 ========================')
print(a.__next__())
print()

print('sendメソッド実行 ========================')
print(a.send('huga'))
print()

print('3 回目nextメソッド実行 ========================')
print(a.__next__())
  • 実行結果
1 回目nextメソッド実行 ========================
line 1

2 回目nextメソッド実行 ========================
moge
line 2

sendメソッド実行 ========================
line 2 huga

3 回目nextメソッド実行 ========================
line 3
  • 考察

v = yield lのように、yield結果をオブジェクトに入れる記述が必要。
nextメソッド実行時は、vにNoneが入る。yield実行時にデータと制御を呼び出し元に戻し処理は停止。
・1回目nextメソッド実行時に、moge出力なし
・2回目nextメソッド実行時に、初めてif v is None:が動作。この時のvはNone(1回目nextメソッド実行結果)
sendメソッド実行時は、vに引数に指定したオブジェクトが入り処理が再開。
 

  • 参考

Pythonのイテレータ、ジェネレータまわりの言語仕様について復習してみる - Qiita
 
 

throwメソッド

 
処理待ち状態のジェネレータオブジェクトに例外を渡す。

  • サンプルコード
def gen():
  for l in open('./data'):
    l = l.strip()
    v = yield l
    if v is None:
      print('moge')
    else:
      yield l + ' ' + v

a = (gen())

print('1 回目nextメソッド実行 ========================')
print(a.__next__())
print()

print('2 回目nextメソッド実行 ========================')
print(a.__next__())
print()

print('throwメソッド実行 ========================')
print(a.throw(ValueError('error occur')))
print()

print('3 回目nextメソッド実行 ========================')
print(a.__next__())
  • 実行結果
1 回目nextメソッド実行 ========================
line 1

2 回目nextメソッド実行 ========================
moge
line 2

throwメソッド実行 ========================
Traceback (most recent call last):
  File "./a.py", line 21, in <module>
    print(a.throw(ValueError('error occur')))
  File "./a.py", line 4, in gen
    v = yield l
ValueError: error occur

 
 

closeメソッド

 
処理待ち状態のジェネレータオブジェクトにGeneratorExit例外を渡し、ジェネレータ処理を正常終了させる。

  • サンプルコード
def gen():
  for l in open('./data'):
    l = l.strip()
    v = yield l
    if v is None:
      print('moge')
    else:
      yield l + ' aaa ' + v

a = (gen())

print('1 回目nextメソッド実行 ========================')
print(a.__next__())
print()

print('2 回目nextメソッド実行 ========================')
print(a.__next__())
print()

print('closeメソッド実行 ========================')
print(a.close())
print()

print('3 回目nextメソッド実行 ========================')
print(a.__next__())
  • 実行結果
1 回目nextメソッド実行 ========================
line 1

2 回目nextメソッド実行 ========================
moge
line 2

closeメソッド実行 ========================
None

3 回目nextメソッド実行 ========================
Traceback (most recent call last):
  File "./a.py", line 25, in <module>
    print(a.__next__())
StopIteration
  • 考察

closeメソッド実行時に、forループは停止。
closeメソッド実行後のジェネレータオブジェクトにnextメソッド実行するとStopIteration例外が発生