2017-08-12 1 views
2

親クラスからサブクラスを開始します整数 - 上記の例では5または2 - メソッドがupdate(self, t)であるため、それらをOスーパークラスの下にグループ化することは理にかなっています。これを実現するために、よりオブジェクト指向の方法がある場合、私は、しかし、思ったんだけど、実行時には、私は、次の形式のOオブジェクトを生成する入力のリストがあると

Os = [] 
for inp in inps: 
    if inp[0] == 'A': 
     Os.append(A(inp[1])) 
    elif inp[0] == 'B': 
     Os.append(B(inp[1])) 

、その後

for O in Os: O.update(t) 

を:私はループでプログラムを完了できました。一つの方法は、私は考え、Oクラスの偽の「Oコンストラクタ」外を作るために次のようになります。

def initO(inp): 
    if inp[0] == 'A': 
     return A(inp[1]) 
    elif inp[0] == 'B': 
     return B(inp[1]) 

Os = [initO(inp) for inp in inps] 

これは私の意見では、よりエレガントで、かつすべての集中的な目的のために私が望む結果を与えます。しかし、Pythonでクラスシステムを完全に乱用しているように感じます。おそらくOコンストラクタからAとBを開始することで、これを行うより良い方法がありますか?

EDIT:AとB

答えて

2

のスーパークラスとしてOを維持しながら、理想的には

Os = [O(inp) for inp in inps] 

を使用できるようになりますが、実際のクラスに名前をマップするためにdictを使用することができます:

dct = {'A': A, 'B': B} 

[dct[name](argument) for name, argument in inps] 

それとも、リスト内包表記を使用しない場合:

dct = {'A': A, 'B': B} 
Os = [] 
for inp in inps: 
    cls = dct[inp[0]] 
    Os.append(cls(inp[1])) 
1

をPythonでという名前で呼び出すことは技術的に可能ですが、私は強くお勧めしません。クリーンな方法は、おそらく辞書を使用している:

trans = { 'A' : A, 'B' : B } 

def initO(inp): 
    cons = trans.get(inp[0]) 
    if cons is not None: 
     return cons(*inp[1:])

は、だからここtransクラス(したがって、対応するコンストラクタ)の名前をマップする辞書です。

initOでは、ルックアップを実行します。ルックアップが成功した場合は、残りの引数をinpとしてコンストラクタconsを呼び出します。

0

ABについて詳しく知りませんが、それは言うまでもありません。しかし、これは古典的なケースのように、Cのような言語でswitchのように見えます。Pythonにはswitchという文がないので、dictまたはdictのような構文が代わりに使用されます。

allowed = {'A', 'B'} 
Os = [globals()[f](x) for (f, x) in inps if f in allowed] 
:あなたはサニタイズしたい場合は

Os = [globals()[f](x) for (f, x) in inps] 

、あなたはこのような何かを行うことができます。あなたが直接あなたのクラスがglobals()機能を使用して取得することができ

あなたの入力がクリーンであることを確認している場合は、

固定された辞書とサニタイズされた入力を希望する場合は、このソリューションを変更することもできます。

allowed = {'A', 'B'} 
classname_to_class = {k: v for (k, v) in globals().iteritems() if k in allowed} 
# Now, you can have a dict mapping class names to classes without writing 'A': A, 'B': B ... 

代わりに、すべてのあなたのクラス定義の前に付けることができれば、あなたもこのような何か行うことができます:

