0

Pythonで列挙を作成しようとしています。私はいくつかの解決策を見てきました( ここで@alec thomasによる2番目の回答が最も興味をそそられました)が、列挙を不変にしたいと思います。不変のpython レシピを見つけましたが、dict のようなキーと値の関連付けが必要です。

ダックパンチングを使用して、またはプロパティAttributeErrorを呼び出そうとした場合にスローするプロパティをクラスに追加しようとしていました。fsetfdel

fgetプロパティの機能を定義する際に問題が発生しました。これが私がこれまでに持っているコードです:

def enum(*sequential, **named):
    # Build property dict
    enums = dict(zip(sequential, range(len(sequential))), **named)

    # Define an errorhandler function
    def err_func(*args, **kwargs):
        raise AttributeError('Enumeration is immutable!')

    # Create a base type
    t = type('enum', (object,), {})

    # Add properties to class by duck-punching
    for attr, val in enums.iteritems():
        setattr(t, attr, property(lambda attr: enums[attr], err_func, err_func))

    # Return an instance of the new class
    return t()

e = enum('OK', 'CANCEL', 'QUIT')
print e
print e.OK
print e.CANCEL
print e.QUIT

# Immutable?
e.OK = 'ASDF'  # Does throw the correct exception
print e.OK

これからの出力は次のとおりです。

<__main__.enum object at 0x01FC8F70>
Traceback (most recent call last):
  File "enum.py", line 24, in <module>
    print e.OK
  File "enum.py", line 17, in <lambda>
    setattr(t, attr, property(lambda attr: enums[attr], err_func, err_func))
KeyError: <__main__.enum object at 0x01FC8F70>

おそらく、これは列挙を作成する最良の方法ではありませんが、短いので、このダック パンチ/モンキー パッチの概念全体をもっと探求したいと思いました。

4

2 に答える 2

1

当面の問題は、 のgetterpropertyではselfなく、唯一のパラメーターとして使用されることattrです。したがって、lambda self: val代わりに次のようなものを使用する必要があります。

ただし、反復ごとに変化するnamelambdaをバインドするため、これは機能しません。したがって、何らかの方法でラップする必要があります。 val

def getter(val):
    return lambda self: val

for attr, val in enums.iteritems():
    setattr(t, attr, property(getter(val), err_func, err_func))
于 2012-10-18T18:00:34.220 に答える
0

最終的な実装 (@nneonneo に感謝)。

  • 重複する列挙キーをチェックします
  • 列挙型が空かどうかを確認します
  • 列挙項目の削除または変更を許可しない

    def enum(*sequential, **named):
        # Check for duplicate keys
        names = list(sequential)
        names.extend(named.keys())
        if len(set(names)) != len(names):
            raise KeyError('Cannot create enumeration with duplicate keys!')
    
        # Build property dict
        enums = dict(zip(sequential, range(len(sequential))), **named)
        if not enums:
            raise KeyError('Cannot create empty enumeration')
    
        # Function to be called as fset/fdel
        def err_func(*args, **kwargs):
            raise AttributeError('Enumeration is immutable!')
    
        # function to be called as fget
        def getter(cls, val):
            return lambda cls: val
    
        # Create a base type
        t = type('enum', (object,), {})
    
        # Add properties to class by duck-punching
        for attr, val in enums.iteritems():
            setattr(t, attr, property(getter(t, val), err_func, err_func))
    
        # Return an instance of the new class
        return t()
    
于 2012-10-18T19:14:02.333 に答える