「新しい」スタイルのクラス(python 3.2)を使用しています)を使用して、クラスを複数のファイルに分割する方法はありますか?大きなクラス(実際には単一のクラスである必要があります)オブジェクト指向の設計の観点から、カップリングなどを検討しますが、クラスの編集を簡単にするために、いくつかのファイルに分割するのは良いことです。
あなたの問題が本当にエディターで大きなクラスを処理しているだけの場合、私が実際に探す最初の解決策は、問題を解決するためのより良い方法です。 2番目の解決策は、より良いエディター、できればコードの折りたたみを備えたエディターです。
つまり、クラスを複数のファイルに分割する方法はいくつかあります。 Pythonを使用すると、__init__.py
を入れてフォルダをモジュールとして使用できます。これにより、他のファイルからのインポートが可能になります。この機能は、各ソリューションで使用します。たとえば、最初にbigclass
と呼ばれるフォルダ。
フォルダーには、最終的にクラスを構成するさまざまな.py
ファイルを配置します。それぞれに、最終的なクラスnotクラスの関数と変数の定義を含める必要があります。同じフォルダの__init__.py
に次のように書き込んで、それらをすべて結合します。
class Bigclass(object):
from classdef1 import foo, bar, baz, quux
from classdef2 import thing1, thing2
from classdef3 import magic, moremagic
# unfortunately, "from classdefn import *" is an error or warning
num = 42 # add more members here if you like
これには、object
から直接派生した単一のクラスが作成されるという利点があり、継承グラフではこれが見栄えが良くなります。
多重継承を使用して、クラスのさまざまな部分を組み合わせることができます。個々のモジュールで、クラスの一部を使用してBigclass
のクラス定義を記述します。次に、__init__.py
に次のように記述します。
import classdef1, classdef2, classdef3
class Bigclass(classdef1.Bigclass, classdef2.Bigclass, classdef3.Bigclass):
num = 42 # add more members if desired
多重継承が問題になる場合は、can単一継承を使用します。各クラスにチェーン方式で別のクラスを継承させるだけです。複数のクラスで何も定義しない場合、順序は関係ありません。たとえば、classdef2.py
は次のようになります。
import classdef1
class Bigclass(classdef1.Bigclass):
# more member defs here
classdef3
は、classdef2
からBigclass
をインポートして追加します。あなたの__init__.py
は最後のものをインポートするだけです:
from classdef42 import Bigclass
私は通常、どのファイルからどのメンバーをインポートするかについてより明示的ですが、これらのソリューションのいずれでも機能するので、#1を選択します。
これらのシナリオのいずれかでクラスを使用するには、フォルダー名をモジュール名として使用して、クラスをインポートするだけです:from bigclass import Bigclass
次のようなデコレータでこれを行うことができます:
class Car(object):
def start(self):
print 'Car has started'
def extends(klass):
def decorator(func):
setattr(klass, func.__name__, func)
return func
return decorator
#this can go in a different module/file
@extends(Car)
def do_start(self):
self.start()
#so can this
car = Car()
car.do_start()
#=> Car has started
数百行を含むクラス定義は「実際に」発生しますが(人気のあるオープンソースのPythonベースのフレームワークでいくつか見ました)、メソッドが何をしているかを熟考すれば、長さを減らすことができると思いますほとんどのクラスの管理可能なポイント。いくつかの例:
あなたの質問に直接取り組むために、クラスの定義を分割することが可能です。 1つの方法は、クラスを定義し、それから外部関数をメソッドとして追加することによって、クラスを「モンキーパッチ」することです。もう1つは、組み込みtype
関数を使用してクラスを「手動で」作成し、その名前、基本クラス、およびそのメソッドと属性を辞書に提供することです。しかし、そうしないと定義が長くなるという理由だけでこれを行うことはお勧めしません。その種の治療法は私の考えでは病気よりも悪いです。
私は以前に似たようなもので遊んでいました。私のユースケースは、抽象構文ツリー内のノードのクラス階層でした。 prettyprinting機能は別のprettyprint.pyファイルにありますが、クラスのメソッドとしてはまだあります。
私が試みたのは、装飾された関数を指定されたクラスの属性として配置するデコレーターを使用することでした。私の場合、これはprettyprint.pyに多数のdef prettyprint(self)
が含まれ、すべてが異なる@inclass(...)
で装飾されていることを意味します
これに関する問題は、サブファイルが常にインポートされていること、およびそれらがメインクラスに依存していることを確認する必要があることです。これにより、循環依存性が生じ、乱雑になる場合があります。
def inclass(kls):
"""
Decorator that adds the decorated function
as a method in specified class
"""
def _(func):
setattr(kls,func.__name__, func)
return func
return _
## exampe usage
class C:
def __init__(self, d):
self.d = d
# this would be in a separate file.
@inclass(C)
def meth(self, a):
"""Some method"""
print "attribute: %s - argument: %s" % (self.d, a)
i = C(10)
print i.meth.__doc__
i.meth(20)
私はそれを使用していませんが、 このパッケージはパーシャルと呼ばれます パーシャルクラスのサポートを追加すると主張しています。
これを自分で実装する方法は他にもいくつかあるようです。
クラスの個別の部分を別々のファイルのミックスインとして実装し、それらをどこかにインポートしてサブクラス化することができます。
または、クラスの各メソッドをどこかに実装し、中央のファイルにそれらをインポートして、クラスの属性として割り当て、オブジェクト全体を作成することもできます。そのようです:
a.py:
def AFunc( self, something ):
# Do something
pass
b.py:
def BFunc( self, something ):
# Do something else
pass
c.py:
import a, b
class C:
AFunc = a.AFunc
BFunc = b.BFunc
本当に必要な場合は、このプロセスを自動化することもできます。モジュールa
およびb
によって提供されるすべての関数をループし、C
に属性として追加します。 。それは完全に行き過ぎかもしれませんが。
それを実行する他の(おそらくより良い)方法があるかもしれませんが、それらは心に浮かんだ2つです。
まず、クラスを複数のファイルに分割すると編集が簡単になることはわかりません。まともなIDEは、1つのファイルでも複数でも、メソッドを簡単に見つけることができるはずです。まともなIDEを使用していない場合、クラスを分割すると、メンテナは指定されたファイルを推測する必要がありますメソッドが入っており、簡単ではなく難しく聞こえます。
より根本的に、このクラスは大きすぎて、その重みをサポートするために特別な言語機能が必要なため、根本的に壊れているように見えます。何行のコードについて話しているのですか?ほぼ間違いなく、次のいずれかを実行することをお勧めします。
同じ状況に遭遇しました-クラスを2つのファイルにスライドさせたいのですが。その理由は-GUIレイアウトのパート1が必要なため、レイアウトのみで、別のファイルがすべての機能を保持しているためです。 c#のPartialクラスのようです。 1つはXAML用、もう1つは関数用です。
これを行うPythonicの方法は、必ずしもミックスインを使用するのではなく、多重継承を介して行われることを付け加えておきます。 ___init__
_呼び出しでsuper().__init__(*args, **kwargs)
を使用してインスタンス属性を追加し、ベースクラスに引数を渡すことができます(Raymond Hettingerによる「スーパースーパースーパー」プレゼンテーション 1 を参照)。これにより、依存関係の注入が可能になり、基本クラスの構成について考えるようになります(1つの基本クラスだけが___init__
_に属性を設定し、その属性を使用するすべてのクラスがそれから継承する場合に最適です)。
これには通常、基本クラス(またはこのパターン用に作成されているクラス)を制御する必要があります。
別のオプションは、___get__
_を介して関数を返す記述子を使用して、分離された方法で機能をクラスに追加することです。
___init_subclass__
_を見て、追加することもできます。クラス生成中のクラスへのメソッド(python 3.6に追加されたと思いますが、確認してください)