a

関数 topic

import

モジュールをインポートする。

import math

print(type(math))
# <class 'module'>

print(math)
# <module 'math' from '/usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/lib/python3.7/lib-dynload/math.cpython-37m-darwin.so'>

from <モジュール名> import <オブジェクト名>でオブジェクトをインポートできる。

from math import pi

print(pi)
# 3.141592653589793

# 他のオブジェクトを使用しようとするとエラーNameErrorになる。
# print(math.radians(180))
# NameError: name 'math' is not defined

組み込み関数

docs.python.org

関数オブジェクト

def hello():
    print("ハロー")

h = hello  # 関数を変数に代入
h()  # 関数オプジェクトを実行
  • 引数に関数オブジェクトを渡す

def do(func):
    func()

def hello():
    print("ハロー")

def bye():
    print("バイバイ")

h2 = hello
do(h2)  # 変数(関数オブジェクト)で渡す
# ハロー
do(bye)  # 関数のまま渡す
# バイバイ

クロージャ(関数閉包)

  • 関数の中に関数を定義する
    戻り値に関数を返す
# クロージャの定義
def charge(price) :
    # 関数の実態
    def calc(num) :
        return price * num
    return calc

# クロージャ(関数オブジェクト)を2種類作る 
child = charge(400)    # 子供料金400円
adult = charge(1000)    # 大人料金1000円

# 料金を計算する
price1 = child(3)    # 子供3人
price2 = adult(2)    # 大人2人
print(price1)
# 1200
print(price2)
# 2000

無名関数(ラムダ式)

lambda 引数, 引数,... : 実行するステートメント

Pythonではラムダ式で無名関数を記述する

func = lambda w, h : w * h
num = func(3, 4)
print(num)
# 12

ラムダ式を直接実行

num = (lambda w, h: w * h)(3, 4)
print(num)
# 12

map(関数, イテラブル)

イテラブルの要素を関数に渡し、戻りをmapに格納する

def double(x) :
    return x * 2
    
nums = [4, 3, 7, 6, 2, 1]
nums2 = map(double, nums)
print(nums2)
# <map object at 0x1071661d0>
print(list(nums2))  # mapはlist()で変換できる
# [8, 6, 14, 12, 4, 2]
nums = [4, 3, 7, 6, 2, 1]
nums2 = map(lambda n : n * 2, nums)
print(list(nums2))
# [8, 6, 14, 12, 4, 2]
  • リストの内包表記で同一のロジックが書ける
nums = [4, 3, 7, 6, 2, 1]
nums3 = [n * 2 for n in nums]
print(nums3)
# [8, 6, 14, 12, 4, 2]

filter(boolを返す関数 ,イテラブル)

  • filter()を使って正の値だけを抜き出したリストを作る
nums = [4, -3, 9, 1, -2, -4, 5]
nums2 = filter(lambda x : x>0, nums)  # 関数をラムダ式で記述
print(nums2)
# <filter object at 0x10f017ef0>
print(list(nums2))
# [4, 9, 1, 5]
  • リストの内包表記で同一のロジックが書ける
nums = [4, -3, 9, 1, -2, -4, 5]
nums2 = [n for n in nums if n > 0]
print(nums2)
# [4, 9, 1, 5]

イテレータとジェネレータ

イテレータは要素を1つづつ取り出せるオブジェクト
(イテラブルなオブジェクトとは違い、呼び出し場所が自由)
ジェネレータ関数はイテレータ(イテレータのように要素を取り出せるオブジェクト)をつくる関数

イテラブルからイテレータをつくる : iter(イテラブル)

colors = ["red", "blue", "green"]
colors_iter = iter(colors)
print(colors_iter)
# <list_iterator object at 0x10e301f98>
print(next(colors_iter))  # イテレータの次の要素を取り出す
# red
print(next(colors_iter))
# blue
print(next(colors_iter))
# green
print(next(colors_iter))
# Traceback (most recent call last):  # イテレータが空なのでエラーになる
#   File "/test_def_topic.py", line 61, in <module>
#     print(next(colors_iter))
# StopIteration

ジェネレータ関数でイテレータをつくる

def menu_generator() :
    yield "ワイン"  # ジェネレータの戻りはyeild(イールド)
    yield "サラダ"
    yield "スープ"
    yield "ステーキ"
    yield "アイスクリーム"

menu = menu_generator()  # ジェネレータ関数でmenuジェネレータをつくる
print(type(menu))
# <class 'generator'>
print(next(menu))
# ワイン

ジェネレータオブジェクトをfor-inで回す

def menu_generator() :
    yield "ワイン"  # ジェネレータの戻りはyeild(イールド)
    yield "サラダ"
    yield "スープ"
    yield "ステーキ"
    yield "アイスクリーム"

menu = menu_generator()
for n in menu:
    print(n)
# ワイン
# サラダ
# スープ
# ステーキ
# アイスクリーム

ループのジェネレータ関数

def num_generator() :
    n = 0
    while True :  # ループにしとく
        num = n*n + 1    # 数列式
        num = yield num
        n += 1

gen = num_generator()    # ジェネレータを作る
for i in range(0, 5) :
    print(next(gen))    # ジェネレータから次の値を取り出す
# 1
# 2
# 5
# 10
# 17

ジェネレータ式

内包表記と似ている

odd_gen = (odd for odd in range(1, 6, 2))  # ()で囲む
print(next(odd_gen))
# 1
print(next(odd_gen))
# 3

ジェネレータに値を送る : send(値)

def testgen() :
    n = 0
    while True :
        received = yield n  # send()の値が入る
        if received :
            n = received
        else :
            n = n + 1  # nがnext()で取り出される

gen = testgen()  # ジェネレータをつくる
print(next(gen))
# 0
print(next(gen))
# 1
print(gen.send(10))  # ジェネレータに値を送る
# 10
print(next(gen))
# 11

サブジェネレータ(サブイテレータ)

サブジェネレータ : yield from ジェネレータ
サブイテレータ : yield from イテラブル

def main_gen(n):  # メインのジェネレータ
    yield "start"
    yield from range(n, 0, -1)    # サブイテレータから値を作る
    yield from "abc"    # サブイテレータから値を作る
    yield from [10, 20, 30]    # サブイテレータから値を作る
    yield from sub_gen()    # サブジェネレータから値を作る
    yield "end"

    # サブジェネレータ
def sub_gen():
    yield "X"
    yield "Y"
    yield "Z"

m = main_gen(3)
print(list(m))
# ['start', 3, 2, 1, 'a', 'b', 'c', 10, 20, 30, 'X', 'Y', 'Z', 'end']