初版作成 2016.2.5
最終更新 2024.12.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 fname カレントディレクトリの fname.py をインポート fname.func1 で fname.py の中の関数 func1 を使う import fname as f f.func1 で参照できる from fname import func1, func2 fname の中の関数 func1, func2 をインポート func1 で参照できる sys.path.append("..") import のときの path に .. を追加
# より右側 行の途中も可 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 が入ることがある。 これはバックスラッシュと円記号の違いに由来する utf-8 バックスラッシュは 5C 円記号は C2 A5
import abc 同一フォルダの abc.py をインポート import xxx.abc 直下の xxx というフォルダ内の abc.py をインポート from abc import xxx, yyy 直下の abc.py の中の class xxx, class yyy をインポート sys.path.append('..') import 対象のフォルダに .. を追加する