4

私は python (3.2+) プラグイン ライブラリを作成しており、構成ファイルから自動的に処理されるいくつかの変数を作成する関数を作成したいと考えています。

ユース ケースは次のとおりです (クラス変数)。

class X:
    option(y=0)
    def __init__(self):
        pass

(インスタンス変数):

class Y:
    def __init__(self):
        option(y=0)

オプションのドラフト コードは次のとおりです。

def option(**kwargs):
    frame   = inspect.stack()[1][0]
    locals_ = frame.f_locals
    if locals_ == frame.f_globals:
        raise SyntaxError('option() can only be used in a class definition')

    if '__module__' in locals_:
        # TODO

    else:
        for name, value in kwargs.items():
            if not name in locals_["self"].__class__.__dict__:
                setattr(locals_["self"].__class__, name, VirtualOption('_'+name, static=False))
            setattr(locals_["self"], '_'+name,value)

オプションがクラス変数として宣言されている場合、最初のケースに問題があります。この関数が使用されたクラスへの参照を何らかの方法で取得することは可能ですか (例ではクラス X へ)?

4

2 に答える 2

2

クラスがまだ作成されていないため、クラスへの参照を取得できません。親フレームは一時的な関数を指しており、その関数がlocals()完了するとクラス本体として使用されます。

そのため、親フレームのローカル変数に変数を追加するだけで、クラスの構築が完了するとこれらがクラスに追加されます。

短いデモ:

>>> def foo():
...     import sys
...     flocals = sys._getframe(1).f_locals
...     flocals['ham'] = 'eggs'
... 
>>> class Bar:
...     foo()
... 
>>> dir(Bar)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__locals__', '__lt__', '__module__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'ham']
>>> Bar.ham
'eggs'
于 2013-01-04T16:36:38.077 に答える
0

ここではメタクラスが適しているように思われます。

python2.x構文

def class_maker(name,bases,dict_):
    dict_['y']=0
    return type(name,bases,dict_)

class X(object):
    __metaclass__ = class_maker
    def __init__(self):
        pass

print X.y
foo = X()
print foo.y

python3.x構文

python3はmetaclassクラス定義でキーワードを使用しているようです。

def class_maker(name,bases,dict_):
    dict_['y']=0
    return type(name,bases,dict_)

class X(metaclass=class_maker):
    def __init__(self):
        pass

print( X.y )
foo = X()
print( foo.y )
print( type(foo) )

または、あなたがあなたの質問に持っているものの線に沿ってもっと:

def class_maker(name,bases,dict_,**kwargs):
    dict_.update(kwargs)
    return type(name,bases,dict_)

class X(metaclass=lambda *args: class_maker(*args,y=0)):
    def __init__(self):
        pass

print( X.y )
foo = X()
print( foo.y )
print( type(foo) )
于 2013-01-04T16:21:30.590 に答える