局部函数对象没有属性“ __code __”

时间:2019-07-04 06:17:22

标签: python python-3.x partial functools

我正在编写一个小型应用程序,该应用程序需要用户输入才能为他们提供一组最佳参数以供使用。 (对这些集合中的每一个进行排名,用户可以选择他们想要使用的任何一个)

为此,我从一个选择数组中选择一个函数(取决于上下文),使用functools.partial部分填充该函数,然后将部分对象返回到另一个模块,该模块依次调用C ++具有python接口的库(dlib)。

直到今天,我还没有使用functools.partial来填充函数,并且没有遇到任何问题。但是为了使代码少重复且更易于理解,我在其中添加了代码。添加该部分后,出现以下错误:

  

AttributeError:'functools.partial'对象没有属性'__code __'

我阅读了几篇文章,并意识到这是partial对象的问题,因为它们通常缺少__name____module__等属性,但我不确定如何解决此问题。

PS:我正在使用python 3.7

编辑

我正在添加一个小代码来重现错误

from functools import partial
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_breast_cancer
from dlib import find_max_global

def objective_calculator(*args, X, y):
    args = args[0]
    model = LogisticRegression()
    model.set_params(**{'class_weight': args[0], 'max_iter':args[1]})
    model.fit(train['data'], train['target'])
    predictions = model.predict(X)
    return accuracy_score(y, predictions)

train = load_breast_cancer()
obj_calc = partial(objective_calculator, X=train['data'], y=train['target'])
lower_bounds = [0.1, 10] # class_weight, max_iter
upper_bounds = [0.5, 200] # class_weight, max_iter
is_integer_variable = [False, True]

find_max_global(f=obj_calc,
                bound1=lower_bounds,
                bound2=upper_bounds,
                num_function_calls=2,
                is_integer_variable=is_integer_variable,
                solver_epsilon=1,)

运行上面的代码会导致以下错误

  

AttributeError:'functools.partial'对象没有属性'__code __'

建议手动将__code__属性添加到部分对象吗?

2 个答案:

答案 0 :(得分:1)

AttributeError: 'functools.partial' object has no attribute '__code__'

为解决此错误,我们可以使用

包装

functools.WRAPPER_ASSIGNMENTS更新属性, 默认为(“ 模块”,“ 名称”,“ 文档”)  在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进行折叠包装,并创建包装的部分对象,其属性将从函数“ fun”的属性中获取。

导入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)

# after returning functools.wraps

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'



 >>>

现在我们可以获得原始功能文档。

python(CPython)3。

从functools导入包装,部分包装,WRAPPER_ASSIGNMENTS

尝试:

 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)))

*仅当我们无法包装部分包装时,我们才定义新的包装功能* *使用原始包装纸复制文档*

在(Python 3.5)中,我们引用了原始函数,并且将其保留在局部函数中。您可以通过.func:

对其进行访问

functools导入部分

 def a(b):
print(b)


In[20]:  c=partial(a,5)


In[21]:  c.func.__module__

Out[21]: '__main__'

In[22]:  c.func.__name__

Out[22]: 'a'

答案 1 :(得分:1)

我不敢向__code__对象添加partial属性。 __code__属性允许对已编译 Python代码的低级别访问。通常,它通常不会在通用脚本中使用,并且可能在此处用于与基础C ++库进行接口。

防弹方式是定义一个新功能。在Python中,def是一个可执行语句,可以迭代地重新定义一个函数:

def objective_calculator(*args, X, y):
    ...

for X, y in ...:
    def obj_calc(*args):
        return objective_calculator(*args, X, y)
    ...
    find_max_global(f=obj_calc, ...)

obj_calc现在是真正的Python函数,它将具有自己的__code__属性。


如果dlib库支持它,则可以使用lambda

find_max_global(f=lambda *args: objective_calculator(*args, X, y), ...)

lambda几乎是一个真正的函数,确实具有__code__属性,但是在Python中它被定义为一个单独的对象类,因此取决于dlib库的要求(我找不到关于它的任何引用)它可能行不通。