资讯

精准传达 • 有效沟通

从品牌网站建设到网络营销策划,从策略到执行的一站式服务

python修饰器函数的简单介绍

什么是 NUMBA?

蓝海大脑深度学习高性能液冷服务器研究人员表示:

让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:申请域名网站空间、营销软件、网站建设、太和网站维护、网站推广。

为了提高执行速度,Numba 会在执行前立即将 Python 字节代码转换为机器代码。

Numba 可用于使用可调用的 Python 对象(称为修饰器)来优化 CPU 和 GPU 功能。修饰器是一个函数,它将另一个函数作为输入,进行修改,并将修改后的函数返回给用户。这种模组化可减少编程时间,并提高 Python 的可扩展性。

Numba 还可与 NumPy 结合使用,后者是一个复杂数学运算的开源 Python 库,专为处理统计数据而设计。调用修饰器时,Numa 将 Python 和/或 NumPy 代码的子集转换为针对环境自动优化的字节码。它使用 LLVM,这是一个面向 API 的开源库,用于以编程方式创建机器原生代码。Numba 针对各种 CPU 和 GPU 配置,提供了多种快速并行化 Python 代码的选项,有时仅需一条命令即可。与 NumPy 结合使用时,Numba 会为不同的数组数据类型和布局生成专用代码,进而优化性能。

如何在Python Flask框架中运行重复任务

Flask是一个使用Python编写的轻量级Web应用框架,凭借更灵活、轻便、安全且容易上手的特性,成为企业常用的Python框架之一。在完成Web前端、Linux以及MySQL相关的课程之后,专业的杭州Python学习班都会讲解Flask框架知识,以下是整理的相关知识点。

Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架。开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。

默认情况下,Flask不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask支持用扩展来给应用添加这些功能,如同是Flask本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。

Flask框架的特点:

1)Flask自由、灵活,可扩展性强,第三方库的选择面广,开发时可以结合自己最喜欢用的轮子,也能结合最流行最强大的Python库;

2)入门简单,即便没有多少web开发经验,也能很快做出网站;

3)非常适用于小型网站;

4)非常适用于开发Web服务的API;

5)开发大型网站无压力,但代码架构需要自己设计,开发成本取决于开发者的能力和经验。

Flask框架运行解释

1.app = Flask(__name__)

创建Flask对象app,Flask类的构造函数只有一个必须指定的参数,即程序主模块或包的名字。在大多数程序中,Python的__name__变量就是所需要的值。

2.@app.route('/')

web浏览器把请求发送给Web服务器,Web服务器再把请求发送给Flask程序实例。程序实例需要知道对每个URL请求运行哪些代码,所以保存了一个URL到Python函数的映射关系。处理URL和函数之间的关系的程序称为路由。在Flask程序中定义路由的最简便方式,是使用程序实例提供的app.route修饰器,把修饰的函数注册为路由。route()装饰器告诉 Flask什么样的URL 能触发我们的函数。这和Java中的注释有异曲同工之妙。修饰器是Python语言的标准特性,可以使用不同的方式修改函数的行为。惯常用法是使用修饰器把函数注册为事件的处理程序。

3.def index():函数

index()函数放在@app.route('/')后面,所以就是把index()函数注册为路由。如果部署程序的服务器域名为,在浏览器中访问后,会触发服务器执行index()函数。

4.@app.route('/user/')

同@app.route('/'),如果部署程序的服务器域名为,在浏览器中访问后,会触发服务器执行下方修饰函数。

5.app.run(debug=True)

程序实例用run方法启动Flask继承Web服务器。

6.if __name__ == '__main__'

当Python解释器,读py文件,它会执行它发现的所有代码。在执行代码之前,它会定义一些变量。例如,如果这个py文件就是主程序,它会设置__name__变量为"__main__"。如果这个py被引入到别的模块,__name__会被设置为该模块的名字。

python函数的几种参数类型

#Python 2.5 #这个可以用修饰器来完成 #但是一般不会限制参数类型 #给你个思路: def argfilter(*types): def deco(func): #这是修饰器 def newfunc(*args): #新的函数 if len(types)==len(args): correct = True for i in range(len(args)): if not isinstance(args[i], types[i]): #判断类型 correct = False if correct: return func(*args) #返回原函数值 else: raise TypeError else: raise TypeError return newfunc #由修饰器返回新的函数 return deco #返回作为修饰器的函数 @argfilter(int, str) #指定参数类型 def func(i, s): #定义被修饰的函数 print i, s #之后你想限制类型的话, 就这样: #@argfilter(第一个参数的类名, 第二个参数的类名, ..., 第N个参数的类名) #def yourfunc(第一个参数, 第一个参数, ..., 第N个参数): # ... # #相当于: #def yourfunc(第一个参数, 第一个参数, ..., 第N个参数): # ... #yourfunc = argfilter(第一个参数的类名, 第二个参数的类名, ..., 第N个参数的类名)(yourfunc)

