Python / IndentデコレータとChoiceデコレータ

前回の投稿からの続きです。

デコレータによって、 いろいろと技巧的なことができるようになります。

Indent

Indentデコレータは、インデントレベルを保持するためにクラス内で定義され、メンバ関数をデコレートします。

また、デコレータは多段に適用できます、その場合、順番が変わると挙動が変わるので注意が必要です。

作為的で長くなってしまいましたが、「メンバ関数をデコレートする」手法と「多段にデコレートする」手法を合わせて例示します。


from functools import wraps

# ////////////////////////////////////////////////////////
# =================================================
class Indenter:
  INDENT_WIDTH = 4
  # ================================================
  def __init__(self, *args, **kwds):
    self.__dict__.update(kwds)

    self.IndentLevel = 0
  # ================================================
  # -----------------------------------------------------------------------------
  def inc(self):
    self.IndentLevel += 1
    return self.IndentLevel
  # -----------------------------------------------------------------------------
  def dec(self):
    self.IndentLevel -= 1
    return self.IndentLevel
  # ================================================
  # decorator Indent
  def indent(a_Func):
    @wraps(a_Func)
    def wrapper(self, *args):  # wrapperはメンバ関数になるのでself引数が必要
      print(' ' * Indenter.INDENT_WIDTH * self.IndentLevel, end='')
      a_Func(self, *args)
    return wrapper
  # ================================================
  # decorator Kool
  def kool(a_Func):
    @wraps(a_Func)
    def wrapper(self, *args):  # wrapperはメンバ関数になるのでself引数が必要
      print('KOOL! ', end='')
      a_Func(self, *args)
    return wrapper
  # ================================================
  @indent
  def writeI(self, *args):
    print(*args)
  # ================================================
  @kool
  def writeK(self, *args):
    print(*args)
  # ================================================
  @indent
  @kool
  def writeIK(self, *args):
    print(*args)
  # ================================================
  @kool
  @indent
  def writeKI(self, *args):
    print(*args)

print('\n... Indent')
i = Indenter()
i.writeI('A')
i.inc()
i.writeI('B')
i.inc()
i.writeI('C')
i.inc()
i.writeI('D')
i.dec()
i.dec()
i.dec()
i.writeI('A')

... Indent
A
    B
        C
            D
A

print('\n... Kool')
i = Indenter()
i.writeK('A')
i.inc()
i.writeK('B')
i.inc()
i.writeK('C')
i.inc()
i.writeK('D')
i.dec()
i.dec()
i.dec()
i.writeK('A')

... Kool
KOOL! A
KOOL! B
KOOL! C
KOOL! D
KOOL! A

print('\n... Indent Kool')
i = Indenter()
i.writeIK('A')
i.inc()
i.writeIK('B')
i.inc()
i.writeIK('C')
i.inc()
i.writeIK('D')
i.dec()
i.dec()
i.dec()
i.writeIK('A')

... Indent Kool
KOOL! A
    KOOL! B
        KOOL! C
            KOOL! D
KOOL! A

print('\n... Kool Indent')
i = Indenter()
i.writeKI('A')
i.inc()
i.writeKI('B')
i.inc()
i.writeKI('C')
i.inc()
i.writeKI('D')
i.dec()
i.dec()
i.dec()
i.writeKI('A')

... Kool Indent
KOOL! A
KOOL!     B
KOOL!         C
KOOL!             D
KOOL! A

Choice

下記は与えられた複数のリストから値を選んで、重複のないリストを作り、関数に渡し、 その結果のリストを構築する、choiceデコレータです。


from functools import wraps

# ================================================
def choice(a_Func):
    # --------------------------------------------------------------------------
    def loop(*args):
        if len(args) is 0:
            return []
        if len(args[1:]) is 0:
            return [[i] for i in args[0]]
        return [[i] + j for i in args[0] for j in loop(*args[1:])]
    # --------------------------------------------------------------------------
    @wraps(a_Func)
    def wrapper(*args):
        # mapに渡すために、lambdaでargsを展開してます
        return [i for i in map((lambda args: a_Func(*args)), loop(*args))]
    return wrapper

# ================================================
# tupleに包む
@choice
def hoge(*args):
    return tuple(args)

hoge((1,2), (3,4))
... [(1, 3), (1, 4), (2, 3), (2, 4)]

# ================================================
# 合計する
@choice
def fuga(*args):
    return sum(args)

fuga((1,2), (3,4))
... [4, 5, 5, 6]

# ================================================
# 文字列にして連結
@choice
def var(*args):
    l_Return = ''
    for i in args:
        l_Return += str(i)
        l_Return += ', '
    return l_Return

var((1,2,3), ('A', 'B', 'C'), ('a', 'b', 'c'))
...
['1, A, a, ', '1, A, b, ', '1, A, c, ', '1, B, a, ', '1, B, b, ', '1, B, c, ', '1, C, a, ', '1, C, b, ', '1, C, c, ',
 '2, A, a, ', '2, A, b, ', '2, A, c, ', '2, B, a, ', '2, B, b, ', '2, B, c, ', '2, C, a, ', '2, C, b, ', '2, C, c, ',
 '3, A, a, ', '3, A, b, ', '3, A, c, ', '3, B, a, ', '3, B, b, ', '3, B, c, ', '3, C, a, ', '3, C, b, ', '3, C, c, ']

ひと通り、Pythonのデコレータについて、でした。

目録

  1. Python / 不便が便利
  2. Python / 内省的(introspective)とはどういうことか
  3. Python / 第一級関数と無名関数
  4. Python / デコレータは愉快
  5. Python / デコレータと引数
  6. Python / デコレータのカスタム
  7. Python / IndentデコレータとChoiceデコレータ

0 件のコメント:

コメントを投稿