pythonプライベートプロパティ_ゼロからPython-第017課:オブジェクト向けプログラミング進級


前回の授業ではPythonのオブジェクト向けプログラミングの基礎知識について説明しましたが、この授業ではオブジェクト向けプログラミングに関する内容について引き続き議論します.
可視性とアトリビュートアクセラレータ
多くのオブジェクト向けプログラミング言語では、オブジェクトのプロパティは通常、プライベート(private)または保護(protected)のメンバーに設定され、簡単にはこれらのプロパティに直接アクセスできません.オブジェクトのメソッドは、通常、公開されたメソッドは、オブジェクトが受け入れることができるメッセージであり、オブジェクトが外部に露出する呼び出しインタフェースでもあるため、いわゆるアクセス可視性である.Pythonでは、オブジェクト属性名に接頭辞の下線を付けることで、属性のアクセスの可視性を説明することができ、例えば、__nameでプライベート属性を表し、_nameで保護された属性を表し、コードは以下に示す.
class Student:

    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def study(self, course_name):
        print(f'{self.__name}    {course_name}.')


stu = Student('   ', 20)
stu.study('Python    ')
print(stu.__name)

上記のコードの最後の行では、AttributeError(プロパティエラー)の異常が発生します.異常メッセージは'Student' object has no attribute '__name'です.このことから,__で始まる属性__nameはプライベートであり,クラスの外では直接アクセスできないが,クラス内のstudyメソッドではself.__nameでアクセスできる.
注意しなければならないのは、Pythonは文法的にプライベート属性のプライバシーを厳格に保証していないことです.プライベート属性と方法に名前を変えてアクセスを妨害しているだけです.実際に名前を変えるルールがまだアクセスできることを知っていれば、上のコードを少し修正してプライベートにアクセスすることができます.
class Student:

    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def study(self, course_name):
        print(f'{self.__name}    {course_name}.')


stu = Student('   ', 20)
stu.study('Python    ')
print(stu._Student__name, stu._Student__age)

Pythonでは、「We are all consenting adults here」(みんな大人)という名言に基づいて設定されています.Python言語の設計者は、Python言語自体がアクセスの可視性を厳格に制限するのではなく、プログラマーが自分の行為に責任を負うべきだと考えているが、多くのプログラマーは閉鎖よりも開放的で、オブジェクトの属性を私有化することは必要ではないと考えている.
Pythonでは、propertyデザイナによって「プライベート」属性の読み取りおよび変更方法を提供することができ、デザイナは通常、クラス、関数、またはメソッドの宣言の前に配置され、@シンボル表現によってクラス、関数、またはメソッドに適用される.装飾器の概念は後で授業で特別テーマの形式で説明します.ここではproperty装飾器の使い方を知るだけでいいです.
class Student:

    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    #      (getter  ) -   __name  
    @property
    def name(self):
        return self.__name

    #      (setter  ) -   __name  
    @name.setter
    def name(self, name):
        #   name            __name  
        #    __name     '   ',     
        # self.__name = name if name else '   '
        self.__name = name or '   '

    @property
    def age(self):
        return self.__age


stu = Student('   ', 20)
print(stu.name, stu.age)    #     20
stu.name = ''
print(stu.name)    #    
# stu.age = 30     # AttributeError: can't set attribute

実際のプロジェクト開発では、プライベート属性をあまり使わず、属性装飾器の使用も少ないので、上記の知識点を簡単に理解すればいいです.
ダイナミックプロパティ
Pythonは動的言語ですウィキペディアの動的言語の解釈は次のとおりです.「実行時に構造を変えることができる言語.例えば、新しい関数、オブジェクト、さらにはコードを導入することができ、既存の関数を削除したり、他の構造上の変化をすることができる.動的言語は非常に柔軟で、現在流行しているPythonやJavaScriptは動的言語であり、それ以外にPHP、Rubyなども動的言語に属しているが、C、C++などの言語は動的言語に属していないと言います.
Pythonでは、以下に示すように、Pythonが動的タイプ言語としての特権であるオブジェクトに属性を動的に追加できます.オブジェクトのメソッドは本質的にオブジェクトの属性であり、オブジェクトに受信できないメッセージを送信すると、AttributeErrorの異常が発生します.
class Student:

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


stu = Student('   ', 20)
#  Student      sex  
stu.sex = ' '

オブジェクトを使用するときにオブジェクトにダイナミックにプロパティを追加したくない場合は、Pythonの__slots__魔法を使用します.Studentクラスについては、クラスに__slots__ = ('name', 'age')を指定できます.これにより、Studentクラスのオブジェクトにはnameageの属性しかありません.他の属性を動的に追加すると、異常が発生します.コードは次のようになります.
class Student:
    __slots__ = ('name', 'age')

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


stu = Student('   ', 20)
# AttributeError: 'Student' object has no attribute 'sex'
stu.sex = ' '

