Python有没有类似Java的匿名内部类?

时间:2008-12-10 23:26:57

标签: python class anonymous-class

在Java中,您可以使用匿名内部类定义新的内联类。当您只需要重写该类的单个方法时,这非常有用。

假设您要创建OptionParser的子类,该子类仅覆盖单个方法(例如exit())。在Java中,您可以编写如下内容:

new OptionParser () {

    public void exit() {
        // body of the method
    }
};

这段代码创建了一个扩展OptionParser并仅覆盖exit()方法的匿名类。

Python中有类似的习惯用法吗?在这些情况下使用哪种成语?

11 个答案:

答案 0 :(得分:38)

您可以使用type(name, bases, dict)内置函数动态创建类。例如:

op = type("MyOptionParser", (OptionParser,object), {"foo": lambda self: "foo" })
op().foo()

由于OptionParser不是新式类,因此必须在基类列表中明确包含object

答案 1 :(得分:18)

Java主要使用匿名类来模仿闭包或简单地编写代码块。因为在Python中你可以很容易地传递方法,所以不需要像匿名内部类那样笨重的构造:

def printStuff():
   print "hello"

def doit(what):
   what()

doit(printStuff) 

编辑:我知道这不是这种特殊情况所需要的。我刚刚描述了Java中匿名内部类最常见的python解决方案。

答案 2 :(得分:11)

您可以通过三种方式完成此任务:

  1. 适当的子类(当然)
  2. 以对象作为参数调用的自定义方法
  3. (您可能想要的) - 向对象添加新方法(或替换现有方法)。
  4. 选项3的示例(已编辑以删除“新”模块的使用 - 它已被弃用,我不知道):

    import types
    class someclass(object):
        val = "Value"
        def some_method(self):
            print self.val
    
    def some_method_upper(self):
        print self.val.upper()
    
    obj = someclass()
    obj.some_method()
    
    obj.some_method = types.MethodType(some_method_upper, obj)
    obj.some_method()
    

答案 3 :(得分:11)

嗯,类是第一类对象,因此如果需要,可以在方法中创建它们。 e.g。

from optparse import OptionParser
def make_custom_op(i):
  class MyOP(OptionParser):
    def exit(self):
      print 'custom exit called', i
  return MyOP

custom_op_class = make_custom_op(3)
custom_op = custom_op_class()

custom_op.exit()          # prints 'custom exit called 3'
dir(custom_op)            # shows all the regular attributes of an OptionParser

但是,真的,为什么不在正常水平定义班级呢?如果您需要自定义它,请将自定义作为参数放入__init__

(编辑:修复代码中的输入错误)

答案 4 :(得分:6)

Python不直接支持这种(匿名类),但由于其简洁的语法,它并非真正必要:

class MyOptionParser(OptionParser):
    def exit(self, status=0, msg=None):
        # body of method

p = MyOptionParser()

唯一的缺点是你将MyOptionParser添加到你的命名空间,但正如John Fouhy指出的那样,如果要多次执行它,你可以在函数内隐藏它。

答案 5 :(得分:5)

Python可能有更好的方法来解决您的问题。如果你能提供你想要做的更具体的细节,那将会有所帮助。

例如,如果需要更改代码中特定点调用的方法,可以通过将函数作为参数传递来实现(函数是python中的第一类对象,可以将它们传递给函数等) )。您还可以创建匿名lambda函数(但它们仅限于单个表达式)。

此外,由于python非常动态,你可以在创建对象的方法object.method1 = alternative_impl1后更改它,虽然它实际上有点复杂,请参阅gnud's answer

答案 6 :(得分:2)

在python中,你有使用lambda语句声明的匿名函数。我不太喜欢它们 - 它们不那么可读,而且功能有限。

但是,您所谈论的内容可能会在python中以完全不同的方式实现:

class a(object):
  def meth_a(self):
    print "a"

def meth_b(obj):
  print "b"

b = a()
b.__class__.meth_a = meth_b

答案 7 :(得分:0)

您始终可以按变量隐藏类:

 class var(...):
     pass
 var = var()

而不是

 var = new ...() {};

答案 8 :(得分:0)

这就是您在Python 3.7中要做的

#!/usr/bin/env python3
class ExmapleClass:
    def exit(self):
        print('this should NOT print since we are going to override')

ExmapleClass= type('', (ExmapleClass,), {'exit': lambda self: print('you should see this printed only')})()
ExmapleClass.exit()

答案 9 :(得分:0)

我通常在python3中使用内部类完成此操作

for(var i in records){
  var data = records[i];
  console.log(data.getString("Name"));
}

当我使用双下划线时,这将“ mangling”与内部类混合在一起,从外部您仍然可以使用class SomeSerializer(): class __Paginator(Paginator): page_size = 10 # defining it for e.g. Rest: pagination_class = __Paginator # you could also be accessing it to e.g. create an instance via method: def get_paginator(self): return self.__Paginator() 以及子类来访问内部类,但是SomeSerializer .__ Paginator不起作用,这如果您希望它更“匿名”,则可能是您的愿望,也可能不是。

但是,如果您不需要整形,我建议对单个下划线使用“私有”表示法。

在我的情况下,我只需要一个快速子类来设置一些类属性,然后将其分配给我的RestSerializer类的类属性,因此双下划线将表示“根本不再使用它”和如果我开始在其他地方重新使用它,则可能没有下划线。

答案 10 :(得分:0)

不合常理,你可以使用一次性名称 _ 作为派生类名称:

class _(OptionParser):

    def exit(self):
        pass  # your override impl