Domanda

In Java è possibile definire una nuova linea di classe utilizzando le classi interne anonime. Questo è utile quando è necessario riscrivere un solo metodo della classe.

Si supponga di voler creare una sottoclasse di OptionParser che sostituisce solo un unico metodo (ad esempio exit()). In Java è possibile scrivere qualcosa di simile a questo:

new OptionParser () {

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

Questo pezzo di codice crea una classe anonima che si estende <=> e sovrascrivere solo il metodo <=>.

C'è un idioma simile in Python? Quale linguaggio è usato in queste circostanze?

È stato utile?

Soluzione

È possibile utilizzare il type(name, bases, dict) funzione built-in per creare classi sulla volare. Ad esempio:

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

Dato OptionParser non è una classe di nuovo stile, è necessario includere esplicitamente object nella lista delle classi di base.

Altri suggerimenti

Java utilizza le classi anonime per lo più di imitare le chiusure o semplicemente blocchi di codice. Dal momento che in Python si può facilmente passare intorno metodi non c'è bisogno di un costrutto come goffo come classi interne anonime:

def printStuff():
   print "hello"

def doit(what):
   what()

doit(printStuff) 

Edit: Sono consapevole del fatto che questo non è ciò che è necessario in questo caso particolare. Ho appena descritto la soluzione pitone più comune al problema più comunemente per classi interne anonime in Java.

Bene, le classi sono oggetti di prima classe, in modo da poterli creare nei metodi, se si desidera. per es.

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

Ma, in realtà, perché non basta definire la classe a livello normale? Se avete bisogno di personalizzarlo, mettere la personalizzazione come argomenti a __init__.

(edit: fissa gli errori di battitura nel codice)

È possibile raggiungere questo obiettivo in tre modi:

  1. La corretta sottoclasse (ovviamente)
  2. un metodo personalizzato che si richiama con l'oggetto come argomento
  3. (quello che probabilmente si desidera) - l'aggiunta di un nuovo metodo ad un oggetto (o la sostituzione di uno già esistente)
  4. .

Esempio di opzione 3 (a cura di eliminare l'uso del modulo "nuovo" - è deprecato, non lo sapevo):

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

Python non supporta questo (classi anonime) direttamente, ma a causa della sua sintassi concisa, non è davvero necessario:

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

p = MyOptionParser()

L'unico inconveniente è che si aggiunge MyOptionParser per lo spazio dei nomi, ma come John Fouhy sottolineato, è possibile nascondere che all'interno di una funzione, se avete intenzione di farlo più volte.

Python ha probabilmente modi migliori per risolvere il problema. Se si potesse fornire dettagli più specifici di ciò che si vuole fare sarebbe d'aiuto.

Ad esempio, se è necessario modificare il metodo di essere chiamato in un punto specifico nel codice, è possibile farlo passando alla funzione come parametro (le funzioni sono oggetti di prima classe in Python, è possibile passare alle funzioni, ecc ). È inoltre possibile creare funzioni anonime lambda (ma sono limitato a una singola espressione).

Inoltre, dal momento che pitone è molto dinamica, è possibile modificare i metodi di un oggetto dopo che è stato creato object.method1 = alternative_impl1, anche se in realtà è un po 'più complicato, vedi La risposta di gnud

In Python si dispone di funzioni anonime, dichiarato istruzione using lambda. Non mi piacciono molto -. Non sono così leggibili, e hanno funzionalità limitate

Tuttavia, ciò che si sta parlando può essere implementato in Python con un approccio completamente diverso:

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

def meth_b(obj):
  print "b"

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

Si può sempre nascondere classe da variabili:

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

anziché

 var = new ...() {};

Questo è quello che si potrebbe fare 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()

Lo faccio in python3 di solito con le classi interne

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

come ho usato doppia sottolineatura, questa mescola l'idea di "scempio" con classi interne, al di fuori si può ancora accedere alla classe interna con SomeSerializer._SomeSerializer__Paginator, e anche sottoclassi, ma SomeSerializer .__ Paginator non funziona, che potrebbe o potrebbe non essere il vostro whish se si vuole un po 'più "anonimo".

Comunque suggerisco di usare la notazione "privato" con un singolo trattino basso, se non è necessario il mutilazione.

Nel mio caso, ho solo bisogno di una sottoclasse veloce per impostare alcuni attributi di classe, seguiti da assegnandola al attributo di classe di mia classe RestSerializer, quindi la doppia sottolineatura dovrebbe indicare a "non utilizzare affatto ulteriormente" e potrebbe cambiare per nessun sottolineatura, se comincio riutilizzo altrove.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top