day28

作者: 两分与桥 | 来源:发表于2018-04-18 21:08 被阅读4次

with open as f: 函数触发 enterexit

class Open:
    def __init__(self,name):
        self.name = name
    def __enter__(self): #开始时执行
        print('执行enter')
        return self
    def __exit__(self, exc_type, exc_val, exc_tb): # 结束时执行
        print('执行exit')

with Open('a.txt') as f:
    print(f)
    print(f.name)

输出结果:
执行enter
<__main__.Open object at 0x0000023A6CD6A080>
a.txt
执行exit

with obj as f

with obj as f:
    '代码块'
    
1.with obj  ---> 触发obj.__enter__(), 拿到返回值

2.as f -----> f=返回值

3.with obj as f  等同于  f=obj.__enter__()

4.执行代码块
一:没有异常的情况下,整个代码块运行完毕后去触发__exit__,它的三个参数都为none
二:在有异常的情况下,从异常出现的位置直接触发__exit__
    a: 如果__exit__的返回值为True,代表吞掉了异常
    b: 如果__exit__的返回值不为True,代表吐出了异常
    c: __exit__的运行完毕就代表了整个with语句的执行完毕

异常信息

>>> abc
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'abc' is not defined

NameError ----->class
name 'abc' is not defined ----->异常的值
Traceback ----->追踪信息

用新式类作输入类型检测,get,set,del

class Type:
    def __init__(self, key):
        self.key = key
    def __get__(self, instance, owner):
        print('get 方法')
        print(instance)
        print(owner)
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        print('set 方法')
        print(instance)
        print(value)
        if not isinstance(value,str):
            print("必须传入字符串")
            return
        instance.__dict__[self.key] = value
    def __delete__(self, instance):
        print('del 方法')
        print(instance)
        del instance.__dict__[self.key]

class earth:
    name = Type('name')
    def __init__(self, name, age):
        self.name = name
        self.age = age


e = earth('libai', 20)
print(e.__dict__)
print(e.name)
e.name = 12
print(e.__dict__)
print('----------------------------------')
del e.name
print(e.__dict__)

输出结果:
set 方法
<__main__.earth object at 0x000002257741AEF0>
libai
{'name': 'libai', 'age': 20}
get 方法
<__main__.earth object at 0x000002257741AEF0>
<class '__main__.earth'>
libai
set 方法
<__main__.earth object at 0x000002257741AEF0>
12
必须传入字符串
{'name': 12, 'age': 20}
----------------------------------
del 方法
<__main__.earth object at 0x000002257741AEF0>
{'age': 20}

改进上面的程序,使得可以检测 多种类型

class Type:
    def __init__(self, key, except_type):
        self.key = key
        self.except_type = except_type
    def __get__(self, instance, owner):
        print('get 方法')
        print(instance)
        print(owner)
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        print('set 方法')
        print(instance)
        print(value)
        if not isinstance(value,self.except_type):
            print("必须传入 %s " %self.except_type)
            return
        instance.__dict__[self.key] = value
    def __delete__(self, instance):
        print('del 方法')
        print(instance)
        del instance.__dict__[self.key]

class earth:
    name = Type('name', str)
    age = Type('age', int)
    def __init__(self, name, age):
        self.name = name
        self.age = age


e = earth('libai', 20)
print('---------------------------------')
e.name = 20
print('---------------------------------')

e.age = 'bbs'

输出结果:
set 方法
<__main__.earth object at 0x000002254086D080>
libai
set 方法
<__main__.earth object at 0x000002254086D080>
20
---------------------------------
set 方法
<__main__.earth object at 0x000002254086D080>
20
必须传入 <class 'str'> 
---------------------------------
set 方法
<__main__.earth object at 0x000002254086D080>
bbs
必须传入 <class 'int'> 

类的装饰器,先来一段函数的装饰器

def deco(func):
    print('========================')
    return func

@deco  #deco 函数就是 test 当成func传入deco,返回值再赋给test
def test():
    print('hello,big big world')

test()

输出结果:
========================
hello,big big world

装饰器装饰类

