如何使用基于类的装饰器的缩写表示法为__call__提供* args和** kwargs?

时间:2018-03-10 15:07:08

标签: python decorator python-decorators

我有一个关于python中基于类的装饰器以及参数如何的问题 可以在装饰给定功能时提供。

考虑以下原型:

class MyDecoratorClass:
    def __init__(self, *args, **kwargs):
        # . . . Any code that is needed here
        pass

    def __call__(self, fun_to_decorate, *args, **kwargs):
        def inner(*args, **kwargs):
            # . . . Any code that is needed here
            return fun_to_decorate(*args, **kwargs)
        return inner

考虑要装饰的功能:

def myfun(*args, **kwargs):
    print("myfun was called")

装饰上述功能的一种方法如下:

  • 第1步:创建装饰器类的实例。这会打电话给 构造函数,即__init__。如果我通过任何论点 在下面,它只会出现一次"在__init__内,当实例是 创建

    decorator = MyDecoratorClass()

  • 第2步:指定要装饰的功能,如果需要,请提供 参数列表,对应于*args和/或**kwargs __call__签名,因为它已在班级中定义。

decorated_fun = decorator(myfun, arg1, arg2)

  • 第3步:最后调用已修饰的函数,如果需要,请提供 函数本身的参数列表,如果提供,则对应于 __call__函数内部函数的形式参数列表。 如果我理解正确,内部形式参数的名称空间不同于__call__形式参数的名称空间

    decorated_fun(...)

这很有效。但是,如果我想使用我所拥有的缩写符号 写这样的东西:

@MyDecoratorClass(arg1, arg2)
def myfun(*args, **kwargs):
    print("myfun was called")

在上面的示例中,我传递了相同的两个位置参数arg1arg2。现在 问题是,这两个参数不是(*args, **kwargs)指定的 在__call__中,但实际上是__init__

中指定的那些

所以我的问题是,当我们使用缩写表示法来装饰a 通过带有参数的基于类的装饰来运行,如何访问调用 参数列表是为每个装饰函数提供的参数吗?

1 个答案:

答案 0 :(得分:1)

关于装饰者签名

这样做......

grails run-app

...不是装饰者的工作方式。装饰器采用单个参数,一个函数,并输出一个函数。

特别是,上述内容并不等同于正确的做法。

C:\grails3projects\pmtracker>grails run-app
| Running application...
ERROR org.springframework.boot.SpringApplication - Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean wit
h name 'persistenceInterceptor': Injection of autowired dependencies failed; nes
ted exception is org.springframework.beans.factory.BeanCreationException: Could
not autowire method: public void org.grails.orm.hibernate4.support.AggregatePers
istenceContextInterceptor.setHibernateDatastores(org.grails.orm.hibernate.Abstra
ctHibernateDatastore[]); nested exception is org.springframework.beans.factory.N
oSuchBeanDefinitionException: No qualifying bean of type [org.grails.orm.hiberna
te.AbstractHibernateDatastore] found for dependency [array of org.grails.orm.hib
ernate.AbstractHibernateDatastore]: expected at least 1 bean which qualifies as
autowire candidate for this dependency. Dependency annotations: {}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanP
ostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java
:334)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBean
Factory.createBean(AbstractAutowireCapableBeanFactory.java:482)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getOb
ject(AbstractBeanFactory.java:306)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistr
y.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBe
an(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean
(AbstractBeanFactory.java:197)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.
preInstantiateSingletons(DefaultListableBeanFactory.java:772)
        at org.springframework.context.support.AbstractApplicationContext.finish
BeanFactoryInitialization(AbstractApplicationContext.java:839)
        at org.springframework.context.support.AbstractApplicationContext.refres
h(AbstractApplicationContext.java:538)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationConte
xt.refresh(EmbeddedWebApplicationContext.java:118)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.
java:766)
        at org.springframework.boot.SpringApplication.createAndRefreshContext(Sp
ringApplication.java:361)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java
:307)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:55)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:374)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:363)
        at grails.boot.GrailsApp$run.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSi
teArray.java:48)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
llSite.java:113)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCa
llSite.java:133)
        at pmtracker.Application.main(Application.groovy:8)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not au
towire method: public void org.grails.orm.hibernate4.support.AggregatePersistenc
eContextInterceptor.setHibernateDatastores(org.grails.orm.hibernate.AbstractHibe
rnateDatastore[]); nested exception is org.springframework.beans.factory.NoSuchB
eanDefinitionException: No qualifying bean of type [org.grails.orm.hibernate.Abs
tractHibernateDatastore] found for dependency [array of org.grails.orm.hibernate
.AbstractHibernateDatastore]: expected at least 1 bean which qualifies as autowi
re candidate for this dependency. Dependency annotations: {}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanP
ostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.
java:661)
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject
(InjectionMetadata.java:88)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanP
ostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java
:331)
        ... 22 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No q
ualifying bean of type [org.grails.orm.hibernate.AbstractHibernateDatastore] fou
nd for dependency [array of org.grails.orm.hibernate.AbstractHibernateDatastore]
: expected at least 1 bean which qualifies as autowire candidate for this depend
ency. Dependency annotations: {}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.
raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.
doResolveDependency(DefaultListableBeanFactory.java:1044)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.
resolveDependency(DefaultListableBeanFactory.java:1014)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanP
ostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.
java:618)
        ... 24 common frames omitted
Picked up _JAVA_OPTIONS: -Xmx512M -Xms512M

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':bootRun'.
> Process 'command 'C:\Program Files\Java\jdk1.8.0_31\bin\java.exe'' finished wi
th non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug
option to get more log output.
| Error Failed to start server (Use --stacktrace to see the full trace)

访问decorated_fun = decorator(myfun, arg1, arg2)

中的@decorator(arg1, arg2) def myfun(...): ... # Which is actually equivalent to... myfun = decorator(arg1, arg2)(myfun) 个参数

如果您想要访问传递给__init__的参数,可以将它们存储为实例属性。

__call__

对功能

执行相同操作

虽然,请记住,您不需要使用类装饰器来完成此操作,但以下装饰器将具有相同的行为。

__init__