Python 有类似 Java 的匿名内部类的东西吗?

发布于 2024-07-10 16:40:25 字数 383 浏览 10 评论 0原文

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

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

new OptionParser () {

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

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

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

In Java you can define a new class inline using anonymous inner classes. This is useful when you need to rewrite only a single method of the class.

Suppose that you want create a subclass of OptionParser that overrides only a single method (for example exit()). In Java you can write something like this:

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.

There is a similar idiom in Python? Which idiom is used in these circumstances?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

暮年 2024-07-17 16:40:25

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

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

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

You can use the type(name, bases, dict) builtin function to create classes on the fly. 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.

站稳脚跟 2024-07-17 16:40:25

您可以通过三种方式完成此操作:

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

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

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()
老旧海报 2024-07-17 16:40:25

Java 使用匿名类主要是为了模仿闭包或简单的代码块。 由于在 Python 中您可以轻松地传递方法,因此不需要像匿名内部类那样笨重的构造:

def printStuff():
   print "hello"

def doit(what):
   what()

doit(printStuff) 

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

Java uses anonymous classes mostly to imitate closures or simply code blocks. Since in Python you can easily pass around methods there's no need for a construct as clunky as anonymous inner classes:

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.

感情废物 2024-07-17 16:40:25

好吧,类是第一类对象,因此如果需要,您可以在方法中创建它们。 例如

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__ 中。

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

Well, classes are first class objects, so you can create them in methods if you want. 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

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__.

(edit: fixed typing errors in code)

各自安好 2024-07-17 16:40:25

Python 不直接支持这一点(匿名类),但由于其简洁的语法,这实际上并不是必需的:

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

p = MyOptionParser()

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

Python doesn't support this directly (anonymous classes) but because of its terse syntax it isn't really necessary:

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.

汹涌人海 2024-07-17 16:40:25

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

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

另外,由于 python 非常动态,因此您可以在创建对象后更改对象的方法 object.method1 = Alternative_impl1,尽管它实际上有点复杂,请参阅 gnud 的答案

Python probably has better ways to solve your problem. 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). You can also create anonymous lambda functions (but they're restricted to a single expression).

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

千鲤 2024-07-17 16:40:25

在 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

In python you have anonymous functions, declared using lambda statement. 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:

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

def meth_b(obj):
  print "b"

b = a()
b.__class__.meth_a = meth_b
猫九 2024-07-17 16:40:25

您始终可以通过变量隐藏类:

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

而不是

 var = new ...() {};

You can always hide class by variables:

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

instead of

 var = new ...() {};
天邊彩虹 2024-07-17 16:40:25

这就是你在 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()

This is what you would do in 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()
幸福丶如此 2024-07-17 16:40:25

我在 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 类的类属性,因此双下划线表示“根本不再使用它”并且可能会更改为没有下划线,如果我开始在其他地方重用它。

I do this in python3 usually with inner classes

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".

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.

原来分手还会想你 2024-07-17 16:40:25

反常的是,您可以使用一次性名称 _ 作为派生类名称:

class _(OptionParser):

    def exit(self):
        pass  # your override impl

Being perverse, you could use the throwaway name _ for the derived class name:

class _(OptionParser):

    def exit(self):
        pass  # your override impl
谈情不如逗狗 2024-07-17 16:40:25

这是执行 Maciej 的方法的更奇特的方式。
我定义了以下装饰器:

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

以下代码大致相同(也适用于参数!)

// 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

如果您想定义“内部”类实例,则可以在类/方法/函数中使用此代码。

Here is a more fancy way of doing Maciej's method.
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!)

// 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文