Подтвердить что ты не робот

Есть ли у Python что-то вроде анонимных внутренних классов Java?

В Java вы можете определить новый класс inline, используя анонимные внутренние классы. Это полезно, когда вам нужно переписать только один метод класса.

Предположим, что вы хотите создать подкласс OptionParser, который переопределяет только один метод (например, exit()). В Java вы можете написать что-то вроде этого:

new OptionParser () {

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

Этот фрагмент кода создает анонимный класс, который расширяет OptionParser и переопределяет только метод exit().

В Python есть аналогичная идиома? Какая идиома используется в этих обстоятельствах?

4b9b3361

Ответ 1

Вы можете использовать type(name, bases, dict) встроенную функцию для создания классов "на лету". Например:

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

Так как OptionParser не является классом нового стиля, вы должны явно включать object в список базовых классов.

Ответ 2

Java использует анонимные классы в основном для имитации закрытий или просто блоков кода. Поскольку в Python вы можете легко обойти методы, нет необходимости в конструкции, такой же неуклюжей, как анонимные внутренние классы:

def printStuff():
   print "hello"

def doit(what):
   what()

doit(printStuff) 

Изменить: я знаю, что это не то, что необходимо в этом специальном случае. Я просто описал наиболее распространенное решение python для проблемы, чаще всего анонимные внутренние классы в Java.

Ответ 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()

Ответ 4

Ну, классы - это объекты первого класса, поэтому вы можете создавать их в методах, если хотите. например.

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

(править: исправлены ошибки ввода текста в коде)

Ответ 5

Python не поддерживает это напрямую (анонимные классы), но из-за его краткого синтаксиса это не нужно:

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

p = MyOptionParser()

Единственный недостаток заключается в том, что вы добавляете MyOptionParser в свое пространство имен, но, как указал Джон Фухи, вы можете скрыть это внутри функции, если вы собираетесь делать это несколько раз.

Ответ 6

У Python, вероятно, есть лучшие способы решения вашей проблемы. Если бы вы могли предоставить более конкретные детали того, что вы хотите сделать, это поможет.

Например, если вам нужно изменить метод, вызываемый в определенной точке кода, вы можете сделать это, передав функцию в качестве параметра (функции являются объектами первого класса в python, вы можете передать их функциям и т.д.). Вы также можете создавать анонимные функции lambda (но они ограничены одним выражением).

Кроме того, поскольку python очень динамичен, вы можете изменить методы объекта после его создания object.method1 = alternative_impl1, хотя это на самом деле немного сложнее, см. gnud answer

Ответ 7

В 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

Ответ 8

Вы всегда можете скрыть класс по переменным:

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

вместо

 var = new ...() {};

Ответ 9

Это то, что вы будете делать в 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()

Ответ 10

Я делаю это в 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, поэтому двойное подчеркивание будет означать "не использовать его вообще" и может измениться на никаких подчеркиваний, если я начну использовать его в другом месте.

Ответ 11

#!/usr/bin/env python
import os;os.system("""ruby << 'GOZER'
anonymous_class = Class.new do
  def hi(name)
    puts "Hello: #{name}."
  end

  def too_late(message)
    exit 1
  end
end

anonymous_ghoul = anonymous_class.new
anonymous_ghoul.hi("Egon Spengler")
anonymous_ghoul.too_late <<-quote

There something very import I forgot to tell you.

Don't cross the streams.

It would be bad.

quote
GOZER""")