简体   繁体   English

Python 是否有类似 Java 的匿名内部类?

[英]Does Python have something like anonymous inner classes of Java?

In Java you can define a new class inline using anonymous inner classes.在 Java 中,您可以使用匿名内部类内联定义一个新的 class 。 This is useful when you need to rewrite only a single method of the class.当您只需要重写 class 的单个方法时,这很有用。

Suppose that you want create a subclass of OptionParser that overrides only a single method (for example exit() ).假设您想要创建一个OptionParser的子类,它只覆盖一个方法(例如exit() )。 In Java you can write something like this:在 Java 你可以这样写:

new OptionParser () {

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

This piece of code creates a anonymous class that extends OptionParser and override only the exit() method.这段代码创建了一个匿名的 class,它扩展OptionParser并且只覆盖了exit()方法。

There is a similar idiom in Python? Python中有类似的成语吗? Which idiom is used in these circumstances?在这些情况下使用哪个成语?

You can use the type(name, bases, dict) builtin function to create classes on the fly.您可以使用type(name, bases, dict)内置函数动态创建类。 For example:例如:

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

Since OptionParser isn't a new-style class, you have to explicitly include object in the list of base classes.由于 OptionParser 不是新式类,因此您必须在基类列表中显式包含object

Java uses anonymous classes mostly to imitate closures or simply code blocks. Java 主要使用匿名类来模仿闭包或简单的代码块。 Since in Python you can easily pass around methods there's no need for a construct as clunky as anonymous inner classes:由于在 Python 中您可以轻松地传递方法,因此不需要像匿名内部类那样笨重的构造:

def printStuff():
   print "hello"

def doit(what):
   what()

doit(printStuff) 

Edit: I'm aware that this is not what is needed in this special case.编辑:我知道这不是这种特殊情况所需要的。 I just described the most common python solution to the problem most commonly by anonymous inner classes in Java.我刚刚描述了 Java 中匿名内部类最常见的问题的最常见的 Python 解决方案。

You can accomplish this in three ways:您可以通过三种方式完成此操作:

  1. Proper subclass (of course)适当的子类(当然)
  2. a custom method that you invoke with the object as an argument您使用对象作为参数调用的自定义方法
  3. (what you probably want) -- adding a new method to an object (or replacing an existing one). (您可能想要的)——向对象添加新方法(或替换现有方法)。

Example of option 3 (edited to remove use of "new" module -- It's deprecated, I did not know ):选项 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()

Well, classes are first class objects, so you can create them in methods if you want.好吧,类是第一类对象,因此您可以根据需要在方法中创建它们。 eg例如

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

But, really, why not just define the class at the normal level?但是,真的,为什么不只是在正常级别定义类呢? If you need to customise it, put the customisation in as arguments to __init__ .如果您需要自定义它,请将自定义作为__init__参数。

(edit: fixed typing errors in code) (编辑:修复了代码中的打字错误)

Python doesn't support this directly (anonymous classes) but because of its terse syntax it isn't really necessary: Python 不直接支持这个(匿名类),但由于其简洁的语法,它并不是真正必要的:

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

p = MyOptionParser()

The only downside is you add MyOptionParser to your namespace, but as John Fouhy pointed out, you can hide that inside a function if you are going to do it multiple times.唯一的缺点是您将 MyOptionParser 添加到您的命名空间,但正如 John Fouhy 指出的那样,如果您要多次执行此操作,则可以将其隐藏在函数中。

Python probably has better ways to solve your problem. Python 可能有更好的方法来解决您的问题。 If you could provide more specific details of what you want to do it would help.如果您可以提供有关您想要做什么的更具体的细节,那将会有所帮助。

For example, if you need to change the method being called in a specific point in code, you can do this by passing the function as a parameter (functions are first class objects in python, you can pass them to functions, etc).例如,如果您需要更改在代码中特定点调用的方法,则可以通过将函数作为参数传递来实现(函数是 Python 中的第一类对象,您可以将它们传递给函数等)。 You can also create anonymous lambda functions (but they're restricted to a single expression).您还可以创建匿名lambda函数(但它们仅限于单个表达式)。

Also, since python is very dynamic, you can change methods of an object after it's been created object.method1 = alternative_impl1 , although it's actually a bit more complicated, see gnud's answer另外,由于python非常动态,您可以在创建对象后更改对象的方法object.method1 = alternative_impl1 ,虽然它实际上有点复杂,请参阅gnud的答案

In python you have anonymous functions, declared using lambda statement.在 python 中,你有匿名函数,使用 lambda 语句声明。 I do not like them very much - they are not so readable, and have limited functionality.我不太喜欢它们——它们不那么易读,而且功能有限。

However, what you are talking about may be implemented in python with a completely different approach:但是,您所谈论的可能是在 python 中以完全不同的方法实现的:

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

def meth_b(obj):
  print "b"

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

This is what you would do in Python 3.7这就是你在 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()

I do this in python3 usually with inner classes我通常使用内部类在 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()

as i used double underscore, this mixes the idea of "mangling" with inner classes, from outside you can still access the inner class with SomeSerializer._SomeSerializer__Paginator , and also subclasses, but SomeSerializer.__Paginator will not work, which might or might not be your whish if you want it a bit more "anonymous".当我使用双下划线时,这将“重整”的想法与内部类混合在一起,从外部您仍然可以使用SomeSerializer._SomeSerializer__Paginator以及子类访问内部类,但 SomeSerializer.__Paginator 将不起作用,这可能会也可能不会如果您希望它更“匿名”,那么您的愿望。

However I suggest to use "private" notation with a single underscore, if you do not need the mangling.但是,如果您不需要重整,我建议使用带有单个下划线的“私有”表示法。

In my case, all I need is a fast subclass to set some class attributes, followed up by assigning it to the class attribute of my RestSerializer class, so the double underscore would denote to "not use it at all further" and might change to no underscores, if I start reusing it elsewhere.就我而言,我只需要一个快速子类来设置一些类属性,然后将其分配给我的 RestSerializer 类的类属性,因此双下划线将表示“不再使用它”并且可能会更改为没有下划线,如果我开始在其他地方重用它。

You can always hide class by variables:您始终可以通过变量隐藏类:

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

instead of代替

 var = new ...() {};

Being perverse, you could use the throwaway name _ for the derived class name:不正常,您可以使用一次性名称_作为派生类名称:

class _(OptionParser):

    def exit(self):
        pass  # your override impl

Here is a more fancy way of doing Maciej's method .这是执行 Maciej 方法的更奇特的方法 I defined the following decorator:我定义了以下装饰器:

def newinstance(*args, **kwargs):
    def decorator(cls):
        return cls(*args, **kwargs)
    return decorator

The following codes are roughly equivalent (also works with args!)以下代码大致相同(也适用于 args!)

// java

MyClass obj = new MyClass(arg) {
    public void method() {
        // body of the method
    }
};
# python

@newinstance(arg)
class obj(MyClass):
    def method(self):
        pass # body of the method

You can use this code from within a class/method/function if you want to define an "inner" class instance.如果要定义“内部”class 实例,则可以在类/方法/函数中使用此代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM