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

假如要限制 xy 的值一定是一个整数或者浮点数

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)返回给当前的函数操作。

总༗结༗

posted @ 2016-03-06 18:24  蓝色骨头  阅读(190)  评论(0编辑  收藏  举报