__slots__
これは珍しい質問ですが、クラスに追加した属性に基づいて、クラスの属性を動的に生成したいと思います。
たとえば、クラスがある場合:
class A(object):
one = 1
two = 2
__slots__ = ['one', 'two']
引数を手動で指定するのではなく、動的にこれを実行したいのですが、どうすればよいですか?
__slots__
これは珍しい質問ですが、クラスに追加した属性に基づいて、クラスの属性を動的に生成したいと思います。
たとえば、クラスがある場合:
class A(object):
one = 1
two = 2
__slots__ = ['one', 'two']
引数を手動で指定するのではなく、動的にこれを実行したいのですが、どうすればよいですか?
スロットを定義しようとしている時点では、クラスはまだ構築されていないため、Aクラス内から動的に定義することはできません。
必要な動作を得るには、メタクラスを使用してAの定義をイントロスペクトし、slots属性を追加します。
class MakeSlots(type):
def __new__(cls, name, bases, attrs):
attrs['__slots__'] = attrs.keys()
return super(MakeSlots, cls).__new__(cls, name, bases, attrs)
class A(object):
one = 1
two = 2
__metaclass__ = MakeSlots
注意すべき非常に重要なことの1つは、これらの属性がクラスに残っている場合、__slots__
生成は役に立たないことです...わかりました、おそらく役に立たないことではありません-クラス属性が読み取り専用になります。おそらくあなたが望むものではありません。
簡単な方法は、「わかりました。初期化してから、非表示にします」と言うことです。素晴らしい!これを行う1つの方法は次のとおりです。
class B(object):
three = None
four = None
temp = vars() # get the local namespace as a dict()
__slots__ = temp.keys() # put their names into __slots__
__slots__.remove('temp') # remove non-__slots__ names
__slots__.remove('__module__') # now remove the names from the local
for name in __slots__: # namespace so we don't get read-only
del temp[name] # class attributes
del temp # and get rid of temp
これらの初期値を維持したい場合は、もう少し作業が必要です...考えられる解決策の1つは次のとおりです。
class B(object):
three = 3
four = 4
def __init__(self):
for key, value in self.__init__.defaults.items():
setattr(self, key, value)
temp = vars()
__slots__ = temp.keys()
__slots__.remove('temp')
__slots__.remove('__module__')
__slots__.remove('__init__')
__init__.defaults = dict()
for name in __slots__:
__init__.defaults[name] = temp[name]
del temp[name]
del temp
ご覧のとおり、メタクラスなしでこれを行うことは可能ですが、誰がそのすべての定型文を望んでいますか?メタクラスは間違いなくこれをクリーンアップするのに役立ちます:
class MakeSlots(type):
def __new__(cls, name, bases, attrs):
new_attrs = {}
new_attrs['__slots__'] = slots = attrs.keys()
slots.remove('__module__')
slots.remove('__metaclass__')
new_attrs['__weakref__'] = None
new_attrs['__init__'] = init = new_init
init.defaults = dict()
for name in slots:
init.defaults[name] = attrs[name]
return super(MakeSlots, cls).__new__(cls, name, bases, new_attrs)
def new_init(self):
for key, value in self.__init__.defaults.items():
setattr(self, key, value)
class A(object):
__metaclass__ = MakeSlots
one = 1
two = 2
class B(object):
__metaclass__ = MakeSlots
three = 3
four = 4
これで、すべての面倒な作業がメタクラスに保持され、実際のクラスは読みやすく(うまくいけば!)理解しやすくなります。
属性以外にこれらのクラスに何かを含める必要がある場合は、それが何であれ、ミックスインクラスに入れることを強くお勧めします。最終クラスに直接入れると、メタクラスがさらに複雑になります。