高校化学2924392 views
りんご209490 views
中学理科1630641 views
中学英語811710 views
雑学1473612 views
いろは3010814 views
世界の国564520 views
ヒストリア290598 views
高校生物551766 views
高校倫理1440106 views
Help
Tools
NewsSpreadsheetCalendarBookkeepingMarkdown TablesSlidesTier ListPen ToolIllustrationCrayonWatercolorPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchSwirl EffectLine ArtOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsRolling DiceCross SectionsMotion PathMechanicsWavesElectromagnetic WavesCapacitorsLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHOrganic Reaction MapPeriodic TableComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseMuscle ContractionHormones and HomeostasisRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic TheoryShogi StrategyPiano Rhythm Game

English

Python のメタクラスで関数の自動登録を実装する

メタクラスを使うと、クラス定義時に関数やメソッドを自動的に登録する仕組みを作れます。プラグインシステムやコマンドパターンの実装に有用です。

基本的なアイデア

クラスが定義されるとき、メタクラスの __new__ または __init__ が呼ばれます。ここでクラスの属性を走査し、特定の条件を満たす関数を登録できます。

class PluginMeta(type):
    registry = {}
    
    def __new__(mcs, name, bases, namespace):
        cls = super().__new__(mcs, name, bases, namespace)
        if name != "PluginBase":
            mcs.registry[name] = cls
        return cls

class PluginBase(metaclass=PluginMeta):
    pass

class EmailPlugin(PluginBase):
    def execute(self):
        print("Sending email")

class SMSPlugin(PluginBase):
    def execute(self):
        print("Sending SMS")

print(PluginMeta.registry)
# {'EmailPlugin': <class 'EmailPlugin'>, 'SMSPlugin': <class 'SMSPlugin'>}

特定のデコレータが付いたメソッドを登録

メソッドにマーカーを付けて、それを自動収集するパターンです。

def command(name):
    def decorator(func):
        func._command_name = name
        return func
    return decorator

class CommandMeta(type):
    def __new__(mcs, name, bases, namespace):
        cls = super().__new__(mcs, name, bases, namespace)
        cls._commands = {}
        for attr_name, attr_value in namespace.items():
            if hasattr(attr_value, "_command_name"):
                cls._commands[attr_value._command_name] = attr_value
        return cls

class Bot(metaclass=CommandMeta):
    @command("hello")
    def say_hello(self):
        return "Hello!"
    
    @command("bye")
    def say_goodbye(self):
        return "Goodbye!"

print(Bot._commands)
# {'hello': <function Bot.say_hello>, 'bye': <function Bot.say_goodbye>}

init_subclass による代替

Python 3.6 以降では、メタクラスを使わずに __init_subclass__ で同様のことができます。

class PluginBase:
    registry = {}
    
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        PluginBase.registry[cls.__name__] = cls

メタクラスはより強力ですが、__init_subclass__ で十分な場合はそちらを選ぶとコードがシンプルになります。