Javaでは、匿名の内部クラスを使用してインラインで新しいクラスを定義できます。これは、クラスの単一のメソッドのみを書き直す必要がある場合に役立ちます。
単一のメソッドのみをオーバーライドするOptionParser
のサブクラスを作成するとします(たとえば、exit()
)。 Javaでは、次のように記述できます。
_new OptionParser () {
public void exit() {
// body of the method
}
};
_
このコードは、OptionParser
を拡張し、exit()
メソッドのみをオーバーライドする匿名クラスを作成します。
Pythonにも同様のイディオムがありますか?このような状況で使用されるイディオムはどれですか?
type(name, bases, dict)
組み込み関数を使用して、その場でクラスを作成できます。例えば:
op = type("MyOptionParser", (OptionParser,object), {"foo": lambda self: "foo" })
op().foo()
OptionParserは新しいスタイルのクラスではないため、基本クラスのリストにobject
を明示的に含める必要があります。
Javaは主に匿名クラスを使用して、クロージャーまたは単にコードブロックを模倣します。 Pythonではメソッドを簡単に渡すことができるので、匿名の内部クラスのように不格好な構造は必要ありません。
def printStuff():
print "hello"
def doit(what):
what()
doit(printStuff)
編集:私はこれがこの特別な場合に必要なものではないことを知っています。 Javaの匿名内部クラスによる問題の最も一般的なpythonソリューションについて説明しました。
これは、次の3つの方法で実行できます。
オプション3の例(「新しい」モジュールの使用を削除するために編集されました-非推奨です、私は知りませんでした):
import types
class someclass(object):
val = "Value"
def some_method(self):
print self.val
def some_method_upper(self):
print self.val.upper()
obj = someclass()
obj.some_method()
obj.some_method = types.MethodType(some_method_upper, obj)
obj.some_method()
クラスはファーストクラスのオブジェクトなので、必要に応じてメソッドで作成できます。例えば.
from optparse import OptionParser
def make_custom_op(i):
class MyOP(OptionParser):
def exit(self):
print 'custom exit called', i
return MyOP
custom_op_class = make_custom_op(3)
custom_op = custom_op_class()
custom_op.exit() # prints 'custom exit called 3'
dir(custom_op) # shows all the regular attributes of an OptionParser
しかし、実際には、通常のレベルでクラスを定義しないのはなぜですか?カスタマイズする必要がある場合は、カスタマイズを__init__
の引数として入力します。
(編集:コードの入力エラーを修正)
Pythonはこれを直接サポートしていません(匿名クラス)が、構文が簡潔なため、実際には必要ありません。
class MyOptionParser(OptionParser):
def exit(self, status=0, msg=None):
# body of method
p = MyOptionParser()
唯一の欠点は、名前空間にMyOptionParserを追加することですが、John Fouhyが指摘したように、複数回実行する場合は、関数内に非表示にすることができます。
Pythonには、おそらく問題を解決するためのより良い方法があります。あなたがやりたいことのより具体的な詳細を提供することができれば、それは助けになるでしょう。
たとえば、コード内の特定のポイントで呼び出されるメソッドを変更する必要がある場合は、関数をパラメーターとして渡すことでこれを行うことができます(関数は、Pythonのファーストクラスのオブジェクトであり、関数に渡すことができます)。匿名のlambda
関数を作成することもできます(ただし、これらは単一の式に制限されています)。
また、pythonは非常に動的であるため、オブジェクトの作成後にオブジェクトのメソッドを変更できますobject.method1 = alternative_impl1
、実際にはもう少し複雑ですが、 gnudの答え を参照してください。
pythonには、ラムダステートメントを使用して宣言された無名関数があります。私はそれらがあまり好きではありません-それらはあまり読みにくく、機能が制限されています。
ただし、あなたが話していることは、まったく異なるアプローチでpythonに実装される可能性があります。
class a(object):
def meth_a(self):
print "a"
def meth_b(obj):
print "b"
b = a()
b.__class__.meth_a = meth_b
私は通常、内部クラスを使用してpython3でこれを行います
class SomeSerializer():
class __Paginator(Paginator):
page_size = 10
# defining it for e.g. Rest:
pagination_class = __Paginator
# you could also be accessing it to e.g. create an instance via method:
def get_paginator(self):
return self.__Paginator()
二重アンダースコアを使用したので、これは「マングリング」の概念と内部クラスを組み合わせたものです。外部からはSomeSerializer._SomeSerializer__Paginator
で内部クラスにアクセスできますが、SomeSerializer .__ Paginatorは機能しません。もう少し「匿名」にしたい場合は、気にしないでください。
ただし、マングリングが必要ない場合は、単一の下線付きの「プライベート」表記を使用することをお勧めします。
私の場合、必要なのは、いくつかのクラス属性を設定するための高速サブクラスと、それに続くRestSerializerクラスのクラス属性に割り当てることだけです。したがって、二重アンダースコアは「これ以上使用しない」ことを示し、次のように変更される可能性があります。他の場所で再利用し始めた場合、アンダースコアはありません。
クラスはいつでも変数で非表示にできます。
class var(...):
pass
var = var()
の代わりに
var = new ...() {};
これは、Python 3.7で行うことです
#!/usr/bin/env python3
class ExmapleClass:
def exit(self):
print('this should NOT print since we are going to override')
ExmapleClass= type('', (ExmapleClass,), {'exit': lambda self: print('you should see this printed only')})()
ExmapleClass.exit()