当前位置: 首页 > news >正文

为啥做网站/武汉seo网站

为啥做网站,武汉seo网站,tomcat 网站开发,营销型网站设计文章目录1 上下文管理1.1 上下文管理的安全性1.2 返回值1.3 方法的参数1.4 计算函数的运行时间1.5 主要应用场景1.6 contextlib.contextmanager2 反射2.1 反射相关的函数2.2 反射相关的魔术方法2.2.1 __getattr__2.2.2 __setattr__2.2.3 __delattr__2.3 __getattribute__1 上下…

文章目录

  • 1 上下文管理
    • 1.1 上下文管理的安全性
    • 1.2 返回值
    • 1.3 方法的参数
    • 1.4 计算函数的运行时间
    • 1.5 主要应用场景
    • 1.6 contextlib.contextmanager
  • 2 反射
    • 2.1 反射相关的函数
    • 2.2 反射相关的魔术方法
      • 2.2.1 __getattr__
      • 2.2.2 __setattr__
      • 2.2.3 __delattr__
    • 2.3 __getattribute__

1 上下文管理

文件IO操作可以对文件对象使用上下文管理,它主要使用with..as..语法.

with open('123.txt') as f:print(f)

要想自己写的类实现上下文管理,那么需要用到两个方法__exit__和__enter__.

方法意义
__enter__进入与此对象相关的上下文,如果存放该方法,with语法会把该方法的返回值绑定到as子句中指定的变量上
__exit__退出与此对象相关的上下文
class Text:def __enter__(self):print('enter------')def __exit__(self, exc_type, exc_val, exc_tb):print('exit-------')with Text() as f :print('进来了')
print('出来了')# enter------
# 进来了
# exit-------
# 出来了

实例化对象的时候,并不会调用__enter__方法,只有进入with语句体中,才会调用__enter__方法,然后执行语句体,最后离开with语句块的时候,再调用__exit__方法.

with可以开启一个上下文运行环境,在执行前做一些准备工作,执行后,做一些收尾工作,它并不会开启一个新的作用域.

1.1 上下文管理的安全性

class Text:def __enter__(self):print('enter------')def __exit__(self, exc_type, exc_val, exc_tb):print('exit-------')with Text() as f :raise Exception# Traceback (most recent call last):
# enter------
#   File "E:/Python - base - code/chapter08面向对象/练习3.py", line 169, in <module>
#     raise Exception
# exit-------
# Exception

我们可以看到,with语句体中当异常抛出时,__exit__已经可以执行完毕,所以上下文管理是安全的.

1.2 返回值

class Text:def __enter__(self):print('enter------')def __exit__(self, exc_type, exc_val, exc_tb):print('exit-------')with Text() as f :print(f)   # None

这里之所以是None,是因为,__enter__函数的返回值为None,所以如果哪些类的实例化属性或实例本身要在with语句内部使用,可以在__enter__函数中进行返回.

class Text:def __init__(self):self.name = 'daxin'def __enter__(self):print('enter------')return selfdef __exit__(self, exc_type, exc_val, exc_tb):print('exit-------')with Text() as f:print(f.name)   # daxin

1.3 方法的参数

方法的参数如下:

  • __enter__(self):没有其他参数
  • __exit__(self, exc_type, exc_val, exc_tb): 这三个参数都与异常有关系,如果上下文管理内部没有产生异常,那么三个属性的值都为None,否则
    • exc_type: 异常类型
    • exc_val: 异常的值
    • exc_tb: 异常的追踪信息

注意:__exit__函数的返回值很重要,当返回值等效为True,表示压制异常(异常不会上报),等效False时,表示不压制异常(此时异常会上报)

class A:def __init__(self):passdef __enter__(self):print('Enter ~~~~~')def __exit__(self, exc_type, exc_val, exc_tb):print('exit ~~~~~')print(exc_type)print(exc_val)print(exc_tb)return Truewith A():raise Exception('Test')# Enter ~~~~~
# <class 'Exception'>
# Test
# <traceback object at 0x000001E4D0A5C808>