def deco(obj):
    print('========================')
    obj.x = 1
    obj.y = 2
    obj.z = 3
    return obj

@deco  #deco 函数就是 test 当成obj传入deco,返回值再赋给test
class test:
    pass

print(test.__dict__)

输出结果:
========================
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'test' objects>, '__weakref__': <attribute '__weakref__' of 'test' objects>, '__doc__': None, 'x': 1, 'y': 2, 'z': 3}

函数也存在 dict 属性 ,一切皆对象

def deco(obj):
    print('========================')
    obj.x = 1
    obj.y = 2
    obj.z = 3
    return obj

@deco
def test():
    pass

print(test.__dict__)

输出结果:
========================
{'x': 1, 'y': 2, 'z': 3}

装饰器,改成类型检测,如果检测到不匹配,就print 和不写入

def deco(**kwargs): #接收参数传入**kwargs
    def wrapper(obj): #返回的 wrapper 传入earth
        print('========================')
        for key,value in kwargs.items(): # .items() 格式为元组
            setattr(obj, key, Type(key, value))
        return obj
    print(kwargs)
    return wrapper

#类型传入检测
class Type:
    def __init__(self, key, except_type):
        self.key = key
        self.except_type = except_type
    def __get__(self, instance, owner):
        print('get 方法')
        print(instance)
        print(owner)
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        print('set 方法')
        print(instance)
        print(value)
        if not isinstance(value,self.except_type):
            print("必须传入 %s " %self.except_type)
            return
        instance.__dict__[self.key] = value
    def __delete__(self, instance):
        print('del 方法')
        print(instance)
        del instance.__dict__[self.key]

@deco(name=str,age=int) #name 传入类型 str,age传入类型 int
class earth:
    def __init__(self, name, age):
        self.name = name
        self.age = age

e = earth('libai', '23') #触发set方法

print('*************************************************')
print(earth.__dict__)
print(e.__dict__)

输出结果:
{'name': <class 'str'>, 'age': <class 'int'>}
========================
set 方法
<__main__.earth object at 0x0000025C38B4E080>
libai
set 方法
<__main__.earth object at 0x0000025C38B4E080>
23
必须传入 <class 'int'> 
*************************************************
{'__module__': '__main__', '__init__': <function earth.__init__ at 0x0000025C38B34950>, '__dict__': <attribute '__dict__' of 'earth' objects>, '__weakref__': <attribute '__weakref__' of 'earth' objects>, '__doc__': None, 'name': <__main__.Type object at 0x0000025C38B4AF98>, 'age': <__main__.Type object at 0x0000025C38B4E048>}
{'name': 'libai'}

@property 就是把装饰的类或者函数当成参数传入 property(类) 中,执行完后把返回值再赋给所装饰的类,下面是自定义的 @property,与原生的@property 有类似的功能

class Lazyproperty:
    def __init__(self, func):
        self.func = func
        print('func = ', self.func)
    def __get__(self, instance, owner):
        print('instance = ', instance)
        print('owner = ', owner)
        # 以下这句 self.func(instance) 被执行并赋值给print打印时,
        # 会执行一遍 test 函数,这也就是为什么输出结果中会有两个 test被打印
        print('------------------>>>', self.func(instance))
        print('***************************************************')
        return self.func(instance)

class earth:
    def __init__(self):
        pass
    @Lazyproperty
    def test(self):
        print('test')
        return '你好吗?'

e = earth()
print(e.test)

输出结果:
func =  <function earth.test at 0x0000021C699B47B8>
instance =  <__main__.earth object at 0x0000021C699CAEB8>
owner =  <class '__main__.earth'>
test
------------------>>> 你好吗?  # test 被打印两次
***************************************************
test
你好吗?

优先级寻找十分重要啊,

