带引导页的网站,网页制作工具哪些好用,哪些品牌网站做的好,龙岗网站建设方案装饰器是python语言中的语法糖#xff0c;可以通过装饰器对函数的功能进行拓展。
为什么需要装饰器
我们假设你的程序实现了say_hello()和say_goodbye()两个函数。
def say_hello():print(hello!)def say_goodbye():print(hello!) # 此处应打印go…装饰器是python语言中的语法糖可以通过装饰器对函数的功能进行拓展。
为什么需要装饰器
我们假设你的程序实现了say_hello()和say_goodbye()两个函数。
def say_hello():print(hello!)def say_goodbye():print(hello!) # 此处应打印goodbyeif __name__ __main__:say_hello()say_goodbye()假设上述代码中的say_goodbye函数出现了bug为了之后能更好的维护现在需要在调用方法前记录函数调用名称以定位出错位置。
[DEBUG]: Enter say_hello()
Hello![DEBUG]: Enter say_goodbye()
Goodbye!实现方式
def say_hello():print([DEBUG]: enter say_hello())print(hello!) def say_goodbye():print([DEBUG]: enter say_goodbye())print(hello!)if __name__ __main__:say_hello()say_goodbye()对上述代码进行优化
def debug():import inspectcaller_name inspect.stack()[1][3] # 可以返回函数名与当前函数的返回值print([DEBUG]: enter {}().format(caller_name))def say_hello():debug()print(hello!)def say_goodbye():debug()print(goodbye!)if __name__ __main__:say_hello()say_goodbye()上述代码需要在每个业务函数里都要调用一下debug()函数是不是很难受万一老板说say相关的函数不用debugdo相关的才需要呢
那么装饰器这时候应该登场了。 装饰器本质上是一个Python函数它可以让其他函数在不需要做任何代码变动的前提下增加额外功能装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景比如插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计有了装饰器我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。 概括的讲装饰器的作用就是为已经存在的函数或对象添加额外的功能。
如何实现一个装饰器
在早些时候 (Python Version 2.42004年以前)为一个函数添加额外功能的写法是这样的。
def debug(func):def wrapper():print([DEBUG]: enter {}().format(func.__name__))return func()return wrapperdef say_hello():print(hello!)say_hello debug(say_hello)say_hello()上面的debug函数其实已经是一个装饰器了它对原函数做了包装并返回了另外一个函数额外添加了一些功能。因为这样写实在不太优雅在后面版本的Python中支持了语法糖下面代码等同于早期的写法。
def debug(func):def wrapper():print([DEBUG]: enter {}().format(func.__name__))return func()return wrapperdebug
def say_hello():print(hello!)say_hello()这是最简单的装饰器但是有一个问题如果被装饰的函数需要传入参数那么这个装饰器就坏了。因为返回的函数并不能接受参数你可以指定装饰器函数wrapper接受和原函数一样的参数比如
def debug(func):def wrapper(something): # 指定一毛一样的参数print([DEBUG]: enter {}().format(func.__name__))return func(something)return wrapper # 返回包装过函数debug
def say(something):print(hello {}!.format(something))say(顾安)这样你就解决了一个问题但又多了N个问题。因为函数有千千万你只管你自己的函数别人的函数参数是什么样子鬼知道还好Python提供了可变参数*args和关键字参数**kwargs有了这两个参数装饰器就可以用于任意目标函数了。
def debug(func):def wrapper(*args, **kwargs):print([DEBUG]: enter {}().format(func.__name__))return func(*args, **kwargs)return wrapperdebug
def say(something):print(hello {}!.format(something))say(顾安)带参数的装饰器
假设我们前文的装饰器需要完成的功能不仅仅是能在进入某个函数后打出log信息而且还需指定log的级别那么装饰器就会是这样的。
def logging(level):def wrapper(func):def inner_wrapper(*args, **kwargs):print([{level}]: enter function {func}().format(levellevel,funcfunc.__name__))return func(*args, **kwargs)return inner_wrapperreturn wrapperlogging(levelINFO)
def say(something):print(say {}!.format(something))# 如果没有使用语法等同于
# say logging(levelINFO)(say)logging(levelDEBUG)
def do(something):print(do {}....format(something))if __name__ __main__:say(hello)do(my work)是不是有一些晕你可以这么理解当带参数的装饰器被打在某个函数上时比如logging(levelDEBUG)它其实是一个函数会马上被执行只要它返回的结果是一个装饰器时那就没问题。细细再体会一下。
基于类的装饰器
装饰器函数其实是这样一个接口约束它必须接受一个callable对象作为参数然后返回一个callable对象。在Python中一般callable对象都是函数但也有例外。只要某个对象重载了__call__()方法那么这个对象就是callable的。
class Test:def __call__(self):print(call me!)t Test()
t() # call me像__call__这样前后都带下划线的方法在Python中被称为内置方法有时候也被称为魔法方法。重载这些魔法方法一般会改变对象的内部行为。上面这个例子就让一个类对象拥有了被调用的行为。
回到装饰器上的概念上来装饰器要求接受一个callable对象并返回一个callable对象。那么用类来实现也是也可以的。我们可以让类的构造函数__init__()接受一个函数然后重载__call__()并返回一个函数也可以达到装饰器函数的效果。
class Logging:def __init__(self, func):self.func funcdef __call__(self, *args, **kwargs):print([DEBUG]: enter function {func}().format(funcself.func.__name__))return self.func(*args, **kwargs)Logging
def say(something):print(say {}!.format(something))say(木木)带参数的类装饰器
如果需要通过类形式实现带参数的装饰器那么会比前面的例子稍微复杂一点。那么在构造函数里接收的就不是一个函数而是传入的参数。通过类把这些参数保存起来。然后在重载__call__方法是就需要接收一个函数并返回一个函数。
class Logging:def __init__(self, levelINFO):self.level leveldef __call__(self, func): # 接收函数def wrapper(*args, **kwargs):print([{level}]: enter function {func}().format(levelself.level,funcfunc.__name__))func(*args, **kwargs)return wrapper # 返回函数Logging(levelINFO)
def say(something):print(say {}!.format(something))say(木木)property属性
property - 简介
什么是property属性
一种用起来像是使用的实例属性一样的特殊属性可以对应于某个方法。
class Foo:def func(self):pass# 定义property属性propertydef prop(self):passfoo_obj Foo()
foo_obj.func() # 调用实例方法
foo_obj.prop # 调用property属性class Goods:propertydef money(self):return 100goods Goods()
print(goods.money)property属性的定义和调用要注意一下几点
定义时在实例方法的基础上添加 property 装饰器并且仅有一个self参数调用时无需括号
简单的示例
对于京东商城中显示电脑主机的列表页面每次请求不可能把数据库中的所有内容都显示到页面上而是通过分页的功能局部显示所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据 这个分页的功能包括
根据用户请求的当前页和总数据条数计算出 m 和 n根据m 和 n 去数据库中请求数据
class Pager:def __init__(self, current_page):# 用户当前请求的页码第一页、第二页...self.current_page current_page# 每页默认显示10条数据self.per_items 10propertydef start(self):val (self.current_page - 1) * self.per_itemsreturn valpropertydef end(self):val self.current_page * self.per_itemsreturn val# ############### 调用 ###############
p Pager(1)
print(p.start) # 就是起始值即m
print(p.end) # 就是结束值即nPython的property属性的功能是property属性内部进行一系列的逻辑计算最终将计算结果返回。
property属性的两种方式
装饰器 即在方法上应用装饰器类属性 即在类中定义值为property对象的类属性 装饰器方式 在类的实例方法上应用property装饰器
Python中的类有经典类和新式类新式类的属性比经典类的属性丰富。 如果类继object那么该类是新式类
经典类具有一种property装饰器
class Goods:propertydef price(self):return 100obj Goods()
result obj.price # 自动执行 property 修饰的 price 方法并获取方法的返回值
print(result)新式类具有三种property装饰器
class Goods(object):propertydef price(self):print(property)price.setterdef price(self, value):print(price.setter)price.deleterdef price(self):print(price.deleter)obj Goods()
print(obj.price) # 自动执行 property 修饰的 price 方法并获取方法的返回值
obj.price 123 # 自动执行 price.setter 修饰的 price 方法并将 123 赋值给方法的参数
del obj.price # 自动执行 price.deleter 修饰的 price 方法注意
经典类中的属性只有一种访问方式其对应被 property 修饰的方法新式类中的属性有三种访问方式并分别对应了三个被property、方法名.setter、方法名.deleter修饰的方法
由于新式类中具有三种访问方式我们可以根据它们几个属性的访问特点分别将三个方法定义为对同一个属性获取、修改、删除
class Goods(object):def __init__(self):# 原价self.original_price 100# 折扣self.discount 0.8propertydef price(self):# 实际价格 原价 * 折扣new_price self.original_price * self.discountreturn new_priceprice.setterdef price(self, value):self.original_price valueprice.deleterdef price(self):del self.original_priceobj Goods()
print(obj.price) # 获取商品价格
obj.price 200 # 修改商品原价
print(obj.price)
del obj.price # 删除商品原价
# 当前属性被删除之后再获取则报错
# print(obj.price)类属性方式创建值为property对象的类属性 当使用类属性的方式创建property属性时经典类和新式类无区别
class Goods:def get_price(self):return 100price property(get_price)obj Goods()
result obj.price # 自动调用get_price方法并获取方法的返回值
print(result)property方法中有个四个参数
第一个参数是方法名调用 对象.属性 时自动触发执行方法第二个参数是方法名调用 对象.属性 XXX 时自动触发执行方法第三个参数是方法名调用 del 对象.属性 时自动触发执行方法第四个参数是字符串调用 对象.属性.__doc__ 此参数是该属性的描述信息
class Foo(object):def get_bar(self):print(getter...)return a...def set_bar(self, value):必须两个参数print(setter:, value)return set value valuedef del_bar(self):print(deleter...)return b...BAR property(get_bar, set_bar, del_bar, description...)obj Foo()print(obj.BAR) # 自动调用第一个参数中定义的方法get_bar
obj.BAR c # 自动调用第二个参数中定义的方法set_bar方法并将“c”当作参数传入
desc Foo.BAR.__doc__ # 自动获取第四个参数中设置的值description...
print(desc)
del obj.BAR # 自动调用第三个参数中定义的方法del_bar方法由于类属性方式创建property属性具有3种访问方式我们可以根据它们几个属性的访问特点分别将三个方法定义为对同一个属性获取、修改、删除
class Goods(object):def __init__(self):# 原价self.original_price 100# 折扣self.discount 0.8def get_price(self):# 实际价格 原价 * 折扣new_price self.original_price * self.discountreturn new_pricedef set_price(self, value):self.original_price valuedef del_price(self):del self.original_pricePRICE property(get_price, set_price, del_price, 价格属性描述...)obj Goods()
print(obj.PRICE) # 获取商品价格
obj.PRICE 200 # 修改商品原价
print(obj.PRICE)
del obj.PRICE # 删除商品原价property - 应用
私有属性添加getter和setter方法
class Money(object):def __init__(self):self.__money 0def get_money(self):return self.__moneydef set_money(self, value):if isinstance(value, int):self.__money valueelse:print(error:不是整型数字)money Money()
print(money.get_money())
money.set_money(10)
print(money.get_money())使用property升级getter和setter方法
class Money(object):def __init__(self):self.__money 0def get_money(self):return self.__moneydef set_money(self, value):if isinstance(value, int):self.__money valueelse:print(error:不是整型数字)# 定义一个属性当对这个money设置值时调用setMoney,当获取值时调用getMoneymoney property(get_money, set_money)money_obj Money()
money_obj.money 100 # 调用setMoney方法
print(money_obj.money) # 调用getMoney方法使用property取代getter和setter方法 重新实现一个属性的设置和读取方法,可做边界判定
class Money(object):def __init__(self):self.__money 0# 使用装饰器对money进行装饰那么会自动添加一个叫money的属性当调用获取money的值时调用装饰的方法propertydef money(self):return self.__money# 使用装饰器对money进行装饰当对money设置值时调用装饰的方法money.setterdef money(self, value):if isinstance(value, int):self.__money valueelse:print(error:不是整型数字)money_obj Money()
money_obj.money 100
print(money_obj.money)结语
以上就是关于python专题中的装饰器全部内容了欢迎同学们在评论区讨论交流有任何python开发、数据采集相关需求也可以后台或V加regentwan与我联系哟~