Python/整理中
複素数編集
Pythonは複素数を扱う組込みのcomplex型をサポートしています。整数はint型、浮動小数点数はfloat型です。
虚数単位は数学では一般的に を用いますが、Pythonでは j
を用います。
これは電気工学・電子工学の慣習で電流(intensity of electricity)の i(または I)との混同を避けるためです。
また変数 j
と区別するため 1j
のように必ず係数を付けます。
複素数も実数も有限精度での近似にすぎないため誤差は生じます。
>>> import cmath >>> cmath.exp(1j * cmath.pi) (-1+1.2246063538223773e-16j)
または
>>> from cmath import exp, pi >>> exp(1j * pi) (-1+1.2246063538223773e-16j)
または
>>> from cmath import e, pi >>> e ** (1j * pi) (-1+1.2246063538223773e-16j)
**は冪乗演算子です。import
はモジュールをインポートします。
import
はモジュールをインポートします。from modname import object0, object1, ..., objectN
でモジュールmodnameからオブジェクトobject0, object1, ..., objectNを現在の名前空間にインポートすることができます。基本的な数学関数および定数はmathモジュール、複素変数を扱える関数および定数はcmathモジュールで定義されています。このほかにもさまざまなモジュールが存在し、モジュールを作成することもできます。Pythonでは組込みのset型およびfrozenset型で集合を扱うこともできます[1]。
正規表現編集
Pythonの 正規表現(regular expression)は組込みではなくモジュールreをインポートし使用します。
正規表現とは、検索のような機能です。詳しくは上記リンク『正規表現』のリンク先を読んでください。
検索 search編集
pythonで文字列中の検索をしたい場合、search という関数を re.search() という形式で使います。
なお、Perl など他の言語では、似たような演算を match という場合もありますが、しかし python では、matchという関数が別の意味で使われているので(後述)、混同しないように気をつけてください。
- コード例
import re string = 'books' m = re.search('oo', string) if m: print("あった") else: print("なかった")
- 実行結果
あった
- 解説
Pythonでは、正規表現を使うには、まずreをインポートする必要があります。
文字列中の文字を検索するには re.serach 関数を使って
re.search("検索したい文字列", 検索対象の文字列または文字列変数)
のように記述します。
検索する文字列を「oo」から、たとえば「goo」に返ると、とうぜん「book」には「goo」という文字の並びは無いので、検索しなくなります。
- コード例
import re string = 'books' m = re.search('goo', string) if m: print("あった") else: print("なかった")
- 結果
なかった
下記のように、 re.search 関数中でひとまとめに検索しても可能です。
- コード例
import re string = 'books' m = re.search('oo', 'books') if m: print("あったよ") else: print("なかったよ")
- 結果
あったよ
先頭 match編集
正規表現の関数 re.match は、対象の文字が、文字列の先頭にないと検索にヒットしません。
下記の2種類のコードとその結果を見比べてください。
「book」の文字列中に「oo」があるにもかかわらず、先頭は「oo」からは始まらないので、 re.match の場合には「oo」ではヒットせず、「boo」にしないとヒットしないのです。
- コード例1
import re string = 'books' m = re.search('boo', string) if m: print("あった") else: print("なかった")
- 結果
あった
- コード例2
import re string = 'books' m = re.search('oo', string) if m: print("あったぜ") else: print("なかったぜ")
- 結果
なかったぜ
split関数編集
Pythonに限らず、PerlやC#などでもsplit関数というのがあり、1個の文字列を、区切り文字でくぎってリスト(配列)に代入し、リストのいくつもの個数の要素に代入していく機能が、モダンなプログラム言語にはあります。
このうち Python の split関数は、正規表現のreモジュールで扱われますので、python では関数 re.split を使うことになります。(他のプログラム言語では、正規表現とは無関係なのが一般的。)
import re string = 'きみとぼく' m = re.split('と', string) print ("1個目は" , m[0]) print ("2個目は" , m[1])
- 結果
1個目は きみ 2個目は ぼく
対話モード編集
対話モードでも、正規表現は使えます。
- 対話例
>>> import re >>> m = re.match(r'<title>(.*?)</title>', '<TITLE>Example Web Page</TITLE>', re.I) >>> m.group(0) '<title>Example Web Page</title>' >>> m.group(1) 'Example Web Page'
r''
やr""
のようなraw文字列はエスケープ文字を解釈しないので、\d
や\s
などのメタ文字を書くのに重宝します。matchメソッドは第一引数に正規表現パターン、第二引数にマッチ対象文字列、第三引数にre.I
やre.IGNORECASE
やre.M
やre.MULTILINE
やre.S
やre.DOTALL
などのフラグを指定します。Pythonに正規表現リテラルというものは存在しません。
matchメソッドはマッチオブジェクトを返します。マッチオブジェクトのgroupメソッドを使用して一致部分を抽出します。group(0)
はマッチ全体、group(1), group(2), ..., group(N)
は後方参照です。matchメソッドで対象文字列にマッチしなかった場合はマッチオブジェクトではなくNoneを返します。マッチに失敗する可能性がある場合は必ずif m == None:
あるいはif not m:
(None
はFalse
)で確認してください。
HTTPクライアント編集
Python 2ではurllibまたはurllib2、Python 3以降はurllib.requestのurlopenメソッドを使用してHTTPクライアントを作成することができます。
# -*- coding: utf-8 -*- try: from urllib.request import urlopen except: from urllib2 import urlopen print( urlopen('http://www.example.com/').read().decode() )
レスポンスはbytesで返ってくるので、decodeメソッドを使用してstrに変換しています。
JSON編集
JSONを扱うにはimport json
します。
>>> import json >>> json.dumps({'key': 'value'}) '{"key": "value"}' >>> json.loads(json.dumps({'key': 'value'})) {'key': 'value'} >>>
このコードから、オブジェクトのコピー(特にディープコピー)にJSONを利用できることに気がつくと思いますが、その用途にはモジュール copy の copy() や deepcopy() を使います。
インクリメントとデクリメント編集
PythonにはC/C++やJavaにあるインクリメント演算子とデクリメント演算子はないので、加算・減算と再代入で実現します。
>>> a=50 >>> a=a+1 >>> print(a) 51 >>> a=50 >>> a=a-1 >>> print(a) 49
累算代入文編集
Pythonにインクリメント演算子とデクリメント演算子はありませんが、累算代入文( augmented assignment statement )[2]の加算代入文・減算代入文はあります。
>>> a=50 >>> a+=1 >>> print(a) 51 >>> a=50 >>> a-=1 >>> print(a) 49
pass編集
passは「文法上必ず処理を書かなくてはならないが何も処理を書きたくない」というときに使います。
>>> def p(): ... pass ... >>> p()
ラムダ式編集
無名関数を定義するにはlambda
文を使用します。
>>> (lambda x: x * x)(2) 4
ヒアドキュメント編集
ヒアドキュメントは複数に渡る文字列リテラルで、文字列を""" """
あるいは''' '''
で囲みます。
docstring編集
モジュール・クラス・関数の冒頭の文字列リテラルは docstring と呼ばれドキュメントを記すために使われ、 オブジェクト.__doc__ で参照できます。 また、doctestではドキュメントの中の用例を使ってテストを行うときに使われます。
- docstringの例
"""モジュールのdocstring""" class MyClass: """クラスのdocstring""" def method(self): """メソッドのdocstring""" def function(): """関数のdocstring""" print(f'''\ {__doc__=} {MyClass.__doc__=} {MyClass.method.__doc__=} {function.__doc__=} ''')
- 実行結果
__doc__='モジュールのdocstring' MyClass.__doc__='クラスのdocstring' MyClass.method.__doc__='メソッドのdocstring' function.__doc__='関数のdocstring'
ジェネレーター編集
Pythonではジェネレーターを簡単に書くことができます。ジェネレーターを用いると、最初のフィボナッチ数を求めるプログラムは次のように書くことができます。
- ジェネレーターの例
def fibgen(n): a, b = 0, 1 for _ in range(n) : yield a a, b = a + b, a for i in fibgen(8) : print(i, end=' ') print() print(tuple(fibgen(8)))
- 実行結果
0 1 1 2 3 5 8 13 (0, 1, 1, 2, 3, 5, 8, 13)
- Pythonでは特に指定のない変数は自動的にローカル変数(レキシカルスコープ)になります。
a, b = 0, 1
というのは分割代入(Destructuring assignment)で、a = 0; b = 1
と同じ意味です。a, b = a + b, a
も同様ですが、代入は一気に行われるため、t = a; a = a + b; b = t
と同義です(aとbの値が入れ替わります)。- Pythonでは
while True:
のように制御構文の条件式をかっこで囲む必要がありません。定義済みキーワードとして、真を表すTrue、偽を表すFalse、そしてNoneが存在します。 - yield文はreturn文と似ていますが、サブルーチンの戻り値を処理の「途中で」返すことができるところが違います。
- nextメソッドを呼ぶと、「途中から」処理が継続されます(for文では暗黙に next メソッドが呼出されます)。このような関数をジェネレーターといいます。
内包表記とジェネレータ式編集
Pythonには、シーケンスの内包表記とジェネレータ式があります。
- 内包表記とジェネレータ式
for label, expr in {"加算":"1 + 1", "リスト内包表記":"[2 ** x for x in range(5)]", "集合内包表記":"{2 ** x for x in range(5)}", "辞書内包表記":"{x: 2 ** x for x in range(5)}", "ジェネレータ式":"(2 ** x for x in range(5))", "タプルコンストラクターにジェネレータ式を適用":"tuple(2 ** x for x in range(5))", }.items() : print(f'''{label}: {expr} ⇒ {eval(expr)} : {type(eval(expr))}''')
- 実行結果
加算: 1 + 1 ⇒ 2 : <class 'int'> リスト内包表記: [2 ** x for x in range(5)] ⇒ [1, 2, 4, 8, 16] : <class 'list'> 集合内包表記: {2 ** x for x in range(5)} ⇒ {1, 2, 4, 8, 16} : <class 'set'> 辞書内包表記: {x: 2 ** x for x in range(5)} ⇒ {0: 1, 1: 2, 2: 4, 3: 8, 4: 16} : <class 'dict'> ジェネレータ式: (2 ** x for x in range(5)) ⇒ <generator object <genexpr> at 0x14ac1a9e56d0> : <class 'generator'> タプルコンストラクターにジェネレータ式を適用: tuple(2 ** x for x in range(5)) ⇒ (1, 2, 4, 8, 16) : <class 'tuple'>
- Pythonの式を表す文字列(Ex. "1 + 1")を要素としたタプルをループ変数exprで回しています。
print(f'{label}:\n {expr}\n ⇒ {eval(expr)} : {type(eval(expr))}')
は、- を表示します。
ラベル: 式 ⇒ 式の評価結果 : 式の評価結果の型
(2 ** x for x in range(5))
は、タプル内包表記…ではなく、ジェネレータ式で未評価のシーケンス(generator)を返します(組込み関数のrange同様、この時点ではメモリーオブジェクトではありません)。- タプルのコンストラクターにジェネレータ式を渡すと、タプルが返ります(タプルはイミュータブルですがメモリーオブジェクトです)。
代入演算子編集
if文やwhile文の条件には式が要求されるので代入文 =
は使えませんでした。
しかし、条件式の中で代入を行うのがふさわしいケースもあります。
このため Python 3.8で、条件式中でもつかえる代入演算子(Assignment Expressions) :=
(俗称:セイウチ演算子;Walrus operator)が導入されました[3]。
- 代入演算子の使用例
a = "1234567" # 7文字 if (n := len(a)) > 5: print("文字が5文字より多いです" , n - 5, "文字オーバー") print(f"あなたは{n} 文字を入力しました")
- 実行結果
文字が5文字より多いです 2 文字オーバー あなたは7 文字を入力しました
代入演算子を使った条件式を含む文のブロックの外に出ても、そのまま代入した効果は残ります。
なお、f"あなたは{n} 文字を入力しました"
はテンプレート・リテラルです。
エスケープシーケンス編集
たとえばprint()関数で、「こんにちは」と表示させたい場合なら
print("こんにちは")
と書きました。 では、" を含んだ文字列を表示するにはどうしたら良いでしょう? やり方は、いくつかあります。
- " を含んだ文字列を表示する方法
print('"') print("\"") print("\42") print("\x22")
- クオート文字を ' に変えました。素朴ですがパワフルな方法です。
- しかし、この方法では " と ' は1つの文字列の中で共存できません。
- " の前に \ を前置すると文字列を閉じる " を打消すことができます。
- \ は、¥(円記号)の半角で表示されるかもしれませんが、文字コードと機能は同じです。
- \ に続けて " の文字コードを8進数で表記します。
- 10進数ではないので注意してください。
- \ に続けて x それに続けて文字コードを16進数で表記します。
2. から 4. の様に、 \ を前置して文字列中に所望に文字を書く方法をエスケープシーケンス( escape sequence )といい、エスケープシーケンスに前置する文字 ' をエスケープ文字( escape character )といいます。
エスケープシーケンスの一覧編集
エスケープシーケンスの一覧 エスケープシーケンス 意味 \<改行> バックスラッシュと改行を無視 \\ バックスラッシュ自身 ( \
)\' シングルクォーテーション ( '
)\" ダブルクオーテーション ( "
)\a ASCII ベル(アラート) (BEL) \b ASCII バックスペース (BS) \f ASCII フォームフィード (FF) \n ASCII ラインフィード (LF) \r ASCII キャリッジリターン (CR) \t ASCII 水平タブ (TAB) \v ASCII 垂直タブ (VT) \ooo 8進数キャラクタコードによる文字指定 ooo \xhh 16進数キャラクタコードによる文字指定 hh \uxxxx 16ビットの16進数値xxxxを持つUnicode文字 \Uxxxxxxxx 32ビットの16進数値xxxxxxxxを持つUnicode文字
print関数編集
# 「ようこそ」 と出力
print("ようこそ")
#から行末まではコメントです。文字列の出力はprint()
を使います。Python 2まではprint
は文でしたが、Python 3では組込み関数printとなったため、かっこが必須となります。
文字列は" "
で囲んでも' '
で囲んでも同じ意味であり、エスケープ文字の取り扱いに違いはありません。
備考編集
- インデントについて
Pythonのブロックはスペース4つのインデントによって表されます(オフサイドルールといいます)。
- pythonについて
pythonは、Googleなどの企業のみならず、MITの初年度のプログラミングの授業でも採用されています。英語圏ではRubyやPerlよりも普及しています。
Pythonは1990年にグイド・ヴァンロッサムによって作られました。誰が書いても同じソースコードになるように(違う目的のコードは違う見た目になるように)設計されており、常に読みやすいプログラムを書くことができます。教育用プログラミング言語としても秀逸です。
文字列の書式化編集
Pythonには、いくつかの異なる文字列の書式化の方法があります。
書式化付き文字列化編集
C言語のsprintf()
に相当する書式付き文字列化は、Pythonでは文字列の % 演算子を使います。
また、書式化文字列に % によるフィールドが複数ある場合は、下のようにタプルを使います。
>>> print("%d.%d.%d" % (2, 6, 4)) 2.6.4
文字列の format メソッド編集
文字列の format メソッドを使う方法[4]。
>>> print("{} {} {}".format(2, 6, 4)) 2.6.4
f文字列編集
PEP 498で新しく f文字列 が追加されました[5]。
>>> print(f"{4} {9} {8}") 4 9 8
- 文字列の書式化
print("%d %d %d" % (0!=0, 0==0, 999)) print("{} {} {}".format(0!=0, 0==0, 999)) print(f"{0!=0} {0==0} {999}") print(f"{abs(-123)} {2**10} {999}")
- 実行結果
0 1 999 False True 999 False True 999 123 1024 999
pip編集
pipはPythonのパッケージインストーラーです[6]。Python Package Index[7] などのインデックスからパッケージをインストールするのに使用します。
pipがインストールされているかは、(インターラクティブ・モードではなく)コマンドラインから確認します。
- FreeBSD
% uname FreeBSD % pip -V pip 22.1 from /usr/local/lib/python3.10/site-packages/pip (python 3.10)
- Windows 10
PS C:\Users\user1> pip.exe -V pip 21.2.4 from C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.2544.0_x64__qbz5n2kfra8p0\lib\site-packages\pip (python 3.9)
- GNU/Linux
$ uname -a Linux localhost 4.14.275-19064-g577a877aa35d #1 SMP PREEMPT Wed May 25 19:32:47 PDT 2022 x86_64 Intel(R) Celeron(R) N4020 CPU @ 1.10GHz GenuineIntel GNU/Linux $ pip -V pip 21.3.1 from /usr/local/lib/python3.10/site-packages/pip (python 3.10)
YAML編集
YAMLは、構造化データやオブジェクトを文字列にシリアライズするためのデータ形式の一種です。 Pythonは、初期状態ではYAMLを利用できませんが、pyYaml [8]をインストールすることで、pythonでYAMLを処理できるようになります。
pipがインストール済みならば、
- コマンドライン
% sudo pip install pyyaml
で pyYaml をインストールできます。 YAMLとPythonは別個の出自なのですが、YAMLはデータ構造をインデントで表し[9]、Pythonはプログラム構造をインデントをあらわすので似通った外観になります。
YAMLファイルの読出し編集
- test.yaml
名前:
姓: 山田
名: 太郎
国籍: 日本
性別: 男
部活: 野球部
- test-yaml.py
import yaml with open('/workspace/test.yaml') as f: obj = yaml.safe_load(f) print(f"""\ {obj=} {obj["国籍"]=} {obj["名前"]["姓"]=} """)
- 実行結果
obj={'名前': {'姓': '山田', '名': '太郎'}, '国籍': '日本', '性別': '男', '部活': '野球部'} obj["国籍"]='日本' obj["名前"]["姓"]='山田'
- import で yaml をインポートする必要があります。
- pythonでYAMLのセミコロンのデータを読取った場合の辞書型のオブジェクトを返します
かつてYAMLの読取りには、yaml.load()が使われていましたが、セキュリティ上の懸念から deprecated となり、yaml.load() を使うと
Main.py:4: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
と警告されます。yaml.safe_load() を使いましょう。
オブジェクトのYAMLへの変換編集
- コード例
import yaml obj = { "a": [2,3,5,7], "b": 3.14, "c": "test test", } s = yaml.dump(obj) print("*** Block style ***") print(s); print("*** Load ***") print(yaml.safe_load(s)) s = yaml.dump(obj, default_flow_style=True) print("*** Flow style ***") print(s);
- 実行結果
*** Block style *** a: - 2 - 3 - 5 - 7 b: 3.14 c: test test *** Load *** {'a': [2, 3, 5, 7], 'b': 3.14, 'c': 'test test'} *** Flow style *** {a: [2, 3, 5, 7], b: 3.14, c: test test}
YAMLファイルの書込み編集
- コード例
import yaml obj = { "a": [2,3,5,7], "b": 3.14, "c": "test test", } with open('/workspace/test.yaml', "w") as f: yaml.dump(obj, f) with open('/workspace/test.yaml') as f: for s in f: print(s, end='') print("-"*40) with open('/workspace/test.yaml') as f: print(yaml.safe_load(f))
- 実行結果
a: - 2 - 3 - 5 - 7 b: 3.14 c: test test ---------------------------------------- {'a': [2, 3, 5, 7], 'b': 3.14, 'c': 'test test'}
pickle と marshal編集
pickleモジュールは、Pythonのオブジェクト構造をシリアル化およびデシリアル化するためのバイナリプロトコルを実装しています[10]。 marshalモジュールも、Pythonのオブジェクト構造をシリアル化およびデシリアル化するためのバイナリプロトコルの実装ですが、将来に渡ってフォーマットを変えないことは保証されていないので、その用途にはpickleモジュールあるいはshelveモジュールを使ってください[11]。 marshalモジュールは、主に.pycファイルのPythonモジュールの "擬似コンパイル "コードの読み書きをサポートするために存在します。
- コード例
import pickle obj = [1,3,5,7] obj.append(obj) print(f'{obj=}') pkl = pickle.dumps(obj) print(f'{pkl=}') print(f'{pickle.loads(pkl)=}') import marshal msl = marshal.dumps(obj) print(f'{msl=}') print(f'{marshal.loads(msl)=}')
- 実行結果
obj=[1, 3, 5, 7, [...]] pkl=b'\x80\x04\x95\x0f\x00\x00\x00\x00\x00\x00\x00]\x94(K\x01K\x03K\x05K\x07h\x00e.' pickle.loads(pkl)=[1, 3, 5, 7, [...]] msl=b'\xdb\x05\x00\x00\x00\xe9\x01\x00\x00\x00\xe9\x03\x00\x00\x00\xe9\x05\x00\x00\x00\xe9\x07\x00\x00\x00r\x00\x00\x00\x00' marshal.loads(msl)=[1, 3, 5, 7, [...]]
shelve編集
shelveモジュールは、永続的な辞書の実装です[12]。
- コード例
import shelve filename = "/workspace/temp.shelve" with shelve.open(filename) as sh: sh['x'] = 1 sh['y'] = "abc" sh['z'] = [0, 1, 2] print(f'{sh["z"]=}') with shelve.open(filename) as sh: print(f'{ {k:v for k,v in sh.items()}=}')
- 実行結果
sh["z"]=[0, 1, 2] {k:v for k,v in sh.items()}={'z': [0, 1, 2], 'x': 1, 'y': 'abc'}
脚註編集
- ^ setはミュータブルな集合、frozensetはイミュータブルな集合で
fs = frozenset({2,3,5,7,11})
の様に組込み関数frozensetを使って生成します - ^ [https://docs.python.org/ja/3/reference/simple_stmts.html#augmented-assignment-statements 3.10.4 Documentation » Python 言語リファレンス » 7. 単純文 (simple statement)]
- ^ “PEP 572 -- Assignment Expressions” (2018年2月28日). 2021年11月12日閲覧。
- ^ PEP-3101
- ^ PEP-498
- ^ “pip documentation v21.3.1” (2021/12/20 accessdate=2021/12/20).テンプレート:Cite web/error
- ^ “The Python Package Index (PyPI) is a repository of software for the Python programming language.” (2021/12/20 accessdate=2021/12/20).テンプレート:Cite web/error
- ^ https://github.com/yaml/pyyaml
- ^ インデントでデータ構造を表すスタイルをブロックスタイルと呼びます。YAMLには他にフロースタイルと言う形式があり、これはYAML1.2からはJSONそのものです。YAML Ain’t Markup Language (YAML™) version 1.2
- ^ “3.10.0 Documentation » The Python Standard Library » Data Persistence » pickle — Python object serialization” (2021年12月2日). 2021年12月2日閲覧。
- ^ “3.10.0 Documentation » The Python Standard Library » Data Persistence » marshal — Internal Python object serialization” (2021年12月2日). 2021年12月2日閲覧。
- ^ “3.10.0 Documentation » The Python Standard Library » Data Persistence » shelve — Python object persistence” (2021年12月2日). 2021年12月2日閲覧。