第 8 章: オブジェクト指向プログラミングの基礎

第 8 章: オブジェクト指向プログラミングの基礎

以前の記事を参照してください:
第 3 章: ブランチ構造
第 4 章: ループ構造
第 5 章: プログラム ロジックの構築 第 6 章
: 関数とモジュールの使用
第 7 章: 文字列と共通データ構造
または、列「Python チュートリアル」ビューに移動してください。


リソースディレクトリ: コード (8)
記事リソースのダウンロード: (1-15 章)
リンク: https://pan.baidu.com/s/1Mh1knjT4Wwt__7A9eqHmng?pwd=t2j3
抽出コード: t2j3

現代を生きるプログラマーであれば「オブジェクト指向プログラミング」という言葉を聞いたことがあるはずですが、「オブジェクト指向プログラミング」とは何かを一言で説明できるかとよく聞かれますが、まずはより正式な用語から見てみましょう。

「一連のデータ構造とそれをオブジェクトに処理するためのメソッドを構成し、同じ動作をするオブジェクトをクラスにまとめ、クラスのカプセル化によって内部の詳細を隠蔽し、ポリモーフィズムによって継承 (特殊化) と一般化 (一般化) によってクラスの特殊化を実現します。 ) オブジェクトタイプに基づいて動的ディスパッチを実現します。

これではさらにわかりにくくなるのでしょうか?それでは、よりわかりやすいステートメントを見てみましょう。次の段落はZhihuからのものです。

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-F3eNhpDP-1679200100642)(./res/oop-zhihu.png)]

注:上記の内容はインターネット上の情報であり、著者個人の見解・意見を表すものではなく、著者自身の立場とは一切関係なく、また、著者は責任を負いません。

前に「プログラムは命令の集合である」と言いましたが、プログラムに記述したステートメントは実行されると 1 つ以上の命令になり、CPU によって実行されます。もちろん、プログラムの設計を簡素化するために、関数の概念を導入し、比較的独立した頻繁に再利用されるコードを関数に組み込み、これらの関数を使用する必要がある場合にその関数を呼び出すだけです (関数の関数の場合)。は複雑すぎて肥大化しているため、関数をさらにサブ関数に分割して、システムの複雑さを軽減できます。しかし、ここまで言って、いわゆるプログラミングとは、プログラマがコンピュータを制御して、コンピュータの動作方法に従ってさまざまなタスクを完了させることであることを発見したかどうかはわかりません。しかし、コンピュータの仕組みは人間の通常の考え方とは異なります。プログラミングをする場合、人間の通常の考え方を放棄してコンピュータに対応しなければならず、プログラミングの面白さは大幅に減ります。それについてしか話せません。もちろん、これらが最も重要なわけではなく、最も重要なことは、複雑なシステムを開発する必要がある場合、コードの複雑さによって開発や保守作業が困難になるため、1960 年代後半に「ソフトウェア危機」が起こり、 「ソフトウェアエンジニアリング」と一連の概念が業界に登場し始めました。

もちろん、現実には上記の問題を解決する「特効薬」がないことはプログラマ界の誰もが知っていますが、ソフトウェア開発者に希望を抱かせるのは、1970 年代に誕生したSmalltalkプログラミング言語です。アイデア (オブジェクト指向プログラミングのプロトタイプは、以前のSimula言語にまで遡ることができます)。このプログラミングの概念によれば、プログラム内のデータとデータを操作する機能は論理的な全体であり、それを「オブジェクト」と呼びます。問題を解決するには、必要なオブジェクトを作成し、そのオブジェクトにさまざまなオブジェクトを送信します。ニュースによると、複数のオブジェクトの協力により、現実世界の問題を解決するための複雑なシステムを構築できるようになりました。

説明:もちろん、オブジェクト指向はソフトウェア開発におけるすべての問題を解決する最後の「特効薬」ではないため、今日のほとんどすべての高度なプログラミング言語は複数のプログラミング パラダイムをサポートしており、Python も例外ではありません。

クラスとオブジェクト

