Python研究ノート9:高度なオブジェクト指向のための@propertyデコレータ

今日は@propertyデコレータについてたくさんの記事を読みましたが、関数についての理解がさらに深まりました。これはオブジェクト指向プログラミングがより高いレベルに入る最初のステップでもあり、今後も頑張っていきます。


1. @ propertyデコレータ

  • Pythonでの属性とメソッドのアクセス許可の問題について説明しました。属性をプライベートとして設定することはお勧めしませんが、属性が外部に直接公開されている場合にも問題があります。たとえば、属性に割り当てられた値は有効です。
  • 以前の提案では、最初に1つのアンダースコアを付けてプロパティに名前を付けることです。このように、プロパティが保護されていることを意味します。プロパティに直接アクセスすることはお勧めしません。プロパティにアクセスする場合は、プロパティのgetter(アクセサ)およびsetter(変更)。器)メソッドを使用して、対応する操作を実行します。これを行う場合は、** @ property **ラッパーを使用してgetterメソッドとsetterメソッドをラップし、プロパティへのアクセスを安全で便利にすることを検討できます。
  • 主な機能は、クラス内のメソッドをクラス内の属性に変換し、属性の定義と既存の属性の変更を容易にすることです。

ケース1:

  • Pythonの組み込みの@propertyデコレータは、プロパティ呼び出す方法としてクラスのメソッドを偽装できます
    • つまり、Foo.func()を呼び出す元のメソッドがFoo.funcのメソッドになりました。
    • デコレータ@propertyを関数に追加すると、関数を呼び出すときに括弧を追加せずに関数を直接呼び出すことができます。
# 创建一个学生类
class Student:

    # 定义学生属性,初始化方法
    # name和score属于实例变量, 其中score属于私有变量
    def __init__(self, name, score):
        self.name = name
        self.__score = score

    # 利用property装饰器把函数伪装成属性
    @property
    def score(self):
        print("My name is {}, score is {}".format(self.name, self.__score))


# 实例化,创建对象
student1 = Student("AD", 3)

student1.score    # My name is AD, score is 3

ケース2:

class Student(object):

    def get_score(self):
         return self._score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')    # integer:整数
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
        
        
# 方法1:
s = Student()
s.score = 60 #实际转化为s.set_score(60)
s.score      #实际转化为s.get_score()

# 方法2:
s = Student()
s.set_score(90)
s.get_score()

s.set_score(9000)

上記のコードには、Pythondの組み込み関数isinstance()が含まれています。

  • isinstance(object、classinfo)関数は、type()と同様に、オブジェクトが既知の型であるかどうかを判別します。
  • 2つのタイプが同じであるかどうかを判断する場合は、isinstance()を使用することをお勧めします。
  • オブジェクトのタイプがclassinfoのタイプと同じである場合は、Trueを返し、それ以外の場合はFalseを返します。
class Student(object):

    @property
    def birth(self):
        return self._birth

    @birth.setter          
    def birth(self, value): # birth是可读写属性
        self._birth = value

    @property
    def age(self):          # age是只读属性,因为age可以根据birth和当前时间计算出来
        return 2015 - self._birth
    """
    注意如果直接将属性名作为函数名,那么属性必须设置为私有属性,否则在用s.score时,不知道调用函数,还是调用属性,
    就会犯RecursionError: maximum recursion depth exceeded in comparison错误
    """


ケース3:

# @perproty装饰器,使得定义新属性和对现有的属性的修改变的更简单
class C(object):
       
    @property
    def x(self):
        "I am the 'x' property."
        return self._x
 
    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x
        
        
# 传统的方法绑定属性和访问属性:
class UserInfo(object):
 
    # name属于私有变量
     def get_name(self):
        """通过类的方法访问类中的属性"""
        return self.__name
 
     def set_name(self, name):
        """通过外部传参的方式绑定属性"""
        self.__name = name
 
 
if __name__ == '__main__':
    user = UserInfo()
    # 绑定name属性
    user.set_name(["AD"])
    print("My name is:", user.get_name())   # My name is: ['AD']
class UserInfo(object):
    @property
    def name(self):
         return self.__name
 
    @name.setter
    def name(self, name):
        if isinstance(name, str):
             self.__name = name
        else:
             raise TypeError("The name must be str")
 
 
if __name__ == '__main__':
    user = UserInfo()
    # 绑定属性
    user.name = "AD"
    print("My name is: ", user.name)  # My name is:  AD
    user.name = ["AD"]
    print("My name is: ", user.name)  # TypeError: The name must be str
  • 最適化されたコードの後、バインドされたプロパティが文字列タイプでない場合、エラーが報告されることがわかります。プロパティに直接バインドし、同様の方法でプロパティにアクセスして、より直感的にアクセスできます。

ケース4:

  • クラス外のプライベートメンバープロパティにアクセスするために使用できます
class UserInfo(object):
 
    def __init__(self, name, age):
        self.__name = name
        self.__age = age
 

if __name__ == '__main__':
    user = UserInfo('AD', 18)
    print(user.__name) # AttributeError: 'UserInfo' object has no attribute '__name'
# 进行优化之后:

class UserInfo(object):
 
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        """通过类的方法访问类中的私有属性"""
        return self.__name
 
if __name__ == '__main__':
    user = UserInfo('AD')
    print("获取name属性:", user.name)

*包括的なケース1:

class Person(object):

    def __init__(self, name, age):
        self._name = name
        self._age = age

    # 1.访问器 - getter方法:
    # name为私有变量,无法从外部进行访问
    @property
    def name(self):
        return self._name

    # 2.访问器 - getter方法:
    @property
    def age(self):
        return self._age

    # 3.修改器 - setter方法:
    @age.setter
    def age(self, age):
        self._age = age

    def play(self):
        if self._age <= 18:
            print('%s正在学Python.' % self._name)
        else:
            print('%s正在打王者.' % self._name)


def main():
    person = Person('李元芳', 17)
    person.play()			      # 李元芳正在学python.
    person.age = 22
    person.play()		          # 李元芳正在打王者.
    # person.name = '狄仁杰'       # AttributeError: can't set attribute


if __name__ == '__main__':
    main()
   

総括する

  • 1. @propertyデコレータは、次のように、クラスのメソッドをプロパティ呼び出しの方法として偽装できます。Foo.func()---- Foo.func
  • 2. @propertyデコレータを使用して、クラス外のプライベートメンバープロパティにアクセスできます
  • 知っておく必要があります
    • このデコレータによってデコレートされたメソッドは、self以外の他のパラメータを渡すことはできません
    • @propertyと@ x.setterを同時に使用する場合は、xと@ x.setterによって変更されたメソッド名が、@ propertyによって変更されたメソッド名と一致している必要があります。

おすすめ

転載: blog.csdn.net/amyniez/article/details/104561163
おすすめ