tr_ikym_blog

某Webサービスに従事する者のブログです。

「マンガでやさしくわかる会社の数字」は初心者には分かりやすかった。

f:id:tr_ikym:20191022235125j:plain:w300

「会社」というものについて最近興味が湧いてきたので、簡単にざっと知れそうな本を読みました。

本の題名は、「マンガでやさしくわかる会社の数字」です。

この「マンガでやさしくわかる」シリーズは大変気に入っています。 ストーリー形式で内容に飽きにくいですし、解説の部分もイラストが多くて理解の助けになります。

内容

キーワードとしては以下のようなものが登場してきました。

原価計算、貸借対照表、損益計算表、キャッシュフロー計算書、在庫管理、ABC分析、手形・小切手、
景気、金利、GDP、日銀短観、物価指数、外国為替、株式、PER、PBR、ROE、
経営分析、売上高利益率、ROA、総回転資本率、流動比率、当座比率、固定比率、自己資本比率、損益分岐点 など

前半では貸借対照表と損益計算表の説明を丁寧にして、途中は割と経済全般の話が入って、後半は経営分析のための指標の説明といった感じでした。

ちなみにマンガのストーリーは、地方のとあるスーパーマーケットの経営を立て直そうというもの。 やや面白かったです。

読書時間

読み終わるまでに要した時間は2時間くらいで、 マンガを読んでいる時間が10分くらいで、残りが解説を読んでいる時間、といった割合でした。

感想

多くの指標が登場しており、初学者が一度に全部覚えるのはなかなかの大変なのですが、 それぞれの説明は優しく具体的なので、何度か読み返してもいいかなと思えました。

全体を通して浅い説明といった感じでした。

「会社」というものに興味を持ち始めたのなら、最初に手に取る本として良いと思います。

マンガでやさしくわかる会社の数字

マンガでやさしくわかる会社の数字

Pythonでクラス内の複数メソッドに一括でデコレータを当てる。

調べて試して、盛大に時間を使って詰まったので備忘録として残します。 本記事はPython3.6.4を想定しています。

背景

  • アプリケーションコード内には多くのクラスが定義されている。
  • それぞれのクラスには、またまた多くのメソッドが定義されている。
  • それら多くのメソッドの前後に、共通処理を挟みたくなった。
class A:
    def method1():
        ....

    def method2():
        ....

    ....(メソッドいっぱい)

class B:
    ....(メソッドいっぱい)

class C:
    ....(メソッドいっぱい)

....(クラスいっぱい)

やりたかったこと

  • クラスにデコレータを付けることで、一括で複数メソッドにデコレータを当てたい。
  • メソッドによってはデコレータを付けたくない。
  • 管理の点から、できるだけシンプルに書きたい。

完成メージ

@decorate_cls()
class A:
    def method1():
        ....

    def method2():
        ....

    ....

@decorate_cls()
class B:
    ....

@decorate_cls()
class C:
    ....

....

やりたくなかったこと

  • それぞれのメソッドにひとつずつデコレータを付ける。

結論

  • いろいろ試してみた結果、下記のような感じでデコレータを作成できた。
  • 登場人物は3つ
    • メソッドに当てる引数付きデコレータ: decorate_fn
    • クラスに当てる引数付きデコレータ: decorate_cls
    • デコレータを当てられるクラス: Test

サンプルコード

from functools import wraps
import inspect

# メソッドに当てる引数付きデコレータ
def decorate_fn(name=''):
    def wrapper(fn):
        @wraps(fn)
        def decorate(*args, **kwargs):
            print(f'----{name} start----')
            result = fn(*args, **kwargs)
            print(f'----{name} end----')
            return result
        return decorate
    return wrapper


# クラスに当てる引数付きデコレータ
def decorate_cls(exclude=[]):
    def decorate(Cls):
        for name, fn in inspect.getmembers(Cls):
            if name.startswith('__'):
                continue
            if callable(getattr(Cls, name)) and not name in exclude:
                setattr(Cls, name, decorate_fn(name)(fn))
        return Cls

    return decorate


# デコレータを当てられるクラス
@decorate_cls(exclude=['not_decorated'])
class Test():
    @classmethod
    def decorated_classmethod(cls):
        print('This is classmethod.')

    def decorated_method(self):
        print('This is decorated method.')

    def not_decorated(self):
        print('This is not decorated.')

if __name__ == '__main__':
    Test.decorated_classmethod()
    test = Test()
    test.decorated_method()
    test.not_decorated()

実行結果

----decorated_classmethod start----
This is classmethod.
----decorated_classmethod end----
----decorated_method start----
This is decorated method.
----decorated_method end----
This is not decorated.

解説

メソッドに当てる引数付きデコレータ

まずは def decorate_fn() から。

これは、メソッドに当てる引数付きデコレータ。 今回は引数としてメソッド名を受け、メソッドの実行前後に下記のようなprint文を挟んだ。

----<method name> start----
----<method name> end----

Python3における引数付きデコレータの書き方については、すでに良い記事があるのでそちらを参考にしてほしい。 qiita.com

自分はちゃんとfunctools.wrapsを使っています。

クラスに当てる引数付きデコレータ

次に、def decorate_cls()

とりあえず再掲。

# クラスに当てる引数付きデコレータ
def decorate_cls(exclude=[]):
    def decorate(Cls):
        for name, fn in inspect.getmembers(Cls):
            if name.startswith('__'):
                continue
            if callable(getattr(Cls, name)) and not name in exclude:
                setattr(Cls, name, decorate_fn(name)(fn))
        return Cls

    return decorate

中身の関数は、クラスオブジェクトを受けて全メソッドを取得し、特殊メソッドでないメソッドに対して先に定義したdecorate_fn()を当てて、それをもとのクラスにsetattr()しています。

分かりにくいところとしてはdecorate_fn(name)(fn)でしょうか。 decorate_fn()は引数付きデコレータですので、まずdecorate_fn(name)までの部分でデコレータに引数だけを与えています。 そして返ってくるデコレータに対して(fn)でメソッドを渡しています。

また、このデコレータも引数付きデコレータにしたかったので、引数を渡せるように関数の入れ子にしています。

デコレータを当てられるクラス

最後に class Test() いくつか適当にメソッドを定義しているクラスです。

最後に

晴れてメソッド一括デコレータを作れました。 あとはひたすらクラスにこのデコレータを当てるだけ。