Declarație variabilă Python (Programare, Python, Python 3.X, Python 2.7, Declarație Variabilă)

bsr a intrebat.

Învățarea Python, , și are câteva îndoieli de bază.

1.Am văzut declarația variabilelor (calea aici) ca

class writer:
    path = ""

uneori, fără declarație explicită, dar inițializând prin __init__.

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

Înțeleg că scopul lui __init__, , dar este recomandabil să se declare variabila în orice alte funcții.

2.Cum pot crea o variabilă care să dețină un tip personalizat?

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

Comentarii

  • Și, referitor la a 2-a întrebare: în Python, variabilele nu au tip: valorile au. Așadar, orice variabilă poate conține obiectele dvs. personalizate. –  > Por jpaugh.
  • Vă va ajuta dacă nu vă mai gândiți la nume/identificatori ca fiind variabile. Acestea sunt referințe la obiecte –  > Por John La Rooy.
  • @gnibbler Sau nume pentru ele… –  > Por detly.
  • @detly, cred că numele este o alegere proastă. Lucrurile au de obicei un singur nume, în timp ce un obiect poate avea mai multe referințe –  > Por John La Rooy.
  • @JohnClements, dar python nu funcționează ca matematica. Dacă vrei să înțelegi python trebuie să știi că obiectele cu un __name__ au un „nume”. Nu toate obiectele au un __name__ atribut, dar puteți avea totuși referințe la ele. Dacă începem să numim „nume” o „referință”, le facem un deserviciu începătorilor în viitor. –  > Por John La Rooy.
5 răspunsuri
Karl Knechtel

Bine, mai întâi de toate.

Nu există așa ceva ca „declararea variabilelor” sau „inițializarea variabilelor” în Python.

Există pur și simplu ceea ce noi numim „atribuire”, dar probabil ar trebui să numim doar „denumire”.

Atribuirea înseamnă „acest nume din partea stângă se referă acum la rezultatul evaluării părții din dreapta, indiferent la ce se referea înainte (dacă se referea la ceva)”.

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

Ca atare, numele din Python (un termen mai bun decât „variabile”, probabil) nu au tipuri asociate; valorile au. Puteți aplica din nou același nume la orice lucru, indiferent de tipul său, dar lucrul respectiv are în continuare un comportament care depinde de tipul său. Numele este pur și simplu o modalitate de a face referire la valoare (obiect). Acest lucru răspunde la a doua întrebare: Puteți nu creați variabile pentru a păstra un tip personalizat. Nu creați variabile pentru a păstra un anumit tip. Nu se „creează” variabile deloc. Se dau nume obiectelor.

Al doilea punct: Python urmează o regulă foarte simplă în ceea ce privește clasele, care este de fapt mult mai coerentă decât ceea ce fac limbaje precum Java, C++ și C#: tot ceea ce este declarat în interiorul clasei class face parte din clasă. Așadar, funcțiile (def) scrise aici sunt metode, adică fac parte din obiectul clasei (nu sunt stocate pe bază de instanță), la fel ca în Java, C++ și C#; dar alte denumiri aici sunt de asemenea parte a clasei. Din nou, numele sunt doar nume și nu au tipuri asociate, iar funcțiile sunt și ele obiecte. în Python. Astfel:

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

Clasele sunt și ele obiecte., , în Python.

