Declaratie van Python-variabelen

Leert Pythonen heeft enkele fundamentele twijfels.

1.Ik heb variabele declaratie(pad hier) gezien als

class writer:
    path = ""

soms geen expliciete declaratie maar initialiseren via __init__.

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

Ik begrijp het doel van __init__, maar is het raadzaam om variabele in andere functies te declareren.

2.Hoe kan ik een variabele maken voor een aangepast type?

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

Antwoord 1, autoriteit 100%

Ok, de eerste dingen eerst.

Er bestaat niet zoiets als “variabele declaratie” of “variabele initialisatie” in Python.

Er is gewoon wat we “toewijzing” noemen, maar we zouden waarschijnlijk gewoon “naamgeving” moeten noemen.

Opdracht betekent “deze naam aan de linkerkant verwijst nu naar het resultaat van de evaluatie van de rechterkant, ongeacht waar het eerder naar verwees (als er iets is)”.

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

Als zodanig hebben de namen van Python (een betere term dan “variabelen”, aantoonbaar) geen bijbehorende typen; de waarden wel. Je kunt dezelfde naam op alles opnieuw toepassen, ongeacht het type, maar het ding heeft nog steeds gedrag dat afhankelijk is van het type. De naam is gewoon een manier om naar de waarde (object) te verwijzen. Dit beantwoordt uw tweede vraag: u maakt geenvariabelen om een aangepast type vast te houden. U maakt geen variabelen voor een bepaald type. Je “maakt” helemaal geen variabelen. Je geeft namen aan objecten.

Tweede punt: Python volgt een heel eenvoudige regel als het gaat om klassen, die eigenlijk veel consistenter is dan wat talen als Java, C++ en C# doen: alles gedeclareerd binnen de classblok maakt deel uit van de klas. De hier geschreven functies (def) zijn dus methoden, d.w.z. een deel van het klasseobject (niet per instantie opgeslagen), net als in Java, C++ en C#; maar andere namen hier maken ookdeel uit van de klas. Nogmaals, de namen zijn slechts namen, en ze hebben geen bijbehorende typen, en functies zijn ook objectenin Python. Dus:

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

Klassen zijn ook objecten, in Python.