class Lazyproperty:
    def __init__(self, func):
        self.func = func
    def __get__(self, instance, owner):
        print('get')
        res = self.func(instance)
        setattr(instance, self.func.__name__, res)
        return res
    # 如果存在 __set__ 方法,class Lazyproperty 为数据描述符,优先级高于实例属性,
    # 寻找属性时会优先寻找 数据描述符,就会每次执行都调用一次 get 方法
    # 现在不存在 __set__ 方法,class Lazyproperty 为非数据描述符,优先级低于实例属性,
    # 寻找属性时会优先寻找 实例属性,
    # 整个程序执行过程:
        # 首先呢,@Lazyproperty 会先执行一遍,把 test 函数当成参数传入,
        # 实例化后再赋给test,下面,实例化 earth 类为 e,直接传参到
        # self.x 和 self.y ;
        # 调用 e.test 过程中,会先寻找 e 的实例属性,实例属性不存在 test,
        # 那就去找非数据描述符, class Lazyproperty 的 get 方法被执行,
        # instance 是类的实例,也就是 e ,self.func 就是 test,
        # owner 是 earth 类,在 earth 类中的 test 函数必须传入一个参数,
        # 也就是 instance ,self.func(instance) 执行结果被存到 e.__dict__
        # 实例属性中,之后 get 方法就不会执行了,因为在实例属性中找得到结果
        # 可以实现不用每次执行都计算一遍
    # def __set__(self, instance, value):
    #     pass

class earth:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    @Lazyproperty
    def test(self):
        return (self.x*self.y)

e = earth(10,22)
print(e.test)
print(e.test)
print(e.test)
print(e.__dict__)

输出结果:
get
220
220
220
{'x': 10, 'y': 22, 'test': 220}

@property 的补充,setter ,deleter

class Foo:
    @property
    def AAA(self):
        print('get 的时候触发')
    @AAA.setter
    def AAA(self, val):
        print('set 的时候触发 ',val)
    @AAA.deleter
    def AAA(self):
        print('del 的时候触发')
#只有在属性 AAA 定义 property 后才能定义 AAA.setter, AAA.deleter
f = Foo()
f.AAA
f.AAA = 'bbb'
del f.AAA

输出结果:
get 的时候触发
set 的时候触发  bbb
del 的时候触发

上面的程序可以这么写

class Foo:
    def get_AAA(self):
        print('get 的时候触发')
    def set_AAA(self, val):
        print('set 的时候触发 ',val)
    def del_AAA(self):
        print('del 的时候触发')
    AAA = property(get_AAA,set_AAA,del_AAA)
#只有在属性 AAA 定义 property 后才能定义 AAA.setter, AAA.deleter
f = Foo()
f.AAA
f.AAA = 'bbb'
del f.AAA

输出结果跟上面是一模一样的

类创建实例对象,元类创建类,python 中任何 class 定义的类其实都是 type 类实例化的对象,类也可以直接用 type 来创建

class Foo:
    def __init__(self):
        pass

def __init__(self):
    pass

earth = type('earth',(object,),{'__init__':__init__,'x':28})
print(earth.__dict__)
print('---------------------------------------------------------')
print(Foo)
print(Foo.__dict__)
print(type(Foo))
print(type(type(type(Foo)))) # type 又是谁创建的呢? 还是 type!

输出结果:
{'__init__': <function __init__ at 0x0000019D88944598>, 'x': 28, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'earth' objects>, '__weakref__': <attribute '__weakref__' of 'earth' objects>, '__doc__': None}
---------------------------------------------------------
<class '__main__.Foo'>
{'__module__': '__main__', '__init__': <function Foo.__init__ at 0x0000019D88944620>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
<class 'type'>
<class 'type'> # 类的类的类的类

自定义元类

class MyType(type):
    def __init__(self, a, b, c):
        print('元类的构造函数执行')
    def __call__(self, *args, **kwargs):
        obj = object .__new__(self)
        self.__init__(obj, *args, **kwargs)
        return obj
class Foo(metaclass=MyType):
    def __init__(self, name):
        self.name = name

f1 = Foo('alex')

最后一个就是 python 的异常与处理, try 与 except,还有 else ,exception,这些就不写了,可以看这个:
http://www.cnblogs.com/linhaifeng/articles/6232220.html
python 编程就学到这里了,下面学习一些模块

相关文章

网友评论

      本文标题:day28

      本文链接:https://www.haomeiwen.com/subject/zlbbkftx.html