2015-07-01 61 views
-1

目标: 执行__init__变量(对象创建)后动态生成方法。执行__init__后动态生成方法

第一(未动力为例):

string_custom_method='''def custom_method(self): 
    print self.text''' 

class Foo: 
    def __init__(self): 
     self.text='foo' 

    exec string_custom_method 

Foo().custom_method() 

这个脚本是非常简单,它的作品好。问题是,我居然需要自定义的string_custom_method内容:

string_custom_method='''def custom_method(self):\n''' 

def create_custom_method(print_end): 
    global string_custom_method 
    string_custom_method+='\t'+'print self.text\n' 
    if print_end: 
     string_custom_method+='\t'+'print "end"' 

class Faa: 
    def __init__(self): 
     self.text='faa' 
     create_custom_method(True) 

    exec string_custom_method 

Faa().custom_method() 

的问题是,我得到以下错误:

def custom_method(self): 
         ^
SyntaxError: unexpected EOF while parsing 

所以我的结论是,蟒蛇读取方法的树前执行__init__这在这种情况下是一个问题。

阅读一些有关这之后,我想,也许通过staticmethod这样的:self.custom_method = staticmethod(...)可以工作, 但问题是,custom_method它没有在全球范围内定义,我无法定义它,直到__init__是执行。

有没有什么办法让这项工作?我知道这个例子看起来不太有用,但我真的需要它来做我的程序!

+2

你愿意解释一下你的真实* *使用情况,而不是这个虚拟实例吗?我认为你在这里有一个XY问题 - 他们当然是比使用exec更好的解决方案(提示:99.90%,exec和eval是错误的解决方案)。 –

+0

@brunodesthuilliers这个虚拟示例解释了相当不错的问题,但没有发布100行我的程序。在我的程序“custom_method”中,它实际上是增加了多个条件和变量的循环。条件和变量并不总是有用的。它依赖于'__init __(self,var1,var2,var3)'定义的变量。如果删除无用​​的变量和条件,我会增加循环的速度,这是我需要的。 – rsm

+1

那么,为什么你要以不必要的条件得到评估的方式编写代码呢?对于* actual *问题,可能有许多解决方案,可能是子类,方法提取,策略模式等等。但动态方法创建几乎肯定不是它。我同意@brunodesthuilliers,这似乎是一个XY问题。 –

回答

1

工作方案,预编译的代码:

funtpl = """ 
def __TheFunction__(self): 
    %s 

""" 

def create_custom_method(print_end): 
    # this would be better done by a template engine I think 
    source = ['print self.text'] 
    if print_end: 
     source.append('print "end"') 

    source = funtpl % "\n ".join(source) 
    bytecode = compile(source, "<string>", "exec",) 
    locals = {} 
    eval(bytecode, globals(), locals) 
    return locals["__TheFunction__"] 



class Faa(object): 
    def __init__(self, print_end): 
     self.text='faa' 
     fun = create_custom_method(print_end) 
     self.custom_method = fun.__get__(self, type(self)) 

f = Faa(True) 
f.custom_method() 

好运运行f.custom_method直通步调试

0

__init__()在执行exec string_custom_method行后被调用。 Class首先被构造,该行在类范围内,所以它在类正在被构造的时候被执行,然后python带着类创建实例,在这个点上调用__init__()

1

如果这样做的动机是你的循环执行了数十亿次,我强烈推荐使用numba jit。

+0

感谢您的评论,我会实施它到我的解决方案。它会使它更快:) – rsm

0

看来,解决方案需要一个不同的方法:

def create_custom_method(print_end): 
    string_custom_method = 'print self.text\n' 
    if print_end: 
     string_custom_method = string_custom_method +'print "end"' 

    return string_custom_method 

class Faa: 
    def __init__(self): 
     self.text='faa' 
     self.cs=create_custom_method(True) 

    def custom_method(self): 
     exec self.cs 

a = Faa() 
a.custom_method() 

定义整个方法复杂太多的代码。只是定义内容方法更容易。

+0

这也适用,但是由于你在每个函数调用时都调用了'exec',python必须解析字符串,编译为字节码等,然后执行它。你以前的预编译方法比较好。 –

+0

@AmitUpadhyay耶,但我不能让工作的代码。这个问题的另一个问题是,如果'string_custom_method'包含'return'关键字,它就不再起作用了。 – rsm