python中修饰器是什么?

就是一个callable object。 它使python编程更加容易。

例如:

@dec

def A(args):

pass

它就等价于dec(A). 当然还有带参数的decorator。我就不举例了。

python文档里有这样一句话。

A function definition may be wrapped by one or more decorator expressions. Decorator expressions are evaluated when the function is defined, in the scope that contains the function definition. The result must be a callable, which is invoked with the function object as the only argument. The returned value is bound to the function name instead of the function object. Multiple decorators are applied in nested fashion.

大概就是说函数的定义可以用多个decorator。decorator就在函数定义时用函数作为参数调用,然后返回一个可调用对象。 所以写decorator的时候一定要返回一个可调用对象。

不知道你明白没。

python中怎么设定函数形参的类型

直接写个名字就行。python的一切默认都是对象,参数没使用前,是没有类型的。甚至函数写不写行参都无所谓。

如何正确地使用Python的属性和描述符

关于@property装饰器

在Python中我们使用@property装饰器来把对函数的调用伪装成对属性的访问。

那么为什么要这样做呢?因为@property让我们将自定义的代码同变量的访问/设定联系在了一起,同时为你的类保持一个简单的访问属性的接口。

举个栗子,假如我们有一个需要表示电影的类:

1

2

3

4

5

6

7

8

class Movie(object):

def __init__(self, title, description, score, ticket):

self.title = title

self.description = description

self.score = scroe

self.ticket = ticket

你开始在项目的其他地方使用这个类,但是之后你意识到:如果不小心给电影打了负分怎么办?你觉得这是错误的行为,希望Movie类可以阻止这个错误。 你首先想到的办法是将Movie类修改为这样:

Python

1

2

3

4

5

6

7

8

class Movie(object):

def __init__(self, title, description, score, ticket):

self.title = title

self.description = description

self.ticket = ticket

if score 0:

raise ValueError("Negative value not allowed:{}".format(score))

self.score = scroe

但这行不通。因为其他部分的代码都是直接通过Movie.score来赋值的。这个新修改的类只会在__init__方法中捕获错误的数据,但对于已经存在的类实例就无能为力了。如果有人试着运行m.scrore= -100,那么谁也没法阻止。那该怎么办?

Python的property解决了这个问题。

我们可以这样做

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

class Movie(object):

def __init__(self, title, description, score):

self.title = title

self.description = description

self.score = score

self.ticket = ticket

@property

def score(self):

return self.__score

@score.setter

def score(self, score):

if score 0:

raise ValueError("Negative value not allowed:{}".format(score))

self.__score = score

@score.deleter

def score(self):

raise AttributeError("Can not delete score")

这样在任何地方修改score都会检测它是否小于0。

property的不足

对property来说,最大的缺点就是它们不能重复使用。举个例子,假设你想为ticket字段也添加非负检查。下面是修改过的新类:

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

class Movie(object):

def __init__(self, title, description, score, ticket):

self.title = title

self.description = description

self.score = score

self.ticket = ticket

@property

def score(self):

return self.__score

@score.setter

def score(self, score):

if score 0:

raise ValueError("Negative value not allowed:{}".format(score))

self.__score = score

@score.deleter

def score(self):

raise AttributeError("Can not delete score")

@property

def ticket(self):

return self.__ticket

@ticket.setter

def ticket(self, ticket):

if ticket 0:

raise ValueError("Negative value not allowed:{}".format(ticket))

self.__ticket = ticket

@ticket.deleter

def ticket(self):

raise AttributeError("Can not delete ticket")

可以看到代码增加了不少,但重复的逻辑也出现了不少。虽然property可以让类从外部看起来接口整洁漂亮,但是却做不到内部同样整洁漂亮。

描述符登场

什么是描述符?

一般来说,描述符是一个具有绑定行为的对象属性,其属性的访问被描述符协议方法覆写。这些方法是__get__()、__set__()和__delete__(),一个对象中只要包含了这三个方法中的至少一个就称它为描述符。

描述符有什么作用?

The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance, a.x has a lookup chain starting witha.__dict__[‘x’], then type(a).__dict__[‘x’], and continuing through the base classes of type(a) excluding metaclasses. If the looked-up value is an object defining one of the descriptor methods, then Python may override the default behavior and invoke the descriptor method instead. Where this occurs in the precedence chain depends on which descriptor methods were defined.—–摘自官方文档

简单的说描述符会改变一个属性的基本的获取、设置和删除方式。

先看如何用描述符来解决上面 property逻辑重复的问题。

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

class Integer(object):

def __init__(self, name):

self.name = name

def __get__(self, instance, owner):

return instance.__dict__[self.name]

def __set__(self, instance, value):

if value 0:

