それでは下記の記事👇の続きをやっていこう!前回までは<基礎編>ということで基本的な文法について体系的まとめました。今回は<関数編>になります。一緒に勉強していこう🤓
Contents
関数(function)とは
✔️print(), str(), input(), split() など、<基礎編>で扱ってきたものはPythonのデフォルトの関数
✔️関数は自分で作ることができ、コードを再利用する際にとても便利で楽
✔️”def”(defineの略)ではじめ関数名を定義し、引数を入れる”()”を書き、その後ろに”:”(コロン)を置く
✔️関数内(add)での処理を関数の外で使いたい場合、”return”と書き返り値を定義
✔️関数名は基本、小文字のアルファベットから記述(❌数字❌ _ (アンダースコアから始まると特別な意味を持つため、この後解説))
1 2 3 4 5 6 7 |
ex.) def add(x, y): z = x + y return z p = add(10, 5) # z = add(10, 5) である必要はないので注意(関数の中と外をごっちゃにしない) print(p) # 15 |
返り値(return)について
✔️return(返り値)がない関数も作ることができる
✔️returnを明示していない関数は“None”を返している
1 2 3 4 5 6 7 8 9 10 11 |
# 返り値がない関数 def print_dict(input_dict): for k, v in input_dict.items(): print(f"key: {k}, value: {v}") dict = {"one": 1, "two": 2} print_dict((dict)) #key: one, value: 1 key: two, value: 2 #returnがないと返り値がNoneになっていることを確認 return_value = print_dict(dict) print(return_value) # None |
✔️returnは複数設定することが出来る
1 2 3 4 5 6 7 8 9 10 |
# returnが複数の例 def get_first_last_word(text): text = text.replace(",", "") # Helloの後ろのカンマをなくす words = text.split() return words[0], words[-1] text = "Hello, My name is Pankun." first, last = get_first_last_word(text) print(f"first: {first} last: {last}") # first: Hello, last: Pankun. |
引数(parameter)について
✔️引数に渡す値のことをargumentという
✔️argsに引数の変数を定義しすることもできる
✔️argsで指定していなくても、引数にデフォルトの値を定義することで実行可能
✔️キーワードパラメーター(引数定義)は最後にまとめて書かないとエラーになる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def func(first, second, third): print(f"first: {first}, second: {second}, third: {third}") # 引数に渡す値のことをarguementという func("1", "2", "3") # first: 1, second: 2, third: 3 # argsに引数の変数を定義しても可 func("1", third="3", second="2") # first: 1, second: 2, third: 3 # argsで指定していなくても、引数にデフォルトの値を定義することで実行可能 def func(first, second, third="3"): print(f"first: {first}, second: {second}, third: {third}") func("1", "2") # first: 1, second: 2, third: 3 # キーワードパラメーター(引数定義)は最後にまとめて書かないとエラーになる def func(first, second="2", third): # Error |
*argsと**kwargs
✔️*args, **kwargs: 不特定多数の引数を関数に渡すことが出来る
✔️*args: 関数に渡す時はtuple型、#**kwargs: 関数に渡す時はdictionary型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# *args, **kwargs: 不特定多数の引数を関数に渡すことが出来る # *args: 関数に渡す時はtuple型 def get_average(*args): num = len(args) if num == 0: return 0 total = sum(args) return total / num average = get_average(1, 2, 3, 4, 5, 6, 7, 8) print(average) # **kwargs: 関数に渡す時はdictionary型 def kwargs_func(**kwargs): param1 = kwargs.get('param1', 1) param2 = kwargs.get('param2', 2) param3 = kwargs.get('param3', 3) print(f"param1: {param1}, param2: {param2}, param3: {param3}") kwargs_func(param1=10, param2=100, param3=1000) |
✔️ *, **: unpacking operatorという
✔️ *→tuple型をunpack ,**→dictionary型をunpack
1 2 3 4 5 6 7 8 9 10 |
# *, **: unpacking operator # *→tuple型をunpack ,**→dictionary型をunpack numbers = (1, 2, 3) print(numbers) # (1, 2, 3) print(*numbers) # 1 2 3 car1 = {'Corolla': 0, 'Voxy': 1} car2 = {'Yaris': 2, 'Rav4': 3} car_sum = {**car1, **car2} print(car_sum) |
値渡し(byref)と参照渡し(byvalue)
✔️pythonは基本的に参照渡しである
✔️integer型はimmutableなのでIDは違う値となる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 参照渡し(byref) <-> 値渡し(byvalue) def add_nums(a, b): print(f"第1引数aのID: {id(a)}") # 第1引数aのID: 4481075952 print(f"第2引数bのID: {id(b)}") #第2引数bのID: 4481075984 c = a + b return c one = 1 two = 2 print(f"oneのID: {id(one)}") # oneのID: 4481075952 print(f"twoのID: {id(two)}") # twoのID: 4481075984 three = add_nums(one, two) print(three) # 3 print(f"threeのID: {id(three)}") # threeのID: 4357610288 |
✔️List型はmutableなのでIDは同じ値となる
1 2 3 4 5 6 7 8 9 10 11 |
def add_car(cars, car): print(f"変更前のcarsのID: {id(cars)}") # 変更前のcarsのID: 4321472256 cars.append(car) print(f"変更後のcarsのID: {id(cars)}") # 変更後のcarsのID: 4321472256 return cars cars = ['Vitz', 'NOAH', '86'] car = 'Rav4' print(f"関数呼び出し前のcarsのID: {id(cars)}") # 関数呼び出し前のcarsのID: 4321472256 add_car(cars, car) print(f"関数呼び出し後のcarsのID: {id(cars)}") # 関数呼び出し後のcarsのID: 4321472256 |
Type annotation(Type hint)
✔️関数の引数と戻り値の型を指定することが出来る
✔️Pythonは基本的には動的型付け言語なので、ソースコードの開発等で使用される例は少ない
1 2 3 4 5 6 |
# Type annotation # 関数の引数と戻り値の型を指定可能 def add_nums(num1: int, num2 :int) -> int: return num1 + num2 print(add_nums(1, 2)) # 3 |
変数のスコープ(scope)
✔️スコープ(scope):変数、メソッド、クラスなどの有効範囲を示す言葉
✔️ローカル変数でグローバル変数を上書きすることはできない
✔️ローカルスコープに変数がない場合はグローバルスコープにある変数を見にいく
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# グローバル変数(モジュール変数) age = 30 def print_age(): age = 20 # ローカル変数 print(f"I'm {age} years old.") print_age() # I'm 20 years old. # ローカル変数でグローバル変数を上書きすることはできない print(age) # 30 def print_age(): # age = 20 print(f"I'm {age} years old.") # ローカルスコープに変数がない場合はグローバルスコープにある変数を見にいく print_age() # I'm 30 years old. |
✔️ローカル変数をグローバル変数にする時は変数の先頭に”global“をつける
✔️”global”でグローバル関数を書き変えるコードはバグの原因となるためあまり良い書き方ではないz
✔️書き換えられたくないグローバル変数は”大文字“で書くことで書き換え不可を明示的に表現できる
1 2 3 4 5 6 7 8 9 10 |
age = 30 # AGE = 30 : constant variable 書き換え不可を明示的に表現出来る def print_age(): global age # ローカル変数をグローバル変数にする時は変数の先頭に"global"をつける age = 20 print(f"I'm {age} years old.") print_age() # I'm 20 years old. print(age) # 20 |
関数のネスト(nested function)
✔️関数の中で関数を定義すること
1 2 3 4 5 6 7 |
# 関数の中で関数を定義(nestefd function) def outer(): def inner(): print("This is inner function.") inner() outer() # This is inner function. |
✔️outer関数で定義した変数はinner関数で使うことが出来る(当然、逆はエラー)
1 2 3 4 5 6 7 8 |
# outer関数で定義した変数はinner関数で使うことが出来る def outer(outer_param): def inner(): # print("This is inner function.") print(outer_param) inner() outer("outer_arg") # outer_arg |
✔️変数の頭に”nonglocal”を付けることでローカル変数から一つ階層が上のグローバル変数にすることが出来る
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 変数の頭に"nonglocal"を付けることでローカル変数からグローバル変数にすることが出来る msg = "I am global" def outer(): msg = "I am outer" def inner(): nonlocal msg msg = "I am inner" print(f"inner(): {msg}") # I am inner inner() print(f"outer(): {msg}") # I am inner outer() print(msg) # I am global |
カプセル化(encapsulation)
✔️外からアクセスできないようにする(情報隠蔽)
✔️実際のコード開発でこの書き方はあまりせず、次に解説するクロージャ(closure)やデコレータ(decorator)のに使用する場合がほとんど
1 2 3 4 5 6 7 8 9 10 11 |
# カプセル化(encapsulation): 外からアクセスできないようにする(情報隠蔽) def casino_entrance(age, min_age=21): if age < min_age: print(f"{age}才未満はお断り") return def inner_casino_entrance(): print("ようこそカジノへ") return inner_casino_entrace() casino_entrance(28) # ようこそカジノへ |
クロージャ(cloaure)
✔️functionもオブジェクトの1つ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# 関数(function)もオブジェクト def compute_square(num): return num * num f = compute_square function_list = ["1", 1, True, f] print(function_list[-1](10)) # 100 # 関数も引数として渡せる def execute_func(func, param): return func(param) print(execute_func(f, 10)) # 100 # 関数をreturnする def return_func(): def inner_func(): print("This is inner function") return inner_func f = return_func() print(f) # <function return_func.<locals>.inner_func at 0x108ff0550> f() # This is inner function |
✔️nested functionを使って関数を返り値、引数に渡すことも出来る
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# Closure: 状態をキープした関数を作ることが出来る # 状態が静的 def power(exponent): def inner_power(base): return base ** exponent return inner_power power_four = power(4) print(power_four(3)) # 81 # 状態が静的 def average(): nums = [] def inner_average(num): nums.append(num) return sum(nums) / len(nums) return inner_average average_nums = average() print(average_nums(5)) # 5.0 print(average_nums(15)) # 10.0 |
デコレータ(decorator)
✔️ある関数に機能を付属し、関数を実行するとある機能も動作する
✔️機能の役割をする関数の先頭に、機能させたい関数に@を付けて記述する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Decorator: 関数に機能を付属する(デコレートする) # main関数: greeting 機能の役割を担う関数: say_name() def greeting(func): def inner(name): print("Hello") func(name) print("Nice to meet you!") return inner @greeting def say_name(name): print(f"I'm {name}.") # say_name = greeting(say_name) say_name("Pankun") # Hello I'm Pankun. Nice to meet you! |
✔️デコレータを作成する時は汎用性を高めるため、関数内の引数に*args, **kwargsを置く
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def greeting(func): def inner(*args, **kwargs): print("Hello") func(*args, **kwargs) print("Nice to meet you!") return inner @greeting def say_name(name): print(f"I'm {name}.") @greeting def say_name_and_origin(name, origin): print(f"I'm {name}. I'm from {origin}") say_name_and_origin("Panchan", "Aichi.") # Hello I'm Panchan. I'm from Aichi. Nice to meet you! |
再帰関数(recursive function)
✔️再帰関数(recursive function): 関数内で自身の関数をcallする関数
1 2 3 4 5 6 7 8 9 10 11 12 |
# 再帰関数(recursive function): 関数内で自身の関数をcallする関数 # 階乗(factorial): 3! - 3 × 2 × 1 = 6 # ex.) n! = n × (n-1) * (n-2) * ... × 1 # n! = n × (n-1)! ←これをプログラミングしていきます def factorial(n): if n == 1: return 1 else: return n * factorial(n-1) print(factorial(3)) # 6 |
✔️フィボナッチ数列は再帰関数で簡単に表現できる
✔️利点:すっきりしたコードで書くことが出来る
✔️弱点:処理が遅い(余分な計算をしてしまう)
✔️キャッシュを使うように設定すれば弱点を補うことが出来る(後ほど詳しく)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# フィボナッチ数列 # 再帰関数を使った時 def fibonacchi_recursive(n): if n < 2: return n return fibonacchi_recursive(n-1) + fibonacchi_recursive(n-2) print(fibonacchi_recursive(6)) # 8 # 再帰関数を使わない時 def fibonacchi(n): if n < 2: return n else: n_1 = 1 n_2 = 0 for _ in range(n-1): result = n_2 + n_1 n_2 = n_1 n_1 = result return result print(fibonacchi(6)) # 8 |
ラムダ関数(lambda)
✔️比較的短く簡略な関数となるときに使う
1 2 3 4 5 6 7 8 9 10 11 12 |
# recursive関数 def power(exponent): def inner_power(base): return base ** exponent return inner_power # lambda関数(無名関数) 返り値がlambda関数となる例 def power(exponent): return lambda base: base ** exponent third_power = power(3) print(third_power(10)) # 1000 |
1 2 3 4 5 6 7 8 9 10 11 |
numbers = [6, 2, 5, 43, 5, 36, 67, 2] # lambda関数を使わない例 def filterfunc(num): return not num % 2 == 0 filtered_num = filter(filterfunc, numbers) print(list(filtered_num)) # [5, 43, 5, 67] # lambda関数を使った例 filtered_num = filter(lambda num: num % 2, numbers) print(list(filtered_num)) # [5, 43, 5, 67] |
docstring
✔️関数の説明をダブルコーテーション3つ(“””)で囲むことで表現することが出来る
✔️docstringは様々な書き方があり、開発で決まったルールで書くようにする
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# reStructuredText def multiply(num1, num2): """ multiply num1 with num2 and return the result :param num1: first number that you want to multiply :param num2: second number that you want to multiply :return: num1 * num2 """ return num1 * num2 print(multiply.__doc__) # multiply num1 with num2 and return the result # :param num1: first number that you want to multiply # :param num2: second number that you want to multiply # :return: num1 * num2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# Google def divided(num1, num2): """ num1 is divided by num2 and return the result Args: num1: number that you want to divide num2: number that num1 is divided by Returns: num1 / num2 """ return num1 / num2 print(divided(6, 2)) # 3.0 |
これでpythonの文法<関数編>は終了です、いかがだったでしょうか?
僕も様々な本やUdemy講座、日々の業務でPythonを使っているのですが、改めてまとめてみるとかなり勉強になりました!
次回は<モジュール編>についてまとめていきたいと思います☀️
今回はこの辺で、ばいばい👋
○Pythonをこれから勉強していきたい方
○Pythonの文法を詳しく知りたい方
○筆者と一緒に勉強をしていこうって思っている方