2024途中振り返り_3

今日は2024年9月30日です。2024年も3/4が過ぎようとしています。いつものように、このタイミングで2024年の途中振り返りをしてみたいと思います。前回の振り返りはこちらになります。

hirocom777.hatenadiary.org

今回は23度目の振り返りです。

2024の目標

2024年1月に立てた目標ですが以下になりますね。順を追って今の状態を見ていきましょう。

hirocom777.hatenadiary.org

健康

体重の維持に成功しています。定期的な運動も何とか継続できました。昼間は暑い日が続いたので、早起きしてウォーキングしてました。人間ドックを受診したのですが、結果は如何に?

AIに挑戦

過去のブログ記事をAIに読み込ませて、改善の提案をしてもらっていますが。すごいですね!!誤字脱字はほぼ100%見抜きますし、プログラムの改善提案もイケています。

AIは何でも解決してくれるわけではなく、しっかりとまとまっている内容について効果的な提案をしてくれるようです。ブログ書き続けてきて良かったです!!

仕事

やってないです(笑)

プログラミング

Pythonの再学習について、引き続きブログを執筆継続しています。相変わらず、いくら書いても終わりが見えません。大変です。あと上にも書いたのですが、過去のブログ記事をAIに読ませると、すごく改善してくれます。やはりPythonはAIと相性がいいようです。

資格を取る

簿記3級の学習ですが、少し停滞しています。ブログ1本だけ。今年中には終わらせたい!!

アウトプット

  • ブログ
    9月末までで本記事を除いて64本の記事を書いています。少しペースが落ちました。7~9月までだと、Python関係で書いた記事が13本。簿記の関係が1本です。また、PV数は伸び悩んでいます。Pythonも簿記も人気がないんですよね。まぁ、PVは直接の目的ではないのですが・・・

  • 講座
    何か講座を作ってみようかと考えています。候補はマイコン講座、アウトプット講座、データベース講座といったところでしょうか。

新しい発見

本の執筆をしました。最初に出したマイコン本の改定版です。本を出してから考えていたことを纏めることができて、内容的にはかなり満足しています。また、執筆と並行して編集作業を他の人に伝えることにも挑戦してみました。

今まで他の人の執筆支援してきて得られたことも、生かせたと思います。

あと、執筆にあたってその内容の一部をツィッター(X)にポストしたのですが、閲覧数がかなり多いですね。新しい発見でした。

次は2024年総括

そんな訳で「2024途中振り返り_3」でした。3か月後に2024年の総括の記事を書こうと思います。今回は、ほとんど本の執筆でしたね。簿記の学習はキリを付けたい!!

デコレーター_4(Python_41)

この連載では、Pythonについて色々な形で再学習に取り組んでいます。前回の記事はこちらになります。

hirocom777.hatenadiary.org

前回は、デコレーターの使用例、応用例を見ていきました。

今回もデコレーターの使用例です。エラー対応について見ていきましょう。

Pythonのエラー処理

まずPythonのエラー処理について述べなければならないのですが、この点については以下のPythonでSQLite3を使用する記事に書いています。参考にしてください。

hirocom777.hatenadiary.org

簡単に説明すると、Pythonのエラー処理は「try-except文」で行います。以下のように記述します。

try: 
    メインの処理
except:
    メインの処理でエラーが発生した場合の処理
else:
    メインの処理が正常に実行された場合の処理(省略可能)
finally:
    メインの処理結果にかかわらず実行される処理(省略可能)

関数を記述する際にエラー処理を記述することがあります。でも、同じようなエラー処理を複数の関数それぞれに記述することは、効率的とは言えません。デコレーターでエラー処理を追加できれば、全体のコードがわかりやすくなります。

基本的なエラー処理

