【问题标题】:How to alias all methods from an object?如何为对象中的所有方法起别名?
【发布时间】:2019-08-19 08:04:54
【问题描述】:

我正在创建一个脚本,它实际上是供其他用户编写代码的环境。

我在一个类中声明了几个方法并实例化了一个对象,因此用户可以将这些方法用作简单的解释器函数,如下所示:

from code import interact

class framework:
    def method1(self, arg1):
    # code for method1
    def method2(self, arg2):
    # code for method2

def main():
    fw = framework()

    # Aliases
    method1 = fw.method1
    method2 = fw.method2

    interact(local=locals())

由于我不希望用户使用fw.method1(arg) 调用方法,因此我设置了别名。问题是,由于框架类正在开发中,我必须不断更新主脚本,为我创建的方法使用新别名。

有没有一种简单的方法可以摆脱调用中的“fw.”部分,并让类框架下的所有方法在 main 下自动可见?

【问题讨论】:

    标签: python python-3.x object interpreter interactive


    【解决方案1】:

    你控制传递给interact的字典,所以把你想要的放进去,不用担心main中的局部变量:

    d={}
    for n in vars(framework):
      if n.startswith('_'): continue  # probably
      x=getattr(fw,n)
      if callable(x): d[n]=x
    interact(local=d)
    

    这适用于常规、静态和类方法。它看不到实例属性(除非它们隐藏类属性)或继承的方法。

    仅当实例将函数存储为属性时,前者才重要(在这种情况下,您可能希望也可能不希望它们可用)。后者很方便,因为它省略了object;如果还有其他基类,则可以通过搜索 framework.__mro__ 轻松包含它们(并且仍然省略 object)。

    【讨论】:

      【解决方案2】:

      我不知道你打算如何处理这些函数,但如果它们不是 static,那么它可能无法在课堂外工作:

      fs = [func for func in dir(c) if callable(getattr(c, func)) and not func.startswith("__")]
      for func in fs:
          globals()[func] = getattr(c, func)
      

      这会将c 类中的所有自定义函数置于全局范围内。

      【讨论】:

      • 哇!你可以写信给 globals() 吗?还有,本地人()?我一直认为它们是只读的,并且您需要一个明确的命名空间来“固定”生成的变量名称。
      • 可以,它们只是字典。对字典的更改会保留,因为它们是通过引用传递的。
      • 不错。顺便说一句,我认为他对静态没问题 - fwframework 的一个实例
      • @JLPeyret:不过,你不是supposed to write to locals()——它(有时)只是实际局部变量的表示。
      【解决方案3】:

      你基本上想做两件事:

      1. 获取类实例的方法列表
      2. 动态地将函数添加到本地范围

      前者可以使用标准库中的inspect 模块来实现,后者可以使用vars

      尝试以下方法:

      import inspect
      
      from code import interact
      
      class framework:
          def method1(self, arg1):
          # code for method1
          def method2(self, arg2):
          # code for method2
      
      def main():
          fw = framework()
      
          # get the methods of fw and update vars().
          # getmembers returns a list of two-tuples with (<Name>, <function>)
          methods = inspect.getmembers(fw, predicate=inspect.ismethod)
          vars().update({method[0]: method[1] for method in methods})
      
          interact(local=locals())
      

      【讨论】:

      • 修改locals()(又名vars()不带参数)是不安全的。幸运的是,没有理由使用 that 字典。
      • 您能否再解释一下为什么它不安全以及应该使用什么替代方案?我知道修改它可能会影响具有相同名称的函数。还有其他缺点吗?
      • 文档says not to。在某些情况下你可以使用exec 来达到效果,但在这里肯定不值得那么痛苦。
      【解决方案4】:

      这与@Davis Herring 的回答类似,经过充实和重新包装:

      #from code import interact
      
      def interact(local):
          local['method1'](42)
          local['method2']('foobar')
      
      
      class Framework:
          def method1(self, arg1):
              print('Framework.method1({!r}) called'.format(arg1))
          def method2(self, arg2):
              print('Framework.method2({!r}) called'.format(arg2))
      
      
      def get_callables(obj):
          return {name: getattr(obj, name) for name in vars(obj.__class__)
                      if callable(getattr(obj, name))}
      
      def main():
          fw = Framework()
      
      #    # Aliases
      #    method1 = fw.method1
      #    method2 = fw.method2
      
          interact(local=get_callables(fw))
      
      
      if __name__ == '__main__':
          main()
      

      输出:

      Framework.method1(42) called
      Framework.method2('foobar') called
      

      【讨论】:

      • 次要观点:在 Python 3 中,我们永远不需要使用 x.__class__ 而不是 type(x)
      猜你喜欢
      • 1970-01-01
      • 2011-07-27
      • 2017-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-06
      相关资源
      最近更新 更多