[Python 3.1] クラスについて

■クラスを定義する
#### public, protected, privateおよびインターフェースの概念は無い
#### 
#### 属性(変数、関数、クラス、メソッド)が公開設定されているか
#### 非公開設定されているかのみで、基本的に読み書きの排他制御は出来ない
#### 
#### 接頭アンダースコア2つ "__" で非公開設定となる
#### 接頭アンダースコア1つ "_" は公開設定 & 余程の事がない限り使わない
#### で下さいの意
#### 
#### 呼び出し側で存在しない属性を使用するとインスタンス変数として新たに
#### 追加される

class Person(object):
    # クラス定数(非公開設定)
    #  だたし、Person._Person__SEX_MALEで参照することが出来てしまう
    __SEX_MALE   = 0
    __SEX_FEMALE = 1

    # クラス定数(公開設定)
    #  ただし、Person.SEX_MALE = 9で外部から書き換えが出来てしまう
    SEX_MALE   = 0
    SEC_FEMALE = 1

    #### そもそも定数という概念が無い?
    #### クラスを使う人が代入しないように祈る
    
    # コンストラクタ
    def __init__(self, name, age, sex):
        # インスタンス変数(非公開設定)
        self.__name = name
        self.__age  = age
        self.__sex  = sex
        self.__etc  = {}
        
        # インスタンス変数(公開設定)
        #  低レベルで局所的なデータ操作用か処理量が多い場合以外では使わない
        #  propertiesで実装した方が拡張性が増す
        self.name  = name
        self._name = name
        self.__temp = "A"  # アクセス制限は下で定義
        
    # デストラクタ
    #  ガベージコレクションやdelされた時に呼ばれる場合がある
    def __del__(self):
        del self.__etc

    # オブジェクトの文字列表現を作る
    #  java.lang.String.toString()相当
    def __str__(self):
        return "Person{{name=\"{}\", age={}}}".format(self.name, self.age)

    # インスタンス変数(公開設定)
    #  外部とはSetter/Getter経由でやり取りし、直接値を触らせない
    #  @xxxxはデコレーター

    # 別名にて参照させる
    @property
    def bloodType(self):
        return self.__temp

    # 変更可能にする
    @bloodType.setter
    def bloodType(self, value):
        self.__temp = value

    # 除去可能にする
    @bloodType.deleter
    def bloodType(self):
        del self.__temp


# クラスの継承
class PersonEx(Person):
    def __init__(self, name, age):
        # スーパークラスのコンストラクタの呼び出し
        Person.__init__(self, name, age)
    
    def __del__(self):
        # スーパークラスのデストラクタの呼び出し
        Person.__del__(self)

class Book(object):
    def __init__(self, *args):
        print( "****Book.__init__" )

# 多重継承
#  継承の記述順(左から右)でメンバが検索される
#  super()は一番左のスーパークラスを指す
class PersonEx2(PersonEx, Book):
    def __init__(self, sex, *args):  # *argsにはsex以外のパラメータが入る
        super(PersonEx2, self).__init__(*args)  # PersonEX.__init__()
        super(__class__, self).__init__(*args)  # PersonEx.__init__()
        super().__init__(*args)                 # PersonEx.__init__()

        self.__sex = sex

class PersonEx3(Book, PersonEx):
    def __init__(self, *args):
        super(PersonEx3, self).__init__(*args)  # Book.__init__()
        super(__class__, self).__init__(*args)  # Book.__init__()
        super().__init__(*args)                 # Book.__init__()

class PersonEx4(PersonEx, Book):
    def __init__(self, *args):
        PersonEx.__init__(self, *args)
        Book.__init__(self, *args)

■インスタンス化
# __init__(self, name, age)の場合、第一引数のselfは暗黙的に自インスタンスが渡さ
# れるので省略する
person = Person("lee",15)

# クラスのチェック
p   = Person("p1",10)
px  = PersonEx("p2",20)
px2 = PersonEx2("p3",30)
isinstance(p,   Person)    はtrue
isinstance(p,   PersonEx)  はfalse
isinstance(p,   PersonEx2) はfalse
isinstance(px,  Person)    はtrue
isinstance(px,  PersonEx)  はtrue
isinstance(px,  PersonEx2)  はfalse
isinstance(px2, Person)    はtrue
isinstance(px2, PersonEx)  はtrue
isinstance(px2, PersonEx2) はtrue

■比較できるクラスを作る
class Person(object):
    # a <  b は __lt__()
    # a <= b は __le__()
    # a >  b は __gt__()
    # a >= b は __ge__()
    # a == b は __eq__()
    # a != b は __ne__()

    # 第1キー __name、第2キー __age
    def __lt__(self, other):
        return ((self.__name, self.__age) <  (other.__name, other.__age))
    
    def __eq__(self, other):
        return ((self.__name, self.__age) == (other.__name, other.__age))

# インスタンスの比較
#  上記で__lt__()と__eq__()は内部値を比較するように実装している
Person("mick",10) <  Person("beck",20) はfalse
Person("mick",10) <  Person("oeck",10) はtrue
Person("mick",10) == Person("mick",10) はtrue

# ソートした結果を返す (__lt__()が使用される)
newPersons = sorted(persons)
newPersons = sorted(persons, reverse=True)  # 逆順

# 中身をソートする (__lt__()が使用される)
persons.sort()
persons.sort(reverse=True)  # 逆順

# __lt__()を実装していなくてもkeyとoperator.attrgetter()を使うと
# ソートが可能。reverseは省略可
import operator
persons.sort( key=operator.attrgetter('age','_Person__name'), reverse=True )
newPersons = sorted( persons, key=operator.attrgetter('age'), reverse=True )

■特定条件のリストを作る
# 18歳未満の名前のリスト
person_under18 = [person.name for person in persons if person.age < 18]

■要素の合計値の算出
total = sum([1, 2, 3, 4, 5])
total = sum([person.age for person in persons])