raise ValueError("Negative value not allowed")

instance.__dict__[self.name] = value

class Movie(object):

score = Integer('score')

ticket = Integer('ticket')

因为描述符优先级高并且会改变默认的get、set行为,这样一来,当我们访问或者设置Movie().score的时候都会受到描述符Integer的限制。

不过我们也总不能用下面这样的方式来创建实例。

a = Movie()

a.score = 1

a.ticket = 2

a.title = ‘test’

a.descript = ‘…’

这样太生硬了,所以我们还缺一个构造函数。

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

class Integer(object):

def __init__(self, name):

self.name = name

def __get__(self, instance, owner):

if instance is None:

return self

return instance.__dict__[self.name]

def __set__(self, instance, value):

if value 0:

raise ValueError('Negative value not allowed')

instance.__dict__[self.name] = value

class Movie(object):

score = Integer('score')

ticket = Integer('ticket')

def __init__(self, title, description, score, ticket):

self.title = title

self.description = description

self.score = score

self.ticket = ticket

这样在获取、设置和删除score和ticket的时候都会进入Integer的__get__、__set__,从而减少了重复的逻辑。

现在虽然问题得到了解决,但是你可能会好奇这个描述符到底是如何工作的。具体来说,在__init__函数里访问的是自己的self.score和self.ticket,怎么和类属性score和ticket关联起来的?

描述符如何工作

看官方的说明

If an object defines both __get__() and __set__(), it is considered a data descriptor. Descriptors that only define __get__() are called non-data descriptors (they are typically used for methods but other uses are possible).

Data and non-data descriptors differ in how overrides are calculated with respect to entries in an instance’s dictionary. If an instance’s dictionary has an entry with the same name as a data descriptor, the data descriptor takes precedence. If an instance’s dictionary has an entry with the same name as a non-data descriptor, the dictionary entry takes precedence.

The important points to remember are:

descriptors are invoked by the __getattribute__() method

overriding __getattribute__() prevents automatic descriptor calls

object.__getattribute__() and type.__getattribute__() make different calls to __get__().

data descriptors always override instance dictionaries.

non-data descriptors may be overridden by instance dictionaries.

类调用__getattribute__()的时候大概是下面这样子:

1

2

3

4

5

6

7

def __getattribute__(self, key):

"Emulate type_getattro() in Objects/typeobject.c"

v = object.__getattribute__(self, key)

if hasattr(v, '__get__'):

return v.__get__(None, self)

return v

下面是摘自国外一篇博客上的内容。

Given a Class “C” and an Instance “c” where “c = C(…)”, calling “c.name” means looking up an Attribute “name” on the Instance “c” like this:

Get the Class from Instance

Call the Class’s special method getattribute__. All objects have a default __getattribute

Inside getattribute

Get the Class’s mro as ClassParents

For each ClassParent in ClassParents

If the Attribute is in the ClassParent’s dict

If is a data descriptor

Return the result from calling the data descriptor’s special method __get__()

Break the for each (do not continue searching the same Attribute any further)

If the Attribute is in Instance’s dict

Return the value as it is (even if the value is a data descriptor)

For each ClassParent in ClassParents

If the Attribute is in the ClassParent’s dict

If is a non-data descriptor

Return the result from calling the non-data descriptor’s special method __get__()

If it is NOT a descriptor

Return the value

If Class has the special method getattr

Return the result from calling the Class’s special method__getattr__.

我对上面的理解是,访问一个实例的属性的时候是先遍历它和它的父类,寻找它们的__dict__里是否有同名的data descriptor如果有,就用这个data descriptor代理该属性,如果没有再寻找该实例自身的__dict__,如果有就返回。任然没有再查找它和它父类里的non-data descriptor,最后查找是否有__getattr__

描述符的应用场景

python的property、classmethod修饰器本身也是一个描述符,甚至普通的函数也是描述符(non-data discriptor)

django model和SQLAlchemy里也有描述符的应用

Python

1

2

3

4

5

6

7

8

9

10

11

12

class User(db.Model):

id = db.Column(db.Integer, primary_key=True)

username = db.Column(db.String(80), unique=True)

email = db.Column(db.String(120), unique=True)

def __init__(self, username, email):

self.username = username

self.email = email

def __repr__(self):

return 'User %r' % self.username

后记

只有当确实需要在访问属性的时候完成一些额外的处理任务时,才应该使用property。不然代码反而会变得更加啰嗦,而且这样会让程序变慢很多。


文章标题:python修饰器函数的简单介绍
文章位置:http://cdkjz.cn/article/docdhge.html
多年建站经验

多一份参考,总有益处

联系快上网,免费获得专属《策划方案》及报价

咨询相关问题或预约面谈,可以通过以下方式与我们联系

业务热线:400-028-6601 / 大客户专线   成都:13518219792   座机:028-86922220