因为__exit__方法return 了True,所以异常被压制,所以不会异常崩溃。

1.4 计算函数的运行时间

下面来计算一个函数的运行时间,主要有两个办法:

  1. 装饰器(一般人都能想到)
  2. 上下文管理期(一般人很难想到)

装饰器版本:

import time
import random
import datetime
import functoolsdef timer(fn):@functools.wraps(fn)  # 拷贝属性信息def wrapper(*args, **kwargs):start = datetime.datetime.now()res = fn(*args, **kwargs)stop = (datetime.datetime.now() - start).total_seconds()print(stop)return resreturn wrapper@timer
def add(x, y):time.sleep(random.randrange(1, 5))return x + yadd(4,5)

装饰器版本2:类装饰器

import time
import random
import datetime
import functoolsclass Timer:def __init__(self,fn):self.fn = fnfunctools.wraps(fn)(self)  # 拷贝用户函数属性信息def __call__(self, *args, **kwargs):start = datetime.datetime.now()res = self.fn(*args,**kwargs)stop = (datetime.datetime.now() - start).total_seconds()print('The fn run time is {}'.format(stop))return res@Timer
def add(x, y):'''from add function'''time.sleep(random.randrange(1, 5))return x + yprint(add(4,5))
print(add.__name__)

上下文管理器方法1:

import time
import random
import datetimedef add(x, y):time.sleep(random.randrange(1, 5))return x + yclass Timer:def __init__(self):self.start = Nonedef __enter__(self):self.start = datetime.datetime.now()def __exit__(self, exc_type, exc_val, exc_tb):self.stop = (datetime.datetime.now() - self.start).total_seconds()print(self.stop)with Timer():add(1, 3)

上下文管理版本2:将要计算的函数当作参数传入上下问管理器中

import time
import random
import datetimedef add(x, y):time.sleep(random.randrange(1, 5))return x + yclass Timer:def __init__(self, fn):self.fn = fnself.start = Nonedef __enter__(self):self.start = datetime.datetime.now()return self.fndef __exit__(self, exc_type, exc_val, exc_tb):self.stop = (datetime.datetime.now() - self.start).total_seconds()print(self.stop)with Timer(add) as f:f(1, 3)

1.5 主要应用场景

根据上下文管理的特性,总结出三个常用的场景:

  1. 增强功能:在代码执行的前后增加代码,以增强其功能。类似装饰器的功能。
  2. 资源管理:打来的资源需要关闭,例如文件对象、网络连接、数据库连接等。
  3. 权限验证:在执行代码之前,做权限的验证,在__enter__中处理。

1.6 contextlib.contextmanager

        它是一个装饰器,用于实现上下文管理,它装饰一个函数,因为函数没有像类那样使用__enter__和__exit__来实现,所以使用contextlib.contextmanger可以使一个函数变为上下文管理器,但是对被装饰的函数有一个要求,必须包含yeild关键字,也就是说这个函数必须返回一个生成器,且只有yield一个值。

这个装饰器接受一个生成器作为参数

from contextlib import contextmanager@contextmanager
def add(x, y):print('hello')yield x + yprint('bye bye')print('start')
with add(4, 5) as f:print(f)
print('end')# start
# hello
# 9
# bye bye
# end

根据打印结果我们分析:

  1. 函数中yield语句前面的,在with语句执行时被触发。
  2. yield返回值被 as 语句交给了f。
  3. yield语句后面的,在退出with语句时执行。

当我们传入参数add(1, [5,]) 时,异常直接是函数异常退出了,并没有执行yield后面的类似__enter__方法的语句,怎么办呢?可以使用try,finally来捕捉

from contextlib import contextmanager@contextmanager
def add(x, y):try:print('hello')yield x + yfinally:print('bye bye')print('start')
with add(1, [5,]) as f:print(f)
print('end')

这样就会打印yield后续语句,虽然会异常退出,但由于错误的参数由用户自主传递,那就让用户自己去解决吧。

业务逻辑简单,可以使用函数加contextlib.contextmanager装饰器实现,业务逻辑复杂的话,可以使用类加__enter__和__exit__来解决。