簡単に言えば、クラスはオブジェクトの設計図とテンプレートであり、オブジェクトはクラスのインスタンスです。この説明は概念を概念で説明するようなものですが、少なくともこの文から、クラスが抽象概念であるのに対し、オブジェクトは具体的なものであることがわかります。オブジェクト指向プログラミングの世界では、すべてがオブジェクトであり、オブジェクトには属性と動作があり、それぞれのオブジェクトは一意であり、オブジェクトは特定のクラス (型) に属している必要があります。共通の特性を持つ多数のオブジェクトの静的な特性(属性)と動的な特性(動作)を抽出すると、「クラス」と呼ばれるものを定義できます。

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-d8S7CzC2-1679200100645)(./res/object-feature.png)]

クラスを定義する

Python では、classキーワードを使用してクラスを定義し、事前に学習した関数を使用してクラスにメソッドを定義することで、オブジェクトの動的な特性を記述することができます。

class Student(object):

    # __init__是一个特殊方法用于在创建对象时进行初始化操作
    # 通过这个方法我们可以为学生对象绑定name和age两个属性
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def study(self, course_name):
        print('%s正在学习%s.' % (self.name, course_name))

    # PEP 8要求标识符的名字用全小写多个单词用下划线连接
    # 但是部分程序员和公司更倾向于使用驼峰命名法(驼峰标识)
    def watch_movie(self):
        if self.age < 18:
            print('%s只能观看《熊出没》.' % self.name)
        else:
            print('%s正在观看岛国爱情大电影.' % self.name)

説明:クラスに記述された関数は通常 (オブジェクト) メソッドと呼ばれ、これらのメソッドはオブジェクトが受信できるメッセージです。

オブジェクトの作成と使用

クラスを定義した後、次の方法でオブジェクトを作成し、オブジェクトにメッセージを送信できます。

def main():
    # 创建学生对象并指定姓名和年龄
    stu1 = Student('骆昊', 38)
    # 给对象发study消息
    stu1.study('Python程序设计')
    # 给对象发watch_av消息
    stu1.watch_movie()
    stu2 = Student('王大锤', 15)
    stu2.study('思想品德')
    stu2.watch_movie()


if __name__ == '__main__':
    main()

アクセスの可視性の問題

Student上記のコードについて、C++、Java、C# などのプログラミング経験を持つプログラマーは、オブジェクトnameとプロパティをバインドするにageはどのような種類のアクセス権 (可視性とも呼ばれる) が必要なのか疑問に思うかもしれません。多くのオブジェクト指向プログラミング言語では、通常、オブジェクトのプロパティをプライベート (プライベート) またはプロテクト (保護) に設定します。これは、単に外部アクセスが許可されていないことを意味し、オブジェクトのメソッドは通常パブリック (パブリック) であるためです。パブリック メソッドは、オブジェクトが受け入れることができるメッセージです。Python では、属性とメソッドに対するアクセス権はパブリックとプライベートの 2 種類しかありません。属性をプライベートにしたい場合は、属性名の先頭に 2 つのアンダースコアを使用できます。次のコードで確認できます。これ。

class Test:

    def __init__(self, foo):
        self.__foo = foo

    def __bar(self):
        print(self.__foo)
        print('__bar')


def main():
    test = Test('hello')
    # AttributeError: 'Test' object has no attribute '__bar'
    test.__bar()
    # AttributeError: 'Test' object has no attribute '__foo'
    print(test.__foo)


if __name__ == "__main__":
    main()

ただし、Python は構文上、プライベート プロパティやメソッドのプライバシーを厳密には保証しません。プライベート プロパティやメソッドの名前を変更してアクセスを妨げるだけです。実際、名前変更のルールを知っていれば、引き続きアクセスできます。以下のコードでこれを確認できます。この設定の理由は、「ここでは全員が同意した大人である」という有名な言葉で説明できますなぜなら、大多数のプログラマーは閉鎖性よりもオープン性の方が優れていると信じており、プログラマーは自分の行動に責任があるからです。

class Test:

    def __init__(self, foo):
        self.__foo = foo

    def __bar(self):
        print(self.__foo)
        print('__bar')


def main():
    test = Test('hello')
    test._Test__bar()
    print(test._Test__foo)


