Pythonデコレータから始めましょう。
Pythonデコレータは、すでに定義されている関数にいくつかの追加機能を追加するのに役立つ関数です。
Pythonでは、すべてがオブジェクトです。Pythonの関数はファーストクラスのオブジェクトです。つまり、変数で参照したり、リストに追加したり、引数として別の関数に渡したりすることができます。
次のコードスニペットを検討してください。
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
def say_bye():
print("bye!!")
say_bye = decorator_func(say_bye)
say_bye()
# Output:
# Wrapper function started
# bye
# Given function decorated
ここでは、decorator関数がsay_hello関数を変更し、その中にコード行をいくつか追加したと言えます。
デコレーターのPython構文
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
@decorator_func
def say_bye():
print("bye!!")
say_bye()
ケースシナリオよりもすべてをまとめましょう。その前に、いくつかのoopsの原則について話しましょう。
ゲッターとセッターは、データのカプセル化の原則を保証するために、多くのオブジェクト指向プログラミング言語で使用されます(これらのデータを操作するメソッドを使用したデータのバンドルと見なされます)。
これらのメソッドはもちろん、データを取得するためのゲッターであり、データを変更するためのセッターです。
この原則によれば、クラスの属性はプライベートになり、他のコードからそれらを隠して保護します。
うん、@ propertyは基本的にゲッターとセッターを使用するためのpythonicな方法です。
Pythonにはプロパティと呼ばれる優れた概念があり、オブジェクト指向のプログラマーの生活をはるかにシンプルにします。
摂氏で温度を保存できるクラスを作成するとします。
class Celsius:
def __init__(self, temperature = 0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
def get_temperature(self):
return self._temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
リファクタリングされたコード、これは私たちがプロパティでそれを達成することができた方法です。
Pythonでは、property()は、プロパティオブジェクトを作成して返す組み込み関数です。
プロパティオブジェクトには、getter()、setter()、delete()の3つのメソッドがあります。
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
def get_temperature(self):
print("Getting value")
return self.temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
temperature = property(get_temperature,set_temperature)
ここに、
temperature = property(get_temperature,set_temperature)
次のように分解されている可能性があります。
# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)
注意点:
- get_temperatureは、メソッドではなくプロパティのままです。
これで、書き込みによって温度の値にアクセスできます。
C = Celsius()
C.temperature
# instead of writing C.get_temperature()
さらに、名前get_temperatureとset_temperatureは不要であり、クラスの名前空間を汚染するため、定義しないでください。
上記の問題に対処するためのpythonの方法は、@propertyを使用することです。
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value")
return self.temperature
@temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
注意点-
- 値を取得するために使用されるメソッドは、「@ property」で装飾されています。
- セッターとして機能しなければならないメソッドは「@ temperature.setter」で修飾されています。関数が「x」と呼ばれていた場合、「@ x.setter」で修飾する必要があります。
- 同じ名前で異なる数のパラメーター「def temperature(self)」と「def temperature(self、x)」を持つ「2」メソッドを作成しました。
ご覧のとおり、コードは明らかにエレガントではありません。
それでは、実際のシーンの1つについてお話ししましょう。
次のようにクラスを設計したとします。
class OurClass:
def __init__(self, a):
self.x = a
y = OurClass(10)
print(y.x)
次に、私たちのクラスがクライアントの間で人気になり、彼らがプログラムでそれを使い始めたと仮定しましょう。オブジェクトへのあらゆる種類の割り当てを行いました。
そしてある運命の日、信頼できるクライアントが私たちのところにやって来て、 "x"は0から1000の間の値でなければならないことを示唆しました、これは本当に恐ろしいシナリオです!
プロパティがあるので簡単です。「x」のプロパティバージョンを作成します。
class OurClass:
def __init__(self,x):
self.x = x
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
これは素晴らしいことではありませんか?想像できる最も単純な実装から始めることができ、インターフェイスを変更せずに、後でプロパティバージョンに自由に移行できます。したがって、プロパティはゲッターとセッターの単なる置き換えではありません!
この実装をここで確認できます