初版作成 2016.2.5
最終更新 2024.04.05
Python 入門 Python 基礎文法最速マスター Python 学習サイト Python-izm JavaDrive
#!/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 で使おうとすると 上記のエラーがが発生する。
import するモジュールと同じ名前を付けてしまうと、 カレントディレクトリにある自分自身を import し、 使いたいモジュールを import することができない。 ゆえに json.py のようなプログラム名で import json すると メソッドがないというエラーがでる。
# より右側 行の途中も可 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))
以下のような書き方もできる a, b = 10, 20 関数の戻り値を 2 個以上返したいとき、 関数側 return(a, b) 呼び出し元 a, b = func() という書き方ができる。 以下のようにリストを使った方がよいかも知れない。 関数側 return([a, b]) 呼び出し元 [a, b] = func()
・メインプログラムの中で使用した変数はグローバル変数 python は変数宣言を必要としない。 print(a) のように変数を参照したとき、未定義の場合 エラーが発生する。 ・def の中では、以下のようにややこしい def gcheck(): print(a) a は未定義なのでグローバル変数 def gcheck(): a = 20 a はローカル変数 print(a) def gcheck(): global a global 宣言したので a はグローバル変数 a = 20 値を利用するだけなら宣言不要 値を代入するときは global 宣言が必要 次の変数のスコープの項も読んでおくこと。 混乱を避けるため、値を利用するだけであっても、 グローバル変数は全て global をつけることを 習慣とした方がよいと思われる。 ・いくつかの def の中でだけ使用し、 メインプログラムの中で使用しないグローバル変数を使う場合 def の中で global 宣言を行う。 fortran の common 宣言と似ている。 スレッドの中で使う変数は全てローカル変数と見なされる。 グローバル変数を使う場合は、必ず 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 個の長さなしの文字列が発生する。 区切り文字に正規表現を用いることができる。 re を使って以下のように書く方法がある。 しかし、以下の方法では行頭に空白がある場合、list[0] は 長さなしの文字列となってしまう。 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)
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 (結果は常に浮動小数点 python2 では 整数/整数=整数) 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""")
3 種類の方法がある。最後の方法は python 3.6 以降 a = 1234.56789 s = "abcd" ○ C ライク sprintf と同じ print("<%05d> <%5d> <%8.2f> <%s>" % (a, a, a, s)) 結果 <01234> < 1234> < 1234.57> <1234.57> <abcd> ○ python 独自 print("<{:05d}> <{:5d}> <{:8.2f}> <{:.2f}> <{}>".format(int(a),int(a),a,a,s)) {} の順番に入る。{} だけでもよい {5} は半角 5 個分のスペースを確保 : を付けるとフォーマット指定 ○ 3.6 以降に使える a = 123 b = 123.456 print('{:5d} and {:8.3f}',format(a,b)) と下は同じ print(f'{a:5d} and {b:8.3f}')
if a == b: print("a = b") elif a == c: print("a = c") else: print("else") if a == b: pass # 何もしないときは pass が必要。怠るとエラー else: 何らかの処理 条件を複数記述するときは and or 比較演算子は C と同一 == != < > <= >=
num = 0 while num < 2: print("num = " + str(num)) num = num + 1 while 1: 無限ループ while True: 無限ループ break ループ脱出 continue ループ先頭へ
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
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:4] [list[2], list[3]] 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] extend は既存のリストの更新、 + は新しいリストの作成 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 に代入する list.remove(element) 値が element である最初の要素を削除する for a in list: のループ中で list.remove を使うのは危険である。 list = [1, 2, 3, 4] for element in list: print(element) if element == 2: list.remove(element) このプログラムでは 1, 2, 4 と表示され、 3 に対する処理が行われない。 その理由は 2 回目のループで 2 が削除された結果、 リストが [1, 3, 4] となり、その次のループは 3 回目のループであるが、3 番目の要素である 4 に対して 処理が行われる。
a = [[1, 2], [3, 4], [5, 6]] print(a) a = [] b = [1, 2] c = [3, 4] d = [5, 6] a.append(b) a.append(c) a.append(d) print(a) for i in range(len(a)): print(a[i][0], a[i][1])
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])
a = [1, 2, 3] b = a 同じオブジェクトを参照するので a を変更すると b の内容も変わる c = copy.copy(a) 2 次元配列の場合は要注意 a = [[1, 2], [3, 4]] b = copy.copy(a) c = copy.deepcopy(a) a[1].append(5) print(b) [[1, 2], [3, 4, 5]] print(c) [[1, 2], [3, 4]] 2 次元配列は、各要素が別のオブジェクトを参照している。 b が作成されたとき [3, 4] は a の 2 個目要素と同じ要素を 参照している。
変更ができないリスト a = (255, 255, 0)
2 つも方法がある (1) \ バックスラッシュ (2) ( ) で囲んだ部分の中では改行してもよい
with open を使う with open("a.txt", "r", encoding = "utf-8") as f: for line in f: print(line, end = "") インデントが終わった瞬間 close する open を使う f = open("a.txt", "r", encoding = "utf-8") encoding は省略可 "shift-jis" for line in f: print(line, end = "") f.close() close() が必要 エラー処理付き 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) ------------ f.seek(0) ファイルの先頭へ seek を実行した後は for,next or readline のいずれも可
2 つの命令がある 1. 読み込んだファイルは 1 つの文字型変数に格納される str = f.read() print(f) 2. 読み込んだファイルを 1 行ずつリストにする lines = f.readlines() print(f) for i in range(len(lines)): lines[i] = lines[i].rstrip("\n") print("|" + lines[i] + "|")
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])
with open("out.txt", "w", newline = "\n") as f: "w":上書き "a":追記 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] あるいは ret = (1, 2, 3) return ret のようにすればよい。 python のアンパック機能により、 [1, 2, 3] と (1, 2, 3) の違いはない。 a, b, c = func() [a, b, c] = func() (a, b, c) = func() どれを使っても a, b, c に数値が入る。 コンマを使って数値を区切ると、暗黙的にタプルを形成する 関数例:ヘッダ検索システム 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 されたときは「偽」となる。
引数は環境変数 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>""")
import cgi method = os.environ.get('REQUEST_METHOD') form = cgi.FieldStorage() for key in form.keys(): print "<p>{} = {}</p>".format(key, form[key].value)
import subprocess os.chdir("dir_name") # ".." なども可能 ret = subprocess.call(cmd) # 正常実行の時 0 が返る ret = subprocess.getoutput(cmd) # 標準出力に出力した文字列が返る print(ret) os.system(cmd) は古いので推奨されない。
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
・文字が含まれているか否かを判定 line = "abc123" if 'c' in line: 見つかったときの処理 ・何文字目か? line = "abc123" a = line.find('123') # a = 3 a = line.find('x') # a = -1 a = line.find('a') # a = 0 見つからないとき -1 見つかったとき n 文字目からなら n-1 を返す。 ・置換 line = line.replace('pre','after')
import re 正規表現 リテラル r'正規表現' r (raw) をつけると、エスケープシーケンス (\) を 無視する。 例えば \t はタブではなく \ と t の 2 文字 変数化 str = re.compile(r'正規表現') ・re.search 部分一致(perl のマッチングと同等。正規表現, グループの使い方も同じ) m にはマッチオブジェクトが入る 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.match() 先頭からマッチング(re.serach の検索文字列の先頭に ^ を つけるのと同等と思われる) 例 m = re.match('Time/div\(second\),(\S*)', line) m = re.match('Points,(\S*)', line) m = re.match('(\S+),(\S*),(\S*),(\S*)$', line) ・re.findall() 全て見つけ出し、リストに入れる list = re.findall("(\w+):", all) 末尾に「:」がある任意の文字列を抽出してリスト変数 list に 入れる。ただし : は除外する
. 任意の1文字 x? 0 個あるいは 1 個の x x* 0 個以上の x x+ 1 個以上の x ^ 行の先頭 $ 行末 \s 空白文字 ( スペース、タブ、改行 ) \S 空白以外の文字 \d 数字 \w 単語を構成する文字 [a-z0-9_] \* * そのもの [0-9\-] 0 〜 9 の文字あるいは '-' 記号の固まり [^\"]+\" " 以外の文字の 1 つ以上の連続の後、" 文字
import sys print("usage: % makehtml.py fname", file = sys.stderr) sys.stderr.write("usage: % makehtml.py fname\n")
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 = "{:04}/{:02}/{:02} {:02}:{:02}:{:02}".\ format(year,month,day,hour,minute,second)
import os, shutil os は低水準ファイル処理用のモジュール shutil は高水準ファイル処理用のモジュール cwd = os.getcwd() cwd の取得 os.chdir("dir") cd 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) ディレクトリ以下全て消去
fname = os.path.basename(full_fname) body, ext = os.path.splitext(fname) splittext でないのに注意! ext の中に . が含まれることに注意! ext には "." の含まれているのに注意!
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
import socket addr = "202.236.176.170" host_tuple = socket.gethostname(addr) hostname = host_tuple[0] hostcname = host_tuple[1] addr2 = host_tuple[2]
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()
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)
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('..') ' 必要な場合は入れる
pid = os.getpid() # 数値型 文字にするには str(os.getpid())
import fcntl 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 未満の実数
インストールはここから 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
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 アンインストール $ pip3 install --force-reinstall module-name pip のアップグレード $ python3 -m pip install --upgrade pip ○ Windows 版 IDLE で使う python のモジュールインストール コマンドプロンプトで where python と打つと、 以下の2箇所に python がある。 (1) C:\Users\user-name\AppData\Local\Programs\Python\Python310\python.exe (2) C:\Users\user-name\AppData\Local\Microsoft\WindowsApps\python.exe IDLE から呼ばれる python は path = sys.executable print(path) で確認すると C:\Users\user-name\AppData\Local\Programs\Python\Python310\pythonw.exe である。(1) のフォルダの python のようだ。 コマンドラインから > py -m pip install module-name あるいは > pip install module-name でインストールすると (2) の python 用にインストールされ、 IDLE から使うことができない。 IDLE から以下のスクリプトを実行してインストールする import subprocess, sys path = sys.executable print(path) module = "Pillow" cmd = path + " -m pip install " + module ret = subprocess.getoutput(cmd) print(ret) cmd = path + " -m pip freeze" ret = subprocess.getoutput(cmd) print(ret)
$ 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 より先に実行すると、セーブされない
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) に変更
・バイナリファイルの 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()
url = "http://denki.nara-edu.ac.jp/~yabu/" ret = requests.get(url) ret.encoding = ret.apparent_encoding if ret.status_code != 200: fname = "err.txt" f = open(fname,"a") print('error occur return code = ' + str(ret.status_code), file = f) f.close() sys.exit(1) text = ret.text list = text.split('\n') for line in list: print(line) n = len(list) for i in range(0, n): print(list[i])
requests の方が高機能だが urllib は標準でついてくる 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 がハングアップする。
python3 から以下のように書く必要がある。 send_str = "l" send_str = send_str.encode('utf-8') rs = serial.Serial('/dev/ttyAMA0', 9600, timeout=10) rs.write(send_str) recv_str = rs.readline() rs.close() recv_str = recv_str.decode('utf-8').rstrip()
python の連想配列の宣言と同じ形式の文字列 import json a = {"name": "tarou", "age": 23} # 連想配列 b = json.dumps(a) # 文字列に変換する c = '{"name": "tarou", "age": 23}' # 文字列 print(a) print(type(a)) print(b) print(type(b)) print(c) print(type(c)) if b == c: print("b == c") else: print("b != c")
fill_color = (255, 255, 255) outline_color = (0, 0, 0) size = (640, 480) bg_color = (255, 0, 0) im = Image.new('RGB', size, bg_color) draw = ImageDraw.Draw(im) fill_color = (0, 255, 0) outline_color = (0, 0, 255) # 左上は (0,0) y は下向き増加 draw.rectangle( (x1, y1, x2, y2), \ fill=fill_color, outline=outline_color, width=0)) # 外接する長方形を指定する draw.ellipse( (x1, y1, x2, y2), \ fill=fill_color, outline=outline_color, width=0)) draw.line( (x1, y1, x2, y2), fill=fill_color, width=10) # 座標の指定は (x1, y1, x2, y2) あるいは ((x1, y1), (x2, y2)) の # どちらでもよい im.save("a.png") im.show() # アニメーション img_list = [] im は画像のオブジェクト img_list.append(im) img_list[0].save("fname.gif", save_all=True, append_images=img_list[1:], optimize=False, duration=50, loop=0) optimize=True にすると意図せぬ結果になったりする loop=0 : 無限ループ dration : 各フレームの表示時間 [ms]
python の class は C++ とは変数の扱いが大幅に 異なる。 全インスタンス共通の変数(classの内側, def の外側 で宣言) そのインスタンス固有の変数(self をつける) 一時変数(無印) class Stack: nstack = 0 # 全インスタンス共通 # そのクラスの最初のインスタンスを作成したときに # 1 回だけ実行される。 def __init__(self): # コンストラクタ self.stack = [] # インスタンス固有 Stack.nstack = Stack.nstack + 1 # nstack = nstack + 1 でも可能 def __str__(self): # print(st) のとき return f"{self.stack}" # f" " はフォーマット済文字列 # 出力したい変数を { } で囲む def push(self, a): self.stack.append(a) def clear(self): self.stack = [] def pop(self): n = len(self.stack) # n はローカル変数 ret = self.stack.pop(n-1) return(ret) st = Stack() st.push(10) st.push(20) st.push(30) print(st) a = st.pop() print(a) a = st.pop() print(a) st.clear() print(st)
-------- module.py ------- a = 10 def sub1(): print("sub1") def sub2(a): print(a + 10) --------------------------- import module print(module.a) module.sub1() module.sub2(20) 変数:モジュール名.変数名 関数:モジュール名.関数名
\ は 5C だが、 IDLE で \ を入れると C2 A5 が入ることがある。 これはバックスラッシュと円記号の違いに由来する