web-dev-qa-db-ja.com

Pythonのプライベートコンストラクター

どこからではなく、クラスの静的関数によってのみ呼び出されるプライベートコンストラクターを作成するにはどうすればよいですか?

58
user1057793

プライベートコンストラクターを作成するにはどうすればよいですか?

本質的に、それは不可能です両方ともpythonは、あなたがその他OOP言語、およびpythonは強制プライバシーではないため、特定のメソッド/プロパティがshouldプライベートと見なされます。詳しく説明します...

最初:pythonで見つけることができるコンストラクターに最も近いものは ___new___ method ですが、これはほとんど使用されません(通常は___init___、作成されたばかりのオブジェクトを変更します(実際、最初のパラメーターとして既にselfを持っています)。

とにかく、pythonは全員が同意する大人であるという仮定に基づいているため、他の言語のようにprivate/publicは強制されません。

他のレスポンダーが言及しているように、「プライベート」であるメソッドは通常、1つまたは2つのアンダースコア(__private_または___private_)が先頭に追加されます。 2つの違いは、後者はメソッドの名前をスクランブルするため、オブジェクトのインスタンス化の外部から呼び出すことはできませんが、前者はそうではありません。

たとえば、クラスA_private(self)__private(self)の両方を定義している場合:

_>>> a = A()
>>> a._private()   # will work
>>> a.__private()  # will raise an exception
_

通常、単一のアンダースコアを使用する必要があります。特にユニットテストの場合、アンダースコアが2つあると非常に注意が必要になります。

HTH!

28
mac

_および__プレフィックスは、オブジェクトのインスタンス化を特定の「ファクトリー」に制限するソリューションを提供しませんが、Pythonは強力なツールボックスであり、望ましい振る舞いは複数の方法で実現できます(Zの@Jesse Wが示したように)。クラスを公開する(isinstanceなどを許可する)が、クラスによってのみ構築が可能であることを保証する可能なソリューションを次に示します。 -メソッド:

class OnlyCreatable(object):

    __create_key = object()

    @classmethod
    def create(cls, value):
        return OnlyCreatable(cls.__create_key, value)

    def __init__(self, create_key, value):
        assert(create_key == OnlyCreatable.__create_key), \
            "OnlyCreatable objects must be created using OnlyCreatable.create"
        self.value = value

createクラスメソッドを使用してオブジェクトを作成します。

>>> OnlyCreatable.create("I'm a test") 
<__main__.OnlyCreatable object at 0x1023a6f60>

createクラスメソッドの作成を使用せずにオブジェクトを構築しようとすると、アサーションのために失敗します。

>>> OnlyCreatable(0, "I'm a test")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 11, in __init__
AssertionError: OnlyCreatable objects can only be created using OnlyCreatable.create

createクラスメソッドの作成を模倣してオブジェクトを作成しようとすると、OnlyCreatable.__createKeyのコンパイラーのマングリングが原因で失敗します。

>>> OnlyCreatable(OnlyCreatable.__createKey, "I'm a test")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'OnlyCreatable' has no attribute '__createKey'

クラスメソッドの外でOnlyCreatableを構築する唯一の方法は、OnlyCreatable.__create_keyの値を知ることです。このクラス属性の値は実行時に生成され、名前には__という接頭辞が付き、アクセス不可としてマークされるため、この値を取得したりオブジェクトを構築したりすることは事実上「不可能」です。

17
Adam

まだ誰もこれに言及していないので、namesがどのスコープで見えるかをかなり制御できます-そして、lots使用可能なスコープ。ここにあります  threeクラスの構築をファクトリメソッドに制限する他の方法:

#Define the class within the factory method
def factory():
  class Foo:
    pass
  return Foo()

OR

#Assign the class as an attribute of the factory method
def factory():
  return factory.Foo()
class Foo:
  pass
factory.Foo = Foo
del Foo

(注:これにより、クラスを外部から参照できます(たとえば、isinstanceチェック用)が、直接インスタンス化することになっていないことは明らかです。)

OR

#Assign the class to a local variable of an outer function
class Foo:
  pass
def factory_maker():
  inner_Foo=Foo
  def factory():
    return inner_Foo()
  return factory
factory = factory_maker()
del Foo
del factory_maker

これにより、impossible(少なくとも、少なくとも1つのマジック(二重アンダースコア)プロパティを使用せずに)Fooクラスにアクセスできますが、複数の関数がそれを使用できるようにします(グローバルFoo名を削除する前にそれらを定義することにより)。

9
Jesse W at Z

Pythonスタイルガイド(PEP 8)

さらに、先頭または末尾のアンダースコアを使用した次の特別な形式が認識されます(これらは通常、大文字と小文字の組み合わせと組み合わせることができます)。

  • __single_leading_underscore_:弱い「内部使用」インジケータ。例えば。 「_from M import *_」は、名前がアンダースコアで始まるオブジェクトをインポートしません。

  • _single_trailing_underscore__:Pythonキーワード、たとえばTkinter.Toplevel(master, class_='ClassName')との競合を避けるために慣例により使用されます

  • ___double_leading_underscore_:クラス属性に名前を付けるとき、名前マングリングを呼び出します(クラスFooBar内で、___boo_は__FooBar__boo_になります。以下を参照)。

  • ___double_leading_and_trailing_underscore___:ユーザー制御の名前空間に存在する「マジック」オブジェクトまたは属性。例えば。 ___init___、___import___、または___file___。そのような名前を発明しないでください。文書化されているとおりにのみ使用してください。

7
gimel

第一に、「コンストラクタ」という用語はPythonには適用されません。なぜなら、__init__()メソッドは1つの役割を果たしますが、オブジェクトが既に作成され初期化が必要なときに呼び出されるメソッドにすぎないためです。

Pythonのクラスのすべてのメソッドはパブリックです。通常、プログラマはメソッドの名前に_または__を使用して「プライベート」メソッドをマークします。例:

# inheriting from object is relevant for Python 2.x only
class MyClass(object): 
    # kinda "constructor"
    def __init__(self):
        pass

    # here is a "private" method
    def _some_method(self):
        pass

    # ... and a public one
    def another_method(self):
        pass
3
Zaur Nasibov
class MongoConn(object):
    @classmethod
    def instance(cls):
        if not hasattr(cls, '_instance'):
            cls._instance = cls()
        return cls._instance

    def __init__(self):
        assert not hasattr(self.__class__, '_instance'), 'Do not call constructor directly!'

単一のインスタンスが必要な場合。

1
BaiJiFeiLong