Python objekt initialisering bug. Eller er jeg misforstår hvordan objekter arbeid?

stemmer
1
  1 import sys
  2 
  3 class dummy(object):
  4     def __init__(self, val):
  5         self.val = val
  6 
  7 class myobj(object):
  8     def __init__(self, resources):
  9         self._resources = resources
 10 
 11 class ext(myobj):
 12     def __init__(self, resources=[]):
 13         #myobj.__init__(self, resources)
 14         self._resources = resources
 15 
 16 one = ext()
 17 one._resources.append(1)
 18 two = ext()
 19 
 20 print one._resources
 21 print two._resources
 22 
 23 sys.exit(0)

Dette vil skrive referansen til objektet tildelt one._resourcesfor både oneog twogjenstander. Jeg vil tro at twoville være en tom matrise som det er helt klart å sette det slik hvis det ikke er definert når du oppretter objektet. Uncommenting myobj.__init__(self, resources)gjør det samme. Bruke super(ext, self).__init__(resources)også gjør det samme.

Den eneste måten jeg kan få det til å fungere er hvis jeg bruker følgende:

two = ext(dummy(2))

Jeg skal ikke behøve å sette standardverdien manuelt når du oppretter objektet å gjøre dette arbeidet. Eller kanskje jeg gjør. noen tanker?

I dette forsøkt ved hjelp av Python 2,5 og 2,6.

Publisert på 07/10/2009 klokken 21:45
kilden bruker
På andre språk...                            


5 svar

stemmer
7

Du bør endre

def __init__(self, resources=[]):
    self._resources = resources

til

def __init__(self, resources=None):
    if resources is None:
        resources = []
    self._resources = resources

og alle vil bli bedre. Dette er en detalj i måten standard argumenter håndteres hvis de er foranderlig. Det er litt mer informasjon i diskusjonen delen av denne siden .

Svarte 07/10/2009 kl. 21:51
kilden bruker

stemmer
6

Ditt problem er at standardverdien blir evaluert på funksjonsdefinisjonen tid. Dette betyr at den samme liste gjenstand deles mellom tilfeller. Se svaret på dette spørsmålet for mer diskusjon.

Svarte 07/10/2009 kl. 21:51
kilden bruker

stemmer
1

Fra http://docs.python.org/3.1/tutorial/controlflow.html :

Standardverdien vurderes bare én gang. Dette gjør en forskjell når standard er en foranderlig gjenstand, for eksempel en liste, ordliste, eller forekomster av de fleste klasser.

Svarte 07/10/2009 kl. 21:52
kilden bruker

stemmer
2

Vennligst les dette svaret for en diskusjon om hvordan å sette opp en klasse fra __init__(). Du har møtt en velkjent innfall av Python: du prøver å sette opp en foranderlig, og din foranderlig blir evaluert en gang når __init__()er kompilert. Standarden Løsningen er:

class ext(myobj):
    def __init__(self, resources=None):
        if resources is None:
            resources = []
        #myobj.__init__(self, resources)
        self._resources = resources
Svarte 07/10/2009 kl. 21:55
kilden bruker

stemmer
0

Dette er et kjent Python fikser .

Du må unngå å bruke en foranderlig objekt på samtalen av en funksjon / metode.

Objektene som gir standardverdiene er ikke skapt på den tiden at funksjonen / metoden kalles . De er laget på den tiden at setningen som definerer funksjonen utføres . (Se diskusjonen på standard argumenter i Python: to enkle tabber : "Uttrykk i standardargumenter er beregnet når funksjonen er definert, ikke når det heter." )

Denne oppførselen er ikke en vorte i Python språket. Det er virkelig en funksjon, ikke en bug. Det er tider når du virkelig ønsker å bruke foranderlig standardargumenter. En ting de kan gjøre (for eksempel) er en liste av resultater fra tidligere besvergelser, noe som kan være veldig praktisk.

Men for de fleste programmerere - spesielt begynner Pythonistas - denne atferden er en fikser. Så for de fleste tilfeller vedta vi følgende regler.

  • Bruk aldri en foranderlig objekt - som er: en liste, en ordbok, eller en klasse eksempel - som standardverdi av et argument.
  • Ignorer regel en bare hvis du virkelig, virkelig, virkelig vet hva du gjør.

Så ... vi planlegger alltid å følge regelen # 1. Nå er spørsmålet hvordan du gjør det ... hvordan å kode functionF for å få den atferd som vi ønsker.

Heldigvis er løsningen enkel. De foranderlig objektene de brukes som standard er erstattet av None, og deretter argumentene testes for None.


Så hvordan kan man gjøre det på riktig måte? En løsning er å unngå å bruke foranderlig standardverdier for argumenter . Men dette er neppe tilfredsstillende, som fra tid til annen en ny liste er en nyttig standard. Det er noen komplekse løsninger som definerer en dekoratør for funksjoner som dype-kopier alle argumenter. Dette er en overkill, og problemet kan løses enkelt slik:

class ext(myobj):
    def __init__(self, resources=None):
        if not resources:
            resources = []
        self._resources = resources
Svarte 07/10/2009 kl. 22:08
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more