2 反射

一个对象能够在运行时,像照镜子一样,显示出其类型信息,这种方法叫做反射。换句话是反射可以在程序运行的同时获取类型定义的信息,比如通过一个对象,找出它的type、class、attribute或者method等。具有反射能力的函数有:type()、isinstance()、callable()、dir()、getattr()等。

2.1 反射相关的函数

内建函数含义
getattr(object, name[, default])通过name返回object的属性值。当属性不存在,将使用default返回。
如果没有设置default,则抛出AttributeError异常,name必须为字符串。
setattr(obj, name, value)obj的属性存在,则覆盖,不存在,则新增。
hasattr(obj, name)判断obj是否存在属性,name必须为字符串,返回值为bool类型
class Person:def __init__(self,name,age):self.name = nameself.age = agedef talk(self):print("{} is talking".format(self.name))daxin = Person('daxin',20)
if hasattr(daxin,'name'):         # 判断daxin是否含有name属性print(getattr(daxin,'name'))  # 如果有,通过getattr获取name属性if not hasattr(daxin,'sing'):     # 判断daxin没有sing方法setattr(daxin,'sing',lambda self:print("{} is singing".format(self.name)))  # 为实例绑定一个sing方法daxin.sing()  # 实例调用

        直接调用时无法执行,提示缺少self参数,想一下,我们定义的方法通常是在类中定义的,在类中我们指定的self参数,在实例调用时会进行传递(因为是实例是绑定在方法上的),而我们绑定的sing方法是绑定在实例本身上的,所以这种情况下,是无法帮我们传递self参数的,所以我们在函数内部也无法调用实例的参数。

这种动态增加属性的方式是运行时改变类或者实例的方式,而装饰器或者Mixin是在定义时就决定了的,因此反射具有更大的灵活性。

命令分发器实例:

class Dispather:def __init__(self):passdef register(self, name, func):setattr(self, name, func)def run(self):while True:cmd = input('>>>: ').strip()if cmd.lower() == 'quit':breakelse:getattr(self, cmd.lower())()d = Dispather()
d.register('ls',lambda :print('hello world'))
d.run()

2.2 反射相关的魔术方法

魔术方法含义
__getattr__(self, name)定义当用户试图获取一个不存在的属性时的行为
__setattr__(self, name, value)定义当一个属性被设置时的行为
__delattr__(self, name)定义当一个属性被删除时的行为

2.2.1 getattr

class A:def __init__(self):passdef __getattr__(self, item):print('__getattr__')return 'daxin'daxin = A()
print(daxin.name)# __getattr__
# daxin

        访问daxin的一个属性name,如果不存在,最后会调用__getattr__方法,它的返回值就是结果。如果没有这个方法,就会抛出AttributeError异常,表示找不到属性。
        查找属性的顺序为:instance.__dict__ --> instance.__class__.__dict__ --> … --> object的__dict__,找不到,调用实例的__getattr__

2.2.2 setattr

class A:def __init__(self):passdef __getattr__(self, item):print('__getattr__')return 'daxin'def __setattr__(self, key, value):self.key = value   # self.key依旧调用self.__setattr__方法# self.__dict__[key] = value daxin = A()
daxin.name = 'daxin'  # 调用__setattr__方法
print(daxin.name)

上面的代码无法执行,会产生递归是为什么呢?

  1. daxin.name = ‘daxin’ 这里会调用daxin的__setattr__方法。
  2. daxin的__stattr__方法内部使用self.key = value的方法赋值,这种方法等同于self.__setattr__ = value,所以会产生递归。
  3. 利用self.__dict__[key]的方式是直接操作实例的字典,所以不会引起递归。

__setattr__()方法,可以拦截对实例属性的增加、修改操作,如果要设置生效,需要自己修改操作实例的__dict__属性。

class Person:def __init__(self,name):self.name = nameself.__dict__['a'] = 5def __getattr__(self, item):print('getattr~~~~~')return getattr(self,item)def __setattr__(self, key, value):print('setattr~~~~~~')self.__dict__[key] = value# setattr(self,key,value)  # 不能这样写,这样写等同于调用对象的__setattr__方法,会产生递归daxin = Person('daxin')
print(daxin.name)
print(daxin.a)

