Dichiarazione delle variabili Python


87

Imparare Python e ha alcuni dubbi di base.

1.Ho visto la dichiarazione della variabile (percorso qui) come

class writer:
    path = ""

a volte, nessuna dichiarazione esplicita ma inizializza tramite __init__.

def __init__(self, name):
    self.name = name

Capisco lo scopo di __init__, ma è consigliabile dichiarare la variabile in qualsiasi altra funzione.

2.Come posso creare una variabile per contenere un tipo personalizzato?

class writer:
    path = "" # string value
    customObj = ??

12
E, riguardo alla seconda domanda: in Python, le variabili non hanno tipo: i valori sì. Quindi qualsiasi variabile può contenere i tuoi oggetti personalizzati.
jpaugh

4
Aiuterà se smetti di pensare a nomi / identificatori come variabili . Sono riferimenti a oggetti
John La Rooy

2
@gnibbler O nomi per loro ...
detly

1
@detly, penso che i nomi siano una cattiva scelta. Le cose di solito hanno un solo nome mentre un oggetto può avere più riferimenti
John La Rooy

2
@JohnClements, ma python non funziona come la matematica. Se vuoi capire Python devi sapere che gli oggetti con un __name__attributo hanno un "nome". Non tutti gli oggetti hanno un __name__attributo, ma puoi comunque avere riferimenti ad essi. Se iniziamo a chiamare un "riferimento" un "nome", stiamo facendo un disservizio ai principianti lungo la pista.
John La Rooy,

Risposte:


205

Va bene, per prima cosa.

Non esistono cose come "dichiarazione di variabili" o "inizializzazione di variabili" in Python.

Esiste semplicemente ciò che chiamiamo "assegnazione", ma probabilmente dovremmo chiamare semplicemente "denominazione".

Assegnazione significa "questo nome sul lato sinistro ora si riferisce al risultato della valutazione del lato destro, indipendentemente da ciò a cui si riferiva prima (semmai)".

foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication

In quanto tali, i nomi di Python (un termine migliore di "variabili", probabilmente) non hanno tipi associati; i valori fanno. Puoi riapplicare lo stesso nome a qualsiasi cosa indipendentemente dal suo tipo, ma la cosa ha ancora un comportamento che dipende dal suo tipo. Il nome è semplicemente un modo per fare riferimento al valore (oggetto). Questo risponde alla tua seconda domanda: non crei variabili per contenere un tipo personalizzato. Non crei variabili per contenere un tipo particolare. Non "crei" affatto variabili. Dai nomi agli oggetti.

Secondo punto: Python segue una regola molto semplice quando si tratta di classi, che in realtà è molto più coerente di ciò che fanno linguaggi come Java, C ++ e C #: tutto ciò che viene dichiarato all'interno del classblocco fa parte della classe . Quindi, le functions ( def) scritte qui sono metodi, cioè parte dell'oggetto classe (non memorizzato su una base per istanza), proprio come in Java, C ++ e C #; ma altri nomi qui sono anche parte della classe. Di nuovo, i nomi sono solo nomi e non hanno tipi associati e anche le funzioni sono oggetti in Python. Quindi:

class Example:
    data = 42
    def method(self): pass

Anche le classi sono oggetti , in Python.

Quindi ora abbiamo creato un oggetto denominato Example, che rappresenta la classe di tutte le cose che sono Examples. Questo oggetto ha due attributi forniti dall'utente (in C ++, "membri"; in C #, "campi o proprietà o metodi"; in Java, "campi o metodi"). Uno di questi è denominato datae memorizza il valore intero 42. L'altro è denominato methode memorizza un oggetto funzione. (Ci sono molti altri attributi che Python aggiunge automaticamente.)

Tuttavia, questi attributi non fanno ancora parte dell'oggetto. Fondamentalmente, un oggetto è solo un insieme di più nomi (i nomi degli attributi), finché non si arriva a cose che non possono più essere suddivise. Pertanto, i valori possono essere condivisi tra diverse istanze di una classe o anche tra oggetti di classi diverse, se lo si imposta deliberatamente.

Creiamo un'istanza:

x = Example()

Ora abbiamo un oggetto separato denominato x, che è un'istanza di Example. Le datae methodnon fanno effettivamente parte dell'oggetto, ma possiamo comunque cercarle tramite a xcausa di qualche magia che Python fa dietro le quinte. Quando guardiamo in alto method, in particolare, otterremo invece un "metodo vincolato" (quando lo chiamiamo, xviene passato automaticamente come selfparametro, cosa che non può accadere se cerchiamo Example.methoddirettamente).

Cosa succede quando proviamo a utilizzare x.data?

Quando lo esaminiamo, viene prima cercato nell'oggetto. Se non viene trovato nell'oggetto, Python cerca nella classe.

Tuttavia, quando assegniamo a x.data , Python creerà un attributo sull'oggetto. Essa non sostituirà l'attributo di classe.

Questo ci consente di eseguire l' inizializzazione degli oggetti . Python chiamerà automaticamente il __init__metodo della classe sulle nuove istanze quando vengono create, se presenti. In questo metodo, possiamo semplicemente assegnare agli attributi per impostare i valori iniziali per quell'attributo su ogni oggetto:

class Example:
    name = "Ignored"
    def __init__(self, name):
        self.name = name
    # rest as before

Ora dobbiamo specificare a namequando creiamo un Example, e ogni istanza ha la sua name. Python ignorerà l'attributo class Example.nameogni volta che cerchiamo l' .nameistanza di un'istanza, perché l'attributo dell'istanza verrà trovato per primo.

Un ultimo avvertimento: la modifica (mutazione) e l'assegnazione sono cose diverse!

In Python, le stringhe sono immutabili. Non possono essere modificati. Quando lo fai:

