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