工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> Python

Python @property デコレーター

Python @property デコレータ

このチュートリアルでは、Python @property デコレーターについて学びます。オブジェクト指向プログラミングでゲッターとセッターを使用する Pythonic な方法。

Python プログラミングは組み込みの @property を提供します オブジェクト指向プログラミングで getter と setter をより簡単に使用できるようにするデコレータ

@property について詳しく説明する前に デコレータは、そもそもなぜそれが必要なのかについて直感を構築しましょう。


ゲッターとセッターのないクラス

温度を摂氏で保存するクラスを作成するとします。また、温度を華氏に変換するメソッドも実装します。これを行う 1 つの方法は次のとおりです。

class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

このクラスからオブジェクトを作成し、temperature を操作できます。 属性:

# Basic method of setting and getting attributes in Python
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32


# Create a new object
human = Celsius()

# Set the temperature
human.temperature = 37

# Get the temperature attribute
print(human.temperature)

# Get the to_fahrenheit method
print(human.to_fahrenheit())

出力

37
98.60000000000001

華氏に変換する際の余分な小数点以下の桁数は、浮動小数点演算エラーによるものです。詳細については、Python 浮動小数点演算エラーをご覧ください。

temperature のようなオブジェクト属性を割り当てたり取得したりするたびに 上記のように、Python はオブジェクトの組み込み __dict__ で検索します。 辞書属性。

>>> human.__dict__
{'temperature': 37}

したがって、man.temperature 内部的に man.__dict__['temperature'] になります .


ゲッターとセッターの使用

Celsius の使いやすさを拡張したいとします。 上記で定義されたクラス。どの物体の温度も摂氏 -273.15 度 (熱力学の絶対零度) を下回ることはできないことがわかっています

コードを更新して、この値の制約を実装しましょう。

上記の制限に対する明らかな解決策は、属性 temperature を非表示にすることです。 (プライベートにする) 新しい getter メソッドと setter メソッドを定義して、それを操作します。これは次のように行うことができます:

# Making Getters and Setter methods
class Celsius:
    def __init__(self, temperature=0):
        self.set_temperature(temperature)

    def to_fahrenheit(self):
        return (self.get_temperature() * 1.8) + 32

    # getter method
    def get_temperature(self):
        return self._temperature

    # setter method
    def set_temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible.")
        self._temperature = value

ご覧のとおり、上記のメソッドは 2 つの新しい get_temperature() を導入します と set_temperature() メソッド。

さらに、temperature _temperature に置き換えられました .アンダースコア _ 先頭の は、Python でプライベート変数を示すために使用されます。


それでは、この実装を使用しましょう:

# Making Getters and Setter methods
class Celsius:
    def __init__(self, temperature=0):
        self.set_temperature(temperature)

    def to_fahrenheit(self):
        return (self.get_temperature() * 1.8) + 32

    # getter method
    def get_temperature(self):
        return self._temperature

    # setter method
    def set_temperature(self, value):
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible.")
        self._temperature = value


# Create a new object, set_temperature() internally called by __init__
human = Celsius(37)

# Get the temperature attribute via a getter
print(human.get_temperature())

# Get the to_fahrenheit method, get_temperature() called by the method itself
print(human.to_fahrenheit())

# new constraint implementation
human.set_temperature(-300)

# Get the to_fahreheit method
print(human.to_fahrenheit())

出力

37
98.60000000000001
Traceback (most recent call last):
  File "<string>", line 30, in <module>
  File "<string>", line 16, in set_temperature
ValueError: Temperature below -273.15 is not possible.

この更新により、新しい制限が正常に実装されました。摂氏 -273.15 度未満に温度を設定することはできなくなりました。

注意 :プライベート変数は実際には Python には存在しません。単に従うべき規範があります。言語自体に制限はありません。

>>> human._temperature = -300
>>> human.get_temperature()
-300

ただし、上記の更新のより大きな問題は、以前のクラスを実装したすべてのプログラムがコードを obj.temperature から変更する必要があることです。 obj.get_temperature()obj.temperature = val のようなすべての式 obj.set_temperature(val) まで .

このリファクタリングは、数十万行のコードを処理する際に問題を引き起こす可能性があります。

全体として、新しいアップデートには後方互換性がありませんでした。これは @property の場所です


プロパティ クラス

上記の問題に対処する pythonic の方法は、 property を使用することです クラス。コードを更新する方法は次のとおりです。

