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

问题描述 投票:39回答:10

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

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

new OptionParser () {

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

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

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

python class anonymous-class
10个回答
38
投票

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

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

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


0
投票

我通常在内部类中使用python3

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._SomeSerializer__Paginator和子类访问内部类,但SomeSerializer .__ Paginator将无法工作,这可能会或可能不会是你的如果你想要它更“匿名”。

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

在我的例子中,我需要的是一个快速子类来设置一些类属性,然后将它分配给我的RestSerializer类的class属性,因此双下划线将表示“不再使用它”并且可能会更改为没有下划线,如果我开始在别处重复使用它。


18
投票

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

def printStuff():
   print "hello"

def doit(what):
   what()

doit(printStuff) 

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


11
投票

那么,类是第一类对象,因此您可以根据需要在方法中创建它们。例如

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__

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


11
投票

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

  1. 适当的子类(当然)
  2. 您以对象作为参数调用的自定义方法
  3. (您可能想要的) - 向对象添加新方法(或替换现有方法)。

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

6
投票

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

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

p = MyOptionParser()

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


5
投票

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

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

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


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

0
投票

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

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

代替

 var = new ...() {};

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()
© www.soinside.com 2019 - 2024. All rights reserved.