classname_to_class = {k[13:]: v for (k, v) in globals().iteritems() if k.startswith('SpecialPrefix'} # 13: is the length of 'SpecialPrefix' 

をこのソリューションは、あなただけで自動的に除去した後(移入接頭辞を使用して、クラスに名前を付けて、辞書を持つことができますあなたがそうするならば、特別な接頭辞)。これらの辞書は、手作業で辞書を生成する必要がない点を除いて、ここに掲載されている他のソリューションのtransdctに相当します。

これまでに掲載他のソリューションとは異なり、これらは、転写エラーの可能性(および必要な定型的なコードの量)を減らすあなたは危険でAとB

+0

ダウン投票には、投票の裏にある理由を説明してください。この解決策は機能しませんか(クラスがローカルで定義されている場合を除いて)、または私は何か間違ったことを述べましたか?私はその質問に答えなかったのですか?十分な警告なしに私がここで採用している悪い習慣はありますか? – lungj

+0

あなたの答えをありがとう。 globals()の使用は、@Willemが参照した "名前で呼び出す"機能ですか? – biffletsbq

+0

Pythonで名前を呼び出すにはいくつかの方法があります(例:https://stackoverflow.com/questions/3061/calling-a-function-of-a-module-from-a-string-with-the-functions -name-in-pythonにはいくつかのwyasが示されています)、どちらが参照されているのかわかりません。あなたの状況によっては、名前を呼ぶことに間違いはありません。私は、上記のものに似ている、タスクを達成する別の方法で私の答えを更新するつもりです。 – lungj

0

より多くのクラスを持っている場合は私たちはメタクラスを使うことができます。これはあなたの特定のアプリケーションに適しているかもしれません。クラスOのサブクラスを定義するたびに、常にOのサブクラスの最新リスト(well、dict)があります。ああ、これはPython 2向けに書かれています(ただし、Python 3に移植可能です)。今

class OMetaclass(type): 
    '''This metaclass adds a 'subclasses' attribute to its classes that 
    maps subclass name to the class object.''' 
    def __init__(cls, name, bases, dct): 
     if not hasattr(cls, 'subclasses'): 
      cls.subclasses = {} 
     else: 
      cls.subclasses[name] = cls 

     super(OMetaclass, cls).__init__(name, bases, dct) 

class O(object): 
    __metaclass__ = OMetaclass 

### Now, define the rest of your subclasses of O as usual. 

class A(O): 
    def __init__(self, x): pass 

class B(O): 
    def __init__(self, x): pass 

、あなたはOのすべてのサブクラスが含まれている辞書、O.subclassesを、持っています。あなたは今、ちょうどこの操作を行うことができます。

Os = [O.subclasses[cls](arg) for (cls, arg) in inps] 

を今、「あなたは、あなたのクラスの約奇妙なプレフィックスを心配する必要はありません、あなたがすでにOをサブクラス化している場合、あなたのコードを変更する必要はありませんが、あなたのプログラムを悪化させるかもしれない魔法(メタクラス)を導入しました。

1

あなたが本当に特別な__subclasses__メソッドを使用することができ、親クラスの中から(直接)のサブクラスを作成したい場合:これは、工場のような役割を果たし

class O(object): 
    def __init__(self, integer): 
     self.value = integer 

    @classmethod 
    def get_subclass(cls, subclassname, value): 
     # probably not a really good name for that method - I'm out of creativity... 
     subcls = next(sub for sub in cls.__subclasses__() if sub.__name__ == subclassname) 
     return subcls(value) 

    def __repr__(self): 
     return '{self.__class__.__name__}({self.value})'.format(self=self) 

class A(O): 
    pass 

class B(O): 
    pass 

を:

>>> O.get_subclass('A', 1) 
A(1) 

かリストの理解として:

>>> [O.get_subclass(*inp) for inp in inps] 

あなたはそれを最適化したい場合

class O(object): 
    __subs = {} 
    def __init__(self, integer): 
     self.value = integer 

    @classmethod 
    def get_subclass(cls, subclassname, value): 
     if not cls.__subs: 
      cls.__subs = {sub.__name__: sub for sub in cls.__subclasses__()} 
     return cls.__subs[subclassname](value) 

おそらく、また、その行動やメタクラスを実装するために__new__を使用することができます:Dあなたはサブクラスに__name__からマップする辞書にサブクラスを置くことができる進行あなたがプログラム中にサブクラスを追加しないことを知っています私はclassmethodが理解しやすく、より柔軟性があるので、ここではより適切かもしれないと思います。

直接サブクラスを必要とするだけでなく、this recipeをチェックして、サブクラスのサブクラスを検索することもできます(私のサードパーティの拡張パッケージで実装しました:iteration_utilities.itersubclasses)。

関連する問題