Așadar, acum am creat o clasă obiect numit Example, , care reprezintă clasa tuturor lucrurilor care sunt Examples. Acest obiect are două caracteristici furnizate de utilizator (în C++, „members”; în C#, „fields or properties or methods”; în Java, „fields or methods”). Unul dintre ele se numește data, , și stochează valoarea întreagă 42. Celălalt se numește method, , și stochează un obiect funcție. (Există mai multe atribute pe care Python le adaugă automat).

Totuși, aceste atribute încă nu fac parte cu adevărat din obiect. În mod fundamental, un obiect este doar un pachet de mai multe nume (numele atributelor), până când se ajunge la lucruri care nu mai pot fi împărțite. Astfel, valorile pot fi partajate între diferite instanțe ale unei clase sau chiar între obiecte din clase diferite, dacă se stabilește în mod deliberat acest lucru.

Să creăm o instanță:

x = Example()

Acum avem un obiect separat numit x, , care este o instanță a clasei Example. Adresa data și method nu fac de fapt parte din obiect, dar putem să le căutăm în continuare prin intermediul lui x datorită unor trucuri magice pe care Python le face în spatele scenei. Când căutăm method, , în special, vom obține în schimb o „metodă legată” (atunci când o apelăm, x este transmisă automat ca fiind self parametru, ceea ce nu se poate întâmpla dacă căutăm Example.method direct).

Ce se întâmplă atunci când încercăm să folosim x.data?

Când îl examinăm, acesta este căutat mai întâi în obiect. Dacă nu este găsit în obiect, Python caută în clasă.

Cu toate acestea, atunci când atribuim la x.data, , Python va crea un atribut al obiectului. Acesta va nu înlocuiește atributul clasei.

Acest lucru ne permite să facem obiect inițializarea obiectului. Python va apela automat atributul clasei __init__ pentru noile instanțe atunci când acestea sunt create, dacă este prezentă. În această metodă, putem pur și simplu să atribuim la atribute pentru a seta valorile inițiale pentru acel atribut pe fiecare obiect:

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

Acum trebuie să specificăm un name atunci când creăm o clasă Example, , iar fiecare instanță are propria sa name. Python va ignora atributul class Example.name ori de câte ori vom căuta în .name a unei instanțe, deoarece atributul instanței va fi găsit primul.

Un ultim avertisment: modificarea (mutația) și atribuirea sunt lucruri diferite!

În Python, șirurile de caractere sunt imuabile. Ele nu pot fi modificate. Atunci când o faceți:

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

nu modificați șirul original „hi „. Acest lucru este imposibil în Python. În schimb, se creează un fișier nou șir de caractere 'hi mom', , și provocați a să nu mai fie un nume pentru 'hi ', , și să înceapă să fie un nume pentru 'hi mom' în schimb. Am făcut b un nume pentru 'hi ' de asemenea, și după ce am reaplicat a numele, b este tot un nume pentru 'hi ', , deoarece 'hi ' există încă și nu a fost modificat.

Dar listele pot fi modificate:

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

Acum b este și [1, 2, 3, 4], deoarece am făcut b un nume pentru același lucru pe care a numit, iar apoi am schimbat acel lucru. Nu am creat o nouă listă pentru a pentru a denumi, deoarece Python tratează pur și simplu += diferit pentru liste.

Acest lucru contează pentru obiecte, deoarece dacă ați avea o listă ca atribut de clasă și ați folosi o instanță pentru a modifica lista, atunci modificarea ar fi „văzută” în toate celelalte instanțe. Acest lucru se datorează faptului că (a) datele fac parte de fapt din obiectul clasă, și nu din orice obiect instanță; (b) deoarece modificați lista și nu faceți o simplă atribuire, nu ați creat un nou atribut de instanță care să ascundă atributul de clasă.

Comentarii

  • Acesta este motivul pentru care le numim „identificatori. 🙂 –  > Por Martijn Pieters.
  • @Karl_Knechtel în exemplul tău cu șirul de caractere, la sfârșit, ce se întâmplă cu ‘hi’ dacă nu îl numim niciodată ‘b’? Este aceasta o scurgere de memorie? –  > Por heretoinfinity.
  • @heretoinfinity : nu; Python folosește garbage collection pentru a elibera obiectele inaccesibile –  > Por John Clements.
O. Aroesti

S-ar putea să fie cu 6 ani întârziere, dar în Python 3.5 și mai sus, declarați un tip de variabilă în felul următor:

variable_name: type_name

sau așa:

variable_name # type: shinyType

Deci, în cazul tău(dacă ai un CustomObject clasă definită), puteți face:

customObj: CustomObject

Vezi acest lucru sau that pentru mai multe informații.

Comentarii

  • Totuși, aceasta nu este o declarație în sensul tradițional, ci un indiciu, pe care verificatoarele de tip static și IDE-urile îl pot indica, dar care va fi totuși rulat și va eșua. –  > Por PhilHibbs.
  • @PhilHibbs Totuși, nu dă greș. Ce vrei să spui prin „eșuează”? –  > Por O. Aroesti.
  • Ceea ce vreau să spun este că dacă faci a: int și apoi faci a='hello, world!' nu va da greș, deci nu se declară a ca fiind un int și numai int. Ar fi trebuit să spun „nu va eșua”, greșeala mea. Dacă ați făcut a: int, , a='hello, world!', , a=a+1 atunci acest lucru ar trebui să eșueze la compilare într-un limbaj cu tipare statică. –  > Por PhilHibbs.
Detaliat

Nu este nevoie să declarați variabile noi în Python. Dacă vorbim despre variabilele din funcții sau module, nu este necesară nicio declarație. Trebuie doar să atribuiți o valoare unui nume acolo unde aveți nevoie de ea: mymagic = "Magic". Variabilele în Python pot conține valori de orice tip și nu puteți restricționa acest lucru.

Totuși, întrebarea dumneavoastră se referă în mod specific la clase, obiecte și variabile de instanță. Modul idiomatic de a crea variabile de instanță este în cadrul __init__ și nicăieri altundeva – în timp ce ați putea crea noi variabile de instanță în alte metode sau chiar în cod fără legătură cu acestea, este o idee proastă. Astfel, codul dvs. va fi mai greu de analizat sau de întreținut.

Deci, de exemplu:

class Thing(object):

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

Ușor. Acum, instanțele acestei clase au o variabilă magic atribut:

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

Crearea de variabile în spațiul de nume al clasei însăși duce la un comportament complet diferit. Este diferit din punct de vedere funcțional și ar trebui să faceți acest lucru numai dacă aveți un motiv anume. De exemplu:

class Thing(object):

    magic = "Magic"

    def __init__(self):
        pass

Acum încercați:

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

Sau:

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"]

Acest lucru se datorează faptului că spațiul de nume al clasei în sine este diferit de spațiul de nume al obiectelor create din aceasta. Vă las pe dumneavoastră să cercetați acest aspect mai mult.

Mesajul pe care trebuie să-l reținem este că, în mod idiomatic, în Python, (a) inițializați atributele obiectului în __init__ și (b) să documentați comportamentul clasei dvs. după cum este necesar. Nu trebuie să vă chinuiți să faceți o documentație completă la nivel de Sfinx pentru tot ceea ce scrieți, dar cel puțin câteva comentarii despre orice detalii de care dumneavoastră sau altcineva ar putea avea nevoie pentru a le prelua.

redhot

Pentru scopul de definire a domeniului de aplicare, eu folosesc:

custom_object = None

ChipJust

Variabilele au domeniu de aplicare, deci da, este adecvat să aveți variabile care sunt specifice funcției dvs. Nu trebuie să fiți întotdeauna explicit cu privire la definiția lor; de obicei, puteți pur și simplu să le folosiți. Doar dacă doriți să faceți ceva specific tipului de variabilă, cum ar fi adăugarea unei liste, trebuie să le definiți înainte de a începe să le folosiți. Un exemplu tipic în acest sens.

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

Apropo, acesta nu este chiar un mod bun de a configura lista. Ar fi mai bine să spunem:

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

…dar divaghez.

Cealaltă întrebare a dumneavoastră. obiectul personalizat ar trebui să fie o clasă în sine.

class CustomObject(): # always capitalize the class name...this is not syntax, just style.
  pass
customObj = CustomObject()