Pythonクラス宣言でメソッドを呼び出す最良の方法は?
-
08-07-2019 - |
質問
クラス C
を宣言していますが、いくつかの宣言は非常に似ています。関数 f
を使用して、これらの宣言のコードの繰り返しを減らしたいです。通常どおり f
を宣言して使用することができます:
>>> class C(object):
... def f(num):
... return '<' + str(num) + '>'
... v = f(9)
... w = f(42)
...
>>> C.v
'<9>'
>>> C.w
'<42>'
>>> C.f(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as first argument (got int instance instead)
おっと!誤って f
を外部に公開しましたが、 self
引数を取りません(明らかな理由のためにできません)。 1つの可能性は、使用後に関数を del
することです。
>>> class C(object):
... def f(num):
... return '<' + str(num) + '>'
... v = f(9)
... del f
...
>>> C.v
'<9>'
>>> C.f
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'f'
しかし、宣言の後で f
を再度使用したい場合はどうすればよいですか?関数を削除することはありません。 「プライベート」にすることができました。 (つまり、名前の前に __
を付けて) @staticmethod
処理を行いますが、異常なチャネルを介して staticmethod
オブジェクトを呼び出すと、非常にファンキーになります:
>>> class C(object):
... @staticmethod
... def __f(num):
... return '<' + str(num) + '>'
... v = __f.__get__(1)(9) # argument to __get__ is ignored...
...
>>> C.v
'<9>'
記述子である staticmethod
オブジェクト自体は呼び出し可能でないため、上記の狂気を使用する必要があります。呼び出す前に、 staticmethod
オブジェクトでラップされた関数を回復する必要があります。
これを行うには、より良い方法が必要です。クラスで関数をきれいに宣言し、その宣言の中でそれを使用し、クラス内から後で使用するにはどうすればよいですか?私もこれをやるべきですか?
解決
簡単に言えば、解決策はfがクラスのメンバーである必要がないということです。私はあなたの思考プロセスが精神的なブロックを引き起こすJavaish言語フィルターを通過したと仮定しています。次のようになります:
def f(n):
return '<' + str(num) + '>'
class C(object):
v = f(9)
w = f(42)
その後、再びfを使用する場合は、単に使用します
>>> f(4)
'<4>'
この物語の教訓は、「Pythonでは、すべてをクラスに強制する 」ということではないと思います。
他のヒント
Ali A の拡張の答え、 モジュールの名前空間でfを避けたい場合(および_fのようなエクスポートされていない名前を使用する場合、または__all__を設定するだけでは不十分です)、 クロージャ内にクラスを作成することでこれを達成できます。
def create_C():
def f(num):
return '<' + str(num) + '>'
class C(object):
v = f(9)
def method_using_f(self, x): return f(x*2)
return C
C=create_C()
del create_C
この方法でCはその定義とメソッド内でfにアクセスできますが、他には何もありません(かなり内省的なイントロスペクションを除きます)
メソッドの( C.method_using_f.im_func.func_closure
))
これはおそらくほとんどの目的ではおそらくやり過ぎです-&quot; _&quot;を使用してfが内部であることを文書化するプレフィックス命名規則は 通常は十分です。
[編集] もう1つのオプションは、使用するメソッドで事前にラップされた関数オブジェクトへの参照を保持することです。たとえば、既定の引数として設定することにより:
class C(object):
def f(num):
return '<' + str(num) + '>'
v = f(9)
def method_using_f(self, x, f=f): return f(x*2)
del f
(クロージャアプローチの方がおそらく良いと思いますが)
これは1つの可能性です。
class _C:
# Do most of the function definitions in here
@classmethod
def f(cls):
return 'boo'
class C(_C):
# Do the subsequent decoration in here
v = _C.f()
これをしようとしていると思います:
class C():
... class F():
... def __call__(self,num):
... return "<"+str(num)+">"
... f=F()
... v=f(9)
>>> C.v
'<9>'
>>> C.f(25)
'<25>'
>>>
より良いまたはより多くのPythonソリューションがあるかもしれません...
&quot;クラス内の関数を宣言し、その宣言中に使用し、クラス内から後で使用する
すみません。できません。
&quot;できません&quot; Pythonとうまくいかないようです
1つのオプション:より良い staticmethod
を記述する:
class staticfunc(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kw):
return self.func(*args, **kw)
def __repr__(self):
return 'staticfunc(%r)' % self.func
始めから始めましょう。
&quot;クラス内の関数を宣言し、その宣言中に使用し、クラス内から後で使用する
すみません。できません。 「クラス内」 「宣言中に使用」と矛盾します。
- クラス内では、宣言の一部として作成されます。
- 宣言中に使用すると、クラス外に存在することを意味します。多くの場合、メタクラスとして。ただし、他の方法もあります。
C.wとC.vがどうなるかは明らかではありません。それらは単なる文字列ですか?その場合、外部関数 f
が最適なソリューションです。 「名前空間を乱雑にしない」少しスペシャスです。結局、あなたは再びそれを使いたいのです。
Cと同じモジュールにあります。だからPythonにはモジュールがあります。関数とクラスを結び付けます。
import myCmod
myCmod.C.w
myCmod.C.v
myCmod.f(42)
wとvが単純な文字列ではない場合、柔軟性が非常に高い非常に優れたソリューションがあります。
一般的に、このようなクラスレベル(&quot; static&quot;)変数には、他のクラスを使用できます。目的のAPIを完全に達成することはできませんが、これは近いです。
>>> class F(object):
def __init__( self, num ):
self.value= num
self.format= "<%d>" % ( num, )
>>> class C(object):
w= F(42)
v= F(9)
>>> C.w
<__main__.F object at 0x00C58C30>
>>> C.w.format
'<42>'
>>> C.v.format
'<9>'
この利点は、Fが拡張可能な適切な一流のものであることです。 「非表示」ではありません露出を避けようとしていること。それは人生の事実なので、オープン/クローズの原則に従い、拡張に対してオープンにすることもできます。