Pytonske måte å konvertere variabel til listen

stemmer
12

Jeg har en funksjon som inndataargument kan enten være et element eller en liste av elementer. Hvis dette argumentet er et enkelt element da jeg satte den i en liste slik at jeg kan iterere over inngangen på en konsistent måte.

Foreløpig har jeg dette:

def my_func(input):
    if not isinstance(input, list): input = [input]
    for e in input:
        ...

Jeg jobber med en eksisterende API slik at jeg ikke kan endre inngangsparametrene. Bruke isinstance () føles Hacky, så er det en riktig måte å gjøre dette?

Publisert på 13/09/2009 klokken 02:01
kilden bruker
På andre språk...                            


8 svar

stemmer
-1

Dette virker som en fornuftig måte å gjøre det. Du ønsker å teste om elementet er en liste, og dette oppnår som direkte. Det blir mer komplisert hvis du ønsker å støtte andre 'liste-lignende' datatyper, også, for eksempel:

isinstance(input, (list, tuple))

eller mer generelt, abstrakt bort spørsmålet:

def iterable(obj):
  try:
    len(obj)
    return True
  except TypeError:
    return False

men igjen, i sammendraget, er metoden enkel og korrekt, noe som høres bra ut for meg!

Svarte 13/09/2009 kl. 02:14
kilden bruker

stemmer
1

Du kan gjøre direkte type sammenligninger hjelp type().

def my_func(input):
    if not type(input) is list:
        input = [input]
    for e in input:
        # do something

Men måten du har det vil tillate noen typen stammer fra listtypen til å bli gått gjennom. Således hindrer de enhver avledet typer fra ved et uhell å bli pakket.

Svarte 13/09/2009 kl. 02:17
kilden bruker

stemmer
0

Din aproach synes rett for meg.

Det ligner på hvordan du bruker atom?i Lisp når du iterere over lister og sjekke gjeldende element for å se om det er en liste eller ikke, fordi hvis det er en liste du ønsker å behandle sine elementer, også.

Så, ja, ser ikke noe galt med det.

Svarte 13/09/2009 kl. 02:17
kilden bruker

stemmer
2

Du kan sette * før argumentet ditt, på denne måten vil du alltid få en tuppel:

def a(*p):
  print type(p)
  print p

a(4)
>>> <type 'tuple'>
>>> (4,)

a(4, 5)
>>> <type 'tuple'>
>>> (4,5,)

Men som vil tvinge deg til å ringe funksjon med variable parametere, jeg vet ikke om det er akseptabelt for deg.

Svarte 13/09/2009 kl. 02:19
kilden bruker

stemmer
12

Vanligvis strenger (vanlig og Unicode) er de eneste iterables du vil likevel vurdere som "enkeltelementer" - den basestringinnebygde finnes spesielt for å la deg teste for enten slags strenger med isinstance, så det er veldig FN-grotty for den spesielle saken ;-).

Så mitt forslag til tilnærming for de mest generelle tilfellet er:

  if isinstance(input, basestring): input = [input]
  else:
    try: iter(input)
    except TypeError: input = [input]
    else: input = list(input)

Dette er en måte for å behandle hver iterable BORTSETT strengene som en liste direkte, strenger og tall og andre ikke-iterables som scalars (for å være normalisert til én-punkt lister).

Jeg eksplisitt lage en liste av alle slags iterable slik at du vet at du kan videre utføre alle slags liste trick - sortering, itera mer enn én gang, legge til eller fjerne elementer for å legge til rette for gjentakelse, etc, alt uten å endre den faktiske inngang listen (hvis liste faktisk det var ;-). Hvis alt du trenger er et enkelt vanlig forsløyfe da det siste trinnet er unødvendig (og faktisk unhelpful hvis f.eks inngang er en stor åpen fil) og jeg vil foreslå en ekstra generator i stedet:

def justLoopOn(input):
  if isinstance(input, basestring):
    yield input
  else:
    try:
      for item in input:
        yield item
    except TypeError:
      yield input

nå i hver eneste en av dine funksjoner som trenger et slikt argument normalisering, du bare bruke:

 for item in justLoopOn(input):

Du kan bruke en hjelpe normalisering-funksjonen, selv i det andre tilfellet (hvor du trenger en skikkelig liste for videre nefarious formål); faktisk, i slike (sjeldne) tilfeller, du kan bare gjøre:

 thelistforme = list(justLoopOn(input))

slik at (uunngåelig) noe-hårete normalisering logikk er bare på ett sted, akkurat som det skal være -)

Svarte 13/09/2009 kl. 02:24
kilden bruker

stemmer
0

Det er en ok måte å gjøre det (ikke glem å inkludere tupler).

Men du kan også være lurt å vurdere om argumentet har en __iter__ metode eller __getitem__ metode . (merk at strengene har __getitem__ stedet for __iter__.)

hasattr(arg, '__iter__') or hasattr(arg, '__getitem__')

Dette er trolig den mest generelle kravet om en liste-lignende type enn bare å sjekke type.

Svarte 13/09/2009 kl. 02:24
kilden bruker

stemmer
7

Jeg liker Andrei Vajna forslag om hasattr(var,'__iter__'). Merk disse resultatene fra noen typiske Python typer:

>>> hasattr("abc","__iter__")
False
>>> hasattr((0,),"__iter__")
True
>>> hasattr({},"__iter__")
True
>>> hasattr(set(),"__iter__")
True

Dette har den ekstra fordelen av å behandle en streng som en ikke-iterable - strenger er en gråsone, som noen ganger du ønsker å behandle dem som et element, andre ganger som en sekvens av tegn.

Merk at i Python tre den strtypen spiller har __iter__attributtet og dette virker ikke:

>>> hasattr("abc", "__iter__")
True
Svarte 13/09/2009 kl. 02:29
kilden bruker

stemmer
3

For det første er det ingen generell metode som kunne fortelle "en enkelt element" fra "liste over elementer" siden av definisjonen listen kan være et element av en annen liste.

Jeg vil si at du må definere hva slags data du måtte ha, slik at du kan ha:

  • noen etterkommer av listmot noe annet
    • Test med isinstance(input, list)(slik at ditt eksempel er korrekt)
  • en hvilken som helst rekkefølge, bortsett fra typen strenger ( basestringi Python 2.x, stri Python 3.x)
    • Bruk sekvens metaclass: isinstance(myvar, collections.Sequence) and not isinstance(myvar, str)
  • noen sekvenstype mot kjente tilfeller, som int, str,MyClass
    • test med isinstance(input, (int, str, MyClass))
  • noen iterable unntatt strenger:
    • test med

.

    try: 
        input = iter(input) if not isinstance(input, str) else [input]
    except TypeError:
        input = [input]
Svarte 13/09/2009 kl. 05:25
kilden bruker

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