if __name__ == "__main__":
    main()

実際の開発では、サブクラスにアクセスできなくなるため、プロパティをプライベートに設定することはお勧めしません (後述)。したがって、ほとんどの Python プログラマは、属性が保護されていることを示すために、属性名を 1 つのアンダースコアで始める命名規則に従います。このクラスの外部のコードは、そのような属性にアクセスするときに注意する必要があります。このアプローチは文法規則ではありません。単一のアンダースコアで始まる属性とメソッドは依然として外部からアクセスできるため、多くの場合、ヒントまたは比喩です。この点については、私の「Python - その年」を参照してください。私たちが踏んできた穴」について記事で説明しました。

オブジェクト指向の柱

オブジェクト指向には、カプセル化、継承、ポリモーフィズムという 3 つの柱があります。後者の 2 つの概念については次の章で詳しく説明しますが、ここではまずカプセル化とは何かについて説明します。私自身のカプセル化の理解は、「隠せる実装の詳細をすべて隠し、単純なプログラミング インターフェイスのみを外部に公開 (提供) すること」です。クラスで定義したメソッドは、実際にはデータとそのデータに対する操作をカプセル化します。オブジェクトを作成した後は、オブジェクトにメッセージを送信して (メソッドを呼び出して)、メソッド内のコードを実行するだけです。たとえば、メソッドの名前と、渡されるパラメーター (メソッドの外部ビュー) のみを知る必要があり、メソッド内部の実装の詳細 (メソッドの内部ビュー) を知る必要はありません。

練習

演習 1: デジタル時計を記述するクラスを定義します。

参考回答:

from time import sleep


class Clock(object):
    """数字时钟"""

    def __init__(self, hour=0, minute=0, second=0):
        """初始化方法

        :param hour: 时
        :param minute: 分
        :param second: 秒
        """
        self._hour = hour
        self._minute = minute
        self._second = second

    def run(self):
        """走字"""
        self._second += 1
        if self._second == 60:
            self._second = 0
            self._minute += 1
            if self._minute == 60:
                self._minute = 0
                self._hour += 1
                if self._hour == 24:
                    self._hour = 0

    def show(self):
        """显示时间"""
        return '%02d:%02d:%02d' % \
               (self._hour, self._minute, self._second)


def main():
    clock = Clock(23, 59, 58)
    while True:
        print(clock.show())
        sleep(1)
        clock.run()


if __name__ == '__main__':
    main()

演習 2: 平面上の点を記述し、点を移動して別の点までの距離を計算するメソッドを提供するクラスを定義します。

参考回答:

from math import sqrt


class Point(object):

    def __init__(self, x=0, y=0):
        """初始化方法
        
        :param x: 横坐标
        :param y: 纵坐标
        """
        self.x = x
        self.y = y

    def move_to(self, x, y):
        """移动到指定位置
        
        :param x: 新的横坐标
        "param y: 新的纵坐标
        """
        self.x = x
        self.y = y

    def move_by(self, dx, dy):
        """移动指定的增量
        
        :param dx: 横坐标的增量
        "param dy: 纵坐标的增量
        """
        self.x += dx
        self.y += dy

    def distance_to(self, other):
        """计算与另一个点的距离
        
        :param other: 另一个点
        """
        dx = self.x - other.x
        dy = self.y - other.y
        return sqrt(dx ** 2 + dy ** 2)

    def __str__(self):
        return '(%s, %s)' % (str(self.x), str(self.y))


def main():
    p1 = Point(3, 5)
    p2 = Point()
    print(p1)
    print(p2)
    p2.move_by(-1, 2)
    print(p2)
    print(p1.distance_to(p2))


if __name__ == '__main__':
    main()

注:この章の図は、 Grady Booch らによる書籍『オブジェクト指向の分析と設計』から引用しています。この本は、オブジェクト指向プログラミングに関する古典的な本です。興味のある読者は、この本を購入して読んで、オブジェクト指向の詳細を学ぶことができます。方向性のある知識。

おすすめ

転載: blog.csdn.net/xyx2023/article/details/129649163