example - python class method



Qual è lo scopo delle classi interne di Python? (5)

Le classi interne / nidificate di Python mi confondono. C'è qualcosa che non può essere realizzato senza di loro? Se è così, qual è quella cosa?

https://src-bin.com


Answer #1

C'è qualcosa che non può essere realizzato senza di loro?

No. Sono assolutamente equivalenti a definire la classe normalmente al massimo livello, e quindi a copiare un riferimento ad essa nella classe esterna.

Non penso ci siano motivi speciali per cui le classi annidate sono "permesse", a parte il fatto che non ha alcun senso esplicitamente "non consentire" loro.

Se stai cercando una classe che esiste all'interno del ciclo di vita dell'oggetto esterno / proprietario e ha sempre un riferimento a un'istanza della classe esterna - le classi interne come fa Java - allora le classi nidificate di Python non sono quella cosa. Ma puoi incidere qualcosa come quella cosa:

import weakref, new

class innerclass(object):
    """Descriptor for making inner classes.

    Adds a property 'owner' to the inner class, pointing to the outer
    owner instance.
    """

    # Use a weakref dict to memoise previous results so that
    # instance.Inner() always returns the same inner classobj.
    #
    def __init__(self, inner):
        self.inner= inner
        self.instances= weakref.WeakKeyDictionary()

    # Not thread-safe - consider adding a lock.
    #
    def __get__(self, instance, _):
        if instance is None:
            return self.inner
        if instance not in self.instances:
            self.instances[instance]= new.classobj(
                self.inner.__name__, (self.inner,), {'owner': instance}
            )
        return self.instances[instance]


# Using an inner class
#
class Outer(object):
    @innerclass
    class Inner(object):
        def __repr__(self):
            return '<%s.%s inner object of %r>' % (
                self.owner.__class__.__name__,
                self.__class__.__name__,
                self.owner
            )

>>> o1= Outer()
>>> o2= Outer()
>>> i1= o1.Inner()
>>> i1
<Outer.Inner inner object of <__main__.Outer object at 0x7fb2cd62de90>>
>>> isinstance(i1, Outer.Inner)
True
>>> isinstance(i1, o1.Inner)
True
>>> isinstance(i1, o2.Inner)
False

(Questo usa decoratori di classi, che sono nuovi in ​​Python 2.6 e 3.0, altrimenti dovresti dire "Inner = innerclass (Inner)" dopo la definizione della classe.)


Answer #2

C'è qualcosa di cui hai bisogno per girare la testa per essere in grado di capirlo. Nella maggior parte delle lingue, le definizioni di classe sono direttive per il compilatore. Cioè, la classe viene creata prima che il programma venga mai eseguito. In python, tutte le istruzioni sono eseguibili. Ciò significa che questa affermazione:

class foo(object):
    pass

è una dichiarazione che viene eseguita in fase di esecuzione proprio come questa:

x = y + z

Ciò significa che non solo è possibile creare classi all'interno di altre classi, è possibile creare classi ovunque si desideri. Considera questo codice:

def foo():
    class bar(object):
        ...
    z = bar()

Quindi, l'idea di una "classe interiore" non è in realtà una costruzione linguistica; è un costrutto programmatore. Guido ha un ottimo riassunto di come è successo here . Ma in sostanza, l'idea di base è che semplifica la grammatica della lingua.


Answer #3

Citato da http://www.geekinterview.com/question_details/64739 :

Vantaggi della classe interiore:

  • Raggruppamento logico di classi : se una classe è utile solo per un'altra classe, è logico incorporarla in quella classe e mantenerla insieme. Annidare queste "classi di supporto" rende il loro pacchetto più snello.
  • Incremento aumentato : prendi in considerazione due classi di primo livello A e B in cui B ha bisogno di accedere ai membri di A che altrimenti sarebbero dichiarati privati. Nascondendo la classe B all'interno della classe, i membri di AA possono essere dichiarati privati ​​e B può accedervi. Inoltre, la stessa B può essere nascosta dal mondo esterno.
  • Codice più leggibile e gestibile: l'inserimento di classi di piccole dimensioni all'interno delle classi di alto livello avvicina il codice a dove viene utilizzato.

