3

メタクラスの存在と使用により、クラス作成プロセスの洗練されたハンドルが提供されるため、多くのコード作成から解放されることがわかりました。これをアプリケーションで使用します。そこでは、複数の相互作用するサーバーがインスタンス化されます。詳しく説明するには:

各デバイスは、その操作に固有のサーバー クラスをインスタンス化します。これは、最終的にこの 1 つのクラスのサブクラス (のサブクラス) ですBaseServer。現在、一部のデバイス サーバーには が必要であり、一部のデバイス サーバーには(module: )ThreadedTCPserverが必要です。を使用すると の動作がオーバーライドされるため、それらをすべて同じクラスから派生させることはできません。SimpleTCPServersocketserverThreadingMixinSimpleTCPServer

この動的なクラス構成を処理するためにMetaServerType、BaseServer の基本クラスを as(SimpleTCPServer,)または asとして選択する を作成しました(ThreadedTCPServer,)--> 動的に構成されたサーバー クラスの望ましい結果を生成します! (ウーフー)

ここで質問があります。パラメータが保存されている構成ファイルを使用したいと考えています。これらのパラメータは、MetaServerType によってデフォルトで使用されます。例: config.default_loglevel、または config.default_handler など。また、メタクラスの仕様に従って、(コマンドラインまたはその他の方法で) 個々のサーバーをオーバーライドできます。

プログラム フローを介して渡される構成オブジェクトのインスタンスを 1 つだけ持つことは、良い設計方法ですか? これを行う 1 つの方法は、メタクラスのクラス本体で構成オブジェクトを初期化することですが、私のプログラム フローは別の場所で開始されます。これは、メタクラスが数回呼び出され、構成のさまざまなインスタンスが生成されることを意味します。インポート時にメタクラスが呼び出されているようです(?)

したがって、詳細な回答は大歓迎です:

  1. メタクラスに構成情報を提供するにはどうすればよいですか?
  2. 単一の構成インスタンスをプログラム フローに渡し、編集、更新、そしておそらく最終的に書き込む良い方法は何ですか?
  3. メタクラスへの入力引数を何らかの形で拡張できますMetaclass.__new__(meta, name, bases, attrs)か?
    1. おまけの質問: これにより、(インスタンスではなく) 状態を「一時停止」または「再開」できるように、(サーバーの) 有限状態マシンに一歩近づきますか?
4

1 に答える 1

3

1 - メタクラスに構成情報を提供するにはどうすればよいですか?

これを行うにはいくつかの方法があります - メタクラスは独自のモジュールに存在するため (そして、同じアプリケーションにインポートされた回数に関係なく、モジュールは一度に実行されます)、それらを構成する良い方法です。import構成に使用される「グローバル変数」をセットアップする、呼び出し可能なオブジェクト(同じモジュール上のクラスまたは関数のいずれか)を持つことです。

「グローバル」という名前が由来する C による評判の悪さにもかかわらず、Python のグローバル変数は実際には「モジュール」変数です。つまり、そのモジュール内のすべての関数 (メソッドを含む) がこれらの変数にアクセスできます。他のモジュールの関数またはコードは、そのモジュール名の前に付ける必要があります。

したがって、次のような関数:

def configure_servers(p1, p2,...):
    global opt1, opt2, ...
    opt1 = p1
    opt2 = p2
    (...)

サーバー インスタンスが作成される前に、アプリケーションのエントリ ポイントから呼び出すことができます。(もちろん、p1, p2, ... の代わりに、読み込まれる構成ファイルのパスを渡すこともできます)

2 - 単一の構成インスタンスをプログラム フローに渡して、編集、更新、そしておそらく最終的に書き込む良い方法は何ですか?

メタクラス モジュールのグローバル (モジュール) 変数名は、それらすべてで読み取ることができ、複雑な構成オブジェクトに関連付けることができます。おそらく、上記のような「構成」機能の存在により、この質問は時代遅れになる可能性があります。

しかし、「シングルトン」オブジェクト、つまりインスタンスが 1 つしかないオブジェクトが本当に必要な場合は、簡単な方法で行うことができます。メタクラス ディクショナリに単一のクラスを用意し、そのインスタンス。クラスの代わりに辞書がある場合は、より良く、よりきれいになります。

「実際の」シングルトン オブジェクトを作成する必要がある場合は、クラスを作成して__new__メソッドをオーバーライドし、最初に作成されたインスタンスが常に返されるようにする必要があります。例:

class Singleton(object):
   _instance = None
   def __new__(cls, *args, **kw):
       if cls._instance is not None:
           return cls._instance
       self = object.__new__(cls, *args, **kw)
       cls._instance = self
       return self

3 - メタクラスへの入力引数を Metaclass.new(meta, name, bases, attrs) を超えて何らかの方法で拡張できますか?

言語構文を利用しない。つまり、メタクラスを通常の Python 呼び出しとして呼び出すことは常に可能ですが、それでは言語構文を使用してクラスを記述することができなくなります。クラス本体を辞書として定義して渡す必要がありますattrs。電話。

たとえば、派生例外クラスを作成するには、次のようにします。

MyException = type("MyException", (Exception, ), {})

それ以外の:

class MyException(Exception):
    pass

追加情報をメタクラスに渡す通常の方法は、クラス本体で固定名の属性を使用することです。次に、メタクラスはこれらの属性を内部でチェックし、attrsそれらを使用します。attrsその後、結果のクラスに保持するか、この時点で辞書から削除するかを選択できます。

メタクラスに渡す必要がある情報が実行時にしかわからない場合、これらの属性は他の (モジュール レベルの) 変数を指すか、クラスの作成時に評価される Python 式を含むことができます。

mod_server_type = "TCP"

class YAServer(ParentServer):
   __metaclass__ = ServerMetaBase
   _sever_type = mod_server_type
   with open("config_file") as config:
      _server_params = pickle.load(config)
   del config

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

上記の例では、メタクラスは属性_server_type_server_params 属性を使用して、クラスの作成をさらに制御できます。

于 2011-04-04T00:01:07.547 に答える