たぶんこれは技術的な質問よりもスタイルの質問の方が多いかもしれませんが、いくつかのメンバー変数を持つpythonクラスがあり、ユーザーがいくつかのメンバー変数を初期化するように動作させたい最初にクラスのインスタンスを作成し(つまり、__init__
関数で)、後で呼び出されるメンバー関数の引数から他のメンバー変数を定義したいので、すべてのメンバー変数を初期化する必要があります__init__
関数で(および後で定義される値をダミー値に設定する)、または__init__
関数でいくつかを初期化し、後の関数でいくつかを初期化します。いくつかの例です。
この例では、var3
関数で__init__
が最初に0に設定され、その後my_funct関数で目的の値に設定されます。
class myClass(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
self.var3=0
def my_funct(self,var3):
self.var3=var3
この例では、var3
は__init__
関数でまったく定義されていません
class myClass(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
def my_funct(self,var3):
self.var3=var3
どちらの方法でも大きな違いはないと思います(メモリ使用量のわずかな違いかもしれません)。しかし、何らかの理由で、これらのいずれかが他よりも優先されるのではないかと考えていました。
オブジェクト指向プログラミングでは、インスタンス化後およびメソッドの終了後、オブジェクトが常に一貫した状態になるようにするのは開発者次第です。それ以外は、自由にクラスを開発できます(サブクラス化/オーバーライドなどの特定の原則に留意してください)。
Pylint などのツールは、__init__
の外部にインスタンス変数を設定しているときに警告を出します。 __init__
内のすべてのインスタンス変数を設定することはよりクリーンであると言えますが、常に従わなければならないルールではありません。
__init__
で必ずしも必要ではない変数を任意のデフォルト値に初期化することは実際に思いとどまります。
OOこれが当てはまる場合、あなたの使用に疑問を投げかけますが、__init__
がすべてを実行せず、クラスが望む有効で理解可能なケースがあると確信しています。他のメソッドで追加の属性を追加することにより、さらに自分自身を変更します。
私の意見では、使用したいメソッドの実行中に変数が設定されたかどうかをテストする適切な方法は、hasattr
を使用することです。これは、これがメソッドを使用する有効な方法であり、テストが適切な方法で動作を切り替えるだけの場合です。
別の方法は、それを試して使用し、例外を処理して、クラスのユーザーが間違っていることに関するユーザーフレンドリーな情報を提供することです。これは、メソッドを実行する前に属性を設定する必要がある場合です。
つまり、クラスを初期化しましたが、z_init
メソッドを実行する前にz_run
メソッドを呼び出して、z
属性が存在することを確認する必要があります。
もう1つの、おそらくPython的な方法は、docstringでメソッドの使用方法を文書化し、それが不適切に使用された場合に例外が飛ぶようにすることです。これは何かの最初の実装に十分であり、次のタスクに集中できます。これは上記と同じ状況にあり、メソッドには属性を設定する必要があります。
変数を任意のデフォルト値に初期化するという考えが好きではない理由は、これが混乱を招く可能性があり(任意であるため)、回線ノイズであるためです。
値がnot任意であり、単に変更可能なデフォルト値である場合、オーバーライド可能な__init__
メソッドでデフォルト値を使用する必要があります。また、実際には有効な初期状態にすることもできます。これはnot任意であり、__init__
メソッドで設定する必要があります。
したがって、本当の答えはそれは依存します、あなたはおそらくそれを避けて、OOこれを行うには、他のメソッドに属性を追加するか、属性を任意の値に初期化します。
Simeon Visserはオブジェクトを一貫した状態に保つように言っていますが、彼はあなたの抽象的な例に基づいてどのような一貫性があるのかについての根拠を持ちません。 Pylintはこの種のことを警告しますが、lintプログラムからの警告は、通常がコードのにおいを示すものについて、高レベルのレビュー担当者に警告できるようにするためのものです。本当のレビュアーはすべてのコードを読んで理解するべきであり、したがってPylintを本当に必要としないので、私は高レベルのレビュアーと言います。
経験則を破る例:
class Mutant(object):
"""A mutant!"""
def __init__(self):
"""A mutant is born with only 1 eye and 1 mouth"""
self.eyes = 1
self.mouth = 1
self.location = 'Montana'
def roll_to(self, location):
"""If they have limbs, running is less dangerous"""
if hasattr(self, 'limbs'):
print 'Your mutant broke its limbs off!!'
del self.limbs
self.location = location
def run_to(self, location):
"""If they don't have limbs, running is not effective"""
if not hasattr(self, 'limbs'):
print 'Your mutant tries to run but he has no limbs.'
else:
self.location = location
def grow_limbs(self, number_of_limbs):
"""Ah, evolution!"""
assert number_of_limbs > 0, 'Cannot grow 0 or less limbs...'
if hasattr(self, 'limbs'):
self.limbs += number_of_limbs
else:
self.limbs = number_of_limbs
以下は、sololearn.com(Pythonを学ぶための無料サイト)からの抜粋です。
「プロパティは、インスタンス属性へのアクセスをカスタマイズする方法を提供します。メソッドの上にプロパティデコレータを配置することで作成されます。つまり、メソッドと同じ名前のインスタンス属性にアクセスすると、代わりにメソッドが呼び出されます。
プロパティの一般的な用途の1つは、属性を読み取り専用にすることです。」
例(sololearn.comからも):
class Pizza:
def __init__(self, toppings):
self.toppings = toppings
@property
def pineapple_allowed(self):
return False
pizza = Pizza(["cheese", "tomato"])
print(pizza.pineapple_allowed)
pizza.pineapple_allowed = True
結果:
>>>
False
AttributeError: can't set attribute
>>>
Var3がvar1とvar2に依存している場合
class myClass:
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
@property
def var3(self):
return(self.var1+self.var2) #var3 depends on var1 and var2
m1=myClass(1,2)
print(m1.var3) # var3 is 3
var3は、セッター関数を使用して任意に設定することもできます。 Noneを使用すると、var3を任意の値に設定することを回避できることに注意してください。
class myClass2(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
self._var3=None # None or an initial value that makes sense
@property
def var3(self):
return(self._var3)
@var3.setter
def var3(self,value):
self._var3=value
m2=myClass(1,2)
print(m2.var3) # var3 is none
print(m2.var3(10)) # var3 is set to 10