代码之家  ›  专栏  ›  技术社区  ›  Vlad

如何在类python中执行“exec”定义

  •  3
  • Vlad  · 技术社区  · 6 年前

    伙计们。我最近开始学习课程,当我四处游玩的时候,我试图做如下的事情:

    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()
    

    它当然会出错,但我的问题是:是否可以将方法存储在 初始化 '然后在以后的其他方法中调用它?如果可能的话,这是一个好的做法还是坏的做法?

    3 回复  |  直到 6 年前
        1
  •  2
  •   Pax Vobiscum    6 年前

    你可以,但一般来说不可以。

    我会说 be careful with exec .但除此之外,没有什么能真正阻止你这么做

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

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

        2
  •  0
  •   bruno desthuilliers    6 年前

    是否可以在“init”中存储方法

    取决于你所说的“存储”是什么意思?但是如果您的意思是“定义”,是的,您可以定义函数(注意: 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
    

    如果可能的话,这是一个好的做法还是坏的做法?

    好吧,如上所述,这是荒谬的、混乱的和低效的,所以我看不出这是如何成为良好实践的。和一起做 执行 只是一个完整的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)
    

    这就是所谓的“战略”设计模式。

        3
  •  0
  •   Serge Ballesta    6 年前

    你可以做你想做的,但是你必须使用的全局参数和局部参数 exec 要限制执行危险字符串和获取函数定义的风险:

    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的字符串是受控制的,所以这里没有安全问题,但是 执行 eval 应尽可能避免。

    除非你真的需要这样的代码,否则它会导致一个难以理解的类,而可读性应该是Python程序员的首要考虑。

    所以回答你的第二个问题,这真是一个可怕的练习。千万不要说我建议用它。