如何执行存储在列表对象中的修饰类方法?

时间:2014-11-22 23:11:38

标签: python-3.x

我需要将类方法存储到列表中并通过循环执行它们。我定义了一个装饰器并使用它将类方法附加到列表中。该类在一个单独的模块中定义,并在主I循环中通过列表定义并调用存储在该列表中的类方法。当我运行main时,我收到错误:

TypeError:example_01()缺少1个必需的位置参数:' self'

我知道我需要创建一个类Bar实例来执行它的方法,但这会阻止我使用该列表。什么是使用这种结构的正确方法? 请帮忙......

我正在使用python 3.4

由于

mybar.py
========

examples = list()

def example(fn):
    try: name = 'Example %d' % int(fn.__name__[7:])
    except: name = fn.__name__

    def wrapped():
        print('Running: %s\n' % name)
        fn()
        print('\n')
    examples.append(wrapped)
    return wrapped


class Bar:
    def __init__(self):
        self.message = "I'm %s" % (__name__)

    @example
    def example_01(self):
       print(self.message)
       print("Executing example_01")

    @example
    def example_02(selfs):
        print(self.message)
        print("Executing example_02")

main.py
=======
from bar import mybar


def main():
    for example in mybar.examples:
        example()


if __name__ == "__main__":
    main()

我修改了我的代码,为每个类方法使用@classmethod装饰器,但是它有效,但我不明白为什么。我不必用Bar明确调用example()。也没有像python doc中记载的那样将类对象提供给类函数的参数,例如def example_01(cls)。请有人解释一下

mybar.py
=======
class Bar:
data = 25
def __init__(self):
    self.message = "I'm %s" % (__name__)
    Bar.data = 30

@classmethod
@example
def example_01():
    print("Executing example_01")
    print("Data: ", Bar.data)

@classmethod
@example
def example_02():
    print("Executing example_02")
    print("Data: ", Bar.data)

输出:

Running: example_01
Executing example_01
Data:  25
Running: example_02
Executing example_02
Data:  25

2 个答案:

答案 0 :(得分:1)

在Python中,函数(采用简单的参数列表)和方法(采用参数加上特殊的selfcls参数)之间存在区别。一旦将函数分配给类名称空间内的变量,该函数就成为一种方法。

在装饰函数example_01example_02的时候,它们实际上不是方法而是普通函数。这些函数将附加到examples,因此不会调用生成的类方法。

你无法轻松解决这个问题。你首先用@example装饰(然后你还没有类方法),或者先用@classmethod装饰(然后你所拥有的只是一个不是类方法的中间对象) 。获取最终类方法的唯一方法是在分配之后类中检索方法,这显然不能从装饰器中完成。

最简单的方法是完全删除装饰器并以简单的方式将类方法分配给examples

examples = [Bar.example_01, Bar.example_02]

如果你真的想使用一个装饰器,你可以在examples中放一个包装器,它使用getattr从类中检索类方法并返回未修改的 function fn

请注意,由于message变量是在类Bar的构造函数中设置的,因此您需要一个Bar实例来访问它。如果要在不创建虚拟实例的情况下从类方法访问变量,则必须在类名称空间中进行设置。但是,__name__变量没有在那里设置,所以你基本上不能像你想要的那样使用message变量。此外,在类方法中,第一个参数是类本身(通常称为cls),而不是self(实例),以及以{{1}结尾的print语句导致双线中断。

这是最终代码的样子:

\n

答案 1 :(得分:0)

如果您不想使用装饰器,则可以检索类的方法列表,并使用方法__getattribute __()从类的实例调用每个方法。这是代码:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 <system.webServer>
   <httpProtocol>
     <customHeaders>
       <add name="Access-Control-Allow-Origin" value="*" />
     </customHeaders>
   </httpProtocol>
 </system.webServer>
</configuration>