def error_handler(func):
    def wrap(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except:
            print(f"エラーが発生しました")
    return wrap

@error_handler
def divide(a, b):
    return a / b

print(divide(10, 2))
# 5.0
print(divide(10, 0))  # エラーが発生しました
# None

エラー(例外)が発生した場合は、エラーメッセージを表示して終了するようになりました。 except部分を以下のように書き換えると、エラーの種類とエラー種類を確認できます。

        except Exception as e:
            print(f"エラーが発生しました: {e}")
            print(f"エラー種類: {e.__class__.__name__}")

Exceptionクラスはすべての例外が当てはまります。結果は以下の様になりました。

print(divide(10, 0)) 
# エラーが発生しました: division by zero
# エラー種類: ZeroDivisionError
# None

print(divide(10, [0]))
# エラーが発生しました: unsupported operand type(s) for /: 'int' and 'list'
# エラー種類: TypeError
# None

エラーの内容と、エラー種類が表示されました。

その他のPythonのエラーの種類については、以下を参照してください。 docs.python.org

エラーによって処理を変える

エラー種類によって、処理を分けることもできます。

def error_handler(func):
    def wrap(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except ZeroDivisionError:
            print("0で割ることはできません")
        except TypeError:
            print("データ型の指定が不正です")
    return wrap

@error_handler
def divide(a, b):
    return a / b

print(divide(10, 2))
# 5.0
print(divide(10, 0))  # 0で割ることはできません
# None
print(divide(10, [0])) # データ型の指定が不正です
# None

正常に終了した場合の後処理

正常に終了した場合の処理を追加することもできます。

def error_handler(func):
    def wrap(*args, **kwargs):
        try:
            re = func(*args, **kwargs)
        except Exception as e:
            print(f"エラーが発生しました")
        else:
            print("正常に終了しました") 
            return re
    return wrap

@error_handler
def divide(a, b):
    return a / b

print(divide(10, 2)) # 正常に終了しました
# 5.0
print(divide(10, 0))  # エラーが発生しました
# None

次回もデコレーター(キャッシング)

いかがでしょうか。デコレーターを使うとスマートなエラー処理が書けそうです。次回はデコレーターを使ったキャッシングについて考えてみます。お楽しみに!!

Python再学習のまとめはこちら!!

デコレーター_3(Python_40)

この連載では、Pythonについて色々な形で再学習に取り組んでいます。前回の記事はこちらになります。

hirocom777.hatenadiary.org

前回は、デコレーターの意味について学びました。色々な引数のパターンに対応するために、デコレーター関数の中にラッパー関数を持たせます。

今回はデコレーターの使用例、応用例を見ていきます。

所用時間の確認

関数を開発しているときに、実行にかかる時間を測定したい場面があります。そんな時にデコレーターを使用すれば、関数本体に手を加えることなく所用時間を測ることができます。

import time

def timer_deco(func):
    def wrap(*args, **kwargs):
        print(func.__name__)
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"所要時間: {end_time - start_time} 秒")
        return result
    return wrap

@timer_deco
def test_func():
    print("test_func処理開始")
    time.sleep(2)

test_func()
# test_func
# test_func処理開始
# 所要時間: 2.000764846801758 秒

開発が完了したら、関数の前に記述しているデコレーターを削除すればいいのです。

作業ログ

関数が実行される際にログ(記録)を取りたい場合があります。関数が1つだけの場合は該当の関数に記述すればいいのですが、複数の関数に対して同様のログを取りたい場合は、関数毎にコードを書くのは非効率です。このような処理の場合、デコレーターの使用が有効です。

import datetime

def log_deco(func):
    def wrap(*args, **kwargs):
        result = func(*args, **kwargs)
        print(datetime.datetime.now() , end = " : 関数 ")
        print(func.__name__ , end = ": 引数 ")
        print(*args, **kwargs, end = ": 返り値 : ")
        print(result)
        return 
    return wrap

@log_deco
def func_1():
    pass

@log_deco
def func_2(a,b):
    return a * b

@log_deco
def func_3(val_1,val_2 = 2):
    return val_1 * val_2

func_1()
func_2(3, 4)
func_3(3)
# 2024-09-20 09:59:05.340213 : 関数 func_1: 引数 : 返り値 : None
# 2024-09-20 09:59:05.340213 : 関数 func_2: 引数 3 4: 返り値 : 12
# 2024-09-20 09:59:05.340213 : 関数 func_3: 引数 3: 返り値 : 6

この例では標準出力に出力していますが、実際にはファイルに出力することになるでしょう。色々な引数のパターンに対応できています。

条件チェック

特定の条件を満たした対象のみ、関数の使用を許可したい場合があります。そんな関数が複数ある場合、デコレーターで条件チェック機能をまとめて実装すると効率的です。

def rank_check(func):
    def wrap(user):
        if user['rank'] in ["A","B"]:
            return func(user)
        else:
            print(f"{user['name']}さんは、使用できません")
    return wrap

@rank_check
def say_hello(user):
    print(f"{user['name']}さん、こんにちは")

user_1 = {"name": "Alice", "rank": "A"}
user_2 = {"name": "Tom", "rank": "B"}
user_3 = {"name": "Bob", "rank": "C"}

say_hello(user_1)
say_hello(user_2)
say_hello(user_3)
# Aliceさん、こんにちは
# Tomさん、こんにちは
# Bobさんは、使用できません

この例ではランクがAかBのメンバーのみ、関数say_helloを使用できます。

クラスのインスタンスメソッドへの適用

クラスのインスタンスメソッドにも、デコレーターを使用できます。

def deco(func):
    def wrap(self):
        print(f"{func.__name__}が呼ばれました")
        return func(self)
    return wrap

class MyClass:
    @deco
    def greet(self):
        print("こんにちは")

obj = MyClass()
obj.greet()
# greetが呼ばれました
# こんにちは

次回もデコレーター(エラー対応)

いかがでしょうか。デコレーターは色々な使い道が考えられますね。次回はデコレーターを使ったエラー対応について考えてみます。お楽しみに!!

hirocom777.hatenadiary.org

Python再学習のまとめはこちら!!

デコレーター_2(Python_39)

この連載では、Pythonについて色々な形で再学習に取り組んでいます。前回の記事はこちらになります。

hirocom777.hatenadiary.org

前回は、デコレーターについて学びました。複数の関数の前後に決まった処理を追加したいとき、その処理をまとめておくと便利です。

今回もデコレーターです。デコレーターの利点について考えてみようと思います。

デコレーターの意味

関数の中身を変更せずに機能追加するということは、関数の前後に処理を追加することです。対象の関数の前後の処理をまとめて関数にしてしまえばいいのです。対象の関数は引数で渡します。 Pythonでは関数自体もオブジェクトですので、このような記述が可能です。以下のようなイメージになります。

def 関数(対象の関数):
    前処理
    対象の関数呼び出し
    後処理

実際の例を見てみましょう。

def deco(func):
    print('decoの前処理が実行されました')
    func()
    print('decoの後処理が実行されました')

def check():
    print('checkが実行されました')

deco(check)
# decoの前処理が実行されました
# checkが実行されました
# decoの後処理が実行されました

これで十分なのであれば問題ないのですが、これでは対象の関数に引数が渡せません。この問題はデコレーターで解決できます。デコレーター関数は、以下のように記述します。

def デコレーター関数(デコレートする関数):
    def ラッパー関数(引数):
        前処理
        デコレートする関数(引数)
        後処理
    return ラッパー関数

デコレートする関数は、以下のように記述します。

# 関数の定義
@デコレーター関数
def デコレートする関数(引数):
    # 処理

# 呼び出し
デコレートする関数(引数)

実際の例を見てみましょう。

def deco(func):
    def wrap(arg):
        print('wrapの前処理が実行されました')
        func(arg)
        print('wrapの後処理が実行されました')
    return wrap

@deco
def check(arg):
    print(f'{arg} が渡されました')

check('ABC')
# wrapの前処理が実行されました
# ABC が渡されました
# wrapの後処理が実行されました

このように、デコレーターを使うと引数が必要な関数に対しても機能を追加できるのです。

色々な引数に対応する

上の例では1つの引数を持つ関数に対応しました。しかし、関数に渡される引数の数は決まっていませんし、キーワード引数を使用した関数もあります。この問題に対応するために、可変長位置引数と可変長キーワード引数を使用します。デコレーター関数は、以下のように記述します。

def デコレーター関数(デコレートする関数):
    def ラッパー関数(*args, **kwargs):
        前処理
        デコレートする関数(*args, **kwargs)
        後処理
    return ラッパー関数

args, *kwargs」は、可変長位置引数と可変長キーワード引数を意味します。慣例的にこの様に記述します。「args」は任意の数の位置引数、「*kwargs」は任意の数のキーワード引数を受け取ります。 デコレートする関数は、今までと同じです。

実際の例を見てみましょう。

def deco(func):
    def wrap(*args, **kwargs):
        print('前処理「',end = "")
        func(*args, **kwargs)
        print('」後処理')
    return wrap

実際の動きを見てみましょう。

@deco
def check_1():
    print('check_1実行。',end = "")

check_1()
# 前処理「check_1実行。」後処理

@deco
def check_2(arg):
    print(f'check_2実行。引数は {arg} です。',end = "")

check_2("ABC")
# 前処理「check_2実行。引数は ABC です。」後処理

@deco
def check_3(arg_1,arg_2):
    print(f'check_3実行。引数は {arg_1} と{arg_2}です。',end = "")

check_3("DEF" ,10 )
# 前処理「check_3実行。引数は DEF と10です。」後処理

@deco
def check_4(arg_1,arg_2 = 100):
    print(f'check_4実行。引数は {arg_1} と{arg_2}です。',end = "")

check_4("GHI")
# 前処理「check_4実行。引数は GHI と100です。」後処理

色々な引数で、デコレーターが機能していることがわかります。

次回はデコレーターの応用例

いかがでしょうか。デコレーター、なんだか便利じゃないですか? 次回もデコレーターです。デコレーターの応用例を見ていきます。お楽しみに!!

hirocom777.hatenadiary.org

Python再学習のまとめはこちら!!

デコレーター_1(Python_38)

この連載では、Pythonについて色々な形で再学習に取り組んでいます。前回の記事はこちらになります。

hirocom777.hatenadiary.org

前回は、イテレータについて学びました。イテラブル、イテレータの仕組みがわかったと思います。

今回は、デコレーターです。クラスのスタティックメソッド、クラスメソッドを学んだ時に出てきました。複数の関数の前後に決まった処理を追加したいとき、その処理をまとめておくと便利です。

関数のカスタマイズ

関数の中身を変更せずに機能追加するということは、関数の前後に処理を追加することになります。以下のようなイメージになります。

前処理
対象の関数呼び出し
後処理

これでは普通のプログラムなので、この処理自体を関数にまとめてしまいます。デコレートする関数自体は、この関数の引数として渡してしまいましょう。Pythonでは関数自体もオブジェクトですので、このような記述が可能です。

def 関数(対象の関数):
    前処理
    対象の関数呼び出し
    後処理

実際の例を見てみましょう。

def deco(func):
    print('decoの前処理が実行されました')
    func()
    print('decoの後処理が実行されました')

def check():
    print('checkが実行されました')

check() # checkが実行されました

deco(check)
# decoの前処理が実行されました
# checkが実行されました
# decoの後処理が実行されました

この例のように「check()」と、関数名の最後に"()"が付く場合は関数を実行します。「deco(check)」におけるcheckのように"()"が付かない場合は関数自体を意味します。 関数checkを引数に指定して関数decoを実行すると、処理をまとめて実行します。

デコレーター

デコレーターは、関数やメソッド、クラスの定義の前に記述(デコレート)することで、中身を変更せずに特定の処理を追加できる機能です。追加する機能を記述した関数を作成して、対象の関数をデコレートします。以下のように記述します。

def デコレーター関数(デコレートする関数):
    def ラッパー関数():
        前処理
        デコレートする関数の呼び出し
        後処理
    return ラッパー関数

引数で指定したデコレートする関数に、前後の処理を追加した関数(ラッパー関数)を定義して返しています。Pythonでは関数自体もオブジェクトなので、このようなことも可能なのです。

返ってきた関数を実行すると、まとめて処理を実行します。デコレートする関数は、デコレーター関数の引数として指定されています。ラッパー関数は、上のスコープで指定された内容をデコレートする関数として参照しています。

デコレートする関数を実行するには、以下のように記述します。

# 関数の定義
def デコレートする関数():
    # 処理

# 呼び出し
デコレーター関数(デコレートする関数)()

「デコレーター関数(デコレートする関数)」には、デコレーター関数内のラッパー関数が定義され、最後に「()」を付けることで呼び出しています。

実際の例を見てみましょう。

def deco(func):
    print('decoが実行されました')
    def wrap():
        print('wrapの前処理が実行されました')
        func()
        print('wrapの後処理が実行されました')
    return wrap

def check():
    print('checkが実行されました')

deco(check)()
# decoが実行されました
# wrapの前処理が実行されました
# checkが実行されました
# wrapの後処理が実行されました

「deco(check)」はdeco関数が実行された結果(wrap関数)を意味し、「deco(check)()」で、その関数を実行します。

ところで先にデコレーターのことを「関数やメソッド、クラスの定義の前に記述(デコレート)することで、中身を変更せずに特定の処理を追加できる機能」とご紹介しました。実をいうと、上の呼び出し方法は、以下のように簡略化して記述できます。

# 関数の定義
@デコレーター関数
def デコレートする関数():
    # 処理

# 呼び出し
デコレートする関数()

実際の例を見てみましょう。

def deco(func):
    print('decoが実行されました')
    def wrap():
        print('wrapの前処理が実行されました')
        func()
        print('wrapの後処理が実行されました')
    return wrap

@deco
def check():
    print('checkが実行されました')

check()
# decoが実行されました
# wrapの前処理が実行されました
# checkが実行されました
# wrapの後処理が実行されました

このように記述すると「@deco」で一度deco関数が実行されます。結果、check関数がdeco関数内のwrap関数に書き換わります。

シンプルな記述で同様の結果が得られました。

次回はデコレーターの応用

いかがでしょうか。デコレーターはおもしろい機能ですね。でも、ここまでやらなくても最初にご紹介した例でいいんじゃないでしょうか? 次回はデコレーターの使いどころと、応用方法について学ぼうと思います。お楽しみに!!

hirocom777.hatenadiary.org

Python再学習のまとめはこちら!!

ジェネレーター(Python_37)

この連載では、Pythonについて色々な形で再学習に取り組んでいます。前回の記事はこちらになります。

hirocom777.hatenadiary.org

前回は、イテレータについて学びました。イテラブル、イテレータの仕組みがわかったと思います。

今回は、ジェネレーターです。イテレータ同様繰り返しのデータを扱う仕組みのようですが、どのようなものなのでしょうか。

ジェネレーターとは

ジェネレーターとは、必要になったときに次のデータを生成する仕組みです。以下は前回ご紹介したリストからイテレータを生成して処理する例です。

it = iter([0,1,2]) # イテラブル(リスト)からイテレータを生成

print(next(it)) # 0 を返す
print(next(it)) # 1 を返す
print(next(it)) # 2 を返す
print(next(it)) # 例外 StopIteration が発生する

この例では、処理に必要なデータ(リスト)は、あらかじめ用意されています。上の例ではデータ量は少ないのですが、データ量が膨大になると、そのデータがメモリを占有してしまいます。また、データを用意するために複雑な計算を要する場合などでは、データの用意に時間がかかって、処理の開始が遅れてしまったりします。

このような時にジェネレーターを使用すると、効率のよいプログラムが書けます。以下は上記の例をジェネレーターで書き換えたものです。

def generate_test_1(end):
    for i in range(0, end):
        yield i

ge = generate_test_1(3)

print(next(ge)) # 0 を返す
print(next(ge)) # 1 を返す
print(next(ge)) # 2 を返す
print(next(ge)) # 例外 StopIteration が発生する

これを「ジェネレーター関数」といいます。通常の関数は、returnで値を返して終了となりますが、ジェネレーター関数ではyieldで値を返します。yieldが呼ばれると関数の実行は一時停止し、次に呼び出されたときにその次の場所から再開します。 これならばデータ量が多い場合でも、データがメモリを占有することはありません。データ型はジェネレーター型です。

print(type(ge)) # <class 'generator'> を返す

また、ジェネレーターは特殊メソッド「iterメソッド」、「nextメソッド」を持っています。ジェネレーターは、イテレータの一種です。

先の例ではデータ数を指定していましたが、データ数を指定せずに(無限に)値を返すジェネレーター関数も記述可能です。

def generate_numbers():
    i = 0
    while(True):
        yield i
        i += 1

ge = generate_numbers()

print(next(ge)) # 0 を返す
print(next(ge)) # 1 を返す
          ・
          ・

この例ではyieldで値を返した後、次の呼び出しでは次の文から再開します。関数の場合はreturnの後に記述された内容は無効になりますが、yieldでは有効になります。

ジェネレーター式

内包表記と似た様な記法で、ジェネレーターを生成する方法もあります。以下は、1~5の整数のうち奇数のみのリストを返すリスト内包表記です。

[i for i in range(1,6) if i % 2]

この値を順に返すジェネレーターは、以下のように記述できます。

ge = (i for i in range(1,6) if i % 2)

print(next(ge)) # 1 を返す
print(next(ge)) # 3 を返す
print(next(ge)) # 5 を返す
print(next(ge)) # 例外 StopIteration が発生する

リスト内包表記との違いは、"[]"ではなく"()"で括る点です。

無限に続くジェネレーター式

データ数を指定せずに(無限に)値を返すジェネレーター式は、「itertoolsモジュール」をインポートすることで可能になります。countオブジェクトを使用して、引数には開始する数値を指定します。引数を省略すると0になります。

import itertools

ge = (i for i in itertools.count(3))

print(next(ge)) # 3 を返す
print(next(ge)) # 4 を返す
print(next(ge)) # 5 を返す
          ・
          ・

次回はデコレーター

いかがでしょうか。ジェネレーターを使うと、効率よく繰り返しのデータを作成できます。次回はデコレーターです。関数やメソッド、クラスの定義の前に記述するのですが、どのような機能があるのでしょうか。お楽しみに!!

hirocom777.hatenadiary.org

Python再学習のまとめはこちら!!

イテレータ(Python_36)

この連載では、Pythonについて色々な形で再学習に取り組んでいます。前回の記事はこちらになります。

hirocom777.hatenadiary.org

前回は、カレンダーについて見ていきました。calendarモジュールを使ってカレンダーの表示ができます。

今回は、イテレータについてです。前回の後半でcalendarモジュールを使って、日付データのイテレータを作成できる旨ご紹介しました。「イテレータ」とは何なんでしょうか。

イテラブル

for文の説明をした記事で、以下の様に説明しました。

要素を取り出す順番が決まっているオブジェクトを、イテラブルなオブジェクトといいます。以下のように記述します。

for 変数 in イテラブルなオブジェクト:
   # 処理 

ここでいう「イテラブルなオブジェクト(以下、イテラブル)」とは、「イテレータを生成できるオブジェクト」のことです。そして「イテレータ」とは、「要素を1つずつ取り出せるオブジェクト」なのです。

先のfor文の例の様にイテラブルを配置すると、自動的にイテレータが生成され、要素を1つずつ取り出して処理します。イテレータ自身もイテラブルです。よって、for文は以下の様にも書けます。

for 変数 in イテレータ:
   # 処理 

dir()関数を使用して確認すると、イテラブルには必ず特殊メソッド「iterメソッド」があります。iterメソッドを使用することで、イテレータを生成します。

イテレータにも(イテレータ自身もイテラブルなので)iterメソッドがあります。加えてイテレータには「nextメソッド」があります。nextメソッドを使用すると、イテレータの次の要素を取得できます。

for文は、これらの特殊メソッドを使用してイテレータから1つずつ要素を取り出して処理しています。

イテレータの作成

イテラブルを指定してiter()関数を使用すると、iterメソッドが呼び出されてイテレータが作成されます。イテレータを指定してnext()関数を使用すると、nextメソッドが呼び出されてイテレータの次の要素が取得できます。

以下はiter()関数とnext()関数の使用例です。

it = iter([0,1,2]) # イテラブル(リスト)からイテレータを生成

print(next(it)) # 0 を返す
print(next(it)) # 1 を返す
print(next(it)) # 2 を返す
print(next(it)) # 例外 StopIteration が発生する

リストから要素を1つずつ取得しています。最後まで取得すると、次は例外 StopIterationが発生します。

リストのnextメソッド

上の例ではリストからイテレータを生成しています。でも、リスト自体にはnextメソッドが定義されていません。実は、iter()関数が実行された時(iterメソッドを呼び出したとき)、リスト専用の内部イテレータオブジェクト(リストイテレータオブジェクト)が生成されるのです。

iterメソッドは、このオブジェクト内に定義されています。

it = iter([0,1,2])

print(type(it)) # <class 'list_iterator'> を返す

イテレータを作る

クラスにiterメソッド、nextメソッドを記述すれば、独自のイテレータを作成できます。以下は作成例です。

class CountUp:
    def __init__(self, max_value):
        # カウント最大値を設定
        self.max_value = max_value

    def __iter__(self):
        # カウントを初期化してイテレータを生成
        self.current = 1
        return self

    def __next__(self):
        if self.current <= self.max_value:
            # 現在の値を返してカウントアップ
            result = self.current
            self.current += 1
            return result
        else:
            # 最大値を超えたらStopIteration例外を発生させる
            raise StopIteration

# イテレータの作成
my_iterable = CountUp(5)

# forループで使用できる
for value in my_iterable:
    print(value , end = " ") # 1 2 3 4 5 を返す

御覧の通り、イテレータとして動作していることがわかります。「raise StopIteration」は、イテレーターの要素が最後まで取り出された場合の例外です。

次回はジェネレーター

いかがでしょうか。イテラブル、イテレータの仕組みがわかってきました。ところで、似たような仕組みに「ジェネレーター」なるものがあります。次回はこちらを取り上げようと思います。お楽しみに!!

hirocom777.hatenadiary.org

Python再学習のまとめはこちら!!