Python进阶10---魔术方法*
特殊属性
查看属性
#animal.py class Animal: x = 123 def __init__(self,name): self._name = name self.__age = 10 self.weight = 20 print('animal Module\'s names = {}'.format(dir())) #animal Module's names = ['Animal', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__'] #cat.py import animal from animal import Animal class Cat(Animal): x = 'cat' y = 'abcd' class Dog(Animal): def __dir__(self): return ['dog']#指定返回列表 print('*'*10) print('Current Module : {}'.format(dir())) print('animal Module : {}'.format(dir(animal))) print('Cat Module : {}'.format(dir(Cat))) print('object Module : {}'.format(sorted(object.__dict__))) print('object Module : {}'.format(sorted(object.__dict__.keys()))) print('*'*10) tom = Cat('tom') dog = Dog('dog') print(sorted(dir(tom))) print(sorted(tom.__dict__)) print(sorted(dir(Dog))) print(sorted(dir(dog))) #dir()的等价,近似如下,__dict__字典中几乎包括了所有属性 print(sorted(set(tom.__dict__.keys())|set(Cat.__dict__.keys())|set(object.__dict__.keys())))
魔术方法
hash
class A: def __init__(self): self.a = 'a' self.b = 'b' def __hash__(self): return 1 print(hash(A()))#1 print(A(),A())#<__main__.A object at 0x00000000028F54E0> <__main__.A object at 0x00000000028F55F8> a = A() print({A(),A()})#{<__main__.A object at 0x00000000028F55F8>, <__main__.A object at 0x0000000002993F60>} s = {a,a} print(s)#{<__main__.A object at 0x00000000028F54E0>} # set内部机制会先调用is判断是否是同一对象的引用
#如果想要实现set剔除相同的key,还需要增加__eq__函数
class A: def __init__(self): self.a = 'a' self.b = 'b' def __hash__(self): return 1 def __eq__(self, other): return self.a == other.a #相当于是return True print(hash(A()))#1 print(A(),A())#<__main__.A object at 0x00000000029054E0> <__main__.A object at 0x00000000029055F8> print({A(),A()})#{<__main__.A object at 0x00000000029055F8>} s = {A(),A()} print(s)#{<__main__.A object at 0x00000000029055F8>}
查看源码后发现源码中有一句__hash__=None,也就是如果调用__hash__()相当于None(),一定报错。所有类都继承object,
而这个类是具有__hash__()方法的,如果一个类不能被hash,就是把__hash__设置成None了。
#注意 from collections import Hashable print(isinstance(list(),Hashable))#False print(isinstance(list,Hashable))#True
class Point: def __init__(self,x,y): self.x = x self.y = y def __hash__(self): return hash((self.x,self.y)) def __eq__(self, other): return self.x == other.x and self.y == other.y p1 = Point(4,5) p2 = Point(4,5) print(hash(p1))#3713084879518070856 print(hash(p2))#3713084879518070856 print(p1 is p2)#False print(p1 == p2)#True print(set((p1,p2)))#{<__main__.Point object at 0x0000000002993E48>} print(isinstance(p1,Hashable))#True
bool
class A: pass print(bool(A))#True print(bool(A()))#True class B(object): def __bool__(self): return False print(bool(B))#True print(bool(B()))#False class C: def __len__(self): return 0 print(bool(C))#True print(bool(C()))#False
可视化
class A: def __init__(self): self.a = 'a' self.b = 'b' def __repr__(self): return 'repr:{} {}'.format(self.a,self.b) def __str__(self): return 'str:{} {}'.format(self.a,self.b) print(A())#print函数使用__str__ print([A()])#[]使用__str__,但其内部使用__repr__ print(str(A()))#[]使用__str__,str()函数也使用__str__ a1 = A() a2 = A() lst = [a1,a2] print(lst)#[repr:a b, repr:a b] for i in lst: #str:a b str:a b print(i)
运算符重载
class A: def __init__(self,x): self.x = x def __sub__(self, other): return self.x - other.x def __isub__(self, other): tmp = self.x - other.x return A(tmp) def __lt__(self, other): return self.x < other.x def __repr__(self): return str(self.x) def __str__(self): return str(self.x) a = A(1) b = A(3) c = A(5) lst = [a,c,b] print(sorted(lst))#[1, 3, 5] x = A(5) y = A(4) print(x-y,x.__sub__(y))#1 1 x -= y print(x)#1
class Point: def __init__(self,x,y): self.x = x self.y = y def add(self, other): return Point(other.x + self.x,other.y+ self.y) def __add__(self, other): return (self.x+other.x,self.y+other.y) def __eq__(self, other): return self.x == other.x and self.y == other.y def __str__(self): return "Point:{},{}".format(self.x,self.y) p1 = Point(1,1) p2 = Point(1,1) points = (p1,p2) print(points[0].add(points[1]))#Point:2,2 #运算符重载 print(points[0]+points[1])#(2, 2) print(Point(*(points[0]+points[1])))#Point:2,2 print(p1 == p2)#True
运算符重载应用场景
容器相关方法
#购物车 class Item: def __init__(self,name,**kwargs): self.name = name self._spec = kwargs def __repr__(self): return "{} = {}".format(self.name,self._spec) class Cart: def __init__(self): self.items = [] def __len__(self): return len(self.items) def additem(self,item): self.items.append(item) def __add__(self, other):# + # print(other) self.items.append(other) return self def __iter__(self):#迭代和in return iter(self.items)#未加iter()则会TypeError: iter() returned non-iterator of type 'list' def __repr__(self): return str(self.items) def __getitem__(self, index):#索引操作 return self.items[index] def __setitem__(self, key, value):#索引赋值运算 # print(key,value) self.items[key] = value # self[key] = value #不可以,这种方式相当于调用上面的__getitem__ # def __missing__(self, key):#针对dict/set key missing有效 # print('key=',key) cart = Cart() print(len(cart)) print(cart+2+3) #__iter__ for i in cart: print(i) print('*'*10) print(cart[1]) cart[1] =100 #链式编程实现加法 print(cart+2+3+4) cart.__add__(2).__add__(3)
可调用对象
class Fib: def __init__(self): self.lst = [0,1,1] def __len__(self): return len(self.lst) def __iter__(self): return iter(self.lst) def __call__(self,index): if index<0: return IndexError('Wrong Index') if index < len(self.lst): return self.lst[index] for i in range(len(self.lst),index+1): self.lst.append(self.lst[i-2] + self.lst[i-1]) return self.lst[index] def __getitem__(self, index): return self.lst[index] def __str__(self): return str(self.lst) __repr__ = __str__ fib = Fib() print(fib(4))#__call__ print(fib(5)) print(fib(6)) print(fib(100)) print(fib(4)) print(fib[4])#__getitem__ for x in fib: print(x,end=' ')
上下文管理
上下文管理对象
class Point: def __init__(self): print('init') def __enter__(self): print('enter') def __exit__(self, exc_type, exc_val, exc_tb): print('exit') with Point() as f: print('do sth')
上下文管理的安全性
class Point: def __init__(self): print('init') def __enter__(self): print('enter') def __exit__(self, exc_type, exc_val, exc_tb): print('exit') with Point() as f:#虽然抛出异常但是__enter__和__exit__都执行了 raise Exception('error') print('do sth')
import sys class Point: def __init__(self): print('init') def __enter__(self): print('enter') def __exit__(self, exc_type, exc_val, exc_tb): print('exit') with Point() as f:#虽然抛出异常但是__enter__和__exit__都执行了 # raise Exception('error') sys.exit() print('do sth') print('outer') #init #enter #exit
With语句
class Point: def __init__(self): print('init') def __enter__(self): print('enter') def __exit__(self, exc_type, exc_val, exc_tb): print('exit') p = Point() with p as f:#虽然抛出异常但是__enter__和__exit__都执行了 print(p == f)#为什么不相等? print('do sth') print('outer')
class Point: def __init__(self): print('init') def __enter__(self): print('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): print('exit') p = Point() with p as f:#虽然抛出异常但是__enter__和__exit__都执行了 print(p == f)#修改__enter__返回值后相等 print('do sth') print('outer')
__enter__方法和__exit__方法的参数
class Point: def __init__(self): print('init') def __enter__(self): print('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): print('exit') print(exc_type)#<class 'Exception'> print(exc_val)#New Error print(exc_tb)#<traceback object at 0x00000000029FD508> return True#此时会压制异常,即不会抛出异常 p = Point() with p as f: raise Exception('New Error') print('do sth') #输出如下: init enter exit <class 'Exception'> New Error <traceback object at 0x00000000029FD688>
练习
import time import datetime from functools import wraps #装饰器实现 def timeit(fn): @wraps(fn) def wrapper(*args,**kwargs): start = datetime.datetime.now() ret = fn(*args,**kwargs) delta = (datetime.datetime.now() -start).total_seconds() print('{} took {}\'s 装饰器'.format(fn.__name__,delta)) return ret return wrapper @timeit def add(x,y): time.sleep(1) return x + y class TimeIt: def __init__(self,fn): self.fn = fn def __enter__(self): self.start = datetime.datetime.now() return self def __exit__(self, exc_type, exc_val, exc_tb): self.delta = (datetime.datetime.now() - self.start).total_seconds() print('{} took {}\'s 上下文'.format(self.fn.__name__, self.delta)) pass with TimeIt(add): add(4,5) # add took 1.000057's 装饰器 # add took 1.000057's 上下文
def add(x,y): time.sleep(1) return x + y class TimeIt: def __init__(self,fn): self.fn = fn def __enter__(self): self.start = datetime.datetime.now() return self # return self.fn #方法一:实质上还是调用add函数 def __call__(self, *args,**kwargs): return self.fn(*args,**kwargs) def __exit__(self, exc_type, exc_val, exc_tb): self.delta = (datetime.datetime.now() - self.start).total_seconds() print('{} took {}\'s 上下文'.format(self.fn.__name__, self.delta)) pass with TimeIt(add) as foo: print(foo(4,5)) #self(4,5) 利用魔术方法__call__
#类装饰器的实现 import time import datetime from functools import wraps class TimeIt: def __init__(self,fn): self.fn = fn wraps(fn)(self) def __call__(self, *args,**kwargs): start = datetime.datetime.now() ret = self.fn(*args,**kwargs) delta = (datetime.datetime.now() -start).total_seconds() print('{} took {}\'s 类装饰器'.format(self.fn.__name__,delta)) return ret @TimeIt def add(x,y): """This is a function""" time.sleep(1) return x + y add(10,11)#add took 1.000057's 类装饰器 print(add.__doc__)#This is a function print(type(add))#<class '__main__.TimeIt'>
上下文应用场景
contextlib.contextmanager
import contextlib @contextlib.contextmanager def foo(): # print('enter') #l类比于__enter__() yield #yield的值只能有一个,作为__enter__方法的返回值 print('exit') #类比于__exit__() with foo() as f: # raise Exception() print(f)
import contextlib @contextlib.contextmanager def foo(): # print('enter') #类比于__enter__() try: yield #yield的值只能有一个,作为__enter__方法的返回值 finally: print('exit') #类比于__exit__() with foo() as f: raise Exception() print(f)
import contextlib import datetime import time @contextlib.contextmanager def add(x,y): #为生成器函数增加了上下文管理 start = datetime.datetime.now() try: yield x + y #yield的值只能有一个,作为__enter__方法的返回值 finally: delta = (datetime.datetime.now()-start).total_seconds() print(delta) with add(4,5) as f: # raise Exception() time.sleep(1) print(f) #输出如下: # 9 # 1.000058
@functools.total_ordering装饰器
from functools import total_ordering @total_ordering class Person: def __init__(self,age): self._age = age @property def age(self): return self._age def __eq__(self, other):#必须 return self._age == other.age def __lt__(self, other):#多选一 return self._age < other.age p1 = Person('20') p2 = Person('30') if p1<p2: print('p1 older') else: print('p2 older')
反射
概述
反射相关的函数和方法
class Point: def __init__(self,x,y): self.x = x self.y = y def __str__(self): return 'Point({},{})'.format(self.x,self.y) def show(self): print(self.x,self.y) p =Point(4,5) print(p) print(p.__dict__) p.z = 10 print(p.__dict__) print(dir(p))
class Point: def __init__(self,x,y): self.x = x self.y = y def __str__(self): return 'Point({},{})'.format(self.x,self.y) def show(self): print(self.x,self.y) p1 =Point(4,5) p2 =Point(10,10) print(repr(p1),repr(p2),sep='\n') print(p1.__dict__) setattr(p1,'y',16) setattr(p1,'z',10) print(getattr(p1,'__dict__')) #动态调用方法 # if hasattr(p1,'show'): # print(getattr(p1,'show'))#<bound method Point.show of <__main__.Point object at 0x00000000029C3D68>> # getattr(p1,'show')() #动态增加方法 if not hasattr(Point,'add'): setattr(Point,'add',lambda self,other:Point(self.x+other.x,self.y+other.y)) print(Point.add) print(p1.add) print(p1.add(p2))#绑定 #为实例增加方法,未绑定 if not hasattr(p1,'sub'): setattr(p1,'sub',lambda self,other:Point(self.x-other.x,self.y-other.y)) print(p1.sub(p1,p2)) print(p1.sub) #add在谁里面,sub在谁里面 print(p1.__dict__) print(Point.__dict__)
练习
class dispatcher: def cmd1(self): print('cmd1') def reg(self,cmd,fn): if isinstance(cmd,str): # setattr(self.__class__,cmd,fn) setattr(type(self),cmd,fn) else: print('error') def run(self): while True: cmd = input('Please input command:') if cmd.strip() == 'quit': return getattr(self,cmd.strip(),self.defaultfn)() def defaultfn(self): print('default') dis = dispatcher() print(dis.__dict__)#{} print(dispatcher.__dict__)#{'__module__': '__main__', 'cmd1': <function dispatcher.cmd1 at 0x00000000029A10D0>,...} #添加注册函数 dis.reg('cmd2',lambda self:print(2)) dis.reg('cmd3',lambda self:print(3)) #启动 dis.run()
反射相关的魔术方法
__getattr__()
class Base: n = 0 class Point(Base): z = 6 def __init__(self,x,y): self.x = x self.y = y def show(self): print(self.x,self.y) def __getattr__(self, item): print( "missing {}".format(item)) p1 = Point(4,5) print(p1.x)#4 print(p1.z)#6 print(p1.n)#0 print(p1.t) #missing t None
__setattr__()
class Base: n = 0 class Point(Base): z = 6 def __init__(self,x,y): self.x = x self.y = y def show(self): print(self.x,self.y) def __getattr__(self, item): print( "missing {}".format(item)) def __setattr__(self, key, value): print("__setattr__",key,value) p1 = Point(4,5) print(p1.__dict__)#{} print(Point.__dict__)#{'__module__': '__main__', 'z': 6,...} print(p1.x)#missing x None print(p1.z)#6 print(p1.n)#0 print(p1.t) #missing t None p1.__dict__['x'] = 60 print(p1.__dict__)#{'x': 60} print(p1.x)#60
__delattr__()
class Base: n = 0 class Point(Base): Z = 6 def __init__(self,x,y): self.x = x self.y = y def __delattr__(self, item): print('Can not del {}'.format(item)) p = Point(14,5) del p.x p.z = 15 del p.z del p.Z print(Point.__dict__)#{'__module__': '__main__', 'Z': 6, '__init__':...} print(p.__dict__)#{'x': 14, 'y': 5, 'z': 15} del Point.Z print(Point.__dict__)#{'__module__': '__main__', '__init__': ...}
__getattribute__
class Base: n = 5 class Point(Base): z = 6 def __init__(self,x,y): self.x = x self.y = y def __getattribute__(self, item): return item def __getattr__(self, item): print( "missing {}".format(item)) p1 = Point(4,5) print(1,p1.__dict__)#__dict_ print(2,p1.x)#x print(3,p1.z)#z print(4,p1.n)#n print(5,p1.t)#t print(6,p1.__dict__)#__dict__ print(7,Point.z)#6
class Base: n = 5 class Point(Base): z = 6 def __init__(self,x,y): self.x = x self.y = y def __getattribute__(self, item): print('getattribute!!') return object.__getattribute__(self,item) # return item # def __getattr__(self, item): print( "missing {}".format(item)) p1 = Point(4,5) print('*'*10) print(1,p1.__dict__)#getattribute!! 1 {'x': 4, 'y': 5} print(2,p1.x)#getattribute!! 2 4 print(3,p1.z)#getattribute!! 3 6 print(4,p1.n)#getattribute!! 4 5 print(5,p1.t)#getattribute!! missing t 5 None print('*'*10) print(6,p1.__dict__)#getattribute!! 6 {'x': 4, 'y': 5} print(7,Point.z)# 7 6 # print(8,Point.zzzz)#AttributeError: type object 'Point' has no attribute 'zzzz'
总结
描述器Descriptors
描述器的表现
class A: def __init__(self): print('A init') self.a1 = 'a1' class B: x = A() def __init__(self): print('B init') print('-'*20) print(B.x.a1) print('='*20) b = B() print(b.x.a1) #输出结果: A init -------------------- a1 ==================== B init a1
class A: def __init__(self): print('A init') self.a1 = 'a1' def __get__(self, instance, owner): print("A.__get__ {} {} {}".format(self,instance,owner)) class B: x = A() def __init__(self): print('B init') print('-'*20) # print(B.x.a1)报错 print(B.x) print('='*20) b = B() print(b.x) # print(b.x.a1)报错
#输出如下: A init -------------------- A.__get__ <__main__.A object at 0x00000000029D3D68> None <class '__main__.B'> None ==================== B init A.__get__ <__main__.A object at 0x00000000029D3D68> <__main__.B object at 0x00000000029D3D30> <class '__main__.B'> None
class A: def __init__(self): print('A init') self.a1 = 'a1' def __get__(self, instance, owner): print("A.__get__ {} {} {}".format(self,instance,owner)) return self #解决返回None的问题 class B: x = A() def __init__(self): print('B init') self.x = A() #实例属性也指向一个A的实例 print('-'*20) print(B.x.a1) print('='*20) b = B() print(b.x.a1) #输出如下: A init -------------------- A.__get__ <__main__.A object at 0x0000000002993DD8> None <class '__main__.B'> a1 ==================== B init A init a1
描述器定义
属性的访问顺序
class A: def __init__(self): print('A init') self.a1 = 'a1' def __get__(self, instance, owner): print("A.__get__ {} {} {}".format(self,instance,owner)) return self #解决返回None的问题 class B: x = A() def __init__(self): print('B init') self.x = 'b.x' #增加实例属性x print('-'*20) # print(B.x.a1)报错 print(B.x.a1) print('='*20) b = B() print(b.x) # print(b.x.a1)报错 #输出如下: A init -------------------- A.__get__ <__main__.A object at 0x00000000022A3D68> None <class '__main__.B'> a1 ==================== B init b.x
class A: def __init__(self): print('A init') self.a1 = 'a1' def __get__(self, instance, owner): print("A.__get__ {} {} {}".format(self,instance,owner)) return self #解决返回None的问题 # 设置了该函数代表了一个数据描述器,而数据描述器的属性查找顺序优先于实例的__dict__ def __set__(self, instance, value): print("A.__set__{} {} {}".format(self,instance,value)) # self.data = value class B: x = A() def __init__(self): print('B init') self.x = 'b.x' #增加实例属性x print('-'*20) # print(B.x) print(B.x.a1)#A.__get__ <__main__.A object at 0x000000000299D278> None <class '__main__.B'> a1 print('='*20) b = B()#A.__set__<__main__.A object at 0x000000000299D278> <__main__.B object at 0x000000000299D2B0> b.x print(b.x)#A.__get__ <__main__.A object at 0x000000000299D278> <__main__.B object at 0x000000000299D2B0> <class '__main__.B'> <__main__.A object at 0x000000000299D278> print(b.x.a1)#返回a1
本质(进阶)
class A: def __init__(self): print('A init') self.a1 = 'a1' def __get__(self, instance, owner): print("A.__get__ {} {} {}".format(self,instance,owner)) return self # 设置了该函数代表了一个数据描述器,而数据描述器的属性查找顺序优先于实例的__dict__ def __set__(self, instance, value): print("A.__set__{} {} {}".format(self,instance,value)) # self.data = value class B: x = A() def __init__(self): print('B init') self.x = 'b.x' #增加实例属性x self.y = 'b.y' print('-'*20) b = B() print(b.x) # print(b.x.a1)#未屏蔽__set__()方法则返回a1 print(b.y) print('字典:') print(b.__dict__) print(B.__dict__) #屏蔽__set__()方法 # 字典: # {'x': 'b.x', 'y': 'b.y'} # {'__module__': '__main__', 'x': <__main__.A object at 0x0000000002983D30>, '__init__': <function B.__init__ at 0x0000000003A0A048>,...} #未屏蔽__set__()方法 # 字典: # {'y': 'b.y'} # {'__module__': '__main__', 'x': <__main__.A object at 0x000000000299D278>, '__init__': <function B.__init__ at 0x0000000003A0A0D0>,...}
Python中的描述器
class A: @classmethod def foo(cls):#非数据描述器 pass @staticmethod#非数据描述器 def bar(): pass @property#数据描述器 def z(self): return 5 def getfoo(self):#非数据描述器 return self.foo def __init__(self):#非数据描述器 self.foo = 100 self.bar = 200 self.getfoo = 400 # self.z = 300#AttributeError: can't set attribute a = A() print(a.__dict__) print(A.__dict__) #输出如下: {'foo': 100, 'bar': 200, 'getfoo': 400} {'__module__': '__main__', 'foo': <classmethod object at 0x00000000029B3DA0>, 'bar': <staticmethod object at 0x00000000029BD240>, 'z': <property object at 0x000000000047F818>, 'getfoo': <function A.getfoo at 0x0000000003A0A0D0>, '__init__': <function A.__init__ at 0x0000000003A0A158>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
练习
#1 class StaticMethod: def __init__(self,fn): self.fn = fn def __get__(self, instance, owner): print(self,instance,owner) return self.fn class A: @StaticMethod#foo = StaicMethod(foo), #也可以理解为foo重新指向了一个StaticMethod的实例,而StaticMethod类又实现了一个__get__方法,这样就形成了描述器。 def foo(): print('static') f = A.foo f() #输出如下: <__main__.StaticMethod object at 0x0000000002993E48> None <class '__main__.A'> static
#2 from functools import partial class ClassMethod: def __init__(self,fn): self.fn = fn def __get__(self, instance, cls): print(self, instance, cls) return partial(self.fn,cls) class A: @ClassMethod#bar=ClassMethod(bar) def bar(cls): print(cls.__name__) f = A.bar f() #输出如下: <__main__.ClassMethod object at 0x00000000029055F8> None <class '__main__.A'> A
class Person: def __init__(self,name:str,age:int): self.name = name self.age = age
#1 class Person: def __init__(self,name:str,age:int): params = ((name,str),(age,int)) if not self.checkdata(params): raise TypeError() self.name = name self.age = age def checkdata(self,params): for p,t in params: if not isinstance(p,t): return False return True p = Person('tom','20')
class Typed: def __init__(self,name,type): self.name = name self.type = type def __get__(self, instance, owner): pass def __set__(self, instance, value): if not isinstance(value,self.type): raise TypeError(value) instance.__dict__[self.name] = value class Person: name = Typed('name',str)#不优雅 age = Typed('age',int)#不优雅 def __init__(self,name:str,age:int): self.name = name self.age = age p = Person('tom',20)
class Typed: def __init__(self,name,type): self.name = name self.type = type def __get__(self, instance, owner): pass def __set__(self, instance, value): if not isinstance(value,self.type): raise TypeError(value) instance.__dict__[self.name] = value import inspect def typeassert(cls): params = inspect.signature(cls).parameters # print(params) for name,param in params.items(): print(param.name,param.annotation) if param.annotation != param.empty:#注入类属性 setattr(cls,name,Typed(name,param.annotation)) return cls @typeassert #Person = typeassert(Person) class Person: # name = Typed('name',str)#装饰器注入+++++ # age = Typed('age',int)# def __init__(self,name:str,age:int): self.name = name self.age = age p = Person('tom',20)# name <class 'str'> age <class 'int'> print(p.__dict__) # {'name': 'tom', 'age': 20} print(p) # <__main__.Person object at 0x00000000023AD278>
作业
#进阶解法: #实现双向链表 class SingleNode: #代表一个节点 def __init__(self,val,next=None,prev=None): self.val = val self.next = next self.prev = prev def __repr__(self): return str(self.val) class LinkedList: #容器类,某种方式存储一个个节点 def __init__(self): self.head = None self.tail = None self.size = 0 def append(self,val): node = SingleNode(val) if self.head is None:# 0 self.head = node else: self.tail.next = node node.prev = self.tail self.tail = node self.size += 1 def pop(self): if self.tail is None:#0 raise NotImplementedError('Empty') tail = self.tail prev= self.tail.prev if prev is None:#1个节点 self.head = None self.tail = None else:#>1 self.tail = prev prev.next = None self.size -= 1 return tail.val def insert(self,index,val):#1,7 if index < 0: raise Exception('Error') cur = None for i,current in enumerate(self.iternodes()): if i == index: cur = current break if cur is None:#说明索引越界或空链表,直接末尾追加 self.append(val) return node = SingleNode(val) prev = cur.prev if prev is None:#1个节点,头部插入 self.head = node node.next = cur cur.prev = node else:#>=2 node.next = cur prev.next = node cur.prev = node node.prev = prev
self.size += 1 def remove(self,index): if self.tail is None: raise Exception('Empty') if index < 0: raise ValueError("Wrong Index()".format(index)) current = None for i,node in enumerate(self.iternodes()): if i == index: current = node break if current is None: raise ValueError('Wrong Index {}. Out of boundary'.format(index)) prev = current.prev next = current.next if prev is None and next is None:#only one node self.head = None self.tail = None elif prev is None: self.head = next next.prev = None elif next is None: self.tail = prev prev.next = None else: prev.next = next next.prev = prev del current self.size -= 1 def iternodes(self,reversed = False): current = self.tail if reversed else self.head while current: yield current current = current.prev if reversed else current.next __iter__ = iternodes def __getitem__(self, index): #index >= 0 for i,node in enumerate(self.iternodes(False if index>=0 else True),0 if index>=0 else 1): if i == abs(index): return node #index < 0 # for i,node in enumerate(self.iternodes(True),1): # if -i == index: # return node def __setitem__(self, key, value): self[key].val = value a = SingleNode(1) b = SingleNode(2) c = SingleNode(3) d = SingleNode(4) e = SingleNode(5) f = SingleNode(6) ll = LinkedList() ll.append(a) ll.append(b) ll.append(c) ll.append(d) ll.append(e) ll.append(f) # ll.insert(1,0) # ll.insert(0,0) # ll.insert(10,100) # print('pop元素:',ll.pop()) # print('pop元素:',ll.pop()) # print('pop元素:',ll.pop()) # ll.insert(0,10) for node in ll.iternodes(): print(node) print(ll[-2])#5 print(ll[2])#3
进阶题
#实现类property装饰器,类名称为Property #基本结构如下,是一个数据描述器 class Property: def __init__(self, fget=None, fset=None, fdel=None): self.fget = fget self.fset = fset def __get__(self, instance, owner): if instance is not None: return self.fget(instance) return self def __set__(self, instance, value): self.fset(instance,value) # instance.__dict__['_data'] = value def setter(self,fn): self.fset = fn return self class A: def __init__(self,data): self._data = data @Property# data = Property(data) data==>obj def data(self): return self._data @data.setter# data = data.setter(data) data==>obj def data(self,value): self._data = value a = A(10) print(a.data) a.data = 100 print(a.data)
做一枚奔跑的老少年!