あなたが本当に欲しいものを言うのは難しいです。しかし、新しいクラスが登場するたびにプロパティを追加するメタクラスは、あなたが必要とするものであればよりうまくいくかもしれません。
あなたのコードを理解できれば、新しいインスタンスを作成すると(新しいインスタンスを作成し、他のインスタンスの参照を取得する)古いクラスには新しいインスタンスへの参照が移入されません。第二に
しかし、dinamically __new__
inisdeプロパティを作成することがハックようだ - しかし、あなたはただそれほど複雑なコードのメタクラス__getattr__
と__dir__
メソッドを実装することができます
シンプルなバージョンは、クラスのためではなく、そのインスタンスのために働きます - インスタンスは、メタクラスの__getattr__
をトリガしませんので:
class Pipeable(type):
_classes = {}
def __new__(metacls, name, bases, namespace, **kwds):
cls = type.__new__(metacls, name, bases, namespace)
metacls._classes[name] = cls
return cls
def __getattr__(cls, attr):
classes = cls.__class__._classes
if attr not in classes:
raise AttributeError
def pipe_within(*args, **kwargs):
return cls(*args, op=classes[attr], **kwargs)
print('piping...')
return pipe_within
def __dir__(cls):
regular = super().__dir__()
return sorted(regular + list(cls.__class__._classes.keys()))
class Op(metaclass=Pipeable):
def __init__(self, op=None):
if op is not None:
print('piped!')
self.op = op
Op.Op()
(だけでなく、時間をかけて私はメタクラスで使用する命名規則は、このパラメータを選んだことに注意してください - ほとんどの彼らの方法はで作成したクラスを取るよう彼らは普通のクラスの "自己"の代わりに、私はこの命名法に従うのが簡単だと分かります。しかし、必ずしも「正しい」とは限りません)
しかし、作成されたクラスに直接__dir__
と__getattr__
を作成することで、インスタンスに対して機能させることができます。あなたが作成しているクラスはすでにスーパークラスであっても、__getattr__
またはカスタム__dir__
を持っているため、ラップする必要があります。確保することにより、それが「正しいことを行う」 -
class Pipeable(type):
_classes = {}
def __new__(metacls, name, bases, namespace, **kwds):
cls = type.__new__(metacls, name, bases, namespace)
metacls._classes[name] = cls
original__getattr__ = getattr(cls, "__getattr__", None)
if hasattr(original__getattr__, "_metapipping"):
# Do not wrap our own (metaclass) implementation of __getattr__
original__getattr__ = None
original__dir__ = getattr(cls, "__dir__") # Exists in "object", so it is always found.
# these two functions have to be nested so they can get the
# values for the originals "__getattr__" and "__dir__" from
# the closure. These values could be set on the class created, alternatively.
def __getattr__(self, attr):
if original__getattr__:
# If it is desired that normal attribute lookup have
# less precedence than these injected operators
# move this "if" block down.
try:
value = original__getattr__(self, attr)
except AttributeError:
pass
else:
return value
classes = self.__class__.__class__._classes
if attr not in classes:
raise AttributeError
def pipe_within(*args, **kwargs):
return cls(*args, op=classes[attr], **kwargs)
print('piping...')
return pipe_within
__getattr__._pipping = True
def __dir__(self):
regular = original__dir__(self)
return sorted(regular + list(self.__class__.__class__._classes.keys()))
__dir__.pipping = True
if not original__getattr__ or not hasattr(original__getattr__, "_pipping"):
cls.__getattr__ = __getattr__
if not hasattr(original__dir__, "_pipping"):
cls.__dir__ = __dir__
return cls
def __getattr__(cls, attr):
classes = cls.__class__._classes
if attr not in classes:
raise AttributeError
def pipe_within(*args, **kwargs):
return cls(*args, op=classes[attr], **kwargs)
print('piping...')
return pipe_within
__getattr__._metapipping = True
def __dir__(cls):
regular = super().__dir__()
return sorted(regular + list(cls.__class__._classes.keys()))
class Op(metaclass=Pipeable):
def __init__(self, op=None):
if op is not None:
print('piped!')
Op().Op()
だから、これは長いことになった。そして、私たちは__dir__
自身と__getattr__
ので、いくつかの余分なケアを再ラップする必要はありません階層内のすべてのクラスとインスタンスは、作成順序に関係なく、互いに見ることができます。
また、どのような複雑さを補うことは正しくクラス階層に__getattr__
と__dir__
の他の可能なカスタマイズをラップしている - あなたはそれらのいずれかのカスタマイズを取得しない場合、これは単純な大きさの順になります
class Pipeable(type):
_classes = {}
def __new__(metacls, name, bases, namespace, **kwds):
cls = type.__new__(metacls, name, bases, namespace)
metacls._classes[name] = cls
def __getattr__(self, attr):
classes = self.__class__.__class__._classes
if attr not in classes:
raise AttributeError
def pipe_within(*args, **kwargs):
return cls(*args, op=classes[attr], **kwargs)
print('piping...')
return pipe_within
def __dir__(self):
regular = original__dir__(self)
return sorted(regular + list(self.__class__.__class__._classes.keys()))
cls.__getattr__ = __getattr__
cls.__dir__ = __dir__
return cls
def __getattr__(cls, attr):
classes = cls.__class__._classes
if attr not in classes:
raise AttributeError
def pipe_within(*args, **kwargs):
return cls(*args, op=classes[attr], **kwargs)
print('piping...')
return pipe_within
def __dir__(cls):
regular = super().__dir__()
return sorted(regular + list(cls.__class__._classes.keys()))
記述子はインスタンスではなくクラスになければなりません。 – user2357112