5

私が現在取り組んでいるプロジェクトの1つでは、クライアントによってインスタンス化できず、特定のインターフェースを介してのみインスタンスを提供できるクラスを作成することを考えていました。つまり、クライアントはそれ以上のインスタンスを作成できません。次のようなハッカー:

>>> try:
...     raise WindowsError
... except:
...     foo = sys.exc_info()
... 
>>> foo
(<type 'exceptions.WindowsError'>, WindowsError(), <traceback object at 0x0000000005503A48>)
>>> type(foo[2])()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot create 'traceback' instances

彼がそれを持ったら。

インスタンス化できないクラスの作成に成功しました。すなわち

>>> class Foo():
...     def __init__(self):
...         raise TypeError("cannot create 'Foo' instances")
... 
>>> bar = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: cannot create 'Foo' instances
>>> bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined

しかし、このすべての同じ定義を使用して、クラスのインスタンスを作成するにはどうすればよいでしょうか?

もちろん、私はこのようなことをすることができます:

>>> class Foo():
...     def __init__(self, instantiate = False):
...         if not instantiate:
...               raise TypeError("cannot create 'Foo' instances")

しかし、私はそれが十分にエレガントだとは思いませんし、クライアントがそれをさらにインスタンス化するのを完全に妨げるわけでもありません。いいえ、私はそのための C++ モジュールを構築する道を進んでいません。

そのようなことを達成する方法について何か提案はありますか? import abc?

Martijnの質問に答え、完全を期すための簡単な理由:

実際には、問題の特定の関連クラスのインスタンスをツリー内のノードと見なすことができ、親と子の両方が接続されたままになり、相互に依存し、認識し、すべてのオブジェクト全体で単一の一意のルートを持つことができます。 python のインスタンス (使用により保証されますpackage)。特定のノードの状態が変化すると、それに応じて、他のノードが自分自身と接続先のデータベースを更新することになります。それとは別に、私はそのようなものをどのように配置できるか知りたいと思っていました (tracebackクラスは私をからかっていました)。

4

1 に答える 1

13

あなたがしていることは悪い考えです、あなたはそれをすべきではありません。他のより良い解決策があると確信しています。とにかく自分のやり方で行くことに決めた場合(そうすべきではありません)、を使用せずにオブジェクトを作成する方法は次の__init__()とおりです。


Python のオブジェクトは__new__()メソッドで作成されます。このメソッド__init__()は、 によって作成されたオブジェクトのみを編集します__new__()。たとえば、__init__()通常、オブジェクトのいくつかの属性を初期化します。

x = Foo()何が起こるかを宣言すると、次のようになります。

  1. x = object.__new__(Foo)最初に呼び出されてオブジェクトを作成します。
  2. Foo.__init__(x)2 番目に呼び出され、いくつかの属性などを既存のオブジェクトに初期化するだけです。

これは、電話をかける必要がないことを意味しますFoo()(結果として、電話__init__()もかけます)。代わりに、直接呼び出すことができます__new__()

class Foo(object):
    def __init__(self):
        raise TypeError("Cannot create 'Foo' instances.")

>>> x = object.__new__(Foo)
>>> x
<__main__.Foo object at 0x02B074F0>

私たちのは、属性のないxのインスタンスになり、クラスで定義された任意のメソッドを使用できます。FooFoo

__init__必要に応じて、属性を初期化するための独自の置換関数を作成できます。

def init_foo(foo, name):
    foo.name = name

>>> init_foo(x, "Mike")
>>> x.name
'Mike'

もちろん、これはFooのインスタンス メソッドでもあります。

class Foo(object):
    def __init__(self):
        raise TypeError("Cannot create 'Foo' instances.")

    def init(self, name):
        self.name = name

>>> x = object.__new__(Foo)
>>> x.init("Mike")
>>> x.name
'Mike'

さらに一歩進んで、classmethod1 回の呼び出しでオブジェクトを作成するために a を使用することもできます。

class Foo(object):
    def __init__(self):
        raise TypeError("Cannot create 'Foo' instances.")

    @classmethod
    def new(cls, name):
        obj = object.__new__(cls)
        obj.name = name
        return obj

>>> x = Foo.new("Mike")
>>> x.name
'Mike'
于 2013-04-23T13:54:58.597 に答える