【python類】類

1. 類的命名空間

1> 簡單變量和屬性名稱
    1. 簡單變量名(無點號):遵循函數LEGB做用域法則
         ==> 賦值(X = value):// 使變量成爲本地變量:除非聲明是全局的
         ==> 引用(X):// LEGB搜索變量
     2. 屬性名稱(點號屬性名稱):遵循模塊和類的規則
         ==> 賦值(object.X = value)  // 實例對象命名空間內建立、修改變量
         ==> 引用(object.X):// 基於類的對象:對象內遵循繼承搜索;模塊:對象中直接讀取X(模塊中存在類對象,模塊沒有繼承的概念)
    2> 命名空間組成:命名空間字典和命名空間連接
        屬性點號運算實際是內部字典的取值; // x.data = x.__dict__['data']

        x.__dict__  // 獲取實例的命名空間
        x.__class__  // 獲取實例的父類
        sub.__bases__  //  sub類的父類

        命名空間連接:當前命名空間找不到,會按照繼承搜索查找
        """
        父類層次:
        B: B --> A
        F: F --> D --> B --> A --> C --> A --E 
        """
        class A: pass
        class B(A): pass
        class C(A): pass
        class D(B,C): pass
        class E: pass
        class F(D,E): pass

2. 繼承

*繼承原理:實際也是繼承樹的應用,子類實例老是先去查找本身的命名空間,而後纔去查找父類命名空間*
    class Manager(Person):
   # 7 調用父類的構造函數:咱們能夠決定哪些參數使用父類,好比此處的Job
             def __init__(self,name,pay):
                     Person.__init__(self,name,'mgr',pay)
             def givePay(self,percent,bouns=.10):
       # 調用方法兩種方式 1) 實例.方法() 2)類.方法(self) 無論哪一種,方法都須要傳遞一個self調用
                     Person.givePay(self,percent + bouns)
   # 6.2 繼承:擴展子類行爲,只能在子類實例對象使用
             def doSomething(self):
                         return '[%s %s]' %(self.__class__.__name__,"考覈")

    """
        # coding:utf-8
        """
        類的繼承
        """

        class Employees:
            def __init__(self,name,salary=0):
                    self.name = name
                    self.salary = salary
            def givePay(self,percent):
                    self.salary = self.salary + (self.salary * percent)
            def work(self):
                    print(self.name,"does stuff")
            def __repr__(self):
                    return "<Employees: name:%s,salary:%s>" %(self.name,self.salary)

        class Chef(Employees):
            def __init__(self,name):
                    Employees.__init__(self,name,50000)
            def work(self):
                    print(self.name,'make foods')

        class Server(Employees):
            def __init__(self,name):
                    Employees.__init__(self,name,40000)
            def work(self):
                    print(self.name,'interfaces to customer')

        class PizzaRobbt(Chef):
                def __init__(self,name):
                        Chef.__init__(self,name)
                def work(self):
                        print(self.name,'make pizza')

        if __name__ == "__main__":
        # 必定要分清楚:object.attr 和 賦值
        # 繼承是從點號運算開始的,觸發實例、類以及超類中屬性搜索
                bob = PizzaRobbt('bob')
                print(bob)
                bob.work()
                bob.givePay(0.2)
                print(bob)

            for kclass in Employees,Chef,Server,PizzaRobbt:
            # kclass.__name__ 是一個字符串
                    obj = kclass(kclass.__name__)
                        obj.work()
            """

            """

            """
                類的組合:order下單包含Server、Customer、PizzaRobbt一塊兒完成一件事情.
            """

            from employees import Server,PizzaRobbt

            class Customer:
                    def __init__(self,name):
                            self.name = name
                    def order(self,server):
                            print(self.name,"order pizza",server)
                    def pay(self,server):
                            print(self.name,'pay money',server)

            class Oven:
                    def bake(self):
                            print('ovens bakes')

            class PizzaShop:
                    def __init__(self):
                            self.server = Server('Pat')
                            self.chef = PizzaRobbt('bob')
                            self.oven = Oven()
                    def order(self,name):
                            customer = Customer(name)
                            customer.order(self.server)
                            self.chef.work()
                            self.oven.bake()
                            customer.pay(self.server)

                if __name__ == "__main__":
                        scene = PizzaShop()
                        scene.order('tom')

             """

3. 抽象超類

*父類中的方法具體在子類中實現;抽象超類是不能被繼承的,除非全部抽象方法都在子類實現*
    """
    class Super:
             def method(self):
                     print("in Super.method")
             def delegate(self):
                     self.action()
       # 要是子類沒有提供action,那麼就會拋錯:採用assert
       # assert False,'action must be method!'

     class Provider(Super):
             def method(self):
                    print('starting Sub.method')
                    Super.method(self)  // 擴展父類的方法
                    print('ending Sub.method')
             def action(self):  // 實現父類的抽象方法
                    print('In Provider.action')
    """

4. 運算符重載

