2016-12-19 20 views
0

いくつかのコードをpython 3からpython 2に変換する必要があります。__prepare__メソッドがクラスdictの関数を設定するメタクラスがあります。 __new__メソッドに変換しようとしましたが、SET_DEFAULTS機能を設定できません。それは可能ですか?__prepare__をPythonのメタクラスに置き換える方法2

私はあなたがそれを行うことができない、初期化

通常
class UazeMessageMeta (type): 

    @staticmethod 
    def __prepare__(name, bases, **kwargs): 
     d = {} 
     for b in bases: 
      if 'DEFAULT_VALUES' in dir(b): 
       d.update(b.DEFAULT_VALUES) 
     return { 
      'SET_DEFAULTS' : lambda **kwargs : d.update(kwargs), 
      'DEFAULT_VALUES' : d 
     } 

class UazeMessage (bytearray): 
    """ 
    A basic message (header only). This class also provides the 
    base behavior for all messages. 
    """ 
    # gp test py27 ----------------- 
    __metaclass__ = UazeMessageMeta 

    # ------------ 

    priority = MessageField(0, 1, Priority) 
    sequence = MessageField(1, 7, FieldType.UNSIGNED) 
    readWrite = MessageField(8, 1, ReadWriteFlag) 
    ack   = MessageField(9, 2, Ack) 
    channel  = MessageField(11, 2, FieldType.UNSIGNED) 
    category = MessageField(13, 3, Category) 
    item  = MessageField(16, 8, FieldType.UNSIGNED) 

    DEFAULT_SIZE = 3 

    def __init__(self, init=0, setdefaults=None, **kwargs): 
     # If init is still or None, initialize the size of the message 
     # using the default size provided in the class. 
     if init == None or init == 0: 
      init = type(self).DEFAULT_SIZE 
     super(UrmpMessage,self).__init__(init) 
     # Set any default or provided fields. 
     initval = {} 
     if (isinstance(init, int) and setdefaults != False) or \ 
      (setdefaults == True): 
      initval = dict(self.DEFAULT_VALUES) 
     initval.update(kwargs) 
     for key, value in initval.items(): 
      setattr(self, key, value) 

class ResetBase (UazeMessage): 
    """Reset response/request structure.""" 

    resetType = MessageField(24, 8, ResetType) 

    SET_DEFAULTS(
     category = Category.OPERATION, 
     resetType = ResetType.SOFT, 
     item  = 0) 

    DEFAULT_SIZE = 4 
+1

あなたの投稿のインデントを確認してください。 Pythonでは重要です。 – jonrsharpe

+0

私は更新しました、ご迷惑をおかけして申し訳ありません。 – WatchdogReset

+0

少なくとも1つのクラスが不足しているようです。 [mcve]を挙げてください。 – jonrsharpe

答えて

1

NameError: name 'SET_DEFAULTS'を持っています。 __prepare__の導入はPython3の基本的な変更です。これにより、クラス本体自体が解析される名前空間のカスタマイズが可能になります。

私はそれを行う主な動機は、(メタクラス__new__または__init__方法で)クラスの初期化は、の宣言順の恩恵を受けることができるように、OrderedDictでクラス本体内のローカル名前空間を交換する方法を提供することだったと思いますメソッドとクラス本体内の属性Python 3.6(今週の最終バージョン)は、クラス本体でデフォルトの辞書が使用されており、メタクラスはもはや必要ではないと考えられるべきです。

__prepare__メカニズムは、それよりも柔軟性があり、より単純な使用法では、クラス本体の辞書に予め定められた値を単純にあらかじめ設定することができます。それがあなたのプロジェクトの行いなのです。

しかし、このコードは特殊な辞書クラスを必要とせず、通常の辞書を事前に入力するだけで、辞書と基本クラスをパラメータとして取り込む通常の関数を記述し、その辞書の既存のコードに従ってください。__prepare__メソッド。次に、クラス本体の先頭にその関数を呼び出し、locals()呼び出しによって返された辞書をパラメータとして渡します。つまり、クラス本体の名前空間はいつものように埋められます。

def prepare(bases, dct): 
    for base in bases: 
     dct["special_attribute"] = {} 
     if "special_attribute" in base.__dict__: 
      dct["special_attribute" ].update(base.__dict__["special_attribute"]) 
    ... 

class MyClass(bytearray): 
    prepare((bytearray,), locals()) 
    ... 

言ったことすべてが、私は実際に可能であればこの時点でPython2にプロジェクトをバックポートしないようにしようすることをアドバイス - それはちょうどあなたのコードベースが複雑になります - と一貫した方法で新しい機能を使用してあきらめて(たとえば、このヒントを__prepare__の代わりに)

+0

あなたの説明をありがとう - それは私が探していたことでした。私はプロジェクトのPython 2と3をコンパチブルにしようとしますが、メタクラスに関しては難しいかもしれません。 – WatchdogReset

+0

Python 3.6で注文されているデフォルトの辞書は、必ずしもPython 3.6+ *まだ*。公式の声明はこれが未来で必ずしもサポートされるつもりはない、きちんとした機能であることがあります。他の言葉では、プログラマは注意してください。 – KronoS

+0

リテラルdictのデフォルトの順序はまだ議論されていますが、クラス本体内での順序付けは別個の問題です(実装レベルでは混在していますが)。属性のクラス本体宣言内の順序は、PEP 520で定義され、現在は言語仕様の一部です。 – jsbueno

関連する問題