Python、はじめました

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

Python SoloLearn Object-Oriented Programming②

f:id:pokita:20180421094155p:plain 

 

Date Hiding

 カプセル化

A key part of object-oriented programming is encapsulation, which involves packaging of related variables and functions into a single easy-to-use object- an instance of class.

 

情報隠蔽

Data hinding states that implementation details of class should be hidden,

and a clean standard interface be presented for those who want to use

the class.

 

カプセル化情報隠蔽、どれも似たような概念なので区別しづらい。

いろいろネットを調べていると、ここが一番的を射ていると思った。

d.hatena.ne.jp

カプセル化情報隠蔽って感じかな

 

いろんな関数(メソッド)や変数(属性)を内包した、

外部の影響から独立したエコシステムをカプセル化と呼び、

その一つの特徴である、classやinstance外からの属性へのアクセスを禁止する

特徴のことを情報隠蔽と呼ぶ。

みたいな。

 

しかし、Python

The Python philosophy is often stated as

"We are all consenting adults here.",

meaning that you shouldn't put arbitrary restrictions on

accessing part of a class.

ということで、そもそも情報隠蔽には反対の立場を取っている。

言語によってそれぞれ哲学があるっての面白い。

一応、class外のコードからは呼ばれないようにする(privateにする)

方法はあるらしい。

 

ダブルアンダースコア__attribute

Strongly private methods and attributes have a double underscore 

at the beggining of their names.

This cause their names to be mangled, which means  that 

they can't be accessed from outside the class.

 

属性名の前にダブルアンダースコア"__"を付けることで、

privateにすることができる。

class Spam:
__egg = 7

def print_egg(self):
print(self.__egg)


s = Spam()
s.print_egg()
>>>7
print(s.__egg)
>>>AttributeError: 'Spam' object has no attribute '__egg'

Spamクラスのメソッドであるprint_egg()からなら、

__egg属性にアクセスできるが、

外部から直接s.__eggとアクセスすることはできない。

これは、属性eggをprivateにするため、というよりは

クラスがいくら継承されようとも属性eggの値が上書きされないようにするため

の手段なのである。

その副産物としてのprivate化なので、用法容量は正しく。

class Spam:
egg = 7

def print_egg(self):
print(self.egg)


class Ham(Spam):
egg = 14

def print_egg(self):
print(self.egg)

def super_print_egg(self):
super().print_egg()


s = Ham()
s.print_egg()
>>>7
s.super.print_egg()
>>>7

class Spamではegg属性は7となっているが、

その継承先であるclass Hamではegg属性は14に上書きされている。

class Hamのinstanceであるs内のおいては、属性eggは14であるため、

class Hamのメソッドであるprint_egg(self.eggの値を出力)においても、

class Spamのメソッドを呼ぶsuper_print_egg(self.eggの値を出力)においても、

同じ7を出力する。

 

これが、ダブルアンダースコアを使うことで、

class Spam:
__egg = 7

def print_egg(self):
print(self.__egg)


class Ham(Spam):
__egg = 14

def print_egg(self):
print(self.__egg)

  def super_print_egg(self):
    super().print_egg()

s = Ham()
s.print_egg()
>>>7
s.super.print_egg()
>>>14

class Spamではegg属性は7となっているが、

その継承先であるclass Hamではegg属性は14に上書きされない!

なぜなら、class Spamの属性である__eggと

その継承先のclass Hamの属性である__eggには明確な名前の相違があるから。

(ダブルアンダースコアによって認識される名前がmangled壊されている。)

 

Class Methods

そもそもメソッドとは?

Methods of objects we've looked at so far are called

by an instance of a class, which is then passed to the self parameter.

 

クラスで定義付けられたメソッドのうち、第一引数にselfを取るメソッドを

インスタンス)メソッドという。

通常、メソッドとはインスタンスメソッドのことを指す。

第一引数にインスタンスを表すselfを伴うことから分かるように、

これらのメソッドはインスタンスが生成されなければ呼び出せないものであり、

selfは各インスタンスオブジェクトを表している。

class Spam:
def __init__(self):
self.name = self

def print_self(self):
print(self.name)


s = Spam()
s.print_self()
t = Spam()
t.print_self()
>>><__main__.Spam object at 0x0000021B0BE7E2E8>
>>><__main__.Spam object at 0x0000021B0BE7E438>

sインスタンスのprint_selfメソッドとtインスタンスのprint_selfメソッドでは

出力がそれぞれ違うことがわかる。

 

クラスメソッド

Class methods are called by a class, which is passed to the cls parameter of the method.

クラスメソッドは、インスタンスを作らずに

クラス内で定義した関数(メソッド)を実行するために存在している。

用途としては、”そのクラスを用いていくつのインスタンスが作られたか”

を調べることなどが挙げられる。

class Number:
__num = 0

def __init__(self):
Number.__num += 1
self.__num += 1
self.math = 10 + 15 * Number.__num
self.english = 10 + 12 * Number.__num
self.science = 10 + 13 * Number.__num

@classmethod
def get_class_num(cls):
return Number.__num


one = Number()
two = Number()
three = Number()
print(Number.get_class_num())
>>>3

 @classmethodを付けずにそのままメソッドとすると、

get_class_num()メソッドを実行するには、インスタンスを作らなければならず、

純粋にインスタンスの個数を調べることができない。

 

今回はここまで。