# coding:utf-8

        """
            運算符重載
        """
        import operator

        class Number:
        # 1. 攔截構造方法
                def __init__(self,data):
                        self.data = data
        # 2. 攔截減法運算
                def __sub__(self, other):
                        return Number(self.data - other)

        class Indexer:
                def __init__(self,data):
                        self.data = data
                # 3.1 攔截索引、切片操做:實例對象擁有索引、切片操做
                # 3.1 重載迭代:每次迭代實例對象時都會調用該方法,傳入索引值
                def __getitem__(self, item):
                        print('getitem:',item)
                        return self.data[item]
                # 3.2 攔截索引賦值、切片賦值操做:實例對象擁有索引賦值、切片賦值操做
                def __setitem__(self, key, value):
                        self.data[key] = value

        class Squeres:
        """
  iter() 迭代器工廠函數
            __iter__() 迭代器協議,能夠在自定義類裏面造成迭代器 調用方式 1:手動next(i)調用    2:可迭代環境調用

     可迭代對象:能夠用迭代環境循環的對象
    迭代器:支持迭代協議(也就是可使用next調用);迭代器是能夠記住狀態的

    可迭代對象不必定是迭代器 (for i in 'spam':)
    迭代器必定是可迭代對象(支持在迭代環境循環調用)
"""
                def __init__(self,start,stop):
                        self.value = start - 1
                        self.stop = stop
                # 3.3 在任何迭代環境中,會優先調用__iter__;以後調用__getitem__
                # __iter__調用迭代協議;__getitem__調用索引取值,知道拋出索引超範
                # __iter__ 根本沒有重載索引表達式:X = Squeres(1,5) X[1] 報錯
                # __iter__ 只循環一次: X = Squeres(1,5) [for i in X] ==> 第二次迭代會爲空
                def __iter__(self):  # 定義了__iter__的方法,類實例是可迭代對象
                        return self  # 此處返回self,每次生成的可迭代對象只能調用一次
                def __next__(self):
                        if self.value == self.stop:
                                raise StopIteration
                        self.value += 1
                        return self.value

            # 調用next方法
            class SkipIterator:
                    def __init__(self,wrapper):
                            self.wrapper = wrapper
                            self.offset = 0
                    def __next__(self):
                            if self.offset >= len(self.wrapper):
                                    raise StopIteration
                            item = self.wrapper[self.offset]
                            self.offset += 2
                            return item

                # 返回迭代器對象
                class SkipObject:
                        def __init__(self,wrapper):
                                    self.wrapper = wrapper
                        def __iter__(self):
                                    return SkipIterator(self.wrapper)

            class Iter1:
            """
    1. 成員關係:contains(映射) --> iter --> getitem
    2. __iter__和__getitem__ 均可捕獲迭代環境
      區別:1 __iter__ 使用迭代協議獲取值(__next__),且能夠保持狀態信息;__getitem__ 使用索引獲取值
           2 __getitem__ 能夠支持索引和切片操做
           3 當字段索引行數據時(list、tuple),二者可替換;爲hash類型時(dict、set),只能用__iter__
"""
                        def __init__(self,value):
                                    self.value = value
                        def __getitem__(self, item):
                                    print("getitem:",item)
                                    return self.value[item]
                        def __iter__(self):
                                    print("iter=>",end="")
                                    self.offset = 0
                                    return self
                        def __next__(self):
                                    print("next:",end="")
                                    if self.offset == len(self.value):
                                            raise StopIteration
                                    item = self.value[self.offset]
                                    self.offset += 1
                                    return item
                    def __contains__(self, item):
                                    print("contanins: ",end='')
                                    return item in self.value

        class Library(object):
                    def __init__(self):
                                self.books = {'title': 'a', 'title2': 'b', 'title3': 'c', }

                    def __getitem__(self, i):
                                return self.books[i]

                    def __iter__(self):
                            # 方法1 使用生成器
                            for titles in self.books:
                                    yield self.books[titles]

        class Empty:
            """
    攔截屬性點號操做;
    若是python能夠在繼承樹(self.__dict__)找到該屬性,那麼__getattr__方法不會被調用

    賦值:self.attr = value ==> self.__setattr__(attr,value)
        """
                    def __init__(self):
                            self.data = 0
                    def __getattr__(self, item):
                            if item == "age":
                                    print("__getattr__:",item,end=" ")
                                    return 40
                            else:
                                    raise AttributeError(item)
                    def __setattr__(self, key, value):
                            if key == "data":
                            # 此處必定用self.__dict__[key] = value
                            # 所以在__setattr__裏面賦值,會再調用__setattr__,形成內存溢出
                                        self.__dict__[key] = value
                            else:
                                        raise AttributeError(key + "not allowed")

            class A:
            """
    1.
    __add__ 原處加法(a + b ;a += 1)
    __radd__ 右側加法
    2.
    a + b ,python會先去a裏面找__add__,找不到會去__radd__查找
    這個例子: b + a 會報錯,由於python會先去B找__add__,而後去A找__radd__,均不知足
    3. 每一個二元運算符都支持:包括 __sub__(減法)
"""
                        def __init__(self,val):
                                    self.val = val
                        def __add__(self, other):
                                    return self.val + other
            class B:
                        def __init__(self,val):
                                    self.val = val
                        def __radd__(self, other):
                                    return self.val + other

            class Callee:
                """
    編寫api接口經常使用:能夠將類和實例調用看成函數來使用,而且能夠將實例的狀態保留到函數內部,天然而然成爲了被一個函數記住
    ==>並調用另外一個函數的實現
    __call__ 任何定義了該方法的類和實例 支持與常規函數一致的調用

    c = Callee()
    c(1,2,3) ==> __call__ (1,2,3) {}
"""
                def __call__(self, *args, **kwargs):
                            print("__call__,",args,kwargs)

        class CallBack:
                    def __init__(self,color):
                            self.color = color
                    def __call__(self):
                            print('turn',self.color)

    class BiJiao:
"""
比較:__lt__ __gt__ __cmp__(python3.0失效,使用operator替代)
"""
            pass

    class Bool1:
"""
    攔截布爾操做
    __bool__ >> __len__
    python 3.0 優先嚐試__bool__ python 2.6優先嚐試__len__
"""
                def __bool__(self):
                            return True
相關文章
相關標籤/搜索