Python 3 の覚え書き

初版作成  2016.2.5
最終更新  2022.08.25


◆◆ 役に立つサイト ◆◆


Python 入門
Python 基礎文法最速マスター
Python 学習サイト
Python-izm

◆◆ ファイル先頭 ◆◆


#!/usr/bin/python
# -*- coding: utf-8 -*-

python2 は 2 行目が必須
python3 は utf-8 の場合 2 行目は不要

漢字コードは utf-8 以外に

euc-jp, shift_jis がある。

FreeBSD, Linux の python で、改行記号が 0d 0a の
ファイルを実行しようとすると、

   filename.py: Command not found.

というエラーが出る。

Linux で開発したものを Windows に ftp で持ってくると
改行記号が 0d 0a になる。それを Linux で使おうとすると
上記のエラーがが発生する。


◆◆ コメント ◆◆


#  より右側  行の途中も可   C++ の // に相当

""" と """ で囲んだ範囲   C++ の /*  */ に相当


◆◆ インデント ◆◆


python はインデントで if, for などの範囲を表す。
インデントの手前の文は右端に : が付く

<python2>

tab はスペース 8 個と等価と見なされる。
エディタで tab 幅を 4 に設定している場合、
スペース 4 個と tab 1 個は、見かけは同じインデントレベルだが
python にとっては異なるインデントレベルとして認識される。

エディタの tab 幅を 4 に設定する場合、
インデントは全て tab にするか、全てスペースにするか、
統一する必要がある。

<python3>

tab とスペースの混在は禁止
スペースの使用が推奨されている
スペースは 4 個が適切


◆◆ 変数 ◆◆


宣言不要

文字と数値は区別される。"  " あるいは '  ' で囲むと文字列。

(注意!)
a = 1
b = "1"
のとき、a == b は成立しない。perl とは異なる。

print で + で文字と数値を連結しようとすると
エラーとなる。型変換の関数 str(  ) が必要。

変数の型

print(type(a))


◆◆ グローバル変数 ◆◆


・メインプログラムの中で使用した変数はグローバル変数

・いくつかの def の中でだけ使用し、
 メインプログラムの中で使用しないグローバル変数を使う場合

  global var1, var2

  のように、def の中で global 宣言が必要

スレッドの中で使う変数は全てローカル変数と見なされる。
グローバル変数を使う場合は、必ず global 宣言が必要。

◆◆ 変数のスコープ ◆◆


メインプログラム中で使用した変数はグローバル
変数である。def の中からでも使える。

def func1():
    print(const)

const = 3
func1()

def func1(): の中の const はグローバル変数
とみなされ、実行すると 3 と表示される。
しかし、以下のプログラムではエラーがでる

def func1():
    print(const)
    const = 4

const = 3
func1()

その理由は func1() の中で const はローカル変数
とみなされ、print(const) の時点では値が定まって
ないので、エラーとなる。

以下のようにすればエラーが出なくなり、
func1() の中で const の値を書き換える
ことができる。

def func1():
    global const
    print(const)
    const = 4

const = 3
func1()
print(const)

◆◆ 代入 ◆◆


以下の代入文が可能
a, b = c, d        # a = c, b = d と等価     2 つ以上の変数に一気に代入可能
a, b = b, a        # テンポラリ変数なしで、値の入れ替えが可能

2 個以上の変数への代入は
以下のようなパターンで使われる。

for i, element in enumerate(list):

i は 0, 1, 2, 3 ....
element は list[0], list[1], list[2] ... が入る。


◆◆ 文字列 ◆◆


連結  str = str1 + str2
分解  list = line.split(',')    list は配列
結合  line = ' '.join(list)
長さ  len(str)
部分文字列  substr = str[1:3]   2,3 文字目

leng = len(str)
last_cha = str[leng-1:leng]    最後の 1 文字
prev_str = str[0:leng-1]       その手前の文字列

line = line.strip()     行頭と行末の空白 (改行記号を含む) を除去する
line = line.lstrip()    行頭の空白を除去する
line = line.rstrip()    行末の空白 (改行記号を含む) を除去する

"  を出力したいときは \"
\\ を出力したいときは \\

◆◆ 文字列の分解 ◆◆


空白(2 個以上の空白が連続する場合を含む)で区切られた文字列 line を
分解するときは

