Domanda

Questa settimana comp.lang.python, un pezzo "interessante" del codice era inviato da Steven D'Aprano come una risposta ad una domanda scherzo compiti a casa. Eccolo:

class MultiplierFactory(object):
    def __init__(self, factor=1):
        self.__factor = factor
    @property
    def factor(self):
        return getattr(self, '_%s__factor' % self.__class__.__name__)
    def __call__(self, factor=None):
        if not factor is not None is True:
            factor = self.factor
        class Multiplier(object):
            def __init__(self, factor=None):
                self.__factor = factor
            @property
            def factor(self):
                return getattr(self,
                '_%s__factor' % self.__class__.__name__)
            def __call__(self, n):
                return self.factor*n
        Multiplier.__init__.im_func.func_defaults = (factor,)
        return Multiplier(factor)

twice = MultiplierFactory(2)() 

Sappiamo che twice è un equivalente per la risposta:

def twice(x):
    return 2*x

Dai nomi Multiplier e MultiplierFactory noi avere un'idea di ciò che è il codice di fare, ma non siamo sicuri dei internals esatte. Diciamo semplificarlo prima.

Logic

if not factor is not None is True:
    factor = self.factor

not factor is not None is True equivale a not factor is not None, che è anche factor is None. Risultato:

if factor is None:
    factor = self.factor

Fino ad ora, è stato facile:)

accesso Attributo

Un altro punto interessante è la funzione di accesso factor curiosi.

def factor(self):
    return getattr(self, '_%s__factor' % self.__class__.__name__)

Durante l'inizializzazione di MultiplierFactory, self.__factor è impostato. Ma in seguito, il codice accede self.factor.

Sembra quindi che:

getattr(self, '_%s__factor' % self.__class__.__name__)

sta facendo esattamente "self.__factor".

Possiamo sempre accedere agli attributi in questo modo?

def mygetattr(self, attr):
    return getattr(self, '_%s%s' % (self.__class__.__name__, attr))

dinamicamente cambiando le firme di funzione

In ogni caso, a questo punto, ecco il codice semplificato:

class MultiplierFactory(object):
    def __init__(self, factor=1):
        self.factor = factor
    def __call__(self, factor=None):
        if factor is None:
            factor = self.factor
        class Multiplier(object):
            def __init__(self, factor=None):
                self.factor = factor
            def __call__(self, n):
                return self.factor*n
        Multiplier.__init__.im_func.func_defaults = (factor,)
        return Multiplier(factor)

twice = MultiplierFactory(2)() 

Codice è quasi pulito ora. La linea unica sconcertante, forse, potrebbe essere:

Multiplier.__init__.im_func.func_defaults = (factor,)

Cosa c'è dentro? Ho guardato il DataModel doc , e ha scoperto che func_defaults era " una tupla contenente valori degli argomenti predefiniti per tali argomenti che hanno valori predefiniti, o None se nessun argomento hanno un valore predefinito ". stiamo solo cambiando il valore di default per factor argomento a __init__ qui Con conseguente codice sarebbe allora:?

class MultiplierFactory(object):
    def __init__(self, factor=1):
        self.factor = factor
    def __call__(self, factor=None):
        if factor is None:
            factor = self.factor
        class Multiplier(object):
            def __init__(self, innerfactor=factor):
                self.factor = innerfactor
            def __call__(self, n):
                return self.factor*n
        return Multiplier(factor)

twice = MultiplierFactory(2)() 

Il che significa che l'impostazione dinamica il valore predefinito era il rumore solo inutile, dal momento che non viene mai chiamato Multiplier senza un parametro di default, destro

E probabilmente potremmo semplificare a:

class MultiplierFactory(object):
    def __init__(self, factor=1):
        self.factor = factor
    def __call__(self, factor=None):
        if factor is None:
            factor = self.factor
        def my_multiplier(n):
            return factor*n
        return my_multiplier

twice = MultiplierFactory(2)() # similar to MultiplierFactory()(2)

Una corretta?

E per coloro affrettandosi a "questa non è una vera domanda" ... leggere di nuovo, le mie domande sono in grassetto + corsivo

È stato utile?

Soluzione

Q1. Possiamo sempre accedere agli attributi in questo modo?

A: No. E 'solo quegli attributi che iniziano con doppia sottolineatura. Ottengono offuscato in quel modo, per impedire l'accesso accidentale / sovrascrivendo dall'esterno della classe.

Q2:? Stiamo semplicemente cambiando il valore predefinito per argomento fattore __init__ qui

A: Sì.

Q2: destro

?

A destra.

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