结果只会输出1次getattr,因为初始化时,已经为字典创建了一个key,a,所以当访问实例属性a时,由于__dict__中存在,所以不会被__getattr__捕获。

setattr本质上也是通过 instance.attribute = value 的方式赋值的。

2.2.3 delattr

删除一个属性时,触发__delattr__方法的执行。可以阻止通过实例来删除属性的操作。

class Person:def __init__(self,name):self.name = nameself.__dict__['a'] = 5def __getattr__(self, item):print('getattr~~~~~')return getattr(self,item)def __setattr__(self, key, value):print('setattr~~~~~~')self.__dict__[key] = valuedef __delattr__(self, item):print('delattr~~~~~~')del self.__dict__[item]  # 删除实例的属性, 也可以在这里啥也不做,提示不能删除,即可阻止实例的属性被删除。daxin = Person('daxin')
print(daxin.name)
del daxin.a  # 触发实例的__delattr__方法的执行。

2.3 getattribute

魔术方法含义
__getattribute__(self, name)定义当该类的属性被访问时的行为

实例所有的属性访问,第一个都会调用__getattribute__方法。

class Person:def __init__(self,name,age):self.name = nameself.age = agedef __getattr__(self, item):return 'getattr'def __getattribute__(self, item):pass# return 'ABC'# raise AttributeError('ABC')daxin = Person('daxin',20)
print(daxin.name)

上面的例子得到以下结论:

  1. 当我们重写__getattribute__方法时,它的返回值就是我们属性访问的结果。
  2. 如果在__getattribute__方法中抛出AttributeErro异常,那么最好会执行__getattr__方法,因为属性没有找到。

__getattribute__方法中为了避免在该方法中无限递归,它的实现应该永远调用基类的同名方法以访问需要的任何属性(object.__getattribute__(self, name))。

实例属性查找顺序:
instance.__getattribute__() --> instance.__dict__ --> instance.__class__.__dict__ --> object.__dict__ --> instance.__getattr__

http://www.jmfq.cn/news/4771585.html

相关文章:

  • 做增员的保险网站/企业网站制作流程
  • 上海有哪些做网站的/网站建设与优化
  • 公司网站网页设计/搜索引擎推广和优化方案
  • php网站开发示例代码/湖南百度seo
  • 给自己的网站做镜像网站/网址注册查询
  • 青海建设云网站/网页设计html代码大全
  • 网站怎么做备案变更/甘肃搜索引擎网络优化
  • 做网站的有什么软件/梧州网站seo
  • 网站域名建设/sem竞价代运营公司
  • 威客网站开发/百度关键词排名突然没了
  • 公司网站做优化/今天最新的新闻头条新闻
  • 关于网站开发书籍/优秀网站网页设计图片
  • 政府网站建设部门外出考察/系统开发
  • Wordpress需要更新吗/北京百度搜索优化
  • 广告设计公司取名/百度官方优化软件
  • 深圳集团网站开发公司/关键词推广操作
  • 怎样做电子商务网站/seo优化服务价格
  • 坪山网站建设设计/seo软件视频教程
  • 公司有必要建设网站吗/关键词优化软件有哪些
  • 珠海企业网站建设制作/百度提交网站收录入口
  • 手机端网站动效类怎么做/企业网络营销成功案例
  • 360推广 网站建设/网站优化的方法有哪些
  • 国外手机模板网站推荐/seoapp推广
  • 创建一个自己的公司/seo百度快速排名
  • 请为hs公司的钻石礼品网站做网络营销沟通策划_预算是20万./网络营销策划推广方案
  • 做网站行业的动态/百度收录链接提交入口
  • 做网站字体要求/杭州网络整合营销公司
  • 成都新东方烹饪学校网站建设主管/怎么做自己的网站
  • mvc6电商网站开发实战/百度推广哪家做的最好
  • 长春做网站哪里好/电商运营推广是做什么的