Python、はじめました

非IT系私文卒リーマン vs Python の全記録

Python SoloLearn Object-Oriented Programming①

f:id:pokita:20180421094155p:plain

ここ一番つまずいた章でした♨

やっぱオブジェクト指向難しい。。。

いままで勉強してきた各オブジェクトint,str,list,set等を自作する。

それがオブジェクト指向…という考えでOK???

 

 

Classes

 クラスとインスタント

The class describes what the object will be,

but is separete from the object itself.

In other words, a class can be described as an object's blueprint.

class Cat:
def __init__(self, color, legs):
self.color = color
self.legs = legs


print(Cat)
>>><class '__main__.Cat'>

 このCatをclassと呼ぶ。

class Cat:
def __init__(self, color, legs):
self.color = color
self.legs = legs


mink = Cat("pink", 4)
print(mink)
>>><__main__.Cat object at 0x000001D6B8CDE978>

このCatクラスを代入することで生成されたminkオブジェクトを

Catクラスのインスタンスと呼ぶ。

関係は以下のたい焼きの喩がわかりやすい。

f:id:pokita:20180421141901g:plain

 

属性

クラスは関数同様それぞれ独自の名前空間を持っている。

クラス内で定義した変数(関数も含む)を属性といい、

クラス.属性でその値を戻すことができる。

def a_equal_2():
a = 2
return a


print(a_equal_2())
>>>2

関数ではこう定義されるものを、クラスなら

class a_equal_2:
a = 2

print(a_equal_2.a)
>>>2

として表すことができる。

このような属性aをクラス変数と呼ぶことがある。

 

メソッド

Classes can have other methods defined to add to functionality to them.

属性のうち、関数のものをメソッドと呼ぶ。

 class Dog:
  def __init__(self,name,color):
self.name = name
self.color = color

def bark():
print("Woof!")


fido = Dog("Fido", "brown")
fido.bark()
>>>Woof!
print(fido.bark)
>>><bound method Dog.bark of <__main__.Dog object at 0x000002824D50ECF8>>

barkはメソッド(関数)なので、必ず()を付けること。

付け忘れるとそのままmethodオブジェクトを戻してしまう。

 

__init__

This method is called when an instance of the class is created,

using the class name as a function.

 

__init__メソッドはそのほかのメソッドと異なる特殊メソッドと呼ばれる。

クラス内でdefによって関数として定義づけられる、

というところまではその他のメソッドと同じなのだが、

そのメソッドの呼び出し方が、

class_name.__init__()ではなく、

instance_name = class_name(arg1,arg2,…)のときである。

class Dog:
def __init__(self,name,color):
self.name = name
self.color = color


fido = Dog("Fido", "brown")
print(fido.color)
>>>brown

インスタンスを作成するときは、変数にクラスを代入するのが常だが、

そのクラスに持たせた引数をどう処理するかについて定義されているのが、

そのクラス内に書かれた__init__メソッドなのである。

 

事前にクラス変数で属性を決定するのに比べて、

__initi__を持たせた方がよりクラスに柔軟性ができ、

多様なインスタンスを作成することができる。

 

Magic Methods

They are used to create functionally

that can't be represented as  a normal method.

 

オブジェクト指向プログラミングをしていると

メソッドを使えば書けるけど、もっと楽に書きたいな~

というときがある。

例えば単純な足し算したい場合。

class Number:
def __init__(self, x):
self.x = x

def plus(self, other):
return self.x + other.x


nine = Number(9)
one = Number(1)
print(nine.plus(one))
#plusメソッドによってoneインスタンスの属性x=1が呼び出される。
>>>10

ただ単に足し算をしたいだけなのに、右辺をインスタンスに、

左辺を引数に取るようなこの書き方では少々読みづらい。

そこで活躍するのが特殊メソッドたちとなる。

独自クラスは、デフォルトでは演算ができないため、

使う際はイチからdefで定義する必要がある。

 

算術演算子系のオーバーロード(左辺)

メソッド(クラス内での定義) クラス外での書き方  意味
__add__(self, other) self + other 加算
__sub__(self, other) self - other 減算
__mul__(self, other) self * other 乗算
__floordiv__(self, other) self // other 除算
__truediv__(self, other) self / other 除算
__mod__(self, other) self % other あまり
__pow__(self, other) self  ** other 冪乗

上記の特殊メソッドは左側のメソッドとして実行される。

引数selfを左辺に、引数otherを右辺に取る。

class Number:
def __init__(self, x):
self.x = x

def __add__(self, other):
return self.x + other.x


nine = Number(9)
one = Number(1)
print(one + nine) #+からone.__add__(self,nine)が呼ばれる。
>>>10

とっても綺麗になった。

 

算術演算子系のオーバーロード(右辺)

メソッド(クラス内での定義) クラス外での書き方  意味
__radd__(self, other) other + self 加算
__rsub__(self, other) other - self 減算
__rmul__(self, other) other * self 乗算
__rfloordiv__(self, other) other // self 除算
__rtruediv__(self, other) other / self 除算
__rmod__(self, other) other % self あまり
__rpow__(self, other) other ** self 冪乗

上記の特殊メソッドは右側のメソッドとして実行される。

引数selfを右辺に、引数otherを左辺に取る。

class Number:
def __init__(self, x):
self.x = x

def __radd__(self, other):
return self.x + other


one = Number(1)
print(9 + one) #+からone.__radd__(self, 9)が呼ばれる。
>>>10

 ちなみにこの式、oneと9を逆転させると

class Number:
def __init__(self, x):
self.x = x

def __radd__(self, other):
return self.x + other


one = Number(1)
print(one + 9 )
>>>TypeError: unsupported operand type(s) for +: 'Number' and 'int'

という感じでエラーになる。

 

比較演算子系のオーバーロード

メソッド 意味  
__eq__(self, other) self == other 等しい
__ne__(self, other) self != other 等しくない
__lt__(self, other) self < other より小さい
__gt__(self, other) self > other より大きい
__le__(self, other) self <= other 以下
__ge__(self, other) self >= other 以上
class Word:
def __init__(self, text):
self.text = text

def __eq__(self, other):
return self.text.lower() == other.text.lower()


sample1 = Word('Hello')
sample2 = Word('hello')
print(sample1 == sample2)

 

Inheritance

独自クラスは、デフォルトでは演算ができないため、

演算機能を付けるには、いちいち定義しなおさないといけない。

けっこうめんどうだなぁ……

その悩みも継承を使えば楽に解決できる。

例えばこれ。

class Number:
def __init__(self, x):
self.x = x


one = Number(1)
two = Number(2)

print(one + two)
>>>TypeError: unsupported operand type(s) for +: 'Number' and 'Number'

そこで使えるのがtypeオブジェクトintからの継承。

class Number(int):
def __init__(self, x):
self.x = x


one = Number(1)
two = Number(2)

print(one + two)
>>>3

intを継承したことによって、+と同時に-や//等の演算子も使えるようになった。

 

今回はここまで。

 

今回はこんな感じ。