Dus nu hebben we een objectgemaakt met de naam Example, dat de klasse vertegenwoordigt van alle dingen die Exampleen zijn. Dit object heeft twee door de gebruiker geleverde attributen(in C++, “leden”; in C#, “velden of eigenschappen of methoden”; in Java, “velden of methoden”). Een daarvan heet dataen slaat de integerwaarde 42op. De andere heet methoden slaat een functieobject op. (Er zijn nog een aantal attributen die Python automatisch toevoegt.)

Deze attributen maken echter nog steeds niet echt deel uit van het object. Fundamenteel is een object slechts een bundel van meer namen (de attribuutnamen), totdat je bij dingen komt die niet meer kunnen worden opgedeeld. Waarden kunnen dus worden gedeeld tussen verschillende instanties van een klasse, of zelfs tussen objecten van verschillende klassen, als je dat opzettelijk instelt.

Laten we een instantie maken:

x = Example()

Nu hebben we een apart object met de naam x, wat een instantie is van Example. De dataen methodmaken eigenlijk geen deel uit van het object, maar we kunnen ze toch opzoeken via xvanwege wat magie die Python erachter doet de scènes. Wanneer we met name methodopzoeken, krijgen we in plaats daarvan een “gebonden methode” (wanneer we deze aanroepen, wordt xautomatisch doorgegeven als de selfparameter, wat niet kan gebeuren als we Example.methodrechtstreeks opzoeken).

Wat gebeurt er als we x.dataproberen te gebruiken?

Als we het onderzoeken, wordt het eerst in het object opgezocht. Als het niet in het object wordt gevonden, kijkt Python in de klasse.

Als we echter toewijzen aanx.data, zal Python een attribuut voor het object maken. Het zal niethet kenmerk class’ vervangen.

Hierdoor kunnen we objectinitialiseren. Python zal automatisch de __init__methode van de klasse aanroepen op nieuwe instanties wanneer ze worden gemaakt, indien aanwezig. Bij deze methode kunnen we eenvoudig attributen toewijzen om initiële waarden voor dat attribuut op elk object in te stellen:

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

Nu moeten we een nameopgeven wanneer we een Examplemaken, en elke instantie heeft zijn eigen name. Python negeert het klasseattribuut Example.namewanneer we de .namevan een instantie opzoeken, omdat het kenmerk van de instantie als eerste wordt gevonden.

Nog een laatste waarschuwing: modificatie (mutatie) en toewijzing zijn verschillende dingen!

In Python zijn strings onveranderlijk. Ze kunnen niet worden gewijzigd. Wanneer je dat doet:

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

Je verandert nietde originele ‘hi’ string. Dat is onmogelijk in Python. In plaats daarvan maak je een nieuwestring 'hi mom'en zorgt ervoor dat ageen naam meer is voor 'hi ', en wordt in plaats daarvan een naam voor 'hi mom'. We hebben book een naam gemaakt voor 'hi ', en na het opnieuw toepassen van de a-naam, bis nog steeds een naam voor 'hi ', omdat 'hi 'nog steeds bestaat en niet is gewijzigd.

Maar lijsten kunnen worden gewijzigd:

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

Nu is book [1, 2, 3, 4], omdat we been naam hebben gemaakt voor hetzelfde als agenoemd, en toen hebben we dat ding veranderd. We hebben geen nieuwe lijst gemaakt voor aom een naam te geven, omdat Python +=gewoon anders behandelt voor lijsten.

Dit is van belang voor objecten, want als je een lijst als klasse-attribuut had en een instantie zou gebruiken om de lijst aan te passen, dan zou de verandering in alle andere gevallen worden “gezien”. Dit komt omdat (a) de gegevens feitelijk deel uitmaken van het klasseobject en niet van een instantieobject; (b) omdat u de lijst aan het wijzigen was en geen eenvoudige opdracht uitvoerde, heeft u geen nieuw instantiekenmerk gemaakt dat het klassekenmerk verbergt.


Antwoord 2, autoriteit 11%

Dit kan 6 jaar te laat zijn, maar in Python 3.5 en hoger declareer je een variabel type als volgt:

variable_name: type_name

of dit:

variable_name # type: shinyType

Dus in jouw geval (als je een klasse CustomObjecthebt gedefinieerd), kun je het volgende doen:

customObj: CustomObject

Zie ditof datvoor meer info.


Antwoord 3, autoriteit 11%

Het is niet nodig om nieuwe variabelen in Python te declareren. Als we het hebben over variabelen in functies of modules, is er geen declaratie nodig. Wijs gewoon een waarde toe aan een naam waar je die nodig hebt: mymagic = "Magic". Variabelen in Python kunnen waarden van elk type bevatten, en je kunt dat niet beperken.

Uw vraag gaat echter specifiek over klassen, objecten en instantievariabelen. De idiomatische manier om instantievariabelen te maken is in de __init__methode en nergens anders — terwijl u konnieuwe instantievariabelen in andere methoden, of zelfs in niet-gerelateerde code, het is gewoon een slecht idee. Het zal uw code moeilijk maken om over te redeneren of te onderhouden.

Dus bijvoorbeeld:

class Thing(object):
    def __init__(self, magic):
        self.magic = magic

Gemakkelijk. Nu hebben instanties van deze klasse een magic-attribuut:

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

Het maken van variabelen in de naamruimte van de klasse zelf leidt tot totaal ander gedrag. Het is functioneel anders en je moet het alleen doen als je daar een specifieke reden voor hebt. Bijvoorbeeld:

class Thing(object):
    magic = "Magic"
    def __init__(self):
        pass

Probeer nu:

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

Of:

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

Dit komt doordat de naamruimte van de klasse zelf anders is dan de naamruimte van de objecten die ervan zijn gemaakt. Ik laat het aan jou over om daar wat meer onderzoek naar te doen.

De boodschap is dat idiomatische Python (a) objectattributen moet initialiseren in je __init__methode, en (b) het gedrag van je klas moet documenteren als dat nodig is. Je hoeft niet de moeite te nemen van volledige documentatie op Sphinx-niveau voor alles wat je ooit schrijft, maar in ieder geval wat opmerkingen over alle details die jij of iemand anders nodig heeft om het op te pikken.


Antwoord 4, autoriteit 7%

Voor scoping gebruik ik:

custom_object = None

Antwoord 5

Variabelen hebben een bereik, dus ja, het is gepast om variabelen te hebben die specifiek zijn voor uw functie. Je hoeft niet altijd expliciet te zijn over hun definitie; meestal kun je ze gewoon gebruiken. Alleen als u iets specifieks aan het type variabele wilt doen, zoals toevoegen aan een lijst, moet u ze definiëren voordat u ze gaat gebruiken. Typisch voorbeeld hiervan.

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

Trouwens, dit is niet echt een goede manier om de lijst in te stellen. Het is beter om te zeggen:

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

…maar ik dwaal af.

Je andere vraag.
Het aangepaste object moet zelf een klasse zijn.

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

Antwoord 6

Vanaf Python 3 kun je variabelen expliciet per type declareren.

Als u bijvoorbeeld een geheel getal wilt declareren, kunt u dit als volgt doen:

x: int = 3

of:

def f(x: int):
    return x

bekijk deze vraag voor meer informatie hierover:
Een variabele type expliciet declareren in Python

Other episodes