特殊属性

查看属性

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

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

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)
#输出如下:
#
# 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('')
p2 = Person('')
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)#
print(p1.z)#
print(p1.n)#
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)#
print(p1.n)#
print(p1.t) #missing t None
p1.__dict__['x'] = 60
print(p1.__dict__)#{'x': 60}
print(p1.x)#

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

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}

练习

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

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

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:#
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 = 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])#
print(ll[2])#

进阶题

#实现类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)

Python进阶10---魔术方法*的更多相关文章

  1. Python 类的魔术方法

    Python中类的魔术方法 在Python中以两个下划线开头的方法,__init__.__str__.__doc__.__new__等,被称为"魔术方法"(Magic method ...

  2. python进阶10 MySQL补充 编码、别名、视图、数据库修改

    python进阶10 MySQL补充    编码.别名.视图.数据库修改 一.编码问题 #MySQL级别编码 #修改位置: /etc/mysql/mysql.conf.d/mysqld.cnf def ...

  3. python进阶02 特殊方法与特殊属性

    python进阶02 特殊方法与特殊属性 一.初始化.析构 1.初始化 # python中有很多双下划线开头且以下划线结尾的固定方法,它们会在特定的时机被触发执行,这便是特殊方法 # 在实例化的时候就 ...

  4. python进阶之内置方法

    python进阶之内置方法 字符串类型的内置方法 常用操作与方法: 按索引取值 str[index] 切片 ste[start:stop:step] 长度 len(str) 成员运算in和not in ...

  5. Python中的魔术方法详解

    介绍 在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”,中文称『魔术方法』,例如类的初始化方法 __init__ ,Python中所有的魔术方法均在官方文档中 ...

  6. Python中的魔术方法详解(双下方法)

    介绍 在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”,中文称『魔术方法』,例如类的初始化方法 __init__ ,Python中所有的魔术方法均在官方文档中 ...

  7. 流动python - 什么是魔术方法(magic method)

    我们经常看到各种各样的方法已经被包围了由双下划线,例如__init__,他们是魔术方法. 魔术方法python语言预订好"协议",在不同情况下不同的魔术方法,是隐式调用.我们重写这 ...

  8. Python 面向对象(三) 魔术方法

    __getitem__ 在对实例或对象使用索引访问时调用,self[key]__dir__ 收集当前模块的信息,包括继承自其它基类(包括object类)的属性和方法 __new 定义如何创建实例__i ...

  9. Python学习笔记之面向对象编程(三)Python类的魔术方法

    python类中有一些方法前后都有两个下划线,这类函数统称为魔术方法.这些方法有特殊的用途,有的不需要我们自己定义,有的则通过一些简单的定义可以实现比较神奇的功能 我主要把它们分为三个部分,下文也是分 ...

随机推荐

  1. ReentrantLock是如何基于AQS实现的

    ReentrantLock是一个可重入的互斥锁,基于AQS实现,它具有与使用 synchronized 方法和语句相同的一些基本行为和语义,但功能更强大. lock和unlock ReentrantL ...

  2. 如何开发AR增强现实应用与产品

    2016年被称为VR元年,可见火爆程度,但是我要告诉你,其实还有一种技术AR(增强现实)技术,才是下一个真正的“风口”技术.可以预见的是,未来AR应用爆发之时,必将超越VR产业规模,开拓千亿级市场空间 ...

  3. [开源]基于Log4Net简单实现KafkaAppender

    背景 基于之前基于Log4Net本地日志服务简单实现 实现本地日志服务,但是随着项目开发演进,本地日志服务满足不了需求,譬如在预发布环境或者生产环境,不可能让开发人员登录查看本地日志文件分析. Kaf ...

  4. Flink从入门到放弃(入门篇1)-Flink是什么

    戳更多文章: 1-Flink入门 2-本地环境搭建&构建第一个Flink应用 3-DataSet API 4-DataSteam API 5-集群部署 6-分布式缓存 7-重启策略 8-Fli ...

  5. Python:游戏:扫雷(附源码)

    这次我们基于 pygame 来做一个扫雷,上次有园友问我代码的 python 版本,我说明一下,我所有的代码都是基于 python 3.6 的. 先看截图,仿照 XP 上的扫雷做的,感觉 XP 上的样 ...

  6. Centos7+LVS-DR+keepalived实验(包含sorry-server、日志、及HTTP-GET的健康检测)

    目录检索 一.简介 1.lvs-dr原理请参考原理篇 2.keepalived原理请参考原理篇 3.基于lvs-dr+keepalived故障切换架构图如下: 二.部署 1.环境 2.准备RS的web ...

  7. ios键盘弹起 body的高度拉长,页面底部空白问题。ios软键盘将页面抵到上面后,关闭软键盘页面不回弹的问题。

    js 监听ios手机键盘弹起和收起的事件 /* js 监听ios手机键盘弹起和收起的事件 */ document.body.addEventListener('focusin', () => { ...

  8. jQuery里面的DOM操作(查找,创建,添加,删除节点)

    一:创建元素节点(添加) 创建元素节点并且把节点作为元素的子节点添加到DOM树上 append(): 在元素下添加元素 用法:$("id").append("定义的节点& ...

  9. [TCP/IP] 计算机网络性能指标

    速率:连接在计算机网络上的主机在数字信道上传输数据位数的速率单位是 b/s kb/s mb/s gb/s带宽:数字信道所能传输的最高数据率 查看我的网卡是144Mbps吞吐量:单位时间内通过某个网络的 ...

  10. 微信h5 video的问题

    https://blog.csdn.net/hf123lsk/article/details/78920211