a = 'hi '
b = a
a += 'mom'

Non si modifica la stringa "hi" originale. Questo è impossibile in Python. Invece, crei una nuova stringa 'hi mom'e fai asmettere di essere un nome per 'hi 'e inizi a essere un nome per 'hi mom'invece. Abbiamo fatto bun nome anche per 'hi ', e dopo aver applicato nuovamente il anome, bè ancora un nome per 'hi ', perché 'hi 'esiste ancora e non è stato cambiato.

Ma gli elenchi possono essere modificati:

a = [1, 2, 3]
b = a
a += [4]

Ora bè anche [1, 2, 3, 4], perché abbiamo creato bun nome per la stessa cosa che ha achiamato, e poi abbiamo cambiato quella cosa. Non abbiamo creato un nuovo elenco per anominare, perché Python tratta semplicemente in modo +=diverso per gli elenchi.

Questo è importante per gli oggetti perché se avessi un elenco come attributo di classe e utilizzassi un'istanza per modificare l'elenco, la modifica sarebbe "visibile" in tutte le altre istanze. Questo perché (a) i dati fanno effettivamente parte dell'oggetto classe e non di un oggetto istanza; (b) poiché stavi modificando l'elenco e non eseguendo un semplice assegnamento, non hai creato un nuovo attributo di istanza che nasconde l'attributo di classe.


12
Questo è il motivo per cui li chiamiamo "identificatori" . :-)
Martijn Pieters

@Karl_Knechtel nel tuo esempio di stringa alla fine, cosa succede a "ciao" se non lo chiamiamo mai "b"? È una perdita di memoria?
heretoinfinity

2
@heretoinfinity: no; Python usa la garbage collection per liberare oggetti irraggiungibili
John Clements

La dichiarazione delle variabili è ben spiegata in questo video: youtube.com/watch?v=ao2N37E-D9s .
Ishaq Khan

guarda questo video per la risposta youtube.com/…
Thao N

23

Questo potrebbe essere in ritardo di 6 anni, ma in Python 3.5 e versioni successive, dichiari un tipo di variabile come questo:

variable_name: type_name

o questo:

variable_name # type: shinyType

Quindi nel tuo caso (se hai una CustomObjectclasse definita), puoi fare:

customObj: CustomObject

Vedi questo o quello per maggiori informazioni.


Questa non è una dichiarazione nel senso tradizionale, tuttavia, è un suggerimento, che i controlli di tipo statici e gli IDE potrebbero indicare, ma continuerà a funzionare e fallire.
PhilHibbs

@PhilHibbs Non fallisce, però. Cosa intendi con "fallire"?
O. Aroesti

Quello che voglio dire è che se lo fai a: inte poi lo fai a='hello, world!'non fallirà, quindi non si dichiara a essere un int e solo e sempre un int. Avrei dovuto dire "non fallirà", colpa mia. Se così fosse a: int, a='hello, world!', a=a+1allora che dovrebbe riuscire a compilation in un linguaggio statico digitato.
PhilHibbs

22

Non è necessario dichiarare nuove variabili in Python. Se parliamo di variabili in funzioni o moduli, non è necessaria alcuna dichiarazione. Basta assegnare un valore a un nome di cui avete bisogno: mymagic = "Magic". Le variabili in Python possono contenere valori di qualsiasi tipo e non puoi limitarlo.

La tua domanda chiede in particolare su classi, oggetti e variabili di istanza. Il modo più idiomatico per creare variabili di istanza è nel __init__metodo e nessun altro -, mentre si potrebbe creare nuove variabili di istanza in altri metodi, o anche nel codice non correlato, è solo una cattiva idea. Renderà il tuo codice difficile da ragionare o da mantenere.

Quindi per esempio:

class Thing(object):

    def __init__(self, magic):
        self.magic = magic

Facile. Ora le istanze di questa classe hanno un magicattributo:

thingo = Thing("More magic")
# thingo.magic is now "More magic"

La creazione di variabili nello spazio dei nomi della classe stessa porta a un comportamento completamente diverso. È funzionalmente diverso e dovresti farlo solo se hai un motivo specifico per farlo. Per esempio:

class Thing(object):

    magic = "Magic"

    def __init__(self):
        pass

Adesso prova:

thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1

O:

class Thing(object):

    magic = ["More", "magic"]

    def __init__(self):
        pass

thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]

Questo perché lo spazio dei nomi della classe stessa è diverso dallo spazio dei nomi degli oggetti creati da esso. Lascio a te la ricerca un po 'di più.

Il messaggio da portare a casa è che Python idiomatico è quello di (a) inizializzare gli attributi degli oggetti nel tuo __init__metodo e (b) documentare il comportamento della tua classe secondo necessità. Non hai bisogno di darti la pena di una documentazione completa a livello di Sphinx per tutto ciò che scrivi, ma almeno alcuni commenti su qualsiasi dettaglio tu o qualcun altro potreste aver bisogno di raccoglierlo.



1

Le variabili hanno ambito, quindi sì, è appropriato avere variabili specifiche per la tua funzione. Non devi sempre essere esplicito sulla loro definizione; di solito puoi semplicemente usarli. Solo se vuoi fare qualcosa di specifico per il tipo di variabile, come aggiungere per un elenco, devi definirli prima di iniziare a usarli. Tipico esempio di questo.

list = []
for i in stuff:
  list.append(i)

A proposito, questo non è davvero un buon modo per impostare l'elenco. Sarebbe meglio dire:

list = [i for i in stuff] # list comprehension

... ma sto divagando.

La tua altra domanda. L'oggetto personalizzato dovrebbe essere una classe stessa.

class CustomObject(): # always capitalize the class name...this is not syntax, just style.
  pass
customObj = CustomObject()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.