python基础0306
面向对象
可调用对象
def fn():
pass
dir(fn)
['__annotations__',
'__call__',
'__class__',
'__closure__',
'__code__',
'__defaults__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__get__',
'__getattribute__',
'__globals__',
'__gt__',
'__hash__',
'__init__',
'__kwdefaults__',
'__le__',
'__lt__',
'__module__',
'__name__',
'__ne__',
'__new__',
'__qualname__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__']
默认定义的类会自动继承很多内置方法。
class Function:
def __call__(self,name):
print("i am callable, my name is {0}".format(name))
func = Function() # 实例化过程只执行`__init__`
func("sunchao") # 实例方法调用时每次都会重新执行`__call__`
i am callable, my name is sunchao
实例调用的时候会执行那__call__
方法。
class InjectUser:
def __init__(self,default_user):
print("__init__")
self.user = default_user
def __call__(self,fn):
print("__call__")
def wrap(*args,**kwargs):
if "user" not in kwargs.keys():
kwargs['user'] = self.user
print("__call__.wrap()")
return fn(*args,**kwargs)
return wrap
@InjectUser("sunchao")
def do_somthing(*args,**kwargs):
print(kwargs.get("user"))
__init__
__call__
do_somthing()
__call__.wrap()
sunchao
# 等价拆解
def do_somthing(*args,**kwargs):
print(kwargs.get('user'))
InjectUser("suncaho") # 实例初始化
__init__
<__main__.InjectUser at 0x7f72dc318c50> # 实例
InjectUser("suncaho")(do_somthing) # 实例调用
__init__
__call__
<function __main__.InjectUser.__call__.<locals>.wrap> # 实例返回wrap函数
InjectUser("suncaho")(do_somthing)() #函数结果
__init__
__call__
__call__.wrap()
suncaho
装饰器
def wrap(fn): # 1接受一个函数
def test(*args,**kwargs): # 3内层函数接受要装饰函数的参数
if not args:
args = (3,) # 4内层函数修改和控制参数
return fn(*args,**kwargs) # 5返回被装饰函数和修改后的参数
return test # 2返回一个内层函数
@wrap
def fn(x):
print(x)
class Single:
__instance = None
def __init__(self,cls):
print("__init__")
self.cls = cls
def __call__(self,*args,**kwargs):
print("__call__")
if self.__instance is None:
self.__instance = self.cls(*args,**kwargs)
return self.__instance
def do_somthing(*args):
return args
Single #类
__main__.Single
Single(do_somthing) #实例 执行__init__
__init__
<__main__.Single at 0x7f72dc3185c0>
Single(do_somthing)(123) # 实例调用 方法 __call__
__init__
__call__
(123,)
class Grok:
def __init__(self):
print("_Grok.__init__")
Single
__main__.Single
Single(Grok)
__init__
<__main__.Single at 0x7f72dc2cf518>
Single(Grok)()
__init__
__call__
_Grok.__init__
<__main__.Grok at 0x7f72dc2dcf28>
Grok()
_Grok__init__
<__main__.Grok at 0x7f1074303780>
@Single
class Grok:
def __init__(self):
print("_Grok.__init__")
def __call__(self):
print("_Grok.__call__")
__init__
# self.cls = Grok 类
# 装饰器上述过程就是定义 Grok = Single(Grok)
Grok # Single的实例
<__main__.Single at 0x7f72dc2dc940>
Grok() # Single的实例调用,Grok的实例。
__call__ # self._instance = None
_Grok.__init__ # self._instance = Grok实例
<__main__.Grok at 0x7f72dc2e1b00>
Grok() # Single的实例调用,Grok实例
__call__ # self._instance = Grok实例
<__main__.Grok at 0x7f72dc2e1b00>
Grok()() # Single的实例调用,Grok的实例调用
__call__
_Grok.__call__
反射
给定一个对象,然后通过某种方法得到它的属性。(dir()函数)
class Grok:
X = 1
Y = 2
Z = 3
def __init__(self,x,y,z):
self.x=x
self.y=y
self.z=z
def method(self):
pass
grok = Grok(3,2,1)
dir(grok)
...
grok.__dir__()
...
grok.__dict__
{'x': 3, 'y': 2, 'z': 1}
grok.__class__
__main__.Grok
getattr(grok,"x")
3
class Grok:
def __init__(self):
self.__dict = {"x":1,"y":2}
self.a = 3
self.b = 5
def __getattr__(self,name):
print('get {0}'.format(name))
return self.__dict.get(name)
grok = Grok()
grok.x
get x
1
grok.a
3
显式定义的方法和属性直接调用
隐式方法和属性通过调用 __getattr__
属性获得
class Grok:
def method_a(self):
print("a")
def method_b(self):
print("b")
def __getattr__(self,name):
print("print getattr")
grok = Grok()
grok.a
print getattr
类似swith语句
method_a XXX
method_b YYY
default ZZZ
__getattribute__
这个方法几乎不用。
with语句和__enter__
__exit__
class Resource:
def __init__(self):
print('init')
def __enter__(self):
print("enter")
print(self)
return(self)
def __exit__(self,*args,**kvargs):
print('exit')
with Resource() as res:
print(res)
init
enter
<__main__.Resource object at 0x7fea0c7c7e80> #print(self)
<__main__.Resource object at 0x7fea0c7c7e80> #print(res)
exit
描述器
__get__
__set__
__delete__
实现这三种方法的类就叫描述器。
class point:
def __init__(self,x,y):
self.x = x
self.y = y
假如要限制 x 和 y 的值一定是一个整数或者浮点数
class number:
def __init__(self,name):
self.name = name
def __get__(self,instance,cls):
print("get")
if instance is not None:
return instance.__dict__[self.name]
return self
def __set__(self,instance,value):
print("set")
if isinstance(value,(int,float)):
instance.__dict__[self.name] = value
else:
raise TypeError("expect int or float")
def __delete__(self,instance):
del instance.__dict__[self.name]
class point:
x = number("x")
y = number('y')
def __init__(self,a,b):
self.x = a
self.y = b
p = point(5,6)
set
set
p.x # point.x__get__(p,point)
get
5
p.x = "google" # point.x__set__(p,value)
TypeError: expect int or float
point 类变量 x 和 y 是 number 的实例
point 实例初始化是对 number 实例的赋值操作(调用隐藏方法__set__
)
__get__
属性绑定外部方法
class spam:
def spam(self):
pass
def grok(self):
pass
s = spam()
grok.__get__(s,spam) # 将grok绑定到spam类上
<bound method spam.grok of <__main__.spam object at 0x7f583c79df98>>
s.spam # spam.spam.__get__(s.spam)
<bound method spam.spam of <__main__.spam object at 0x7f583c79df98>>
类型检查是描述器用的比较多得地方
class typed:
def __init__(self,name,expect_type):
self.name = name
self.expect_type = expect_type
def __get__(self,instance,cls):
if instance is not None:
return instance.__dict__[self.name]
return self
def __set__(self,instance,value):
if isinstance(value,self.expect_type):
instance.__dict__[self.name] = value
else:
raise TypeError("expected {0}".format(self.expect_type))
def __delete__(self,instance):
del instance.__dict__[self.name]
class B:
x = typed('x',(int,float))
y = typed('y',(int,str))
def __init__(self,x,y):
self.x = x
self.y = y
每次定义单个类变量的类型或觉得很繁琐,可以利用装饰器减少代码量。
from functools import wraps
def typeasser(**kvargs):
def inner(cls):
@wraps(cls)
def wrap(*args):
for k,v in kvargs.items():
setattr(cls,k,typed(k,v))
return cls(*args)
return wrap
return inner
@typeasser(x=int,y=float,z=str,m=int)
class spam:
def __init__(self,x,y,z,m):
self.x = x
self.y = y
self.z = z
self.m = m
s = spam(x=1,y=2.1,z='a',m=123) # 给对象赋初值
上例中
spam = <function __main__.typeasser.<locals>.inner.<locals>.wrap>
加上@wraps装饰器之后
spam = <function __main__.spam> #typeasser(x=int,y=float,z=str,m=int)(spam) = wrap
装饰器接受一个类作为参数,并返回内层函数 wrap 赋值给 spam。
spam 函数接受参数并返回一个对应类的实例(return cls(*args)
)。
其中 spam 函数使用 setattr
方法为这个类赋初值,其中cls类变量的值是类 typed 的实例。函数 spam 返回值为这个类cls的实例,实例初始化时相当于给实例继承自cls类变量 typed 的实例做赋值操作,调用 typed 类的__set__
方法。
模拟实现property装饰器
class Property:
def __init__(self,fget=None,fset=None,fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self,instance,cls):
if self.fget is not None:
return self.fget(instance)
else:
print("Error way")
def __set__(self,instance,value):
if self.fset is not None:
self.fset(instance,value)
else:
print("Error way")
def __delete__(self,instance):
if self.fdel is not None:
self.fdel(instance)
else:
print("Error way")
def getter(self,fn):
return Property(fget=fn,fset=None,fdel=None)
def setter(self,fn):
return Property(fget=None,fset=fn,fdel=None)
def deler(self,fn):
return Property(fget=None,fset=None,fdel=fn)
class spam:
def __init__(self,val):
self.__val = val
@Property
def get_val(self):
return self.__val
@get_val.setter
def set_val(self,value):
self.__val = value
s = spam(5)
s.get_val
5
s.get_val = 7
Error way
s.set_val
Error way
s.set_val = 9
s.get_val
9
类变量和类方法都可以被描述器修饰,但是在使用描述器的时候都需要被定义成描述器的 实例
类变量可以通过直接赋值方式成为描述器的 实例
类方法可以通过装饰器方式成为描述器的 实例
同一个类内的不同的变量或者方法的描述器实例是相互独立的。
被描述的类方法或者类变量都是通过描述器的 __set__
方法赋值,__get__
方法得到值。
类装饰器
class ClassProprety:
def __init__(self,fn):
self.fn = fn
def __get__(self,instance,cls):
return self.fn(cls)
class spam:
__val = 3
@ClassProprety
def val(cls):
return cls.__val
@ClassProprety
def name(cls):
return cls.__name__.upper()
s = spam()
s.val
3
s.name
'SPAM'
# 类方法描述器
class ClassMethod:
def __init__(self,fn):
self.fn = fn
def __get__(self,instance,cls):
return self.fn(cls)
描述器是一个传递协议,可以将描述器得到的更高一级的对象(cls)返回给当前的函数操作。