2017-01-24 10 views
4

Python 2.7クラスオブジェクトで使用できるメソッドを提供したいが、そのインスタンスの属性名前空間を汚染しない。これを行う方法はありますか?インスタンスの属性名前空間を汚染しないPythonクラスメソッドを作成する方法はありますか?

>>> foo.__dict__ 
{} 

が、属性検索のための規則には名前が欠落しているため、バックインスタンスの型に分類されます。

>>> class Foo(object): 
... @classmethod 
... def ugh(cls): 
...  return 33 
... 
>>> Foo.ugh() 
33 
>>> foo = Foo() 
>>> foo.ugh() 
33 
+0

技術

>>> class A(object): ... def __private(self): ... print('boo') ... def hello(self): ... self.__private() ... >>> >>> A().hello() boo 

ではなく、クラスの外のクラスでプライベートメソッドを使用することができ、 'ugh'は* *ではありませんインスタンスの名前空間( 'foo .__ dict__')にあります。 Pythonのルックアップアルゴリズムのためにインスタンス経由でアクセスすることができます。 – chepner

+0

これはPythonに焼き付けられていますか? (http://users.rcn.com/python/download/Descriptor.htmは次のことを確認しているようです: 'たとえば、a.xは.__ dict __ ['x']で始まる参照チェーンを持っています。__dict __ ['x']、型の基本クラスを継承しています(メタクラスを除いて ')クラスオブジェクトで使用できる特別な魔法のものを作成したいのですが、私のクラスを誤って使っている好奇心が強いのでインスタンスから呼び出す可視性を抑える方法があればいいですね。 –

+0

イントロスペクションを制御するもう一つのパワー機能は '__dir__'です。 –

答えて

4

あなたはクラスメソッドの記述をサブクラス化でき):

>>> C.__dict__['foo'].__get__(None, C) 
<bound method C.foo of <class '__main__.C'>> 
>>> C.__dict__['foo'].__get__(c, type(c)) 
AttributeError 

必須読込:Data Model — Implementing DescriptorsおよびDescriptor HowTo Guide

+0

私の脳は発煙しています...あなたは精巧にできますか?表面上はこれが単純なものに見えますが、 '@ classmethod'が実際に何をしているのか分かりません。 –

+0

Hmm。私は試してみましたが、これはPython 2.7で正しく動作するようには見えません。 –

+0

Aha、それはスーパーコールです。 –

4

ughは、名前空間ではありません。これを防ぐには、Foo.__getattribute__を上書きすることができます。

class Foo(object): 
    @classmethod 
    def ugh(cls): 
     return 33 

    def __getattribute__(self, name): 
     if name == 'ugh': 
      raise AttributeError("Access to class method 'ugh' block from instance") 
     return super(Foo,self).__getattribute__(name) 

これが生成します。

>>> foo = Foo() 
>>> foo.ugh() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "tmp.py", line 8, in __getattribute__ 
    raise AttributeError("Access to class method 'ugh' block from instance") 
AttributeError: Access to class method 'ugh' block from instance 
>>> Foo.ugh() 
33 

をあなたが唯一のタイプの名前空間をチェックも含まれ、通常のルックアップ(後に呼び出される、という__getattr__よりも、任意の属性へのアクセスに無条件で呼び出された__getattribute__を、使用する必要があります。 )が失敗する。

2

はい、メタクラスでメソッドを作成できます。

class FooMeta(type): 
    # No @classmethod here 
    def ugh(cls): 
     return 33 

class Foo(object): 
    __metaclass__ = FooMeta 

Foo.ugh() # returns 33 
Foo().ugh() # AttributeError 

メタクラスは電源機能であり、不要な場合はその使用をお勧めします。特に、親クラスに異なるメタクラスがある場合、多重継承には特別な注意が必要です。これはむしろ、それは__getattribute__のデフォルトの実装によって呼び出される記述子コール(にdesugars

class C(object): 
    @classonly 
    def foo(cls): 
     return 42 
>>> C.foo() 
42 
>>> c=C() 
>>> c.foo() 
AttributeError 

を:これは振る舞うだろうかある

class classonly(classmethod): 
    def __get__(self, obj, type): 
     if obj: raise AttributeError 
     return super(classonly, self).__get__(obj, type) 

+0

メタクラスを使用するコストはいくらですか?これはまさに私が探している機能だと思われます。機能をシンプルに保つことができれば、それは私が利用したいものです。私は、何千ものインスタンスオブジェクトを作成するつもりです。メタクラスを使用すると、余分なメモリが必要になりますか? –

+0

@JasonS:主な問題は、メタクラスが非常に強力で、クラスで奇妙なことをたくさんすることです(例えば、 '__add__'のような特殊メソッドをオーバーライドして' Foo + Foo'を意味のある式にすることができます)。これらの多くは、コードの可読性を低下させます。 – Kevin

+0

追加やそのような単純な操作の意味を上書きするためにそれらを使用すると、混乱するでしょうが、それ以外のツールだけです –

1

Pythonには、偶発的なアクセスを減らすために名前を使用するquasi-private variablesがあります。 __nameという形式のメソッドおよびオブジェクト変数は_ClassName__nameに変換されます。 Pythonはクラスのメソッドをコンパイルするときに自動的に名前を変更しますが、サブクラスの名前は変更しません。

私は

>>> A().__private() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'A' object has no attribute '__private' 
>>> 

かでサブクラス

>>> class B(A): 
...  def hello2(self): 
...   self.__private() 
... 
>>> 
>>> B().hello() 
boo 
>>> B().hello2() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in hello2 
AttributeError: 'B' object has no attribute '_B__private' 
+0

bizarre ....より多くの奇妙なコーナーから言語の:-) –

関連する問題