2

装飾されたクラスからクラスを継承できるように、クラスを正しい方法で装飾する方法は? 正しい方法はありますか?

私が次のようなことをするなら:

def singleton(cls):                            
    inst = {}                                  
    def get(*args, **kwargs):                  
        cls_id = id(cls)                       
        if cls_id not in inst:                 
            inst[cls_id] = cls(*args, **kwargs)
        return inst[cls_id]                    
    return get 


@singleton
class A(object):
    @classmethod
    def cls_meth(cls):
        return cls                             

呼び出す前にこれが関数であるため、上記のクラスからクラスを継承する機会はありません。クラスメソッドの同じ問題、関数にはクラスメソッドがありません。

class B(A): # No way! `A` is the function!
    pass

A.cls_meth() # AttributeError: 'function' object has no attribute 'cls_meth'    

私も次のようなことをしています:

class SingletonDecorator(object):                        
    inst = {}                                            
    def __init__(self, cls):                             
        self.cls = cls                                   

    def __call__(self, *args, **kwargs):                 
        cls_id = id(self.cls)                            
        if cls_id not in self.inst:                      
            self.inst[cls_id] = self.cls(*args, **kwargs)
        return self.inst[cls_id]                         


@SingletonDecorator
class A(object):
    pass

クラスからAクラスを継承すると、クラスではSingletonDecoratorなくクラスから継承されAます。

class B(A): # No no no! I do not need a `SingletonDecorator` child class...
    pass

を介してクラスインスタンスを変更する方法があります__metaclass__が、それはまったく別の話です...

4

4 に答える 4

1

デコレーターは、元のクラス (またはそのサブクラス) を返して、さらにサブクラス化できるようにする必要があります。デコレーターとして使用すると、デコレーターはそれ自体のインスタンスを返します (これがクラス呼び出しのデフォルトの動作であるため)。

たとえば、次のようなものです。

def singleton(cls):
    class C(cls):
        _instance = None
        def __new__(c, *args, **kwargs):
            if type(c._instance) != c:
                c._instance = cls.__new__(c, *args, **kwargs)
            return c._instance
    C.__name__ = cls.__name__
    return C

__new__()これは、シングルトン マジックを実行するオーバーライドされたメソッドを持つ元のクラスのサブクラスを返します。このクラスはサブクラス化可能です。

ただし、シングルトンを作成する理由はほとんどありません。多くの場合、これは排除したほうがよいグローバルな状態を隠す方法にすぎません。

于 2012-11-26T22:56:06.317 に答える
0

デコレータは、クラスをサブクラス化するためにクラスを返す必要があります。

>>> def decorator(cls):
...     class Stuff(cls):
...         @classmethod
...         def print_result(kls):
...             print 'results= %s' % kls.results
...     return Stuff
... 
>>> class Foo(object):
...     results = 'grade A'
...     @classmethod
...     def print_result(cls):
...         print cls.results
... 
>>> 
>>> @decorator
... class Bar(Foo):
...     pass
... 
>>> class Baz(Bar):
...     def frobnicate(self):
...         pass
... 
>>> 
>>> Baz.print_result
<bound method type.print_result of <class '__main__.Baz'>>
>>> Baz.print_result()
results= grade A
>>> Foo.print_result
<bound method type.print_result of <class '__main__.Foo'>>
>>> Foo.print_result()
grade A
>>> 
于 2012-11-26T23:47:55.420 に答える
0

この結果についてはほとんど考えていません。

class SD(object):                                          
    """ The right way to decorate classes """              
    inst = {}                                              
    def __init__(self, cls):                               
        self.__dict__.update(cls.__dict__)                 
        self.__name__ = cls.__name__                       
        self.cls = cls                                     

    def __call__(self, *args, **kwargs):                   
        if self.cls not in self.inst:                      
            self.inst[self.cls] = self.cls(*args, **kwargs)
        return self.inst[self.cls]                         

@kindall の回答とコメントに触発されて、別の解決策にたどり着きました。ちなみに、シングルトンは単なる例であり、質問とは関係ありません。

于 2012-11-29T15:47:36.647 に答える
0

装飾されたクラスから継承できるようにするには、デコレーターがラッパーではなく、装飾されたクラス自体を返すようにする必要があります。__new__()-operatorをオーバーロードすることで、このクラスからの新しいオブジェクトの作成を操作できます。これにより、デコレータ自体がクラスの場合、デコレータ メソッドを呼び出すこともできます。もちろん、デコレータにも継承を使用できます。

完全な例については、

装飾されたクラスからの継承

于 2015-10-01T07:51:24.610 に答える