gpt4 book ai didi

python - 菊花链式 Python/Django 自定义装饰器

转载 作者:太空狗 更新时间:2023-10-30 00:40:49 24 4
gpt4 key购买 nike

菊花链式 Python/Django 自定义装饰器是一种很好的风格吗?并传递与收到的参数不同的参数?

我的许多 Django View 函数都以完全相同的代码开始:

@login_required
def myView(request, myObjectID):
try:
myObj = MyObject.objects.get(pk=myObjectID)
except:
return myErrorPage(request)

try:
requester = Profile.objects.get(user=request.user)
except:
return myErrorPage(request)

# Do Something interesting with requester and myObj here

仅供引用,这是 urls.py 文件中相应条目的样子:

url(r'^object/(?P<myObjectID>\d+)/?$', views.myView, ),

在许多不同的 View 函数中重复相同的代码根本不是 DRY。我想通过创建一个装饰器来改进它,它会为我做这些重复的工作,并使新的 View 功能更清晰,看起来像这样:

@login_required
@my_decorator
def myView(request, requester, myObj):
# Do Something interesting with requester and myObj here

所以这是我的问题:

  1. 这是正确的做法吗?风格好吗?请注意,我将更改 myView() 函数的签名。这对我来说有点奇怪和冒险。但我不确定为什么
  2. 如果我制作了多个这样的装饰器,它们执行一些共同的功能,但每个都使用与装饰器收到的参数不同的参数调用包装函数,我可以将它们菊花链在一起吗?
  3. 如果上面的#1 和#2 没问题,那么向这个 myView 的用户指示他们应该传入的参数集的最佳方式是什么(因为只需查看函数定义中的参数不再有效)

最佳答案

这是一个非常有趣的问题! Another one has already been answered in depth on the basic usage of decorators .但它并没有提供太多关于修改参数的见解

可堆叠装饰器

你可以在另一个问题上找到一个堆叠装饰器的例子,下面的解释隐藏在一个非常、非常又长又详细的答案中:

Yes, that’s all, it’s that simple. @decorator is just a shortcut to:

another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)

这就是魔法。作为python documentation声明:装饰器是返回另一个函数的函数

这意味着您可以:

from functools import wraps

def decorator1(f):
@wraps(f)
def wrapper(*args, **kwargs):
do_something()
f(*args, **kwargs)
return wrapper


def decorator2(f):
@wraps(f)
def wrapper(*args, **kwargs):
do_something_else()
f(*args, **kwargs)
return wrapper

@decorator1
@decorator2
def myfunc(n):
print "."*n

#is equivalent to

def myfunc(n):
print "."*n
myfunc = decorator1(decorator2(myfunc))

装饰器不是装饰器

Python 装饰器可能会让那些使用一种语言学习 OOP 的开发人员感到困惑,其中 GoF 已经使用了一半的字典来命名修复语言故障的模式是事实上的设计模式购物。

GoF 的装饰器是它们正在装饰的组件(接口(interface))的子类,因此与该组件的任何其他子类共享此接口(interface)。

Python 装饰器是返回函数 ( or classes ) 的函数。

功能一直向下

Python 装饰器是一个返回函数的函数,任何函数。

大多数装饰器都旨在扩展装饰功能而不妨碍其预期行为。它们是根据 GoF 对装饰器模式的定义而设计的,装饰器模式描述了一种在保持对象接口(interface)的同时扩展对象的方法。

但是GoF的装饰器是一种模式,而python的装饰器是一个特性。

Python 装饰器是函数,这些函数应该返回函数(当提供函数时)。

适配器

让我们采用另一个 GoF 模式:Adapter

An adapter helps two incompatible interfaces to work together. This is the real world definition for an adapter.

[An Object] adapter contains an instance of the class it wraps. In this situation, the adapter makes calls to the instance of the wrapped object.

以一个对象为例——比如一个调度员,他会调用一个函数,该函数接受一些定义的参数,并接受一个函数来完成这项工作但提供另一组参数。第二个函数的参数可以从第一个函数的参数中导出。

一个函数(它是 python 中的一等对象)将获取第一个参数并派生它们以调用第二个并返回从其结果派生的值将是一个适配器。

为传递给它的函数返回适配器的函数将是一个适配器工厂。

Python 装饰器是函数返回函数。包括适配器。

def my_adapter(f):
def wrapper(*args, **kwargs):
newargs, newkwargs = adapt(args, kwargs)
return f(*newargs, **newkwargs)

@my_adapter # This is the contract provider
def myfunc(*args, **kwargs):
return something()

哦哦哦,我看到你在那里做了什么……风格不错吗?

我会说,该死的,又一个内置模式!但是你必须忘记 GoF 装饰器,只记住 python 装饰器是返回函数的函数。因此,您正在处理的接口(interface)是包装函数之一,而不是装饰函数。

一旦你装饰了一个函数,装饰器就定义了契约,要么告诉它保留被装饰函数的接口(interface),要么将它抽象出来。你不再调用那个装饰函数,尝试它甚至很棘手,你调用包装器。

关于python - 菊花链式 Python/Django 自定义装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22651031/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com