Il principale vantaggio è l'organizzazione. Tutto ciò che può essere realizzato con classi interne può essere realizzato senza di loro.


Answer #4

Classi di nidificazione all'interno delle classi:

  • Le classi nidificate gonfiano la definizione della classe rendendo più difficile vedere che cosa sta succedendo.

  • Le classi nidificate possono creare un accoppiamento che renderebbe il test più difficile.

  • In Python puoi mettere più di una classe in un file / modulo, a differenza di Java, quindi la classe rimane ancora vicina alla classe di primo livello e potrebbe anche avere il nome della classe preceduta da un "_" per indicare che gli altri non dovrebbero essere usandolo.

Il posto in cui le classi annidate possono rivelarsi utili è all'interno delle funzioni

def some_func(a, b, c):
   class SomeClass(a):
      def some_method(self):
         return b
   SomeClass.__doc__ = c
   return SomeClass

La classe acquisisce i valori dalla funzione che consente di creare dinamicamente una classe come metaprogrammazione del modello in C ++


Answer #5

Il principale caso d'uso che uso per questo è la proliferazione di piccoli moduli e la prevenzione dell'inquinamento dello spazio dei nomi quando non sono necessari moduli separati. Se sto estendendo una classe esistente, ma quella classe esistente deve fare riferimento a un'altra sottoclasse che deve essere sempre accoppiato ad essa. Ad esempio, potrei avere un modulo utils.py che contiene molte classi helper, che non sono necessariamente accoppiate insieme, ma voglio rinforzare l'accoppiamento per alcune di queste classi helper. Ad esempio, quando implemento https://.com/a/8274307/2718295

: utils.py :

import json, decimal

class Helper1(object):
    pass

class Helper2(object):
    pass

# Here is the notorious JSONEncoder extension to serialize Decimals to JSON floats
class DecimalJSONEncoder(json.JSONEncoder):

    class _repr_decimal(float): # Because float.__repr__ cannot be monkey patched
        def __init__(self, obj):
            self._obj = obj
        def __repr__(self):
            return '{:f}'.format(self._obj)

    def default(self, obj): # override JSONEncoder.default
        if isinstance(obj, decimal.Decimal):
            return self._repr_decimal(obj)
        # else
        super(self.__class__, self).default(obj)
        # could also have inherited from object and used return json.JSONEncoder.default(self, obj) 

Allora possiamo:

>>> from utils import DecimalJSONEncoder
>>> import json, decimal
>>> json.dumps({'key1': decimal.Decimal('1.12345678901234'), 
... 'key2':'strKey2Value'}, cls=DecimalJSONEncoder)
{"key2": "key2_value", "key_1": 1.12345678901234}

Ovviamente, potremmo json.JSONEnocder ereditare del tutto json.JSONEnocder e sovrascrivere il default ():

:

import decimal, json

class Helper1(object):
    pass

def json_encoder_decimal(obj):
    class _repr_decimal(float):
        ...

    if isinstance(obj, decimal.Decimal):
        return _repr_decimal(obj)

    return json.JSONEncoder(obj)


>>> json.dumps({'key1': decimal.Decimal('1.12345678901234')}, default=json_decimal_encoder)
'{"key1": 1.12345678901234}'

Ma a volte solo per convenzione, vuoi che i programmi di utils siano composti da classi per l'estensibilità.

Ecco un altro caso d'uso: voglio una factory per i mutables nel mio OuterClass senza dover richiamare la copy :

class OuterClass(object):

    class DTemplate(dict):
        def __init__(self):
            self.update({'key1': [1,2,3],
                'key2': {'subkey': [4,5,6]})


    def __init__(self):
        self.outerclass_dict = {
            'outerkey1': self.DTemplate(),
            'outerkey2': self.DTemplate()}



obj = OuterClass()
obj.outerclass_dict['outerkey1']['key2']['subkey'].append(4)
assert obj.outerclass_dict['outerkey2']['key2']['subkey'] == [4,5,6]

Preferisco questo schema rispetto al decoratore @staticmethod che altrimenti utilizzeresti per una funzione di fabbrica.





language-features