首页 技术 正文
技术 2022年11月8日
0 收藏 474 点赞 2,001 浏览 21825 个字

特殊属性

Python进阶10—魔术方法*

查看属性

Python进阶10—魔术方法*

#animal.py
class Animal:
x = 123
def __init__(self,name):
self._name = name
self.__age = 10
self.weight = 20print('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())))

魔术方法

Python进阶10—魔术方法*

hash

Python进阶10—魔术方法*

class A:
def __init__(self):
self.a = 'a'
self.b = 'b' def __hash__(self):
return 1print(hash(A()))#
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 Trueprint(hash(A()))#
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>}

Python进阶10—魔术方法*

Python进阶10—魔术方法*

Python进阶10—魔术方法*

查看源码后发现源码中有一句__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.yp1 = Point(4,5)
p2 = Point(4,5)
print(hash(p1))#
print(hash(p2))#
print(p1 is p2)#False
print(p1 == p2)#True
print(set((p1,p2)))#{<__main__.Point object at 0x0000000002993E48>}
print(isinstance(p1,Hashable))#True

bool

Python进阶10—魔术方法*

class A:
passprint(bool(A))#True
print(bool(A()))#Trueclass B(object):
def __bool__(self):
return Falseprint(bool(B))#True
print(bool(B()))#Falseclass C:
def __len__(self):
return 0print(bool(C))#True
print(bool(C()))#False 

可视化

Python进阶10—魔术方法* 

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)

运算符重载

Python进阶10—魔术方法*

Python进阶10—魔术方法*

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)# 

Python进阶10—魔术方法*

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

运算符重载应用场景

Python进阶10—魔术方法*

Python进阶10—魔术方法*

容器相关方法

Python进阶10—魔术方法*

Python进阶10—魔术方法*

#购物车
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)

可调用对象

Python进阶10—魔术方法*

Python进阶10—魔术方法*

Python进阶10—魔术方法*

Python进阶10—魔术方法*

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=' ')

Python进阶10—魔术方法*

上下文管理

Python进阶10—魔术方法*

Python进阶10—魔术方法*

上下文管理对象

Python进阶10—魔术方法*

Python进阶10—魔术方法*

Python进阶10—魔术方法*

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')

Python进阶10—魔术方法*

上下文管理的安全性

Python进阶10—魔术方法*

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')

Python进阶10—魔术方法*

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

Python进阶10—魔术方法*

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')

Python进阶10—魔术方法*

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')

Python进阶10—魔术方法*

__enter__方法和__exit__方法的参数

Python进阶10—魔术方法*

Python进阶10—魔术方法*

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>

练习

Python进阶10—魔术方法*

Python进阶10—魔术方法*

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 + yclass 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))
passwith TimeIt(add):
add(4,5)# add took 1.000057's 装饰器
# add took 1.000057's 上下文

Python进阶10—魔术方法*

def add(x,y):
time.sleep(1)
return x + yclass 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))
passwith TimeIt(add) as foo:
print(foo(4,5)) #self(4,5) 利用魔术方法__call__

Python进阶10—魔术方法*

Python进阶10—魔术方法*

Python进阶10—魔术方法*

#类装饰器的实现
import time
import datetime
from functools import wrapsclass 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 + yadd(10,11)#add took 1.000057's 类装饰器
print(add.__doc__)#This is a function
print(type(add))#<class '__main__.TimeIt'>

上下文应用场景

Python进阶10—魔术方法*

contextlib.contextmanager

Python进阶10—魔术方法*

import contextlib@contextlib.contextmanager
def foo(): #
print('enter') #l类比于__enter__()
yield #yield的值只能有一个,作为__enter__方法的返回值
print('exit') #类比于__exit__()with foo() as f:
# raise Exception()
print(f)

Python进阶10—魔术方法*

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)

Python进阶10—魔术方法*

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)
#输出如下:
#
# 1.000058

Python进阶10—魔术方法*

@functools.total_ordering装饰器

Python进阶10—魔术方法*

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.agep1 = Person('')
p2 = Person('')
if p1<p2:
print('p1 older')
else:
print('p2 older')

反射

概述

Python进阶10—魔术方法*

反射相关的函数和方法

Python进阶10—魔术方法*

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))

Python进阶10—魔术方法*

Python进阶10—魔术方法*

Python进阶10—魔术方法*

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__)

Python进阶10—魔术方法*

练习

Python进阶10—魔术方法*

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()

Python进阶10—魔术方法*

反射相关的魔术方法

Python进阶10—魔术方法*

__getattr__()

class Base:
n = 0class 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)#
print(p1.z)#
print(p1.n)#
print(p1.t) #missing t None

Python进阶10—魔术方法*

Python进阶10—魔术方法*

__setattr__()

class Base:
n = 0class 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)#
print(p1.n)#
print(p1.t) #missing t None
p1.__dict__['x'] = 60
print(p1.__dict__)#{'x': 60}
print(p1.x)#

Python进阶10—魔术方法*

Python进阶10—魔术方法*

 __delattr__()

class Base:
n = 0class 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__': ...}

Python进阶10—魔术方法*

__getattribute__

class Base:
n = 5class 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)#

Python进阶10—魔术方法*

class Base:
n = 5class 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'

Python进阶10—魔术方法*

总结

Python进阶10—魔术方法*

描述器Descriptors

描述器的表现

 Python进阶10—魔术方法*

Python进阶10—魔术方法*

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

Python进阶10—魔术方法*

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

Python进阶10—魔术方法*

Python进阶10—魔术方法*

Python进阶10—魔术方法*

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

Python进阶10—魔术方法*

描述器定义

Python进阶10—魔术方法*

属性的访问顺序

Python进阶10—魔术方法*

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' #增加实例属性xprint('-'*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

Python进阶10—魔术方法*

Python进阶10—魔术方法*

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 = valueclass B:
x = A()
def __init__(self):
print('B init')
self.x = 'b.x' #增加实例属性xprint('-'*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

Python进阶10—魔术方法*

Python进阶10—魔术方法*

Python进阶10—魔术方法*

本质(进阶)

Python进阶10—魔术方法*

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 = valueclass 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进阶10—魔术方法*

Python中的描述器

Python进阶10—魔术方法*

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 attributea = 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}

Python进阶10—魔术方法*

练习

Python进阶10—魔术方法*

#
class StaticMethod:
def __init__(self,fn):
self.fn = fn def __get__(self, instance, owner):
print(self,instance,owner)
return self.fnclass 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
#
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

Python进阶10—魔术方法*

class Person:
  def __init__(self,name:str,age:int):
  self.name = name
  self.age = age

Python进阶10—魔术方法*

#
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 Truep = Person('tom','')

Python进阶10—魔术方法*

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] = valueclass Person:
name = Typed('name',str)#不优雅
age = Typed('age',int)#不优雅 def __init__(self,name:str,age:int):
self.name = name
self.age = agep = Person('tom',20)

Python进阶10—魔术方法*

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] = valueimport 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 = agep = Person('tom',20)# name <class 'str'> age <class 'int'>
print(p.__dict__) # {'name': 'tom', 'age': 20}
print(p) # <__main__.Person object at 0x00000000023AD278>

作业

Python进阶10—魔术方法*

#进阶解法:
#实现双向链表
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:#
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:#
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 = valuea = 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])#
print(ll[2])#

进阶题

Python进阶10—魔术方法*

#实现类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 selfclass 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 = valuea = A(10)
print(a.data)
a.data = 100
print(a.data)
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,491
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,906
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,739
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,492
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,130
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,293