静的メソッドとクラスメソッド
以前クラスで定義したメソッドはすべてオブジェクトメソッドであり、言い換えればこれらのメソッドはすべてオブジェクトが受信できるメッセージである.オブジェクトメソッドに加えて、クラスには静的メソッドとクラスメソッドがあり、この2つのメソッドはクラスに送信されたメッセージであり、両者には実質的な違いはありません.オブジェクト向けの世界では、すべてがオブジェクトであり、私たちが定義した各クラスもオブジェクトであり、静的メソッドとクラスメソッドはクラスオブジェクトに送信されるメッセージです.では、どのようなメッセージがクラスオブジェクトに直接送信されるのでしょうか.
一例を挙げると、三角形クラスを定義し、3つのエッジの長さを伝達することによって三角形を構築し、周長と面積を計算する方法を提供する.周長と面積を計算するのは必ず三角形のオブジェクトの方法で、この点は間違いありません.しかし、三角形オブジェクトを作成するときに、入力された3つのエッジ長が必ずしも三角形を構築できるとは限らないため、与えられた3つのエッジ長が三角形を構成できるかどうかを検証する方法を先に書くことができます.この方法は、この方法を呼び出すときに三角形オブジェクトがまだ作成されていないため、明らかにオブジェクトメソッドではありません.このような方法を静的方法またはクラス方法として設計することができ,すなわち,これらの方法は三角形オブジェクトに送信されるメッセージではなく,三角形クラスに送信されるメッセージであり,コードは以下に示す.
class Triangle(object):
    """    """

    def __init__(self, a, b, c):
        """     """
        self.a = a
        self.b = b
        self.c = c

    @staticmethod
    def is_valid(a, b, c):
        """             (    )"""
        return a + b > c and b + c > a and a + c > b

    # @classmethod
    # def is_valid(cls, a, b, c):
    #     """             (   )"""
    #     return a + b > c and b + c > a and a + c > b

    def perimeter(self):
        """    """
        return self.a + self.b + self.c

    def area(self):
        """    """
        p = self.perimeter() / 2
        return (p * (p - self.a) * (p - self.b) * (p - self.c)) ** 0.5

上記のコードはstaticmethod装飾器を用いてis_validメソッドがTriangleクラスの静的メソッドであることを宣言し、クラスメソッドを宣言する場合はclassmethod装飾器を用いることができる. . を直接使用して静的メソッドとクラスメソッドを呼び出すことができ、両者の違いは、クラスメソッドの最初のパラメータがクラスオブジェクト自体であり、静的メソッドにはこのパラメータがないことである.簡単にまとめると、オブジェクトメソッド、クラスメソッド、静的メソッドは、メソッドの最初のパラメータが通常のオブジェクトなのか、クラスオブジェクトなのか、メッセージを受信していないオブジェクトなのかを区別する . で呼び出すことができる.静的メソッドは、特定のオブジェクトにバインドされていないため、通常、独立した関数として直接書くこともできます.
継承とマルチステート
オブジェクト向けのプログラミング言語は、既存のクラスに基づいて新しいクラスを作成することをサポートし、重複コードの作成を低減します.継承情報を提供するクラスを親(スーパークラス,ベースクラス)と呼び,継承情報を得たクラスを子(派生クラス,派生クラス)と呼ぶ.例えば、私たちは学生クラスと先生クラスを定義して、私たちは彼らが大量の重複コードを持っていることを発見することができて、これらの重複コードはすべて先生と学生が人としての公共の属性と行為であるので、このような情況の下で、私たちはまず人類を定義して、更に継承を通じて、人類から先生クラスと学生クラスを派生して、コードは以下のように示すべきです.
class Person:
    """  """

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

    def eat(self):
        print(f'{self.name}    .')

    def sleep(self):
        print(f'{self.name}    .')


class Student(Person):
    """   """

    def __init__(self, name, age):
        # super(Student, self).__init__(name, age)
        super().__init__(name, age)

    def study(self, course_name):
        print(f'{self.name}    {course_name}.')


class Teacher(Person):
    """   """

    def __init__(self, name, age, title):
        # super(Teacher, self).__init__(name, age)
        super().__init__(name, age)
        self.title = title

    def teach(self, course_name):
        print(f'{self.name}{self.title}    {course_name}.')



stu1 = Student('   ', 21)
stu2 = Student('   ', 22)
teacher = Teacher('   ', 35, '   ')
stu1.eat()
stu2.sleep()
teacher.teach('Python    ')
stu1.study('Python    ')

継承された構文は、クラスを定義するときに、クラス名の後のカッコで現在のクラスの親を指定します.Python言語では多重継承が許可されています.つまり、1つのクラスに1つ以上の親クラスがあることができます.多重継承の問題については、後でもっと詳しく議論します.サブクラスの初期化方法では、現在のオブジェクトの親オブジェクトを取得するためにPython内蔵関数で設計されたsuper().__init__()によって親初期化方法を呼び出すことができます.上のコードから分かるように、子クラスは親から提供された属性と方法を継承するほか、独自の属性と方法を定義することができるので、子クラスは親よりも多くの能力を持っている.実際の開発では、親オブジェクトを子オブジェクトで置き換えることがよくあります.これは、オブジェクト向けプログラミングでよく見られる動作であり、「Liskov Substitution Principle」(Liskov Substitution Principle)とも呼ばれています.
子クラスは親クラスのメソッドを継承した後、メソッドを書き換えることもできます(メソッドを再実装します).異なる子クラスは親クラスの同じメソッドに対して異なる実装バージョンを与えることができます.このようなメソッドは、プログラムの実行時にマルチステート動作を示します(同じメソッドを呼び出し、異なることをしました).マルチステートはオブジェクト向けプログラミングの最も精髄的な部分であり、もちろん初心者にとって最も理解しにくく、柔軟に運用する部分でもあります.次の授業では、マルチステートという知識点を専門的な例で説明します.
簡単なまとめ
Pythonは動的言語で、Pythonのオブジェクトは動的に属性を追加することができます.オブジェクト向けの世界では、すべてがオブジェクトであり、私たちが定義したクラスもオブジェクトであるため、クラスはメッセージを受信することができ、対応する方法はクラスメソッドまたは静的メソッドである.継承により、既存のクラスから新しいクラスを作成し、既存のクラスコードの多重化を実現できます.
ヒント:このコラムは悪くないと思いますが、
きっといいコレクションを覚えていますよ!