find100

日常の中で見つけた面白そうなことを発信します

MENU

独学プログラマーでオブジェクト指向を学んでみる

この記事は前回の続きです。

前回の記事をまだ読んでいない方はぜひこちらからどうぞ。

find314.hatenablog.com

f:id:find314:20190321084411j:plain

第12章 プログラミングパラダイム

この章ではクラスの定義の仕方やメソッドの書き方、インスタンスの作成方法などが学べます。

個人的には今までの章の中で一番ややこしいと思います。

おそらく最初に手をつけるのが書籍だったらイマイチ理解できなかったかもしれません。
今でも正直微妙なところはありますが。


まず、手続き型プログラミングは一行一行順にプログラムの状態を変えながら実行していくパラダイム(手法)で、状態はグローバル変数に依存しているのでグローバル変数の変更の際にエラーが起きやすいです。

また、関数型プログラミングは状態がグローバル変数に依存しておらず、関数に渡す引数によって関数の動作が変わるので副作用(グローバル変数の変更)が起きません。

そしてオブジェクト指向のプログラミングは状態をオブジェクトに持たせることでグローバル変数の変更を防いでいます。
オブジェクト指向のプログラミングは複数のクラスの相互作用に関わるオブジェクトの集まりを定義します。

しれっと出てくる__init__()はコンストラクタという特殊メソッドです。
コンストラクタはインスタンスが生成されるときに自動で呼び出されるメソッドのことです。

それでは自分のコードを載せておきます。

#Q!
class Apple:
    def __init__(self,c,t,w,h):
        self.color = c
        self.taste = t
        self.weight = w
        self.hardness = h

#Q2
import math

class Circle:
    def __init__(self,r):
        self.radius = r

    def area(self):
        return self.radius**2*math.pi

circle = Circle(7)
print(circle.area())

#Q3
class Triangle:
    def __init__(self,bottom,height):
        self.height = height
        self.bottom = bottom

    def area(self):
        return self.height*self.bottom*0.5

triangle = Triangle(8,6)
print(triangle.area())

#Q4
class Hexagon:
    def __init__(self,length):
        self.length = length

    def calculate_perimeter(self):
        return self.length*6

hexagon = Hexagon(3)
print(hexagon.calculate_perimeter())

第13章 オブジェクト指向プログラミングの4大要素

4大要素とは、カプセル化・抽象化・ポリモーフィズム・継承の4つのことです。

カプセル化の概念は二つあります。
一つ目は状態を保持する複数の変数と状態を変更したり実行するメソッドをまとめることです。

そして二つ目はデータを外部からいじれないようにすることです。

ただ、本書を読んでいて分かったのはPythonにはプライベート変数がないらしいので名前の前に特定の記号(Pythonの場合は「_」)を付けて、いじらないで下さいよという合図をするそうです。
いじって何か不具合が起きても自己責任でお願いしますというノリっぽいです。

一応いじれるんですね。

抽象化とは、その対象から本当に重要なところだけを抜き出して表現する方法です。

ポリモーフィズムとは、同じインターフェースでも異なるデータ型に対応して実行できますよ、という感じです。

ギリシャ語でPolyが「たくさん」という意味で、Morphが「何でも変化させて形作る」という意味です。

ではp169のチャレンジ問題の自分の答えを載せておきます。

#Q1
class Rectangle:
    def __init__(self, len):
        self.len = len

    def calculate_perimeter(self):
        return self.len*4

class Square:
    def __init__(self, len):
        self.len = len

    def calculate_perimeter(self):
        return self.len*4

rectangle = Rectangle(3)
square = Square(9)
print(rectangle.calculate_perimeter())
print(square.calculate_perimeter())

#Q2
#この解答は間違っています!!!
class Square:
    def __init__(self, len):
        self.len = len

    def change_size(self, n):
         self.len += n

square = Square(5)
print(square.len)

square.change_size(2)
print(square.change_size(2).len)

>>AttributeError: 'NoneType' object has no attribute 'len'



#Q2
class Square:
    def __init__(self, len):
        self.len = len

    def change_size(self, n):
         self.len += n

square = Square(5)
print(square.len)

square.change_size(7)
print(square.len)

square.change_size(-2)
print(square.len)

>>5
>>12
>>10

最初にエラーを出されたのはオブジェクトである(square)とインスタンス名である(len)の間にメソッドを入れたからですかね。

#Q3
class Shape:
    def what_am_i(self):
        print("I am a shape")

class Rectangle(Shape):
    def __init__(self, len):
        self.len = len

    def calculate_perimeter(self):
        return self.len*4

class Square(Shape):
    def __init__(self, len):
        self.len = len

    def calculate_perimeter(self):
        return self.len*4

a_rectangle = Rectangle(5)
print(a_rectangle.what_am_i())

a_square = Square(10)
print(a_square.what_am_i())

#Q4
class Horse:
    def __init__(self, name, living, keeper):
        self.name = name
        self.living = living
        self.keeper = keeper

class Rider:
    def __init__(self, name):
        self.name = name

keeper_name = Rider("Jack Hammer")
white_horse = Horse("Nammily", "Japan", keeper_name)
print(white_horse.keeper.name)

今更気づきましたけどRectangleオブジェクト間違えてますね。
面倒だったので一辺の長さを単純に4倍してますけど・・・。
まぁ動作の上では支障をきたさないので良いですが。

あと本書の解答を見て思ったのですが問題文は「馬に騎手を持たせる」という指示なのに、解答では「騎手に馬を持たせている」ことになってませんか?

僕の考えが違うんですかね・・・。

第14章 もっとオブジェクト指向プログラミング

この章ではインスタンス変数の他にクラス変数という変数の用意の仕方や__init__以外の特殊メソッドについて学べます。

それでは、177ページのチャレンジ問題の自分のコードを載せておきます。

#Q1
class Square:
    square_list = []

    def __init__(self, len):
        self.len = len
        self.square_list.append(self.len)

s1 = Square(14)
s2 = Square(46)

print(Square.square_list)

#Q2
class Square:
    square_list = []

    def __init__(self, len):
        self.len = len
        self.square_list.append(self.len)

    def __repr__(self):
        return "{} by {} by {} by {}".format(self.len, self.len, self.len, self.len)

square = Square(10)
print(square)

#Q3
def para(obj1,obj2):
    return obj1 is obj2

print(para("s", "s"))

第15章 知識を一つにまとめる

object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
これらはいわゆる "拡張比較 (rich comparison)" メソッドです。演算子シンボルとメソッド名の対応は以下の通りです: xy は x.__gt__(y) を呼び出します; x>=y は x.__ge__(y) を呼び出します。

(日本語の公式ドキュメントより引用)

object.__lt__(self, other)とobject.__gt__(self, other)は反対(反射)の関係です。

この章ではチャレンジ問題は用意されていないので本書のコードを写経して終了という感じです。

では、今回は15章までとしておきます。


また、コードに誤りや改善点があれば是非教えてください!

続きはこちらです
find314.hatenablog.com