In python, abbiamo l'incapsulamento di classe al livello dell'oggetto?

0

Sono stato morso usando l'operatore is quando avrei dovuto usare == . Sono consapevole del fatto che il primo test per l'uguaglianza delle identità degli oggetti e che il secondo test per l'uguaglianza dei contenuti degli oggetti.

L'uso di is , pensavo, verifica implicitamente anche l'uguaglianza dei contenuti. Ad esempio if a is b è true, quindi i contenuti devono essere uguali. Questa era l'ipotesi di lavoro e credo che sia ancora vero. Ma ciò che è stato scoperto, e avrebbe dovuto essere noto, è che se if a is b è falso, allora il contenuto di aeb può essere o meno lo stesso.

Esempio (Python 3.3.3):

class Food:
    def favourite_restaurant(self):
        return "the foo diner"


if __name__ == '__main__':

    fr = "the juice bar"
    print('%r  is  %r: %r' % (fr, 'the juice bar', (fr is 'the juice bar')))
    print('%r  ==  %r: %r' % (fr, 'the juice bar', (fr == 'the juice bar')))

    f = Food()
    result = f.favourite_restaurant()
    print('%r  is  %r: %r' % (result, 'the foo diner', (result is 'the foo diner')))
    print('%r  ==  %r: %r' % (result, 'the foo diner', (result == 'the foo diner')))

Il primo blocco di stampa dice:

'the juice bar'  is  'the juice bar': True
'the juice bar'  ==  'the juice bar': True

Il secondo blocco di stampa dice:

result: 'the foo diner'
'the foo diner'  is  'the foo diner': False
'the foo diner'  ==  'the foo diner': True

Sembra che gli oggetti istanziati all'interno dell'istanza di una classe abbiano il proprio gruppo di id, separato dagli oggetti al di fuori della classe.

La mia comprensione del fatto che l'incapsulamento in python è davvero una questione di "adulti consenzienti". In realtà abbiamo incapsulamento ad un livello inferiore?

    
posta Simon Minshall 11.02.2014 - 18:49
fonte

1 risposta

3

Questo non ha nulla a che fare con l'incapsulamento, e tutto con un dettaglio di implementazione Python come quando le stringhe letterali producono un oggetto stringa.

Ciò che sta accadendo in questo caso è che Python utilizza costanti per memorizzare valori letterali usati nel codice. Il tuo valore 'the juice bar' è una costante di questo tipo.

Il compilatore ha memorizzato 'the juice bar' con l'oggetto del blocco di codice per il modulo e sta riutilizzando quell'oggetto. Non stai creando nuovi valori di stringa nel blocco __name__ == '__main__' .

Le funzioni ottengono i propri blocchi di codice, che includono le proprie costanti e quindi i propri oggetti stringa.

Manifestazione:

>>> import dis
>>> code = compile('''\
... fr = "the juice bar"
... print('%r  is  %r: %r' % (fr, 'the juice bar', (fr is 'the juice bar')))
... print('%r  ==  %r: %r' % (fr, 'the juice bar', (fr == 'the juice bar')))
... ''', '<stdin>', 'exec')
>>> code.co_consts
('the juice bar', '%r  is  %r: %r', '%r  ==  %r: %r', None)
>>> dis.dis(code)
  1           0 LOAD_CONST               0 ('the juice bar') 
              3 STORE_NAME               0 (fr) 

  2           6 LOAD_NAME                1 (print) 
              9 LOAD_CONST               1 ('%r  is  %r: %r') 
             12 LOAD_NAME                0 (fr) 
             15 LOAD_CONST               0 ('the juice bar') 
             18 LOAD_NAME                0 (fr) 
             21 LOAD_CONST               0 ('the juice bar') 
             24 COMPARE_OP               8 (is) 
             27 BUILD_TUPLE              3 
             30 BINARY_MODULO        
             31 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
             34 POP_TOP              

  3          35 LOAD_NAME                1 (print) 
             38 LOAD_CONST               2 ('%r  ==  %r: %r') 
             41 LOAD_NAME                0 (fr) 
             44 LOAD_CONST               0 ('the juice bar') 
             47 LOAD_NAME                0 (fr) 
             50 LOAD_CONST               0 ('the juice bar') 
             53 COMPARE_OP               2 (==) 
             56 BUILD_TUPLE              3 
             59 BINARY_MODULO        
             60 CALL_FUNCTION            1 (1 positional, 0 keyword pair) 
             63 POP_TOP              
             64 LOAD_CONST               3 (None) 
             67 RETURN_VALUE         

Questo è uno smontaggio del bytecode solo per il test fr ; nota i riferimenti LOAD_CONST ; questi caricano una costante (memorizzata in posizione 0 in entrambi gli insiemi fr e per confrontarli in seguito se fr is 'the juice bar' ) è lo stesso oggetto.

L'oggetto funzione ha un costrutto co_const simile, che è ciò che Python restituisce doverosamente quando viene chiamato:

>>> class Food:
...     def favourite_restaurant(self):
...         return "the foo diner"
... 
>>> Food.favourite_restaurant.__code__.co_consts
(None, 'the foo diner')
>>> dis.dis(Food.favourite_restaurant)
  3           0 LOAD_CONST               1 ('the foo diner') 
              3 RETURN_VALUE         

Di conseguenza, la stringa 'the foo diner' nel metodo non è lo stesso oggetto della stringa 'the foo diner' utilizzata nel blocco __name__ == '__main__' più in basso.

Armati di questa conoscenza puoi generare interamente nuovi oggetti stringa:

>>> a = 'foo'
>>> b = 'bar'
>>> ab = a + ' ' + b
>>> ab is a + ' ' + b
False
>>> ab == a + ' ' + b
True

In generale, hai ragione. is verifica sempre l'identità, == per l'uguaglianza. Se il test di identità passa, allora è solitamente true che anche gli oggetti sono uguali.

C'è una grande eccezione nella libreria standard:

>>> nan = float('nan')
>>> nan is nan
True
>>> nan == nan
False

La costante a virgola mobile Not-a-number non è mai uguale a nulla. Neanche con se stesso.

Va notato che Python traduce op1 == op2 in una chiamata al object.__eq__() speciale metodo hook , che è libero di restituire ciò che gli piace. Di solito è un booleano, ma non è obbligatorio:

By convention, False and True are returned for a successful comparison. However, these methods can return any value, so if the comparison operator is used in a Boolean context (e.g., in the condition of an if statement), Python will call bool() on the value to determine if the result is true or false.

    
risposta data 11.02.2014 - 19:06
fonte

Leggi altre domande sui tag