gpt4 book ai didi

python - 动态创建的方法和装饰器,得到错误 'functools.partial' 对象没有属性 '__module__'

转载 作者:IT老高 更新时间:2023-10-28 21:03:48 27 4
gpt4 key购买 nike

我目前正在使用 EndpointsModel 为我在 AppEngine 上的所有模型创建一个 RESTful API。由于是 RESTful,这些 api 有很多我想避免的重复代码。

例如:

class Reducer(EndpointsModel):
name = ndb.StringProperty(indexed=False)

@endpoints.api(
name="bigdata",
version="v1",
description="""The BigData API""",
allowed_client_ids=ALLOWED_CLIENT_IDS,
)
class BigDataApi(remote.Service):
@Reducer.method(
path="reducer",
http_method="POST",
name="reducer.insert",
user_required=True,
)
def ReducerInsert(self, obj):
pass

## and GET, POST, PUT, DELETE
## REPEATED for each model

我想让它们变得通用。所以我尝试向类动态添加方法。到目前为止我尝试过的:

from functools import partial, wraps

def GenericInsert(self, obj, cls):
obj.owner = endpoints.get_current_user()
obj.put()
return obj

# Ignore GenericDelete, GenericGet, GenericUpdate ...

import types
from functools import partial

def register_rest_api(api_server, endpoint_cls):
name = endpoint_cls.__name__

# create list method
query_method = types.MethodType(
endpoint_cls.query_method(
query_fields=('limit', 'pageToken'),
path="%ss" % name,
http_method="GET",
name="%s.list" % name,
user_required=True
)(partial(GenericList, cls=endpoint_cls)))

setattr(api_server, "%sList", query_method)

# create insert method
# ...

register_rest_api(BigDataApi, Reducer)

但是我得到了 'functools.partial' 对象没有属性 '__module__' 异常。我认为是因为 endpoints.method 的装饰器和部分装饰器之间存在一些冲突。但不知道如何避免它。

Traceback (most recent call last):
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 239, in Handle
handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 298, in _LoadHandler
handler, path, err = LoadObject(self._handler)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/runtime/wsgi.py", line 84, in LoadObject
obj = __import__(path[0])
File "/Users/Sylvia/gcdc2013/apis.py", line 795, in <module>
register_rest_api(BigDataApi, Reducer)
File "/Users/Sylvia/gcdc2013/apis.py", line 788, in register_rest_api
)(partial(GenericList, cls=endpoint_cls)))
File "/Users/Sylvia/gcdc2013/endpoints_proto_datastore/ndb/model.py", line 1544, in RequestToQueryDecorator
@functools.wraps(api_method)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/functools.py", line 33, in update_wrapper
setattr(wrapper, attr, getattr(wrapped, attr))
AttributeError: 'functools.partial' object has no attribute '__module__'

相关文章:

最佳答案

我也偶然发现了这一点,我真的很惊讶,对我来说,问题是部分对象缺少某些属性,特别是 __module____name__

因为 wraps 默认使用 functools.WRAPPER_ASSIGNMENTS 来更新属性,默认为 ('__module__', '__name__', '__doc__') 在 python 2.7.6 中,有几种方法可以处理这个......

更新仅存在属性...

import functools
import itertools

def wraps_safely(obj, attr_names=functools.WRAPPER_ASSIGNMENTS):
return wraps(obj, assigned=itertools.ifilter(functools.partial(hasattr, obj), attr_names))

>>> def foo():
... """ Ubiquitous foo function ...."""
...
>>> functools.wraps(partial(foo))(foo)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/functools.py", line 33, in update_wrapper
setattr(wrapper, attr, getattr(wrapped, attr))
AttributeError: 'functools.partial' object has no attribute '__module__'
>>> wraps_safely(partial(foo))(foo)()
>>>

这里我们只是过滤掉所有不存在的属性。

另一种方法是严格只处理部分对象,你可以用 singledispatch 折叠 wraps 并创建包装的部分对象,其属性将取自 deepest func 属性。

类似的东西:

import functools

def wraps_partial(wrapper, *args, **kwargs):
""" Creates a callable object whose attributes will be set from the partials nested func attribute ..."""
wrapper = wrapper.func
while isinstance(wrapper, functools.partial):
wrapper = wrapper.func
return functools.wraps(wrapper, *args, **kwargs)

def foo():
""" Foo function.
:return: None """
pass

>>> wraps_partial(partial(partial(foo)))(lambda : None).__doc__
' Foo Function, returns None '
>>> wraps_partial(partial(partial(foo)))(lambda : None).__name__
'foo'
>>> wraps_partial(partial(partial(foo)))(lambda : None)()
>>> pfoo = partial(partial(foo))
>>> @wraps_partial(pfoo)
... def not_foo():
... """ Not Foo function ... """
...
>>> not_foo.__doc__
' Foo Function, returns None '
>>> not_foo.__name__
'foo'
>>>

这稍微好一些,因为现在我们可以得到原始函数文档,之前默认使用部分对象文档字符串。

这可以修改为仅在当前部分对象还没有 set 属性时才搜索,嵌套许多部分对象时应该会稍微快一些...

更新

python(CPython) 3(至少 3.4.3)似乎没有这个问题,因为我不知道也不应该假设所有版本的 python 3 或 Jython 等其他实现也有这个问题这是另一种为 future 做好准备的方法

from functools import wraps, partial, WRAPPER_ASSIGNMENTS

try:
wraps(partial(wraps))(wraps)
except AttributeError:
@wraps(wraps)
def wraps(obj, attr_names=WRAPPER_ASSIGNMENTS, wraps=wraps):
return wraps(obj, assigned=(name for name in attr_names if hasattr(obj, name)))

有几点需要注意:

  • 我们定义一个新的 wraps 函数仅当我们未能包装一个部分,以防将来的 python2 版本或其他版本修复此问题问题。
  • 我们使用原始 wraps 来复制文档和其他信息
  • 我们不使用 ifilter,因为它在 python3 中被删除了,我在有和没有 ifilter 的情况下都进行了计时,但结果尚无定论,至少在 python 中(CPython ) 2.7.6,无论哪种方式,差异充其量都是微不足道的......

关于python - 动态创建的方法和装饰器,得到错误 'functools.partial' 对象没有属性 '__module__',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20594193/

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