そのタイプのインスタンスを返すのではなく、おそらく のサブクラスでmake_lottery_set_type
ある new を返すことを望んでいるようです。class
LotteryGameType
これは実際、Python で行うのは非常に簡単です。クラス定義は、関数の途中であっても、どこでも実行できる通常のコードです。また、実行中にローカル環境にアクセスできます。クラス自体は「ファーストクラスの値」です。つまり、クラスを渡したり、関数から返したりすることができます。そう:
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
def __init__(self, numbers):
super().__init__(name, size, minmax[0], minmax[1])
self.numbers = numbers
return NewLotteryGameType
他のメソッドを追加する場合は、他のクラスにメソッドを追加するのと同じです。例えば:
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
def __init__(self, numbers):
super().__init__(name, size, minmax[0], minmax[1])
self.numbers = numbers
def __eq__(self, rhs):
return set(self.numbers) == set(rhs.numbers)
return NewLotteryGameType
そう:
>>> SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
>>> super1 = SuperLotto([1,2,3,4,5,6])
>>> super2 = SuperLotto([6,5,4,3,2,1])
>>> super3 = SuperLotto([7,8,9,10,11,12])
>>> super1 == super2
True
>>> super1 == super3
False
(明らかに__eq__
、set-equality が使用に適したルールでない場合は、必要に応じて定義できます。)
生成している値を調べようとすると、思ったほどきれいに見えません。たとえば、次のような場所ではSuperLotto
なく、おそらく見たいと思うでしょう。NewLotteryGameType
>>> super1
<__main__.NewLotteryGameType at 0x10259e490>
>>> SuperLotto.__name__
'NewLotteryGameType'
そのためには、 を追加するだけNewLotteryGameType.__name__ = name
です。親クラスから docstring をコピーしたり、その他のさまざまなものをコピーしたりすることもできます。
より一般的にはfunctools.update_wrapper
、インスピレーションを得るために (クラスではなく関数をラップするように設計されていますが、詳細の多くは同じです) を参照し、inspect
クラスが持つことができるすべての属性については、Python バージョンのモジュール ドキュメントを参照してください。
コメントでは、次のように尋ねます。
唯一の問題は、NewLotteryGameType に LotteryGameType から name、set_size、min_set_number、max_set_number などのパラメーターを継承させたいことです。では、NewLotteryGameType.set_size を Python シェルに入力したいとしましょう。私に返してほしい 6.
それは矛盾しています。LotteryGameType
…のインスタンス属性を継承したい場合は、既に行っています。例えば:
>>> super1.set_size
6
クラスからアクセスできるようにする場合は、インスタンス属性にすることはできません。クラス属性にする必要があります。set_size
また、クラス属性に変更してLotteryGameType
継承するだけでは機能しません。クラス属性の全体的なポイントは、クラスのすべてのインスタンスまたはそのサブクラスのいずれかによって同じ値が共有され、サブクラスはすべて異なる値を必要とするためです。
しかし、次のようなことができます。
class LotteryGameType:
def __init__(self, min_set_number, max_set_number):
self.min_set_number = min_set_number
self.max_set_number = max_set_number
def make_lottery_set_type(lottery_name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
name = lottery_name
set_size = size
def __init__(self, numbers):
super().__init__(minmax[0], minmax[1])
self.numbers = numbers
def __eq__(self, rhs):
return set(self.numbers) == set(rhs.numbers)
return NewLotteryGameType
(最初のmake_
パラメーターの名前を に変更しなければならなかったことに注意してください。これは、スコープが機能する方法のためlottery_name
、 class 属性とは異なります。)とはインスタンス属性ではなく、のクラス属性でもありませんが、のクラス属性です。それぞれ。そう:name
name
set_size
LotteryGameType
NewLotteryGameType
>>> SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
>>> SuperDuperLotto = make_lottery_set_type('SuperDuperLotto', 8, (1,100))
>>> SuperLotto.set_size
6
>>> SuperDuperLotto.set_size
8
これらのタイプのインスタンスを作成するとどうなるでしょうか? さて、Python はインスタンスで属性を検索し、次に最も派生したクラスで、次に基本クラスで検索します。したがって、同じ名前のインスタンス属性を作成しない限り (LotteryGameType.__init__
メソッドから余分なパラメーターとインスタンス属性を設定するコードを削除したことに注意してください)、必要なことだけが実行されます。
>>> super1 = SuperLotto([1,2,3,4,5,6])
>>> super1.set_size
6
>>> duper1 = SuperDuperLotto([1,2,3,4,5,6,7,8])
>>> duper1.set_size
8
もちろん、これはLotteryGameType
それ自体ではもはや使用可能な型ではないことを意味します。そのサブクラスのみが使用可能です。しかし、それはおそらくあなたが望んでいたことですよね?直接インスタンスを誤って使用しようとする人がいないことを確認するために、明示的に抽象基本クラスにすることを検討することもできます。LotteryGameType
勇気があれば、メタクラスを読んで、この設計全体を を使用するように適応させる方法を確認したいと思うかもしれませんLotteryGameMetaclass
。そのため、新しいクラスはそれぞれ、(抽象) 基本クラスのサブクラスではなく、そのメタクラスのインスタンスになります。3.4の新しいenum
モジュールのソース、またはほぼ同等の外部flufl.enum
パッケージは、適切なサンプル コードになる可能性があります。次に、両方で遊んで、それらがどのように似ているか、どのように異なるかを確認できます。