list = line.split()

と書く。split の引数を省略すると
区切り文字(スペース, タブ)と解釈する。

list = line.split(' ')

ではダメ。空白が n 個連続している場合、
n-1 個の長さなしの文字列が発生する。
split の省略形を使わずに書くなら、以下のようになる。

line = line.rstrip()            line.strip() も可
list = re.split('\s+',line)     '\s*' でも可
for a in list:
    print(a)


◆◆ 文字列と数値の変換 ◆◆


moji = str(a)
a = int(moji)
b = float(moji)

◆◆ ascii コードと文字の変換 ◆◆


ord("a")    cha ---> ascii
chr(13)     ascii ---> cha

◆◆ 指数表現 ◆◆


1e-6    10^(-6)
1e3     10^3

◆◆ 演算 ◆◆


a % b    a ÷ b の余り
a ** b    a^b
5 / 2    2  整数同士の演算結果は切り捨て
5 / 2.0   2.5
5 // 2.0   2  小数点以下切り捨て


◆◆ 表示 ◆◆


i = 10
s = "10"

print("hello world")     " と ' の違いはない   改行される
print('hello world')

print("abc", end = "")   改行なし
print("abc","def")       , で区切ると半角スペースが 1 個入る  abc def となる

print("abc",i,"def")            abc 10 def と出力される
print("abc" + s + "def")        abc10def と出力される

print("abc" + str(i) + "def")   str( ) を怠るとエラーになる

" を出力するときは \"
ただし、'abc"def'  のように '   ' で囲めばエスケープ不要

