こんにちは。iQeda [@iQeeeda] です。
今回、プログラミング言語 Python の基本文法をまとめてみました。
もし書き方を忘れてしまったときはチェックしてみてください。
目次
Python 実行方法
python
コマンド- Terminal 上のインタラクティブモードで実行していく方法
python [pyファイル]
- py 拡張子 のファイルを実行する
インタラクティブモードを使う場合
# インタラクティブモード起動
python
Python 3.7.7 (default, May 6 2020, 04:59:01)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
# Python コードを記述して実行できる
>>> print("test")
test
# インタラクティブモード終了
exit()
py ファイルを実行する場合
# myapp.py のプログラムを実行する
python myapp.py
UTF8 宣言
- プログラムの冒頭に
coding: utf-8
宣言を行うことがある- Python 2
- ソースコードに日本語が含まれている場合は必須
- Python3
- 宣言不要。別に書いても問題はない
- Python 2
coding: utf-8
コメントアウト
ソースコードに対するコメントの書き方は 3 種類です。
#
- パウンド記号
"""
- ダブルクオテーション
'''
- シングルクオテーション
# 文の区切りにセミコロンを使うこともできるが、文末のセミコロンは通常省略する print("Hello world") """ 複数行コメントアウト """ ''' 複数行コメントアウト '''
変数・定数
- 定数
- Python で定数はサポートされていない
- 大文字で表記しておいて自分で再代入しないよう注意する
# 変数宣言 msg = "Hello World" print(msg) # 定数宣言 ADMIN_EMAIL = "ikeda@gmail.com"
データ型
文字列
- バックスラッシュを使って特殊文字を埋め込むことができる
- 文字列も演算できる
# \n は改行 \t はTAB s = "he\nllo wor\tld" s2 = 'hello again' # 文字列を 3 回出力する print("hello" * 3);
- 複数行の文章を出力したいときはコメントアウトの
""""
や'''
を利用できる- 改行コードも保持してくれる
html = """<html> <body></body> </html>"""
文字列の中に変数を埋め込む
%s
- 文字列 (string)
%d
- 整数 (decimal)
%f
- 浮動小数点 (float)
name = "ikeda" score = 52.8 # name: ikeda, score: 52.800000 print("name: %s, score: %f" % (name, score))
- 埋め込む値に「文字数制限」を設けることもできる
- 文字の「左寄せ・右寄せ」を指定することもできる
name = "ikeda" score = 52.8 # %10s: 10 文字の幅だけ表示 # %10.2f: 小数点以下は 2 桁まで表示 print("name: %10s, score: %10.2f" % (name, score)) # %-10s: 左揃えにして表示 print("name: %-10s, score: %10.2f" % (name, score))
format()
同じことを format()
関数でやることもできます。
name = "ikeda" score = 52.8 # {0} 0 番目の要素に変数 name を埋め込む # {1} 1 番目の要素に変数 score を埋め込む print("name: {0}, score: {1}".format(name, score))
name = "ikeda" score = 52.8 # {0:10s}: 10 文字の幅だけ表示 # {1:10.2f}: 小数点以下は 2 桁まで表示 print("name: {0:10s}, score: {1:10.2f}".format(name, score)) # 右揃え ( > ) # 左揃え ( < ) print("name: {0:>10s}, score: {1:<10.2f}".format(name, score))
文字列を 1 文字ずつ処理する
s = 'string' for char in s: print(char) # 添字つき for index, char in enumerate(s): print(index, char)
isdigit
文字列が数字かどうかを判定するメソッド
if '123'.isdigit(): print('この文字列は数字です')
整数 / 浮動小数点 / 論理値
- 論理値:
True
/False
- 頭文字は大文字なので注意する
i = 10 # インクリメント ( i++ や ++i といった記述方法はない ) i += 1 f = 23.4 flag = True
無限大
float('inf')
という関数を使えば無限大という値を作成することができる。float('-inf')
にすると負の無限大となる。
List のソート処理実装などに使われることが多い。
# min の初期値には「無限大」を設定 ※ 負の無限大じゃないので注意 min = float('inf') # max の初期値には「負の無限大」を設定 ※ 無限大じゃないので注意 max = float('-inf') for n in [8, 1, 3, 4, 10, 7, 9, 2, 5, 6]: # 初回は「無限大」以下の値がきたら min が更新される if n <= min: min = n # 初回は「負の無限大」以上の値がきたら max が更新される if n >= max: max = n
論理記号
and
A and B
なら「A かつ B」
or
A or B
なら「A または B」
not
not A
なら「A の逆」
- Python で以下の論理記号は存在しないので注意する
&&
||
!
# False print(True and False); # True print(True or False); # False print(not True);
1 <= num <= 9
たとえば 1 以上 9 以下の条件は以下のように記述することができる。
if num >= 1 and num <= 9: print('1以上、かつ、9以下') # and を使うよりシンプル if 1 <= num <= 9: print('1以上、かつ、9以下')
キャスト (型変換)
データ型を変更することを「キャスト」と呼ぶ。
input()
- ユーザ入力を受け付ける関数
- Python 3 では文字列で取得する
- 他のデータ型で欲しければキャストする
# int() で囲めば整数でキャストする score = int(input("score ? "))
if 文
- インデント
- 半角スペース 4 つと決まっている
if score > 80: print("Great!") elif score > 60: print("Good!") else: print("so so ...")
条件演算子による if 文 (三項演算子)
- 条件演算子による if 文
真の結果 if 条件 else 偽の結果
print("Great!" if score > 80 else "so so ..." )
in 句
in を使えば、その値を含んでいるかどうか True / False で取得できる。
※ イテレータから要素を取り出す for … in 構文とは別物なので注意
# True 結果になる if 3 in [1, 2, 3, 4, 5]: print('True') # False 結果になる if 3 not in [1, 2, 3, 4, 5]: print('この print は実行されない') # True 結果になる if 'c' in 'abcde': print('True') # 'ABCDEFG' を 'abcdefg' に変換する # in range(65, 91) で Unicode のコードポイント 65 〜 91 の範囲を生成 # コードポイント 65 〜 91 は A 〜 Z のこと # コードポイント 97 〜 122 は a 〜 z のこと print(''.join([chr(ord(char) + 32) if ord(char) in range(65, 91) else char for char in 'ABCDEFG' ]))
all / any / not any
if (all(True, True, True)): print('全部 True なら True') if (any(False, False, True)): print('ひとつでも True があったら True') if (any(False, False, False)): print('すべて False なら True')
ループ処理
while … else 文
i = 0 while i < 10: if i == 5: # break で処理を抜ける場合は else 処理は実行されない break print(i) i += 1 # 条件を満たさなくなったときの処理 else: print("end")
for … in
in の後ろのイテレータから要素をひとつずつ取り出すことができます。
# range は 0 から 10 手前 (つまり 9 ) までのリスト型を作る for i in range(10): if i == 5: # スキップ処理 continue print(i) # 終了処理 else: print("end")
ワンライナーで取り出した要素に処理をかけることもできます。
※ 「内包表記」参照
# 二重 List の 0 番目、1 番目の要素を一緒に取り出すこともできる for name, age in [['sato', 20], ['yamada', 30]]: print(name) # sato print(age) # 20 # 以下と同じ for person in [['sato', 20], ['yamada', 30]]: name = person[0] age = person[1] print(name) print(age)
range(start, stop, [step])
range()
は第三引数まで指定することができる。
第三引数では「数字の刻み方」を指定できる。
# 偶数だけが欲しいなら、第三引数に 2 を指定すればよい for i in range(0, 10, 2): # 0 2 4 6 8 10 print(i) # カウントダウンしたいとき for i in range(5, -1, -1): # 5 4 3 2 1 0 print(i)
zip()
names = ['taro', 'hanako', ‘'jiro'] ages = [25, 30, 27] # zip 関数で複数のリストを同時に for ... in 文で回すこともできる for name, age in zip(names, ages): print(name, age) ''' taro 25 hanako 30 jiro 27 '''
List 型に key をつけて Dictionary 型に変換する
new_items = [] items = [['ikeda', 34], ['iwanaga', 34]] for v in items: k = ['name', 'old'] new_items += [dict(zip(k, v))]
関数
- 関数の引数にはデフォルト値をもたせることができる
# age のデフォルト値 20 def say_hi(name, age = 20): print("hi {0} ({1})".format(name, age)) say_hi("tom", 23) say_hi("bob", 21) say_hi("steve") # 関数の引数名を使って渡す、この際、引数の順番は関係ない say_hi(age = 18, name = "rick")
return
def say_hi(): return "hi" msg = say_hi() print(msg)
関数内関数
- 関数 A 内に関数 B を定義することができる
- 関数 A 外からは関数 B を実行することはできない
- 関数 A が関数 B のオブジェクトを返す場合、関数 A 外から関数 B の実行が可能
- 関数外の変数に対して代入するには
nonlocal
かglobal
宣言が必要
nonlocal
def A(): msg = 'Ohayou' def B(): # ローカル変数 msg の定義ではなく A にある msg を使うよ、という宣言 nonlocal msg msg = 'Hello' B() print(msg) # Hello A()
global
def A(): def B(): # Inner で global 宣言するパターン global msg msg = 'Hello' B() print(msg) # Hello A()
List 要素を追加するだけなら nonlocal も global も不要
def A(): msg = [] def B(): msg.append('Hello') B() print(msg[0]) # Hello A()
関数 A が関数 B のオブジェクトを返す場合
def A(): def B(): return 'Hello' # 関数オブジェクトを返却 return B b = A() c = b() # Hello print(c)
lambda
関数内関数の代わりに lambda 式を定義することもできる。
def A(s1, s2): concat = lambda s1, s2: s1 + ' ' + s2 return concat(s1, s2) # Hello World A('Hello', 'World')
None
- None
- 空っぽを意味するオブジェクト
- None の判定
is None
is not None
- Python に以下の値は存在しない
null
/nil
A = None A is None # True A is not None # False # 以下の書き方は間違い # A == None
pass
pass
- None を return する
- 以下のような場合に使える
- 関数の中身が何もない場合
- 後でコードを記述するのでとりあえず何か書いておきたい場合
def do_pass(): pass msg2 = do_pass() print(msg2) # None
global
- グローバル変数
- ローカル関数の中からでも参照できる
- ローカル関数内でグローバル変数の値を上書きしようとした場合
- 同名のローカル変数を定義しただけの扱いになる
- ※ もし本当にグローバル変数の値を書き換えたい場合
global
キーワードで明示的に同名の変数を宣言する
msg = "hello" def say_hi(): # global キーワードを使う global msg msg = "hello global" print(msg) # hello global say_hi()
class
pass
- 実装がないクラスを作りたいときも
pass
を使うことができる - ちゃんとインスタンス作成できるし、存在しない属性も自由に追加できる
class User: pass # インスタンス作成 tom = User() # 存在しない属性も自由に追加できる tom.name = "Tom" tom.score = 20 bob = User() bob.name = "Bob" bob.level = 5 # ちゃんと表示される print(tom.name) print(bob.level)
コンストラクタ
- Python のコンストラクタの第一引数は
self
- 作られるインスタンス自身のこと
- 実は引数名はなんでもよいが self とするのが慣習
- コンストラクタ内に定義する変数を「インスタンス変数」と呼ぶ
class User: # コンストラクタの第一引数は self # 第二引数以降は自由に設定できる def __init__(self, name): # self.name は「インスタンス変数」という self.name = name tom = User("tom") bob = User("bob") # インスタンス変数の表示 print(tom.name) print(bob.name)
クラス変数
- クラス変数
- クラス直下に宣言した変数
クラス名.クラス変数
で直接呼び出すことができる- インスタンスを作成してインスタンス変数を呼んだのに存在しなかった場合
- 同名のクラス変数があったら呼び出される
class User: # クラス変数 count = 0 def __init__(self, name): # クラス変数にアクセス User.count += 1 self.name = name print(User.count) # 0 tom = User("name") print(User.count) # 1 bob = User("bob") print(User.count) # 2 # count というインスタンス変数がないので、同名のクラス変数 count が呼び出される print(tom.count) # 2
インスタンスメソッド / クラスメソッド
- メソッド
- クラスの中にある関数のこと
- インスタンスメソッドとクラスメソッドの 2 種類ある
- インスタンスメソッド
- クラスのインスンスから呼び出すことができる関数
- 第一引数は
self
とするのが慣習
- クラスメソッド
- クラスから直接呼び出すことができる関数
- デコレーター
@classmethod
で宣言する - クラス変数にアクセスすることができる
class User: count = 0 def __init__(self, name): User.count += 1 self.name = name # インスタンスメソッドの宣言 def say_hi(self): print("hi {0}".format(self.name)) # クラスメソッドの宣言 @classmethod # 引数の cls はこのクラス自身を指す def show_info(cls): # クラス変数にアクセスできる print("{0} instances".format(cls.count)) # インスタンスの作成 tom = User("tom") bob = User("bob") # インスタンスからインスタンスメソッドを実行 tom.say_hi() bob.say_hi() # クラスから直接クラスメソッドを実行 User.show_info()
クラスメソッドの第一引数が self になる理由
Java では this
、Ruby では self
というキーワードで「その関数が実行されるコンキストであるオブジェクト」に参照します。それを可能にしているのは暗黙的な引数が渡されているからです。
Python の設計哲学は「Explicit is better than implicit.」(暗黙的であるよりも明示的のほうがいい) となっているので、メソッドの引数に明示的な変数 self
を渡す必要があるのです。
class Person: def __init__(self, name): self.name = name def greet(self): print("Hi, I'm " + self.name) minky = Person("Momo") # Hi, I'm Momo minky.greet()
別途定義した関数をクラスのメンバメソッドとして登録できる
class Person: def __init__(self, name): self.name = name # 実は self という名前じゃなくてもいいので、ここでは this とする def greet(this): print("Hi, I'm " + this.name) minky = Person("Momo") # Hi, I'm Momo greet(minky) # クラスから外出しされている関数をクラスのメンバメソッドとして登録できる Person.greet = greet # greet の引数 this に Person インスタンスが渡るので、呼び出しの引数は不要 # Hi, I'm Momo minky.greet()
アクセス制限
- アクセス制限
- python にアクセス制限の仕組みはない
- しかし以下の慣習的な明示ルールが 2 つ存在する
_属性名
- このアンダースコアが 1 個の書き方は「以下のルールを明示」する
- クラス内ではアクセス OK
- クラス外ではアクセス NG
- ※ しかし「実際にはアクセスできる」ので非推奨
__属性名
- このアンダースコアが 2 個の書き方は「実際にアクセスできなくする」
- ※ …ように見せる仕掛けが施されている
- 【NG】
インスタンス._クラス名__属性名
- ただし上記のように書いた場合はアクセスできるので注意
- 【NG】
- ※ …ように見せる仕掛けが施されている
- このアンダースコアが 2 個の書き方は「実際にアクセスできなくする」
class User: count = 0 def __init__(self, name): # アクセス制限 self.__name = name def say_hi(self): print("hi {0}".format(self.__name)) tom = User("tom") # アクセスエラー print(tom.__name) tom.say_hi()
アクセスエラーが本当に起きるかプログラムを実行してみましょう。
python myapp.py
Traceback (most recent call last):
File "myapp.py", line 14, in <module>
print(tom.__name)
AttributeError: 'User' object has no attribute '__name'
インスタンス.クラス名__属性名
のように書いてはいけません。
# アクセスできてしまうので注意 print(tom._User__name)
継承
- 継承
- クラス名のあとに
(親クラス名)
を付けると継承する
- クラス名のあとに
super() / オーバーライド
-
super().__init__(引数)
- 親クラスのコンストラクタを使用する
class User: def __init__(self, name): self.name = name def say_hi(self): print("hi {0}".format(self.name)) # User クラスを継承 class AdminUser(User): def __init__(self, name, age): # スーパークラス User のコンストラクタを使用 super().__init__(name) self.age = age def say_hello(self): print("hello {0} ({1})".format(self.name, self.age)) # オーバーライド (スーパークラスのメソッドを上書き) def say_hi(self): print("[admin] hi {0}".format(self.name)) bob = AdminUser("bob", 23) bob.say_hi() bob.say_hello()
多重継承
# A, B -> C class A: def say_a(self): print("A!") def say_hi(self): print("hi! from A!") class B: def say_b(self): print("B!") def say_hi(self): print("hi! from B!") # カッコの中の継承順によって、メソッドの優先順位が変わる class C(B, A): pass c = C() c.say_a() c.say_b() # 継承元がどっちも同じ名前のメソッドを持っているとき # 継承時の継承順によって、呼ばれるメソッドが決まる c.say_hi() # class B のメソッドが呼ばれる
モジュール
モジュールの読み込みには 2 種類の書き方が存在する。
import [モジュール名]
- モジュール名とはファイル名のこと
- 拡張子の py は不要
- モジュール内のすべてを取得する
- 使うときは
モジュール名.関数名
やモジュール名.クラス名
import user ... # 以下のように使用する # モジュール名.クラス名 # モジュール名.関数名 bob = user.AdminUser("bob", 23)
from [モジュール名] import [関数名/クラス名]
- モジュールから指定したものだけを引っ張ってくる
- カンマ区切りで複数指定可能
- 使うときは関数名・クラス名をそのまま使える
from user import AdminUser, User # user.AdminUser のように書かなくてよい bob = AdminUser("bob", 23) tom = User("tom") print(bob.name) bob.say_hi() bob.say_hello()
class User: def __init__(self, name): self.name = name def say_hi(self): print("hi {0}".format(self.name)) class AdminUser(User): def __init__(self, name, age): super().__init__(name) self.age = age def say_hello(self): print("hello {0} ({1})".format(self.name, self.age)) def say_hi(self): print("[admin] hi {0}".format(self.name)) print("hello")
パッケージ
作成したモジュールはパッケージ (ディレクトリ) ごとに管理したい場合が多いと思います。
Python にパッケージの存在を知らせるには __init__.py
というファイルを配置する必要があります。
# ファイル作成
touch __init__.py
ファイルの中身は何も書かなくて大丈夫です。
import [パッケージ名.モジュール名]
mypackage
というパッケージを作成して、その中に user.py
を作成します。
class User: def __init__(self, name): self.name = name def say_hi(self): print("hi {0}".format(self.name)) class AdminUser(User): def __init__(self, name, age): super().__init__(name) self.age = age def say_hello(self): print("hello {0} ({1})".format(self.name, self.age)) def say_hi(self): print("[admin] hi {0}".format(self.name)) print("hello")
上記パッケージ内にあるモジュールを利用してみましょう。
# パッケージからモジュールをインポート import mypackage.user # まわりくどく感じるのが難点 bob = mypackage.user.AdminUser("bob", 23)
from [パッケージ名.モジュール名] import [関数名/クラス名]
# 特定のクラス、関数のみインポートした場合 from mypackage.user import AdminUser # すっきり書ける bob = AdminUser("bob", 23) print(bob.name) bob.say_hi() bob.say_hello()
as
パッケージが増えると名前が長くなりがちです。
モジュールに別名をつけてあげるとよいでしょう。
# モジュールに別名をつけることができる import mypackage.user as mymodule bob = mymodule.AdminUser("bob", 23)
例外処理
- 例外処理
- 例外クラスを継承して独自のエラークラスを作成する
try / except / else / finally
- try
- except
- エラーがあったときの処理
- 他のプログラミング言語いうところの catch
- else
- エラーがなかったときの処理
- finally
- 最後に必ず実行される処理
raise / as
raise エラークラス名("エラーメッセージ")
- そのエラークラスを使って意図的なエラーを起こす
- コンストラクタの引数に
"エラーメッセージ"
が渡される
except エラークラス名 as e
print(e)
するとエラーメッセージを表示できる
# 例外クラスを継承して独自のエラークラスを作成 class MyException(Exception): pass ... def div(a, b): try: if (b < 0): # 意図的に MyException クラスのエラーを発生させる raise MyException("not minus") print(a / b) # ZeroDivisionError クラスは Python で定義されているエラークラス except ZeroDivisionError: print("not by zero!") # MyException クラスでエラーが発生したとき、そのエラーを変数 e で受け取る except MyException as e: print(e) # 例外発生しなかったときの処理 else: print("no exception!") # 必ず最後に実行される処理 finally: print("-- end --") # エラーが発生しないパターン div(10, 3) # 0 の除算でエラーを発生させるパターン div(10, 0) # 独自の例外を発生させるパターン div(10, -3)
リスト型 / タプル型
複雑な演算をしたいときは自分で実装せず、ライブラリを利用しましょう!
- itertools
- https://docs.python.org/ja/3/library/itertools.html
- Python 標準ライブラリなので競技プログラミングでよく使う
- NumPy
- https://numpy.org/
- 超有名ライブラリ。実務ならこれ一択
リスト型
- 順序 (index) つき
[値]
で初期化する
len(リスト型)
- リストの長さを取得する
append(値)
- リストに値を追加する
リスト変数 += [値]
でも追加可能
for value in リスト型
- 要素をすべて変数で取り出すことができる
for index, value in enumerate(リスト型)
- 取り出した要素か何番目の要素か、変数で取り出せるようになる
scores = [40, 50] print(scores[0]) # 40 scores[0] = 45 print(len(scores)) # 2 scores.append(100) print(scores) # [45, 50, 100] for score in scores: print(score) for i, score in enumerate(scores): print("{0}: {1}".format(i, score)) # 同じ要素を繰り返して初期化することもできる print([''] * 3) # ['', '', ''] print([None] * 3) # [None, None, None] print([1] * 5) # [1, 1, 1, 1, 1]
空のリスト判定
a = [] if not a: print('リストは空です')
空のリストに要素を追加する
nums = [1, 2, 3, 4] count = 0 # 空のリスト作成 result = [] for i in nums: count += i # append() を使わずに要素を追加 result += [count] return result
要素を結合して文字列にしてしまう
要素の結合処理をしたいだけなら join メソッドを使いましょう。
わざわざ for … in 構文でループ処理を使って要素を取り出す必要がありません。
list = ['a', 'b', 'c'] str = "".join(list) print(str) # 'abc'
末尾の要素には区切り文字を結合しない、という配慮もしてくれる。
list = ['a', 'b', 'c'] str = " ".join(list) print(str) # 'a b c'
リストとリストを結合する
list = [1, 2, 3] print(list + list) # [1, 2, 3, 1, 2, 3]
タプル型
- 順序 (index) つき
- 複数のデータ型を持てる
- リスト型を持つことも可能
- 値の変更ができない
(値)
で初期化する
items = (50, "apple", 32.5) print(items[1]) # 書き換えエラー発生 # items[1] = "pen"
タプル型とリスト型の互換性
list(タプル型)
- タプル型をリスト型に変換する
tuple(リスト型)
- リスト型をタプル型に変換する
print(list((1, 3, 5))) print(tuple([1, 3, 5]))
スライス
- リストから部分的なリストを作成する
- 文字列のスライスも可能
リスト型のスライス
scores = [40, 50, 70, 90, 60] # index 1 から 4 の手前までの要素でリストを作りたい [50, 70, 90] print(scores[1:4])
scores = [40, 50, 70, 90, 60] # 一番前から index 2 の手前までの要素でリストを作りたい [40, 50] print(scores[:2])
scores = [40, 50, 70, 90, 60] # index 3 から最後の要素までの要素でリストを作りたい [90, 60] print(scores[3:])
scores = [40, 50, 70, 90, 60] # 一番後ろの index から 3 つ分の要素でリストを作りたい [70, 90, 60] print(scores[-3:])
STEP を指定する
[start:stop:step]
として 3 つ目に step を設定することもできます。
指定した step だけ index をスキップして進みます。
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # [1, 3, 5] print(nums[0:6:2])
偶数・奇数番目の index をスライスする
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 偶数番目: [2, 4, 6, 8, 10] ※ index 0 から 2 個飛ばしする even = nums[0::2] # 奇数番目: [1, 3, 5, 7, 9] ※ index 1 から 2 個飛ばしする odd = nums[1::2]
文字列のスライス
s = "hello" print(s[1:4]) # "ell"
逆順に入れ替える
s = "1234" print(s[::-1]) # "4321"
集合型 [和集合/積集合/差集合]
- 値の重複なし
- 順序 (index) なし
- つまり要素の指定ができない
set(リスト型)
で初期化する- リスト型から集合型に変換している
{値}
で初期化することもできる
値 in 集合型
- その値が含まれるか論理値を返す
集合型.add(値)
- その値を追加する
集合型.remove(値)
- その値を取り除く
len(集合型)
- 集合型の要素数を返す
- 集合演算
- 和集合:
|
リスト型1 | リスト型2
- 積集合:
&
リスト型1 & リスト型2
- 差集合:
-
リスト型1 - リスト型2
- 和集合:
a = set([5, 4, 8, 10]) # 省略形 a = {5, 3, 8, 5} # 5 を含むか論理値を返す print(5 in a) # True a.add(2) a.remove(3) print(len(a)) # 集合演算 b = {1, 3, 5, 8} c = {3, 5, 8, 9} # 和集合: 登場する数字だけを表示 print(b | c) # {1, 3, 5, 8, 9} # 積集合: お互い被っている数字だけを表示 print(b & c) # {8, 3, 5} # 差集合: c と被っている数字をなくした b を表示 print(b - c) # {1}
辞書型
- キーと値で管理する
{キー : 値}
で初期化する
for key, value in 辞書型.items():
- キーと値を同時に取り出すことができる
del(辞書型[key])
- キーを指定して要素を削除する
# dict メソッドでオブジェクトを作成することもできる dictionary = dict() sales = {"ikeda" : 200, "tokunaga" : 400} print(sales["ikeda"]) # 200 sales["ikeda"] = 300 # 値を書き換え sales["eeeeg"] = 500 # キー追加 del(sales["tokunaga"]) # キー削除 print(sales) # キーと値を同時に取り出す for key, value in sales.items(): print("{0} : {1}".format(key, value))
イテレータ型
- イテレータ型は反復可能で数えられる値のオブジェクト
- 値を連続で取り出すことができる
- 次の index に進んで、その値だけ取り出すこともできる
iter(list 型)
で初期化する- リスト型からイテレータ型に変換している
next(イテレータ型)
- 次の要素の値になる
scores = [40, 50, 70, 90, 60] # リスト型 → イテレータ型 に変換する it = iter(scores) print(next(it)) # 40 print(next(it)) # 50 print(next(it)) # 70
- 実は
for ... in
の in のあとの部分はイテレータ型が期待されている- リスト型が渡された場合、イテレータ型に変換している
scores = [40, 50, 70, 90, 60] # scores は (内部的に) イテレータ型に変換されている for score in scores: print(score)
ジェネレータ型
- イテレータ型の一種
- ただし値を連続で取り出すことはできない
- 1 つ値を取り出そうとする度に、なにかしらの処理をかけることができる
- 無限に値を生み出すこともできる
yield
yield 値
- ある「値」が設定されたジェネレータ型のオブジェクトを返却する
next(ジェネレータ型)
yield 値
で設定された「値」を取得できる
無限に値を返すジェネレータの実装方法
def get_infinite(): i = 0 # 無限ループ while True: # ジェネレータ型を返却する ※ 無限ループが中断する yield i * 2 # next(g) されると値を吐き出して、この行から処理を再開する ※ 無限ループが再開する # ちゃんと前回までの i の値も保持されている i += 1 # ジェネレータ型のオブジェクトを取得 g = get_infinite() # 値を生成する print(next(g)) # 0 print(next(g)) # 2 print(next(g)) # 4
map
map(関数, イテレータ型)
- イテレータ型の要素を 1 つずつ関数に渡して、ジェネレータ型を生成する
- イテレータ型の代わりにリスト型を渡すこともできる
def triple(n): return n * 3 g = map(triple, [1, 2, 3]) # ジェネレータ型のままだと print できないのでリスト型に変換する print(list(g)) # [3, 6, 9]
数字を桁ごとにリスト要素にする
num = 123 digit = map(int, str(num)) # [1, 2, 3] print(list(digit))
lambda
map(ラムダ式)
を書くこともできる- つまり
map(lambda 無名関数の引数: 無名関数の処理, イテレータ型)
- イテレータ型の要素を 1 つずつ無名関数の引数として渡して処理する
- つまり
g = map(lambda n: n * 3, [1, 2, 3]) print(list(g)) # [3, 6, 9]
filter
filter(論理値を返す関数, イテレータ型)
- 条件合致した要素のみ抽出するジェネレータ型を生成する
# 偶数のとき true を返却する def is_even(n): return n % 2 == 0 # range(10) : 0 - 9 まで値をもつリスト型を作成 g = filter(is_even, range(10)) print(list(g)) # [0, 2, 4, 6, 8] # ラムダ式パターン # g = filter(lambda n: n % 2 == 0, range(10)) # print(list(g))
内包表記
- 内包表記
- 「リスト型・ジェネレータ型・集合型」を生成・加工する際の記法
[]
で囲む[返却する値 for 要素を変数 i として取り回す宣言 in イテレータ型]
- リスト型を返却する
()
で囲む(返却する値 for 要素を変数 i として取り回す宣言 in イテレータ型)
- ジェネレータ型を返却する
{}
で囲む{返却する値 for 要素を変数 i として取り回す宣言 in イテレータ型}
- 集合型を返却する
内包表記の書き方
リスト型の内包表記
# [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] print([i * 3 for i in range(10)])
True で返却する値 for 要素を変数 i として取り回す宣言 in イテレータ型 if 文
とすると、取り出した要素に対して if 文判定をかけて、もし True であれば値を返却するといったことができる。
# if 文で [0, 2, 4, 6, 8] を抽出してから、処理に映る # [0, 6, 12, 18, 24] print([i * 3 for i in range(10) if i % 2 == 0])
ジェネレータ型の内包表記
# <generator object <genexpr> at 0x7f36280ded00> print((i * 3 for i in range(10) if i % 2 == 0)) # print の中では ジェネレータ型の内包表記の () を省略することができる print(i * 3 for i in range(10) if i % 2 == 0)
if 文 の true 結果を sum 関数でカウントする場合。
items = [{name: 'ikeda', old: 34}, {name: 'iwanaga', old: 34}] # 後ろに if を置くパターン print(sum(1 for item in items if item['old'] == 34)) # 前に if を置くと else 必須 (三項演算子) print(sum(1 if item['old'] == 34 else 0 for item in items)) # カウントアップするだけなら 1 は不要で、前の if も else をなくせる print(sum(item['old'] == 34 for item in items))
集合型の内包表記
# {0, 6, 12, 18, 24} print({i * 3 for i in range(10) if i % 2 == 0})
高階関数 reduce
リスト要素を合計したいとか、リスト要素どうしを掛け算したい場合は reduce 関数が便利です。
functools
ライブラリ- reduce
- 第 1 引数: function(必須)
- 第 2 引数: iterable(必須)
- 第 3 引数: initializer(オプション)
- reduce
operator
ライブラリ- reduce の第一引数で渡すことができる関数
add
(足し算)sub
(引き算)mul
(掛け算)truediv
(割り算)
- reduce の第一引数で渡すことができる関数
from functools import reduce from operator import add, mul class Solution: # 受け取った数字の桁ごとの足し算・掛け算を行い、 # 「掛け算の結果 - 足し算の結果」を返却する def subtractProductAndSum(self, n: int) -> int: l = [int(digit) for digit in list(str(n))] # 2 * 3 * 4 = 24 product_of_digits = reduce(mul, l, 1) # 2 + 3 + 4 = 9 sum_of_digits = reduce(add, l, 0) return product_of_digits - sum_of_digits s = Solution() s.subtractProductAndSum(234)
お仕事ください!
僕が代表を務める 株式会社 EeeeG では Web 制作・システム開発・マーケティング相談を行っています。 なにかお困りごとがあれば、Twitter DM や Web サイトからお気軽にご相談ください。
カテゴリ「Develop」の最新記事
Pythonの勉強始めて1ヶ月の者です。色んなサイトを参考に本も読みながら勉強しております。
他のサイトには書かれてない基本的なところが詳しく書かれてあり、大変参考になりました。
しかしたった1年の職業訓練での勉強で就職し、たった2年の実務で独立ってすごいですね。
どのように勉強されたのか詳しく教えていただければ嬉しいです。
また参考になった良い本なども紹介していただければ尚嬉しいです。
お仕事がお忙しいでしょうが、どうかよろしくお願いいたします。
コメントありがとうございます!
僕が駆け出しの頃は動画サイトのプログラミングコードの写経ばかりしていました。いま振り返って「そのやり方が良かったか?」というとそうでもなくて、動画で基本文法を習ってなにかしらのフレームワークの使い方を知ったら、早く Web のサイトやサービス作るとか、アプリ制作とかに移ったほうがいいですw
写経って「先生が黒板に書いたことを自分のノートにまとめてるだけ」って感じでして、それだけやってても当然成績は上がらないんですよね。。。成績を上げたければ問題を解きまくる、プログラミングだったら「サービス・アプリを作れ」になるかなと。
あと身も蓋もないですが「仕事でコードの指摘を受ける (レビューを受ける)」が一番勉強になりますね!なので未経験でもプログラミングできる会社に入るのが一番の近道です。※ それが大変なんですが…
答えになったかわからないですが、なにかあったらまたコメントとか Twitter で絡んでください!
”’と”””のコメントはその中に”’とか”””で括ったテキストがあると逆になっちゃうので注意ね
あとifのインデントに半角4文字ってあるけど別にきまってないよ
ifに限らずpython全体で「インデント」が必須ってだけ。そのインデントがどんなインデントなのかはその部分だけで統一されてる必要があるだけ。半角(ってほんとはutf-8では呼ばないけど)のスペースもしくはタブ。そしてその数はその部分部分で統一されていればよくて、ある部分ではタブ一つ、ある部分では半角5つでもいいよ
その部分が全部同じインデントで統一されてるってことってだけ。一つのソースの各所がそれぞれは違っていてもかまわない。普通は統一してた方がわかりやすいよねってだけ