标签:协议 二次 抽象 关系 *args offset 加法 starting __add__
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
*继承原理:实际也是继承树的应用,子类实例总是先去查找自己的命名空间,然后才去查找父类命名空间*
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‘)
"""
*父类中的方法具体在子类中实现;抽象超类是不能被继承的,除非所有抽象方法都在子类实现*
"""
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‘)
"""
# 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
标签:协议 二次 抽象 关系 *args offset 加法 starting __add__
原文地址:http://blog.51cto.com/kongxiaofa/2325065