ヒアドキュメント(""" で囲む)

print("""line1
line2
line3""")

標準エラー出力

sys.stderr.write("error")

あるいは

print("error", file = sys.stderr)

◆◆ format 付き表示 ◆◆


a = 1234.56789
s = "abcd"

python 2
line = "<%05d> <%5d> <%8.2f> <%s>" % (a, a, a, s)                   python 2
print line

<01234> < 1234> < 1234.57> <1234.57> <abcd>

python 3
line = "<{:05}> <{:5}> <{:8.2f}> <{:.2f}> <{}>".format(int(a),int(a),a,a,s)
print(line)       <01234> < 1234> < 1234.57> <1234.57> <abcd>

<01234> < 1234> < 1234.57> <1234.57> <abcd>

◆◆ フォーマット済み文字リテラル ◆◆


f'abc'

a = 123
b = 'abc'
print('{} and {}',format(a,b)) と以下は同じ
print(f'{a} and {b}')


◆◆ if ◆◆


if a == b:
    print("a = b")
elif a == c:
    print("a = c")
else:
    print("else")

if a == b:
    pass         # 何もしないときは pass が必要。怠るとエラー
else:
    何らかの処理

条件を複数記述するときは  and   or

比較演算子は C と同一

==   !=   <   >   <=  >=



◆◆ while ◆◆


num = 0
while num < 2:
    print("num = " + str(num))
    num = num + 1

while 1:       無限ループ
while True:    無限ループ

    break      ループ脱出
    continue   ループ先頭へ

◆◆ for ◆◆


list = [1, 3, 2]

for num in list:
    print("num = " + str(num))

for i in range(0,4):      0,1,2,3

for i in range(5,2,-1):   5,4,3

◆◆ for #2 ◆◆


list = ['a', 'b', 'c']
for char in list:
    print(char)

'a'
'b'
'c'

for i, char in enumerate(list):
    print(i, char)

0 'a'
1 'b'
2 'c'


◆◆ 配列(リスト) ◆◆


list = [ 1, 30, 50, "abc"]     数値, 文字列  混在可
list[0]     1 つめの要素
len(list)   要素数

sub_list = list[2:3]     list[2] を取り出す
sub_list = list[3:]      list[3] とそれ以降
sub_list = list[:2]      list[1] とそれまで

For との組み合わせ(2 通りの方法)

for item in list:
    print(item)

for i in range(0, len(list)):
    print(list[i])

連結・追加

list1 = [1, 2, 3]
list2 = [4, 5, 6]

list1.extend(list2)     list1 = [1, 2, 3, 4, 5, 6]
list1.append(list2)     list1 = [1, 2, 3, [4, 5, 6]]

list3 = list1 + list2   list3 = [1, 2, 3, 4, 5, 6]

str = "abc"
str2 = "123"

list = []         <---- 空のリスト
list.append(str)
print(list)             ['abc']
list.append(str2)
print(list)             ['abc', '123']
list.extend([str2])
print(list)             ['abc', '123', '123']

削除

a = list.pop(2)

list[2] (3 番目の要素) を削除し、
削除した値を a に代入する

◆◆ 配列(連想配列) ◆◆


hash_list  = {"a": 10, "b": 20, "c": 30}
hash_list2 = dict(aa = 100, bb = 200, cc = 300)  # 別の書き方

hash_list["d"] = 40    # 追加
del(hash_list["a"])    # 削除

list = hash_list.keys()
list2 = sorted(hash_list.keys())

print(list)
print(list2)

for name in hash_list.keys():
    print(name, hash_list[name])

for name in sorted(hash_list2.keys()):
    print(name, hash_list2[name])

◆◆ 継続行 ◆◆


2 つも方法がある
(1)  \    バックスラッシュ
(2) ( ) で囲んだ部分の中では改行してもよい


◆◆ ファイル読み込み ◆◆


ノーマルなやり方

f = open("a.txt", "r", encoding = "utf-8")   encoding は省略可  "shift-jis"
f.close()


with を使うと close を省略可能

with open("a.txt", "r", encoding = "utf-8") as f:
    コード   (インデント必要)

エラー処理付き

try:
    f = open("filename", "r")
except:
    print("cannot find file.")
    sys.exit(1)

1 行ずつ読み込みの命令は 2 つの系統がある。

1. for, next を使う
2. readline を使う

一度どちらかを使うと、その後は同系統の命令を
使わないとエラーになる。

1. for, next 系

for line in f:                  # line の末尾には \n (0a) が入っている
    line = line.rstrip("\n")  # 行末の改行記号を除去
                              #    空白も除去するときは line.rstrip()
    print(line)

next の使い方

next(f)

next を使って読み込むとき、ファイルエンドでエラーが発生
するので、次の try  except の構文が必要

try:
    while True:
        line = next(f)
        line = line.rstrip("\n")
        print(line)
except:
    pass

2. readline 系

while True:
    line = f.readline()     # 1 行読み込む
    if not line:            # if line == "":  でも同じ
        break
    line = line.rstrip("\n")
    print(line)

3. readlines   ファイル全体を読み込む

lines = f.readlines()     # ファイル全てを読み込む
for i in range(len(lines)):
    lines[i] = lines[i].rstrip("\n")
    print("|" + lines[i] + "|")

  ------------

f.seek(0)  ファイルの先頭へ
           seek を実行した後は for,next  or  readline のいずれも可

  ------------

◆◆ ファイル読み込みの注意 ◆◆


python ではファイルから読み込んだものは全て
「文字列」であり、「数値」ではない。
ファイルから変数 a に 12 を読み込んだとする。

if a == 12:

は成立しない。

if a == "12":
if int(a) == 12:
if float(a) == 12:

のいずれかなら、成立する。

例:
1 行読み込み、その行には 2 個の数値が
入っており、それぞれ a, b 代入する。

line = line.strip()
list = line.split()
a = float(list[0])
b = float(list[1])


◆◆ ファイル書き出し ◆◆


f = open("out.txt", "w", newline = "\n")   "w" : 上書き     "a" : 追記
    newline は省略可
    省略時:Linux は "\n", windows は "\r\n"

print の引数は文字列、数値両方

print("abcde", file = f)            # 改行あり
print("abcde", file = f, end = "")  # 改行なし

write の引数は文字列

f.write(line)          # 改行しない
f.write(line + "\n")   # 改行する

f.write("\n".join(lines))  # リストの各要素の末尾に "\n" を挿入して連結

writelines の引数はリスト

f.writelines(lines)    # 改行は挿入されず、連結される


f.close()


◆◆ 終了 ◆◆


sys.exit()      終了コードは 0
sys.exit(1)     終了コードは 1

sys.exit(-1)    終了コードは 255

◆◆ 関数 ◆◆


呼び出し方は C と同じ
関数中で引数の値を変更しても、呼び出し元の変数は不変
複数の値を返したいときは ret = [1, 2, 3]    return ret  のように
リストを使えばよい。

関数例:ヘッダ検索システム

def fhead_f(f, head):

    f.seek(0)

    find = 0

    for line in f:
        line = line.rstrip()    # 行末の改行除去
        line = line.strip()     # 前後の空白除去
        if line == head:
            find = 1
            break

    return find

◆◆ 関数の引数 ◆◆


・デフォルト値の設定
・キーワードを指定することにより順序の入れ替え

def sub(a, b = 3, c = [1, 2, 3]):
    print(a, b, c)

sub(1)              a = 1, b, c はデフォルト値
sub(1, 2)           a = 1, b = 2, c はデフォルト値
sub(1, b=2)         a = 1, b = 2, c はデフォルト値
sub(1, c = [2, 3])  a = 1, c = [2, 3], b はデフォルト値


◆◆ メイン関数 ◆◆


関数はメイン関数よりも上に配置する。
メイン関数は最後に来ることになる。

メイン関数を先頭に持ってきたい場合は、以下のように書く。

def main():
    print("main")
    func()

def func():
    print("func")

if __name__ == "__main__":
    main()

if __name__ == "__name__":
はそのファイルが直接実行されたときのみ「真」となる。
import されたときは「偽」となる。


◆◆ cgi GET 専用 ◆◆


引数は環境変数 QUERY_STRING に入る
コマンドラインから試しに実行するとき
http://.......?key=value  なら
$ export QUERY_STRING=key=value
をあらかじめ実行しておけば良い。

import sys, io
import os
import cgi
import subprocess     ver.2 は commands

# CGI から実行するとき以下が必要
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding = 'utf-8')

err1 = 0
err2 = 0

key = 'QUERY_STRING'
if key in os.environ:
    query = cgi.parse_qs(os.environ[key])
else:
    err1 = 1

key = 'radio1'
if key in query:
    value = cgi.escape(query[key][0])
else:
    err2 = 1

print("""\   <---- これを忘れると空行が 1 つ入り、http のヘッダがないのでエラー発生
Content-type: text/html

<html>
<head>
<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">
<title>タイトル</title>
<style>
body,p { font-size: x-large; margin: 20px; }
</style>
</head>
<body>""")

◆◆ cgi GET POST 両用 ◆◆


import cgi

method = os.environ.get('REQUEST_METHOD')

form = cgi.FieldStorage()
for key in form.keys():
    print "<p>{} = {}</p>".format(key, form[key].value)

◆◆ cgi から外部プログラムを実行する ◆◆


import subprocess

ret = subprocess.getoutput(cmd)
#ret = os.system(cmd)      # Bad header: <p>m というエラーが発生する

print(ret)

ret にコマンドが標準出力に出した文字列が格納される。
os.system(cmd) では apache2 の Bad header というエラーが発生する。


◆◆ 外部コマンドの実行 ◆◆


os.chdir('dir_name')
ret = os.system(cmd)
if ret != 0:
   print("Hit any key")
   inkey = input()
   sys.exit(1)
os.chdir('..')

◆◆ cgi で GPIO やシリアルポートにアクセスする ◆◆


cgi から GPIO, serial をアクセスするプログラムを呼び出す
ときは root 権限が必要。

apache2 の cgi は www-data の権限で動作する。

cmd = "sudo prog.py arg"
ret = subprocess.getoutput(cmd)

とするとき、www-data の権限でパスワードなしで sudo できる
必要がある。

  $ sudo visudo

で以下の行を付加する。

www-data ALL=(ALL) NOPASSWD: ALL


◆◆ 文字列のマッチング・置換 ◆◆


<正規表現あり>

import re

正規表現
 リテラル   r'正規表現'     r (raw) をつけると、エスケープシーケンス (\) を
                             無視する。
                             例えば \t はタブではなく \ と t の 2 文字
 変数化     str = re.compile(r'正規表現')

部分一致(perl のマッチングと同等。正規表現, グループの使い方も同じ)

m = re.search(str, line)
if m:                    あるいは if m != None:
    moji  = m.group(1)
    moji2 = m.group(2)

マッチしたとき:m はオブジェクト
マッチしないとき:m は None

最短・最長マッチ

(.\S*) (.\S+)  などは最長マッチする。
最短マッチしたい場合は (.\S*?) (.\S+?) のように末尾に ? をつける

例:
r'.*?・(.*).pdf'  ……「・」が 2 箇所にある場合、最初の「・」にマッチする。

(参考)
http://www.geocities.jp/m_hiroi/light/python04.html
http://www.yukun.info/blog/2008/08/python-regexp-greedy-reluctant-match.html

先頭からマッチング(re.serach の検索文字列の先頭に ^ を
つけるのと同等と思われる)

例
    m = re.match('Time/div\(second\),(\S*)', line)
    m = re.match('Points,(\S*)', line)
    m = re.match('(\S+),(\S*),(\S*),(\S*)$', line)

<正規表現なし>

・文字が含まれているか否かを判定

line = "abc123"
if 'c' in line:
    見つかったときの処理

・何文字目か?

line = "abc123"
a = line.find('123')       a = 4
a = line.find('x')         a = -1
a = line.find('a')         a = 0

見つからないとき -1
見つかったとき n 文字目からなら n-1 を返す。

・置換

line = line.replace('pre','after')

◆◆ 正規表現 ◆◆


.   任意の1文字
x?  0 個あるいは 1 個の x
x*  0 個以上の x
x+  1 個以上の x
^   行の先頭
$   行末
\s  空白文字 ( スペース、タブ、改行 )
\S  空白以外の文字
\*  * そのもの

[0-9\-]   0 〜 9 の文字あるいは '-' 記号の固まり
[^\"]+\"  " 以外の文字の 1 つ以上の連続の後、" 文字


◆◆ 標準エラー出力 ◆◆


import sys

sys.stderr.write("usage: % makehtml.py fname")

◆◆ コマンドライン引数 ◆◆


import sys

argc = len(sys.argv)    引数の個数 (コマンド名含む)
sys.argv[0]             コマンド名
sys.argv[1]             第 1 引数


◆◆ ディレクトリ、ファイル名の取得 ◆◆


script_fname      = os.path.basename(__file__)   # ファイル名
script_path_fname = os.path.abspath(__file__)    # フルパスのファイル名
script_path       = os.path.abspath(os.path.dirname(__file__))
                          # ファイル名を除いたパス名の部分

自力でやるなら以下のように書く

m = re.match('.*/(.*)$', __file__)  # __file__ の代わりに sys.argv[0] も可
if m != None:
    script_fname = m.group(1)
else:
    print("error")
    sys.exit(1)


◆◆ ファイルの日付 ◆◆


stat = os.stat(fname)
time = stat.st_mtime
dt = datetime.datetime.fromtimestamp(time)
line = dt.strftime("%Y.%m.%d")

◆◆ 現在の日付と時刻の取得 ◆◆


import datetime

d = datetime.datetime.now()
year = d.year
month = d.month
day = d.day
hour = d.hour
minute = d.minute
second = d.second

out_line = "%04d/%02d/%02d %02d:%02d:%02d" % \
           (year,month,day,hour,minute,second)
out_line = out_line + " " + ondo_line


◆◆ ファイル・フォルダの作成・削除 ◆◆


import os, shutil

os は低水準ファイル処理用のモジュール
shutil は高水準ファイル処理用のモジュール

cwd = os.getcwd()       cwd の取得
list = os.listdir(cwd)  ファイルとフォルダのリストの取得

os.path.exists(name)        True/False  ファイル・ディレクトリどちらも可
os.path.isfile(fname)       ファイルの存在
os.path.isdir(dir_name)     ディレクトリの存在
os.path.getsize(file_name)  サイズ

os.rename(fname, fname2)  リネーム  shutil.move と同じ
                          同一ファイルシステムのみ使用可
os.remove(fname)          ファイル削除
os.mkdir(path)            ディレクトリ作成

フォルダだけ取り出す
dir_list = []
list = os.listdir(cwd)
for dir in list:
    if os.path.isdir(dir) == True:
        dir_list.append(dir)

shutil.move(fname, fname2)           move コマンドと同じ
shutil.copy(src_fname, dst_fname)    cp コマンドと同じ
shutil.copy2(src_fname, dst_fname)   更新日時などもコピー
shutil.rmtree(dir)                   ディレクトリ以下全て消去

◆◆ キー入力 ◆◆


line = input("input line  ")
print(line)

◆◆ ソケット通信(クライアント) ◆◆


import socket

host = "denki.nara-edu.ac.jp"
port = 80
size = 4000

addr = (host, port)

out_line1 = "GET /~yabu/index.html HTTP/1.0\r\n"
out_line2 = "\r\n"

so = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
so.connect(addr)
so.send(out_line1)
so.send(out_line2)
recv_data = so.recv(size)
so.close()

lines = recv_data.split("\n")

for line in lines:
    line = line.rstrip()
    print("<" + line + ">")

html の場合、送信元のファイルの改行記号が
0d 0a (Windows) の場合と 0a (Linux) の場合の
2 通りがある。

0d 0a の場合 rstrip() で行末の 0d を除去することが
必要。それを怠ると、上記のプログラムの場合、
行末文字の ">" を行頭の "<" に重ね書きする。

recv_data.split("\r\n")

はダメ。全く分離しない。


◆◆ ソケット通信(サーバー) ◆◆


import socket

port = 10003
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", port))
s.listen(5)

while True:
    sock, addr = s.accept()
    print("Conneted by" + str(addr))
    data = sock.recv(1024)
    print("recv:",data)
    sock.close()

(参照)  http://docs.python.jp/3/howto/sockets.html

◆◆ hostname と ip address ◆◆


import socket
addr = "202.236.176.170"
host_tuple = socket.gethostname(addr)

hostname  = host_tuple[0]
hostcname = host_tuple[1]
addr2     = host_tuple[2]

◆◆ 暗号化 smtp 接続 ◆◆


import smtplib

smtp_server = "smtp.gmail.com"
port_no = 587
id = "xxyyzz@gmail.com"
passwd = "password"

from_addr = "xxyyzz@gmail.com"
to_addr = "to_addr@nifty.com"

charset = "ISO-2022-JP"
subject = "test mail"
text = "send message"

msg = MIMEText(text.encode(charset),"plain",charset)

msg["Subject"] = Header(subject,charset)
msg["From"] = from_addr
msg["To"] = to_addr
msg["Date"] = formatdate(localtime=True)

s = smtplib.SMTP(smtp_server, port_no)
s.ehlo()
s.starttls()          # <-------- これを入れると拒否されるサーバーもある
s.login(id, passwd)
s.sendmail(from_addr, to_addr, msg.as_string())
s.close()

◆◆ ディレイ delay ◆◆


import time

time.sleep(3)    # 3 秒

◆◆ 環境変数の取得 ◆◆


import os

path = os.environ.get('PATH')

for env in os.environ:
    value = os.environ[env]
    print("env = " + env + "   value = " + value)


◆◆ zip ファイルの作成 ◆◆


import os, zipfile

flist = []
flist.append("filea.txt")
flist.append("fileb.exe")
flist.append("filec.docx")

あるいは

flist = ["filea.txt", "fileb.exe", "filec.docx"]

      -----------

os.chdir(dir)  ' 必要な場合は入れる

myzip = zipfile.ZipFile("aaa.zip", 'w', zipfile.ZIP_DEFLATED)
for f in flist:
    myzip.write(f)
myzip.close

os.chdir('..')  ' 必要な場合は入れる

◆◆ プロセス id ◆◆


pid = os.getpid()       # 数値型    文字にするには str(os.getpid())


◆◆ ファイルのロック ◆◆


f = open('rec.txt','a')
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
print (time_str + "," + value, file = f)
#time.sleep(5)
fcntl.flock(f.fileno(), fcntl.LOCK_UN)
f.close()


fcntl.LOCK_EX  でロック
fcntl.LOCK_UN  で開放

ロックしようとしたときに、他のプロセスが既に
ロックしているときは、自分の順番がまわってくるまで
スリープする。

(参照)
https://www.phactory.jp/blog/python_lock/


◆◆ 乱数 ◆◆


import random

random.seed()             現在の時刻が使用される

i = random.randint(2, 4)  2〜4 の整数
f = random.random()       0 以上 1 未満の実数



◆◆ Windows 版 python IDLE のインストール ◆◆


インストールはここから

https://www.python.org/downloads/

ブラウザの情報を利用しているのか、今使っている OS 用の
python をダウンロードする。

exe ファイルをダブルクリックして python をインストールすると
IDE である IDLE もインストールされる。

起動すると shell window が開く。

エディタの設定は Options --- Configure IDLE
背景を黒にする。

shell window と editor window の 2 つがある。

shell window を開くには Run --- python shell
ダイレクトコマンド入力用

editor windows を開くには File --- New File/Open
実行するには Run --- Run Module


◆◆ on を検知するアルゴリズム ◆◆


python に限った話ではないが、
「ボタンを押した」「ラインを通過した」などを
検知するとき、2 つの考え方がある。

(1) 今の値と一つ過去の値を使う方法

now = input()
while True:
    old = now    # 1 つ過去の値を記憶
    now = input()
    if now == ON and old == OFF:
        manage()

(2) 状態変数を使う
    今 off 状態か on 状態かを保持する変数 mode を使う

(2a) モードによって処理を変える

mode = OFF
while True:
    in = input()
    if mode == OFF:
        if in == ON:
            mode = ON
            manage()
    else:
        if in == OFF:
            mode = OFF

(2b) if の順序を逆にした
   コードは少し簡潔になる

mode = OFF
while True:
    in = input()
    if in == on:
        if mode = OFF:
            mode = ON
            manage()
    else:
        mode = OFF

(2b) の方が若干簡潔になるのは、下図のように
in=off のとき mode を気にする必要がないため。

mode \ in|   off     |   on
---------+-----------+----------
off      | mode=off  | mode=on
         |           | manage()
---------+-----------+----------
on       | mode=off


◆◆ ライブラリのインストール ◆◆


pip3 というコマンドでインストールする
pip でインストールすると python2.7 用のライブラリが入る。

# apt install python3-pip      pip3 をインストール

$ pip3 install matplotlib      インストール
$ pip3 freeze                  インストールしたライブラリの確認
$ pip3 list                    インストールしたライブラリの確認
$ pip3 uninstall matplotlib    アンインストール

pip のアップグレード

$ python3 -m pip install --upgrade pip

Windows 版 IDLE で使う python のモジュールインストール

$ py -m pip install module-name



◆◆ matplotlib のインストールと使い方 ◆◆


$ sudo -s

# apt update
# apt install python3-pip
# apt install python3-tk

$ pip3 install matplotlib
$ pip3 install numpy

サンプルプログラム(ファイルからデータを読み込んでグラフを書く)

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# 参照元 https://qiita.com/MENDY/items/fe9b0c50383d8b2fd919
#

import matplotlib.pyplot as plt
import re

x = []
y = []

f = open("data.txt", "r")

for line in f:
    if re.search("^#", line): # コメント行
        continue
    line = line.strip()  # スペースの除去
    if line == "":       # 空行をスキップ
        continue
    list = line.split()  # 文字列分解
    x.append(float(list[0]))  # list[] は文字列なので
    y.append(float(list[1]))  # 数値にコンバート必要

f.close()

print(x)
print(y)

xtics = [0, 5, 10]
ytics = range(0, 11, 2)

fsize = 15

plt.rcParams["axes.linewidth"] = 2
plt.rcParams["xtick.direction"] = "in"
plt.rcParams["ytick.direction"] = "in"

plt.title("Title of figure", fontsize = fsize)
plt.plot(x,y,marker="o",linewidth=1, color="#0000ff")
plt.xlabel("X-Axis", fontsize = fsize)
plt.ylabel("Y-Axis", fontsize = fsize)
plt.xlim([0, 10])
plt.ylim([0, 10])
plt.xticks(xtics, fontsize = fsize)
plt.yticks(ytics, fontsize = fsize)
plt.grid()
plt.legend()

plt.savefig("fig.eps")
plt.savefig("fig.svg", bbox_inches = "tight", pad_inches = 0.05)
plt.savefig("fig.png")
plt.savefig("fig.pdf", bbox_inches = "tight")

plt.show()  # show を savefig より先に実行すると、セーブされない

◆◆ ftp ◆◆


import ftplib

・テキストファイルの get

local_fname = "~/dir1/fname.txt"
remote_fname = "dir2/fname.txt"
# remote_fname の冒頭に / は不要だが、付けても良いケースと
# ダメなケースがある。
# 手動で ftp して  'cd /'  'pwd'  を実行して
# どのディレクトリにいるかを調査すれば良い

ftp = ftplib.FTP("192.168.xx.yy")
ftp.set_pasv("true")
ftp.login("user-name", "passwd")

f = open(local_fname, "w")
command = "RETR " + remote_fname
ftp.retrlines(command, f.write)
f.close()
ftp.close()

・バイナリファイルの get

f = open(local_fname, "wb")
command = "RETR " + remote_fname
ftp.retrbinary(command, f.write)
f.close()
ftp.close()

・テキストファイルの put

src_fname = "/home/user-name/dir1/fname.txt"
dist_fname = "dir2/fname.txt"

ftp = ftplib.FTP("192.168.xx.yy")
ftp.set_pasv("true")
ftp.login("user-name", "passwd")

f = open(src_fname, "rb")
command = "STOR " + dist_fname
ftp.storlines(command, f)
f.close()
ftp.close()

・バイナリファイルの put

ftp.storbinary(command, f) に変更


◆◆ ftps ◆◆


・バイナリファイルの put

from ftplib import FTP_TLS

src_fname  = "/home/pi/aaa/bbb.jpg"   // full path
dist_fname = "dir/bbb.jpg"            // from top dir

ftps = FTP_TLS("192.168.xxx.yy")
ftps.login("user-name", "passwd")
ftps.prot_p()

fp = open(src_fname, 'rb')

command = "STOR " + dist_fname

ftps.storbinary(command, fp)
ftps.close()
fp.close()

◆◆ web アクセス ◆◆


urllib を使う

import urllib.request, urllib.error

url = 'http://denki.nara-edu.ac.jp/~yabu/'

try:
    req = urllib.request.urlopen(url)
except urllib.error.URLError as e:
    if hasattr(e, 'reason'):
        print('We failed to reach a server.')
        print('Reason: ', e.reason)
    elif hasattr(e, 'code'):
        print('The server couldn\'t fulfill the request.')
        print('Error code: ', e.code)
    sys.exit(1)

page = req.read()              # page は b'....\n....\n....'
page2 = page.decode('euc-jp')  # page2 は html ファイルと同一。改行は 0x0a
                               # 変換元の漢字コードを指定。省略時は utf-8
                   # shift jis は 'shift_jis' or 'shift-jis'
lines = page2.split('\n')      # lines はリスト [b'xxxx', b'yyyy', b'zzzz', ...]

f = open("page.txt","w")
print(page, file = f, end = "")
f.close()

f = open("page2.txt","w")
print(page2, file = f, end = "")
f.close()

f = open("lines.txt","w")
print(lines, file = f, end = "")
f.close()

for line in lines:
    print(line)

for i in range(len(lines)):
    print(lines[i])


◆◆ 関数のネスト ◆◆


関数の中に関数を書くことができる。

def outer_function():
    a = 1
    print("outer 1")
    inner_function()  # call 1  NG

    def inner_function():
        print("inner")
        print("a = " + str(a))

    inner_function()  # call 2  OK
    print("outer 2")

inner_function()  # call 3  NG

・内側に書いた関数は外側の関数から呼び出せるが、
 それ以外の場所からは呼び出せない。隠蔽される。
 ゆえに call 3 は NG である。

・内側に書いた関数は、外側の関数の変数にアクセスできる
 ゆえに print("a = " + str(a)) は a = 1 となる。

・python では呼び出す関数を後ろに書くとエラーとなるので、
 call 1 も NG である。


◆◆ 関数を代入 ◆◆


def hello():
    print("hello")

func = hello   # <--- (1)
func()         # <--- (2)

(1) 変数 func に関数 hello を代入
  () はつけない。() をつけると return 値の代入となる
(2) 実行するときは () をつける


◆◆ スレッドの使い方 ◆◆


import threading

thread1 = threading.Thread(target=func1, args=(var1,), daemon=True)
thread1.start()

def func1(var1):
    global g1, g2
    スレッドの処理

・引数はタプルで渡す
 1 個のとき (var1, )  2 個のとき (var1, var2)

・スレッドではグローバル変数は global 宣言する必要がある。
 メインプログラムで使用した変数と同名の変数を使ってもローカル変数となる

・daemon=True にしておかないと、スレッドが走っている状態で
 sys.exit() すると python がハングアップする。

◆◆ Windows 版 python ライブラリのインストール ◆◆


コマンドプロンプトを起動して

py -m pip --upgrade pip
py -m pip install requests