如何在类Python中执行'exec'定义

时间:2018-06-27 14:08:44

标签: python class

伙计们。我最近开始学习课程,并且在玩耍时尝试做这样的事情:

from functools import partial

class test():
    def __init__(self):
         exec('def foo(self, number): x = number; return x') 

    def printingX(self):
         command = partial(self.foo, 1)
         print command
a = test() 
a.printingX()

这当然是一个错误,但是我的问题是:是否可以将方法存储在“ init ”内部,然后在以后的其他方法中调用它?如果可能的话,这是一个好的做法还是不好的做法?

3 个答案:

答案 0 :(得分:2)

您可以,但是通常不能。

我会说be careful with exec。但是除此之外,没有什么阻止您真正做到这一点

>>> class MyClass:
...     def __init__(self):
...         exec('MyClass.foo = lambda self, x: x*x')
...
>>> c = MyClass()
>>> c.foo(3)
9

ALTHOUGH,我的建议是您不要这样做,因为这是非常不切实际的,并且没有惯例。

答案 1 :(得分:0)

  

是否可以将方法存储在'init'中

取决于“存储”是什么意思?但是,如果您要表示“定义”,是的,您可以定义函数(nb:def总是定义一个函数,仅当在类或实例上查询时,它才成为“方法”)。而且您不需要exec

class Foo(object):
    def __init__(self, arg):
        def bar(baaz):
            print("in bar: {}".format(baaz))
        bar(arg)
  

然后在其他方法中调用它?

如果要使其成为方法,可以将其添加到实例中:

class Foo(object):
    def __init__(self, arg):
        self.arg = arg
        def bar(self):
            print("in self.bar: {}".format(self.arg))
        self.bar = bar.__get__(self, type(self))

或该类(这意味着您每次实例化该类都会被覆盖):

class Foo(object):
    def __init__(self, arg):
        self.arg = arg
        def bar(self):
            print("in self.bar: {}".format(self.arg))
        type(self).bar = bar
  

如果可能的话,这是个好习惯吗?

正如上面所写,它是荒谬的,令人困惑的且效率低下的,所以我看不到如何将其视为良好实践。而使用exec进行操作只是一个完整的WTF。

如果目标是以某种方式为每个实例参数化给定方法(基于条件或其他条件),则可以将函数(或任何可调用的FWIW)作为参数传递(python函数是与其他对象一样的对象):

class Foo(object):
    def __init__(self, arg, strategy):
        self.arg = arg
        # we may not want to expose it
        # as part of the class API
        self._strategy = strategy

    def bar(self, value):
        return self._strategy(self, value)


def my_strategy(foo, value):
    return foo.arg * value

f = Foo(42, my_strategy)
f.bar(2)

FWIW,这被称为“策略”设计模式。

答案 2 :(得分:0)

您可以完全按照自己的意愿进行操作,但是必须使用exec的globals和locals参数来限制执行危险字符串并获取函数定义的风险:

class test:
    def __init__(self):
        funcs = {}
        exec('def foo(self, number): x = number; return x',
             {'__builtins__':{}}, funcs)
        for func in funcs:
            if not hasattr(self.__class__, func):
                setattr(self.__class__, func, funcs[func])

此代码在创建第一个对象时明确地将编译后的函数添加到类中。

演示:

>>> test.__dict__
mappingproxy({'__module__': '__main__', '__init__': <function test.__init__ at 0x000001E5C5F27EA0>, '__dict__': <attribute '__dict__' of 'test' objects>, '__weakref__': <attribute '__weakref__' of 'test' objects>, '__doc__': None})
>>> t = test()
>>> test.__dict__
mappingproxy({'__module__': '__main__', '__init__': <function test.__init__ at 0x000001E5C5F27EA0>, '__dict__': <attribute '__dict__' of 'test' objects>, '__weakref__': <attribute '__weakref__' of 'test' objects>, '__doc__': None, 'foo': <function foo at 0x000001E5C5F27F28>})
>>> t.foo(12)
12

这清楚地表明,foo方法在创建其第一个实例时已添加到该类中。

但是... 请不要!。这段代码仅显示Python足够友好,可以在运行时修改类,而如果一个类的属性恰巧是一个函数,则该方法是可以的。好的,传递给exec的字符串是受控制的,因此这里没有安全性问题,但是应尽可能避免使用execeval

除非您真正需要这样的代码,否则当可读性成为Python程序员的首要考虑因素时,这将导致难以理解的类。

所以回答您的第二个问题确实是一个可怕的做法。永远不要说我建议使用它。