LoginSignup
1
2

More than 3 years have passed since last update.

pythonでtraitみたいなこと

Posted at

Overview

ruby の extend みたいな感じにやりたい話。

$ python -V
Python 3.7.2

振る舞いだけ別で定義して後から mixin みたいなことは、言語の機能としてはできないっぽいけど、
type でその場で class 生成して、対象の __class__ に設定すると動的多重継承みたいにできるらしい。

委譲で済むならその方が良いと思うけど。

a.py

class TraitA:
    def m1(self):
        print(self, "m1")

    def m2(self):
        print(self, "m2")

class TraitB:
    def m1(self):
        print(self, "m1")

    def m2(self):
        print(self, "m2")


class Base:

    @classmethod
    def factory(cls, val):
        x = cls(val)

        if val == "A":
            trait = TraitA
        else:
            trait = TraitB

        x.__class__ = type("{}+{}".format(cls.__name__, trait.__name__), (cls, trait), {})

        return x

    def __init__(self, val):
        self.val = val

    def __repr__(self):
        return "<{}>\t{}".format(self.__class__.__name__, str(self.__dict__))

    def is_A(self):
        return isinstance(self, TraitA)

    def is_B(self):
        return isinstance(self, TraitB)

if __name__ == "__main__":
    a = Base.factory("A")
    a.m1()
    a.m2()
    print(a.is_A())
    print(a.is_B())

    print("-"*30)

    b = Base.factory("B")
    b.m1()
    b.m2()
    print(b.is_A())
    print(b.is_B())

実行


$ python a.py
<Base+TraitA>   {'val': 'A'} m1
<Base+TraitA>   {'val': 'A'} m2
True
False
------------------------------
<Base+TraitB>   {'val': 'B'} m1
<Base+TraitB>   {'val': 'B'} m2
False
True
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2