# using property class
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    # getter
    def get_temperature(self):
        print("Getting value...")
        return self._temperature

    # setter
    def set_temperature(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible")
        self._temperature = value

    # creating a property object
    temperature = property(get_temperature, set_temperature)

print() を追加しました get_temperature() 内の関数 と set_temperature() それらが実行されていることを明確に観察します。

コードの最後の行は、プロパティ オブジェクト temperature を作成します。 .簡単に言えば、プロパティはいくつかのコードを添付します (get_temperatureset_temperature ) メンバー属性へのアクセス (temperature ).

この更新コードを使用しましょう:

# using property class
class Celsius:
    def __init__(self, temperature=0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    # getter
    def get_temperature(self):
        print("Getting value...")
        return self._temperature

    # setter
    def set_temperature(self, value):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273.15 is not possible")
        self._temperature = value

    # creating a property object
    temperature = property(get_temperature, set_temperature)


human = Celsius(37)

print(human.temperature)

print(human.to_fahrenheit())

human.temperature = -300

出力

Setting value...
Getting value...
37
Getting value...
98.60000000000001
Setting value...
Traceback (most recent call last):
  File "<string>", line 31, in <module>
  File "<string>", line 18, in set_temperature
ValueError: Temperature below -273 is not possible

ご覧のとおり、temperature の値を取得するコードはすべて 自動的に get_temperature() を呼び出します 辞書 (__dict__) ルックアップの代わりに。同様に、値を temperature に割り当てるコード 自動的に set_temperature() を呼び出します .

上記の set_temperature() も確認できます オブジェクトを作成したときでも呼び出されました。

>>> human = Celsius(37)
Setting value...

理由はわかりますか?

その理由は、オブジェクトが作成されるとき、__init__() メソッドが呼び出されます。このメソッドには self.temperature = temperature という行があります .この式は自動的に set_temperature() を呼び出します .

同様に、 c.temperature のようなアクセス 自動的に get_temperature() を呼び出します .これがプロパティの機能です。いくつかの例を次に示します。

>>> human.temperature
Getting value
37
>>> human.temperature = 37
Setting value

>>> c.to_fahrenheit()
Getting value
98.60000000000001

property を使用して 、値制約の実装に変更は必要ないことがわかります。したがって、実装には下位互換性があります。

注意 :実際の温度値はプライベート _temperature に保存されます 変数。 temperature attribute は、このプライベート変数へのインターフェイスを提供するプロパティ オブジェクトです。


@property デコレータ

Python では、property() property を作成して返す組み込み関数です。 物体。この関数の構文は次のとおりです:

property(fget=None, fset=None, fdel=None, doc=None)

ここで、

実装からわかるように、これらの関数の引数はオプションです。したがって、プロパティ オブジェクトは次のように簡単に作成できます。

>>> property()
<property object at 0x0000000003239B38>

プロパティ オブジェクトには、getter() の 3 つのメソッドがあります。 、 setter() 、および deleter() fget を指定する 、 fset および fdel 後の時点で。これは次の行を意味します:

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)

これら 2 つのコードは同等です。

Python デコレーターに精通しているプログラマーは、上記の構成をデコレーターとして実装できることを認識できます。

get_temperature という名前を定義することすらできません および set_temperature それらは不要であり、クラスの名前空間を汚染するためです。

このために、temperature を再利用します。 ゲッター関数とセッター関数を定義する際に名前を付けます。これをデコレータとして実装する方法を見てみましょう:

# Using @property decorator
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):
        print("Setting value...")
        if value < -273.15:
            raise ValueError("Temperature below -273 is not possible")
        self._temperature = value


# create an object
human = Celsius(37)

print(human.temperature)

print(human.to_fahrenheit())

coldest_thing = Celsius(-300)

出力

Setting value...
Getting value...
37
Getting value...
98.60000000000001
Setting value...
Traceback (most recent call last):
  File "", line 29, in 
  File "", line 4, in __init__
  File "", line 18, in temperature
ValueError: Temperature below -273 is not possible

上記の実装は単純で効率的です。 property を使用することをお勧めします .


Python

  1. Python データ型
  2. Python 演算子
  3. Python pass ステートメント
  4. Python 関数の引数
  5. Python 辞書
  6. Python の継承
  7. Python 演算子のオーバーロード
  8. Python イテレータ
  9. Python クロージャー
  10. Python @property デコレーター
  11. Python 日時