2014-11-22 145 views
0

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

类型错误:example_01()失踪1个人需要的位置参数:“自我”

我有点知道我需要创建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()。也没有提供类对象的类函数的参数像def 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 

回答

1

在Python中,有一个函数之间加上一个特殊的self区别(这需要的参数的普通列表)的方法(这需要参数或参数cls)。一旦函数被分配给类名称空间内的变量,它就成为一种方法。

在您装饰功能example_01example_02时,它们实际上不是方法,而是普通功能。这是你添加到examples的这些函数,所以你的结果类方法不会被调用。

你不能以简单的方式解决这个问题。要么你先装饰@example(然后你还没有类方法),或者你首先用@classmethod装饰(然后你所拥有的是一个不是类方法的中间对象)。获得最后一类方法的唯一方法是检索之后的方法它已被分配,这显然不能从装饰器完成。

最简单的事情将是在一个简单的方式完全放弃装饰,并指定类方法来examples

examples = [Bar.example_01, Bar.example_02] 

如果你真的想用一个装饰,你可以把一个包装中examples其中使用getattr从类中检索类方法,并返回未修改的函数fn

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

这是最后的代码可能是什么样子:

examples = list() 

def example(fn): 
    def wrapped(): 
     print("Running: %s" % fn.__name__) 
     getattr(Bar, fn.__name__)() 
     print() 
    examples.append(wrapped) 
    return fn 

class Bar: 
    @classmethod 
    @example 
    def example_01(cls): 
     print("I'm %s" % cls.__name__) 
     print("Executing example_01") 

    @classmethod 
    @example 
    def example_02(cls): 
     print("I'm %s" % cls.__name__) 
     print("Executing example_02") 
0

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

import types 

class Bar(object): 

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

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

    def example_02(self): 
     print(self.message) 
     print("Executing example_02") 

examples = list() 
testBar = Bar() 
methods = Bar.__dict__ 
for k, v in methods.items(): 
    if isinstance(v, types.FunctionType): 
     if k != '__init__': 
      examples.append(testBar.__getattribute__(k)) 

def main(): 
    for method in examples: 
     method() 

if __name__ == '__main__': 
    main()