collections — Datatyper för behållare

Källkod: Lib/collections/__init__.py


Denna modul implementerar specialiserade datatyper för containrar som ger alternativ till Pythons inbyggda containrar för allmänna ändamål, dict, list, set och tuple.

namedtuple()

fabriksfunktion för att skapa tuple-subklasser med namngivna fält

deque

listliknande behållare med snabba tillägg och öppningar i båda ändar

KedjeMap

diktliknande klass för att skapa en enda vy av flera mappningar

Counter

dict-underklass för räkning av hashable-objekt

OrderedDict

dict-underklass som kommer ihåg i vilken ordning posterna lades till

defaultdict

dict-underklass som anropar en fabriksfunktion för att leverera saknade värden

UserDict

omslag runt ordboksobjekt för enklare underklassning av ordböcker

UserList

omslag runt listobjekt för enklare underklassning av listor

UserString

omslag runt strängobjekt för enklare underklassning av strängar

ChainMap-objekt

Tillagd i version 3.3.

En ChainMap-klass tillhandahålls för att snabbt länka ett antal mappningar så att de kan behandlas som en enda enhet. Det är ofta mycket snabbare än att skapa en ny ordbok och köra flera update()-anrop.

Klassen kan användas för att simulera nästlade scopes och är användbar i templating.

class collections.ChainMap(*maps)

En ChainMap grupperar flera dicts eller andra mappningar tillsammans för att skapa en enda, uppdaterbar vy. Om inga mappningar anges, tillhandahålls en enda tom ordbok så att en ny kedja alltid har minst en mappning.

De underliggande mappningarna lagras i en lista. Listan är offentlig och kan nås eller uppdateras med hjälp av attributet maps. Det finns inget annat tillstånd.

Lookups söker igenom de underliggande mappningarna successivt tills en nyckel hittas. Skrivningar, uppdateringar och borttagningar påverkar däremot bara den första mappningen.

En ChainMap innehåller de underliggande mappningarna genom referens. Så om en av de underliggande mappningarna uppdateras, kommer dessa ändringar att återspeglas i ChainMap.

Alla de vanliga metoderna för ordböcker stöds. Dessutom finns ett maps-attribut, en metod för att skapa nya underkontexter och en egenskap för att komma åt alla mappningar utom den första:

maps

En lista med mappningar som kan uppdateras av användaren. Listan är ordnad från först sökta till sist sökta. Det är det enda lagrade tillståndet och kan modifieras för att ändra vilka mappningar som ska sökas. Listan bör alltid innehålla minst en mappning.

new_child(m=None, **kwargs)

Returnerar en ny ChainMap som innehåller en ny karta följd av alla kartor i den aktuella instansen. Om m specificeras blir det den nya kartan längst fram i listan över mappningar; om den inte specificeras används en tom dict, så att ett anrop till d.new_child() är likvärdigt med: ChainMap({}, *d.maps). Om några nyckelordsargument anges uppdaterar de den map som skickas eller en ny tom dict. Den här metoden används för att skapa underkontexter som kan uppdateras utan att ändra värden i någon av de överordnade mappningarna.

Ändrad i version 3.4: Den valfria parametern m har lagts till.

Ändrad i version 3.10: Stöd för sökordsargument har lagts till.

parents

Egenskap som returnerar en ny ChainMap som innehåller alla kartor i den aktuella instansen utom den första. Detta är användbart för att hoppa över den första kartan i sökningen. Användningsfallen liknar dem för nyckelordet nonlocal som används i nested scopes. Användningsfallen är också parallella med dem för den inbyggda funktionen super(). En referens till d.parents är likvärdig med: ChainMap(*d.maps[1:]).

Observera att iterationsordningen för en ChainMap bestäms genom att skanna mappningarna från sist till först:

>>> baseline = {'music': 'bach', 'art': 'rembrandt'}
>>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}
>>> list(ChainMap(adjustments, baseline))
['music', 'art', 'opera']

Detta ger samma ordning som en serie dict.update()-anrop som börjar med den sista mappningen:

>>> combined = baseline.copy()
>>> combined.update(adjustments)
>>> list(combined)
['music', 'art', 'opera']

Ändrad i version 3.9: Lagt till stöd för operatorerna | och |=, specificerat i PEP 584.

Se även

ChainMap Exempel och recept

I detta avsnitt visas olika sätt att arbeta med kedjade kartor.

Exempel på simulering av Pythons interna lookup-kedja:

import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))

Exempel på att låta användarspecifika kommandoradsargument ha företräde framför miljövariabler som i sin tur har företräde framför standardvärden:

import os, argparse

defaults = {'color': 'red', 'user': 'guest'}

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}

combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
print(combined['user'])

Exempel på mönster för användning av klassen ChainMap för att simulera nästlade kontexter:

c = ChainMap() # Skapa rotkontext
d = c.new_child() # Skapa ett nästlat barnkontext
e = c.new_child() # Barn till c, oberoende av d
e.maps[0] # Aktuell kontextordbok -- som Pythons locals()
e.maps[-1] # Rotkontext -- som Pythons globals()
e.parents # Omslutande kontextkedja -- som Pythons nonlocals

d['x'] = 1 # Ange värde i aktuell kontext
d['x'] # Hämta första nyckeln i kedjan av kontexter
del d['x'] # Ta bort från aktuell kontext
list(d) # Alla nästlade värden
k in d # Kontrollera alla nästlade värden
len(d) # Antal nästlade värden
d.items() # Alla nästlade objekt
dict(d) # Plattas ut till en vanlig ordbok

Klassen ChainMap gör bara uppdateringar (skrivningar och raderingar) till den första mappningen i kedjan medan uppslagningar söker i hela kedjan. Men om djupa skrivningar och raderingar önskas är det enkelt att skapa en underklass som uppdaterar nycklar som finns djupare i kedjan:

class DeepChainMap(ChainMap):
    'Variant of ChainMap that allows direct updates to inner scopes'

    def __setitem__(self, key, value):
        for mapping in self.maps:
            if key in mapping:
                mapping[key] = value
                return
        self.maps[0][key] = value

    def __delitem__(self, key):
        for mapping in self.maps:
            if key in mapping:
                del mapping[key]
                return
        raise KeyError(key)

>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange'         # update an existing key two levels down
>>> d['snake'] = 'red'           # new keys get added to the topmost dict
>>> del d['elephant']            # remove an existing key one level down
>>> d                            # display result
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

Counter-objekt

Ett räkneverktyg tillhandahålls för att stödja praktiska och snabba räkningar. Till exempel:

>>> # Tally occurrences of words in a list
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
...     cnt[word] += 1
...
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

>>> # Find the ten most common words in Hamlet
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
 ('you', 554),  ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
class collections.Counter([iterable-or-mapping])

En Counter är en dict-underklass för att räkna hashable-objekt. Det är en samling där element lagras som nycklar i en ordbok och deras antal lagras som ordboksvärden. Antalet kan vara vilket heltalsvärde som helst, inklusive noll eller negativa värden. Klassen Counter liknar påsar eller multisets i andra språk.

Element räknas från en iterable eller initialiseras från en annan mapping (eller räknare):

>>> c = Counter()                           # a new, empty counter
>>> c = Counter('gallahad')                 # a new counter from an iterable
>>> c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
>>> c = Counter(cats=4, dogs=8)             # a new counter from keyword args

Counter-objekt har ett dictionary-gränssnitt förutom att de returnerar ett nollvärde för saknade objekt i stället för att ge upphov till ett KeyError:

>>> c = Counter(['eggs', 'ham'])
>>> c['bacon']                              # count of a missing element is zero
0

Att nollställa ett räkneverk tar inte bort ett element från ett räkneverk. Använd del för att ta bort det helt:

>>> c['sausage'] = 0                        # counter entry with a zero count
>>> del c['sausage']                        # del actually removes the entry

Tillagd i version 3.1.

Ändrad i version 3.7: Som en underklass till dict ärvde Counter förmågan att komma ihåg inmatningsordning. Matematiska operationer på Counter-objekt bevarar också ordningen. Resultaten sorteras efter när ett element först påträffas i den vänstra operanden och sedan efter den ordning som det påträffas i den högra operanden.

Counter-objekt stöder ytterligare metoder utöver de som är tillgängliga för alla ordböcker:

elements()

Returnerar en iterator över element som upprepar varje element lika många gånger som dess antal. Elementen returneras i den ordning de först påträffades. Om ett elements antal är mindre än ett kommer elements() att ignorera det.

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> sorted(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']
most_common([n])

Returnerar en lista med de n vanligaste elementen och deras antal från det vanligaste till det minst vanliga. Om n utelämnas eller None returnerar most_common() alla element i räknaren. Element med lika antal ordnas i den ordning som de först påträffades:

>>> Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]
subtract([iterable-or-mapping])

Element subtraheras från en iterable eller från en annan mappning (eller räknare). Som dict.update() men subtraherar räkningar istället för att ersätta dem. Både ingångar och utgångar kan vara noll eller negativa.

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> d = Counter(a=1, b=2, c=3, d=4)
>>> c.subtract(d)
>>> c
Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

Tillagd i version 3.2.

total()

Beräkna summan av räkningarna.

>>> c = Counter(a=10, b=5, c=0)
>>> c.total()
15

Tillagd i version 3.10.

De vanliga ordboksmetoderna är tillgängliga för Counter-objekt, förutom två som fungerar annorlunda för räknare.

fromkeys(iterable)

Denna klassmetod är inte implementerad för Counter-objekt.

update([iterable-or-mapping])

Element räknas från en iterable eller läggs till från en annan mappning (eller räknare). Som dict.update() men lägger till räkningar istället för att ersätta dem. Dessutom förväntas iterable vara en sekvens av element, inte en sekvens av par av typen (nyckel, värde).

Counters stöder omfattande jämförelseoperatorer för jämlikhet, delmängd och övermängdsrelationer: ==, !=, <, <=, >, >=. Alla dessa tester behandlar saknade element som om de har noll i antal, så att Counter(a=1) == Counter(a=1, b=0) returnerar sant.

Ändrad i version 3.10: Rika jämförelseoperationer har lagts till.

Ändrad i version 3.10: I likhetstester behandlas saknade element som om de hade noll räkningar. Tidigare ansågs Counter(a=3) och Counter(a=3, b=0) vara skilda.

Vanliga mönster för att arbeta med Counter-objekt:

c.total() # summa av alla räkningar
c.clear() # återställ alla räkningar
list(c) # lista unika element
set(c) # konvertera till en uppsättning
dict(c) # konvertera till en vanlig ordbok
c.items() # tillgång till paren (elem, cnt)
Counter(dict(list_of_pairs))    # konvertera från en lista med (elem, cnt)-par
c.most_common()[:-n-1:-1] # n minst gemensamma element
+c # ta bort noll och negativa räkningar

Flera matematiska operationer finns för att kombinera Counter-objekt för att producera multisets (räknare som har antal större än noll). Addition och subtraktion kombinerar räknare genom att addera eller subtrahera räknevärdena för motsvarande element. Intersection och union returnerar minimum och maximum av motsvarande räkningar. Equality och inclusion jämför motsvarande räkningar. Varje operation kan acceptera inmatningar med signerade räkningar, men utmatningen kommer att utesluta resultat med räkningar på noll eller mindre.

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d                       # add two counters together:  c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d                       # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d                       # intersection:  min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d                       # union:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})
>>> c == d                      # equality:  c[x] == d[x]
False
>>> c <= d                      # inclusion:  c[x] <= d[x]
False

Unary addition och subtraction är genvägar för att addera en tom räknare eller subtrahera från en tom räknare.

>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})

Tillagd i version 3.3: Stöd för unary plus, unary minus och in-place multiset-operationer har lagts till.

Anteckning

Räknare utformades i första hand för att fungera med positiva heltal för att representera löpande räkningar, men man var noga med att inte i onödan utesluta användningsfall som behövde andra typer eller negativa värden. För att hjälpa till med dessa användningsfall dokumenterar detta avsnitt minimiintervall och typbegränsningar.

  • Klassen Counter är i sig en dictionary-subklass utan några restriktioner för dess nycklar och värden. Värdena är avsedda att vara siffror som representerar antal, men du kan lagra vad som helst i värdefältet.

  • Metoden most_common() kräver endast att värdena är ordningsbara.

  • För in-place-operationer som c[key] += 1 behöver värdetypen bara stödja addition och subtraktion. Så bråk, flyttal och decimaler skulle fungera och negativa värden stöds. Detsamma gäller även för update() och subtract() som tillåter negativa och nollvärden för både in- och utdata.

  • Multiset-metoderna är endast avsedda för användningsfall med positiva värden. Ingångsvärdena kan vara negativa eller noll, men endast utgångar med positiva värden skapas. Det finns inga typbegränsningar, men värdetypen måste stödja addition, subtraktion och jämförelse.

  • Metoden elements() kräver heltalsräkningar. Den ignorerar noll och negativa räkningar.

Se även

  • Bag-klass i Smalltalk.

  • Wikipedia-inlägg för Multisets.

  • C++ multisets handledning med exempel.

  • För matematiska operationer på flermängder och deras användningsområden, se Knuth, Donald. The Art of Computer Programming Volume II, avsnitt 4.6.3, övning 19.

  • För att räkna upp alla distinkta fleruppsättningar av en viss storlek över en viss uppsättning element, se itertools.combinations_with_replacement():

    map(Räknare, kombinationer_med_ersättning('ABC', 2)) # --> AA AB AC BB BC CC
    

deque-objekt

class collections.deque([iterable[, maxlen]])

Returnerar ett nytt deque-objekt som initierats från vänster till höger (med append()) med data från iterable. Om iterable inte anges är det nya deque-objektet tomt.

Deques är en generalisering av staplar och köer (namnet uttalas ”deck” och är en förkortning av ”double-ended queue”). Deques stöder trådsäkra, minneseffektiva appends och pops från vardera sidan av deque med ungefär samma O(1) prestanda i båda riktningarna.

Även om list-objekt stöder liknande operationer är de optimerade för snabba operationer med fasta längder och medför O(n) minnesförflyttningskostnader för operationerna pop(0) och insert(0, v) som ändrar både storleken och positionen för den underliggande datarepresentationen.

Om maxlen inte anges eller är None, kan deques växa till godtycklig längd. I annat fall är deque begränsad till den angivna maximala längden. När en deque med begränsad längd är full, när nya objekt läggs till, kasseras ett motsvarande antal objekt från den motsatta änden. Deques med begränsad längd har en funktionalitet som liknar filtret tail i Unix. De är också användbara för att spåra transaktioner och andra datapooler där endast den senaste aktiviteten är av intresse.

Deque-objekt stöder följande metoder:

append(x)

Lägg till x på höger sida av deque.

appendleft(x)

Lägg till x på vänster sida av deque.

clear()

Ta bort alla element från deque och lämna den med längd 0.

copy()

Skapa en ytlig kopia av deque.

Tillagd i version 3.5.

count(x)

Räkna antalet deque-element som är lika med x.

Tillagd i version 3.2.

extend(iterable)

Förläng höger sida av deque genom att lägga till element från iterable-argumentet.

extendleft(iterable)

Förläng vänster sida av deque genom att lägga till element från iterable. Observera att serien av vänstra appends resulterar i att ordningen på elementen i iterable-argumentet vänds.

index(x[, start[, stop]])

Returnerar positionen för x i deque (vid eller efter index start och före index stop). Returnerar den första matchningen eller ger ValueError om den inte hittas.

Tillagd i version 3.5.

insert(i, x)

Sätt in x i deque på position i.

Om införandet skulle leda till att en avgränsad deque växer bortom maxlen, kommer ett IndexError att uppstå.

Tillagd i version 3.5.

pop()

Tar bort och returnerar ett element från höger sida av deque. Om inga element finns, uppstår ett IndexError.

popleft()

Tar bort och returnerar ett element från vänster sida av deque. Om inga element finns, uppstår ett IndexError.

remove(value)

Tar bort den första förekomsten av värde. Om det inte hittas, uppstår ett ValueError.

reverse()

Vänd elementen i deque på plats och returnera sedan None.

Tillagd i version 3.2.

rotate(n=1)

Rotera dekanen n steg åt höger. Om n är negativ, rotera till vänster.

När deque inte är tom är rotation ett steg åt höger likvärdigt med d.appendleft(d.pop()), och rotation ett steg åt vänster är likvärdigt med d.append(d.popleft()).

Deque-objekt har också ett skrivskyddat attribut:

maxlen

Maximal storlek på en deque eller None om den är obegränsad.

Tillagd i version 3.1.

Förutom ovanstående stöder deques iteration, pickling, len(d), reversed(d), copy.copy(d), copy.deepcopy(d), medlemskapstestning med operatorn in och subskriptreferenser som d[0] för åtkomst till det första elementet. Indexerad åtkomst är O(1) i båda ändar men saktar ner till O(n) i mitten. För snabb slumpmässig åtkomst, använd listor istället.

Från och med version 3.5 har deques stöd för __add__(), __mul__() och __imul__().

Exempel:

>>> from collections import deque
>>> d = deque('ghi')                 # make a new deque with three items
>>> for elem in d:                   # iterate over the deque's elements
...     print(elem.upper())
G
H
I

>>> d.append('j')                    # add a new entry to the right side
>>> d.appendleft('f')                # add a new entry to the left side
>>> d                                # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])

>>> d.pop()                          # return and remove the rightmost item
'j'
>>> d.popleft()                      # return and remove the leftmost item
'f'
>>> list(d)                          # list the contents of the deque
['g', 'h', 'i']
>>> d[0]                             # peek at leftmost item
'g'
>>> d[-1]                            # peek at rightmost item
'i'

>>> list(reversed(d))                # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d                         # search the deque
True
>>> d.extend('jkl')                  # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1)                      # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1)                     # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])

>>> deque(reversed(d))               # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear()                        # empty the deque
>>> d.pop()                          # cannot pop from an empty deque
Traceback (most recent call last):
    File "<pyshell#6>", line 1, in -toplevel-
        d.pop()
IndexError: pop from an empty deque

>>> d.extendleft('abc')              # extendleft() reverses the input order
>>> d
deque(['c', 'b', 'a'])

deque Recept

I detta avsnitt visas olika sätt att arbeta med deques.

Deques med begränsad längd ger funktionalitet som liknar filtret tail i Unix:

def tail(filnamn, n=10):
    'Returnera de sista n raderna i en fil'
    med open(filnamn) som f:
        returnera deque(f, n)

Ett annat sätt att använda deques är att upprätthålla en sekvens av nyligen tillagda element genom att appendiera till höger och poppa till vänster:

def glidande_medelvärde(iterabel, n=3):
    # moving_average([40, 30, 50, 46, 39, 44]) --> 40,0 42,0 45,0 43,0
    # https://en.wikipedia.org/wiki/Moving_average
    it = iter(iterabel)
    d = deque(itertools.islice(it, n-1))
    d.appendleft(0)
    s = summa(d)
    för elem i it:
        s += elem - d.popleft()
        d.append(elem)
        ger s / n

En round-robin schemaläggare kan implementeras med inmatningsiteratorer lagrade i en deque. Värden erhålls från den aktiva iteratorn i position noll. Om den iteratorn är uttömd kan den tas bort med popleft(); annars kan den cyklas tillbaka till slutet med rotate()-metoden:

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    iteratorer = deque(map(iter, iterables))
    while iterators:
        försök:
            while True:
                yield next(iteratorer[0])
                iteratorer.rotera(-1)
        except StopIteration:
            # Ta bort en uttömd iterator.
            iteratorer.popleft()

Metoden rotate() ger ett sätt att implementera deque skivning och borttagning. Till exempel, en ren Python-implementering av del d[n] förlitar sig på rotate()-metoden för att positionera element som ska poppas:

def delete_nth(d, n):
    d.rotera(-n)
    d.popleft()
    d.rotera(n)

För att implementera deque slicing, använd ett liknande tillvägagångssätt med rotate() för att föra ett målelement till vänster sida av deque. Ta bort gamla poster med popleft(), lägg till nya poster med extend(), och vänd sedan rotationen. Med mindre variationer på detta tillvägagångssätt är det lätt att implementera stackmanipulationer i Forth-stil som dup, drop, wap, over, pick, rot och roll.

defaultdict-objekt

class collections.defaultdict(default_factory=None, /[, ...])

Returnerar ett nytt ordboksliknande objekt. defaultdict är en subklass av den inbyggda dict-klassen. Den åsidosätter en metod och lägger till en skrivbar instansvariabel. Resterande funktionalitet är densamma som för klassen dict och dokumenteras inte här.

Det första argumentet anger det initiala värdet för attributet default_factory; standardvärdet är None. Alla återstående argument behandlas på samma sätt som om de skickades till dict-konstruktören, inklusive nyckelordsargument.

defaultdict-objekt stöder följande metod utöver de vanliga dict-operationerna:

__missing__(key)

Om attributet default_factory är None, utlöses ett KeyError undantag med key som argument.

Om default_factory inte är None anropas den utan argument för att ange ett standardvärde för den angivna key, detta värde infogas i ordlistan för key och returneras.

Om anrop av default_factory ger upphov till ett undantag, sprids detta undantag oförändrat.

Denna metod anropas av __getitem__()-metoden i dict-klassen när den begärda nyckeln inte hittas; vad den returnerar eller väcker returneras eller väcks sedan av __getitem__().

Observera att __missing__() inte anropas för några andra operationer än __getitem__(). Detta innebär att get() kommer, precis som vanliga ordböcker, att returnera None som standard istället för att använda default_factory.

defaultdict-objekt har stöd för följande instansvariabel:

default_factory

Detta attribut används av metoden __missing__(); det initialiseras från det första argumentet till konstruktören, om det finns, eller till None, om det saknas.

Ändrad i version 3.9: Lagt till operatorer för sammanslagning (|) och uppdatering (|=), specificerade i PEP 584.

defaultdict Exempel

Med list som default_factory är det enkelt att gruppera en sekvens av nyckel-värde-par till en ordbok med listor:

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

När varje nyckel påträffas för första gången finns den inte redan i mappningen, så en post skapas automatiskt med hjälp av funktionen default_factory som returnerar en tom list. Operationen list.append() lägger sedan till värdet i den nya listan. När nycklar påträffas igen fortsätter uppslagningen normalt (listan för den nyckeln returneras) och operationen list.append() lägger till ett annat värde i listan. Denna teknik är enklare och snabbare än motsvarande teknik som använder dict.setdefault():

>>> d = {}
>>> for k, v in s:
...     d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

Om du ställer in default_factory till int blir defaultdict användbar för räkning (som en påse eller multiset på andra språk):

>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
...     d[k] += 1
...
>>> sorted(d.items())
[('i', 4), ('m', 1), ('p', 2), ('s', 4)]

När en bokstav först påträffas saknas den i mappningen, så funktionen default_factory anropar int() för att ange ett standardantal på noll. Inkrementoperationen bygger sedan upp räkningen för varje bokstav.

Funktionen int() som alltid returnerar noll är bara ett specialfall av konstantfunktioner. Ett snabbare och mer flexibelt sätt att skapa konstantfunktioner är att använda en lambda-funktion som kan ge vilket konstant värde som helst (inte bara noll):

>>> def constant_factory(value):
...     return lambda: value
...
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'

Om du ställer in default_factoryset blir defaultdict användbar för att bygga en ordbok med set:

>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
...     d[k].add(v)
...
>>> sorted(d.items())
[('blue', {2, 4}), ('red', {1, 3})]

namedtuple() Fabriksfunktion för tupler med namngivna fält

Namngivna tupler tilldelar varje position i en tupel en betydelse och möjliggör mer läsbar och självdokumenterande kod. De kan användas överallt där vanliga tuplar används, och de ger möjlighet att komma åt fält med namn i stället för positionsindex.

collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)

Returnerar en ny tuple-subklass med namnet typename. Den nya underklassen används för att skapa tuple-liknande objekt som har fält som är tillgängliga genom attributuppslagning samt indexerbara och itererbara. Instanser av subklassen har också en användbar docstring (med typename och field_names) och en användbar __repr__() -metod som listar tuple-innehållet i ett name=value -format.

field_names är en sekvens av strängar, t.ex. ['x', 'y']. Alternativt kan field_names vara en enda sträng där varje fältnamn separeras med blanksteg och/eller kommatecken, t.ex. 'x y' eller 'x, y'.

Alla giltiga Python-identifierare kan användas för ett fältnamn utom namn som börjar med ett understreck. Giltiga identifierare består av bokstäver, siffror och understreck men börjar inte med en siffra eller ett understreck och kan inte vara ett nyckelord som class, for, return, global, pass eller raise.

Om rename är true ersätts ogiltiga fältnamn automatiskt med positionsnamn. Till exempel konverteras ['abc', 'def', 'ghi', 'abc'] till ['abc', '_1', 'ghi', '_3'], vilket eliminerar nyckelordet def och det dubbla fältnamnet abc.

defaults kan vara None eller en iterable av standardvärden. Eftersom fält med ett standardvärde måste komma efter fält utan ett standardvärde, tillämpas defaults på parametrarna längst till höger. Om fältnamnen till exempel är ['x', 'y', 'z'] och standardvärdena är (1, 2), kommer x att vara ett obligatoriskt argument, y kommer att vara standardvärdet 1 och z kommer att vara standardvärdet 2.

Om module definieras sätts attributet __module__ i den namngivna tupeln till det värdet.

Namngivna tuple-instanser har inga ordböcker per instans, så de är lätta och kräver inte mer minne än vanliga tupler.

För att stödja pickling bör den namngivna tuple-klassen tilldelas en variabel som matchar typename.

Ändrad i version 3.1: Lagt till stöd för rename.

Ändrad i version 3.6: Parametrarna verbose och rename blev keyword-only arguments.

Ändrad i version 3.6: Parametern module har lagts till.

Ändrad i version 3.7: Parametern verbose och attributet _source har tagits bort.

Ändrad i version 3.7: Lagt till parametern defaults och attributet _field_defaults.

>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22)     # instantiate with positional or keyword arguments
>>> p[0] + p[1]             # indexable like the plain tuple (11, 22)
33
>>> x, y = p                # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y               # fields also accessible by name
33
>>> p                       # readable __repr__ with a name=value style
Point(x=11, y=22)

Namngivna tupler är särskilt användbara för att tilldela fältnamn till resultattuplar som returneras av modulerna csv eller sqlite3:

EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
    print(emp.name, emp.title)

import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
    print(emp.name, emp.title)

Utöver de metoder som ärvs från tuples har named tuples stöd för ytterligare tre metoder och två attribut. För att undvika konflikter med fältnamn börjar metod- och attributnamnen med ett understreck.

classmethod somenamedtuple._make(iterable)

Klassmetod som skapar en ny instans från en befintlig sekvens eller iterabel.

>>> t = [11, 22]
>>> Point._make(t)
Point(x=11, y=22)
somenamedtuple._asdict()

Returnerar en ny dict som mappar fältnamn till deras motsvarande värden:

>>> p = Point(x=11, y=22)
>>> p._asdict()
{'x': 11, 'y': 22}

Ändrad i version 3.1: Returnerar en OrderedDict istället för en vanlig dict.

Ändrad i version 3.8: Returnerar en vanlig dict istället för en OrderedDict. Från och med Python 3.7 garanteras att vanliga dicts är ordnade. Om de extra funktionerna i OrderedDict krävs, är den föreslagna lösningen att casta resultatet till önskad typ: OrderedDict(nt._asdict()).

somenamedtuple._replace(**kwargs)

Returnerar en ny instans av den namngivna tupeln genom att ersätta angivna fält med nya värden:

>>> p = Point(x=11, y=22)
>>> p._replace(x=33)
Point(x=33, y=22)

>>> for partnum, record in inventory.items():
...     inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())

Namngivna tupler stöds också av den generiska funktionen copy.replace().

Ändrad i version 3.13: Utlös TypeError istället för ValueError för ogiltiga nyckelordsargument.

somenamedtuple._fields

Tupel med strängar som listar fältnamnen. Användbar för introspektion och för att skapa nya namngivna tupeltyper från befintliga namngivna tuplar.

>>> p._fields            # view the field names
('x', 'y')

>>> Color = namedtuple('Color', 'red green blue')
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)
somenamedtuple._field_defaults

Ordbok som mappar fältnamn till standardvärden.

>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
>>> Account._field_defaults
{'balance': 0}
>>> Account('premium')
Account(type='premium', balance=0)

Om du vill hämta ett fält vars namn lagras i en sträng använder du funktionen getattr():

>>> getattr(p, 'x')
11

Om du vill konvertera en ordbok till en namngiven tupel använder du dubbelstjärneoperatorn (enligt beskrivningen i Uppackning av argumentlistor):

>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)

Eftersom en named tuple är en vanlig Python-klass är det lätt att lägga till eller ändra funktionalitet med en subklass. Så här lägger du till ett beräknat fält och ett utskriftsformat med fast bredd:

>>> class Point(namedtuple('Point', ['x', 'y'])):
...     __slots__ = ()
...     @property
...     def hypot(self):
...         return (self.x ** 2 + self.y ** 2) ** 0.5
...     def __str__(self):
...         return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

>>> for p in Point(3, 4), Point(14, 5/7):
...     print(p)
Point: x= 3.000  y= 4.000  hypot= 5.000
Point: x=14.000  y= 0.714  hypot=14.018

Den subklass som visas ovan sätter __slots__ till en tom tupel. Detta hjälper till att hålla minneskraven låga genom att förhindra skapandet av instansordböcker.

Subklassning är inte användbart för att lägga till nya, lagrade fält. Istället skapar du helt enkelt en ny namngiven tupeltyp från attributet _fields:

>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))

Dokumentsträngar kan anpassas genom att göra direkta tilldelningar till fälten __doc__:

>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'

Ändrad i version 3.5: Property docstrings blev skrivbara.

Se även

  • Se typing.NamedTuple för ett sätt att lägga till typhintar för namngivna tupler. Det ger också en elegant notation med hjälp av nyckelordet class:

    class Komponent(NamedTuple):
        part_number: int
        vikt: float
        description (beskrivning): Valfri[str] = Ingen
    
  • Se types.SimpleNamespace() för en föränderlig namnrymd som baseras på en underliggande ordbok i stället för en tupel.

  • Modulen dataclasses innehåller en dekorator och funktioner för att automatiskt lägga till genererade specialmetoder till användardefinierade klasser.

OrderedDict-objekt

Ordnade ordböcker är precis som vanliga ordböcker men har några extra funktioner som rör ordningsoperationer. De har blivit mindre viktiga nu när den inbyggda dict-klassen har fått förmågan att komma ihåg insättningsordning (detta nya beteende blev garanterat i Python 3.7).

Vissa skillnader från dict kvarstår fortfarande:

  • Den vanliga dict utformades för att vara mycket bra på mappningsoperationer. Att spåra insättningsordning var sekundärt.

  • OrderedDict utformades för att vara bra på omordningsoperationer. Utrymmeseffektivitet, iterationshastighet och prestanda för uppdateringsoperationer var sekundära.

  • Algoritmen OrderedDict kan hantera frekventa omordningsoperationer bättre än dict. Som visas i recepten nedan gör detta att den lämpar sig för implementering av olika typer av LRU-cacher.

  • Jämlikhetsoperationen för OrderedDict kontrollerar matchande ordning.

    En vanlig dict kan emulera det ordningskänsliga likhetstestet med p == q and all(k1 == k2 for k1, k2 in zip(p, q)).

  • Metoden popitem() i OrderedDict har en annan signatur. Den accepterar ett valfritt argument för att specificera vilket objekt som ska poppas.

    En vanlig dict kan efterlikna OrderedDicts od.popitem(last=True) med d.popitem() som garanterat öppnar det längst till höger (sista) objektet.

    En vanlig dict kan emulera OrderedDicts od.popitem(last=False) med (k := next(iter(d)), d.pop(k)) som returnerar och tar bort det längst till vänster (första) objektet om det finns.

  • OrderedDict har en move_to_end()-metod för att effektivt flytta ett element till en slutpunkt.

    En vanlig dict kan emulera OrderedDicts od.move_to_end(k, last=True) med d[k] = d.pop(k) vilket flyttar nyckeln och dess associerade värde till den högra (sista) positionen.

    En vanlig dict har inte någon effektiv motsvarighet till OrderedDicts od.move_to_end(k, last=False) som flyttar nyckeln och dess associerade värde till den vänstra (första) positionen.

  • Fram till Python 3.8 saknade dict en __reversed__()-metod.

class collections.OrderedDict([items])

Returnerar en instans av en dict-underklass som har metoder specialiserade på att omorganisera ordningsföljden i ordböcker.

Tillagd i version 3.1.

popitem(last=True)

Metoden popitem() för ordnade lexikon returnerar och tar bort ett (nyckel, värde)-par. Paren returneras i LIFO ordning om last är sant eller FIFO ordning om false.

move_to_end(key, last=True)

Flytta en befintlig key till endera änden av en ordnad ordbok. Objektet flyttas till den högra änden om last är true (standard) eller till början om last är false. Utlöser KeyError om nyckeln inte finns:

>>> d = OrderedDict.fromkeys('abcde')
>>> d.move_to_end('b')
>>> ''.join(d)
'acdeb'
>>> d.move_to_end('b', last=False)
>>> ''.join(d)
'bacde'

Tillagd i version 3.2.

Förutom de vanliga mappningsmetoderna stöder ordnade lexikon även omvänd iteration med hjälp av reversed().

Likhetstester mellan OrderedDict-objekt är ordningskänsliga och motsvarar ungefär list(od1.items())==list(od2.items()).

Jämlikhetstester mellan OrderedDict-objekt och andra Mapping-objekt är okänsliga för ordning som vanliga ordböcker. Detta gör att OrderedDict-objekt kan ersättas var som helst där en vanlig ordbok används.

Ändrad i version 3.5: Objekten, nycklarna och värdena views i OrderedDict stöder nu omvänd iteration med reversed().

Ändrad i version 3.6: Med godkännandet av PEP 468, behålls ordningen för nyckelordsargument som skickas till OrderedDict-konstruktören och dess update()-metod.

Ändrad i version 3.9: Lagt till operatorer för sammanslagning (|) och uppdatering (|=), specificerade i PEP 584.

OrderedDict Exempel och recept

Det är enkelt att skapa en ordnad ordboksvariant som kommer ihåg den ordning som nycklarna senast infogades. Om en ny post skriver över en befintlig post, ändras den ursprungliga inmatningspositionen och flyttas till slutet:

class LastUpdatedOrderedDict(OrderedDict):
    "Lagra objekt i den ordning som nycklarna senast lades till

    def __setitem__(self, nyckel, värde):
        super().__setitem__(nyckel, värde)
        self.move_to_end(nyckel)

En OrderedDict skulle också vara användbar för att implementera varianter av functools.lru_cache():

from collections import OrderedDict
from time import time

class TimeBoundedLRU:
    "LRU Cache that invalidates and refreshes old entries."

    def __init__(self, func, maxsize=128, maxage=30):
        self.cache = OrderedDict()      # { args : (timestamp, result)}
        self.func = func
        self.maxsize = maxsize
        self.maxage = maxage

    def __call__(self, *args):
        if args in self.cache:
            self.cache.move_to_end(args)
            timestamp, result = self.cache[args]
            if time() - timestamp <= self.maxage:
                return result
        result = self.func(*args)
        self.cache[args] = time(), result
        if len(self.cache) > self.maxsize:
            self.cache.popitem(last=False)
        return result
klass MultiHitLRUCache:
    """ LRU-cache som väntar med att cachelagra ett resultat tills
        tills det har begärts flera gånger.

        För att undvika att LRU-cachen töms med engångsförfrågningar,
        vi inte cachelagring förrän en begäran har gjorts mer än en gång.

    """

    def __init__(self, func, maxsize=128, maxrequests=4096, cache_after=1):
        self.requests = OrderedDict() # { uncached_key : request_count }
        self.cache = OrderedDict() # { cached_key : funktion_resultat }
        self.func = func
        self.maxrequests = maxrequests # max antal icke-cachade förfrågningar
        self.maxsize = maxsize # max antal lagrade returvärden
        self.cache_after = cache_after

    def __call__(self, *args):
        om args i self.cache:
            self.cache.move_to_end(args)
            return self.cache[args]
        resultat = self.func(*args)
        self.requests[args] = self.requests.get(args, 0) + 1
        if self.requests[args] <= self.cache_after:
            self.requests.move_to_end(args)
            if len(self.requests) > self.maxrequests:
                self.requests.popitem(last=False)
        annat:
            self.requests.pop(args, None)
            self.cache[args] = resultat
            if len(self.cache) > self.maxsize:
                self.cache.popitem(last=False)
        returnera resultat

UserDict-objekt

Klassen UserDict fungerar som ett omslag runt ordboksobjekt. Behovet av denna klass har delvis ersatts av möjligheten att subklassa direkt från dict; denna klass kan dock vara lättare att arbeta med eftersom den underliggande ordboken är tillgänglig som ett attribut.

class collections.UserDict([initialdata])

Klass som simulerar en ordbok. Instansens innehåll sparas i en vanlig ordbok, som är tillgänglig via attributet data i UserDict-instanser. Om initialdata anges initialiseras data med dess innehåll; notera att en referens till initialdata inte sparas, vilket gör att den kan användas för andra ändamål.

Förutom att stödja metoder och operationer för mappningar, ger UserDict-instanser följande attribut:

data

En riktig ordbok som används för att lagra innehållet i UserDict-klassen.

UserList-objekt

Den här klassen fungerar som ett hölje runt listobjekt. Det är en användbar basklass för dina egna listliknande klasser som kan ärva från dem och åsidosätta befintliga metoder eller lägga till nya. På så sätt kan man lägga till nya beteenden i listor.

Behovet av denna klass har delvis ersatts av möjligheten att subklassa direkt från list; denna klass kan dock vara lättare att arbeta med eftersom den underliggande listan är tillgänglig som ett attribut.

class collections.UserList([list])

Klass som simulerar en lista. Instansens innehåll sparas i en vanlig lista, som är tillgänglig via attributet data i UserList-instanser. Instansens innehåll är initialt inställt på en kopia av list, med den tomma listan [] som standard. list kan vara vilken iterabel som helst, t.ex. en riktig Python-lista eller ett UserList-objekt.

Förutom att stödja metoder och operationer för muterbara sekvenser, ger UserList-instanser följande attribut:

data

Ett verkligt list-objekt som används för att lagra innehållet i UserList-klassen.

Subklassningskrav: Subklasser av UserList förväntas erbjuda en konstruktor som kan anropas med antingen inga argument eller ett argument. Listoperationer som returnerar en ny sekvens försöker skapa en instans av den faktiska implementationsklassen. För att göra detta förutsätts att konstruktören kan anropas med en enda parameter, som är ett sekvensobjekt som används som datakälla.

Om en härledd klass inte vill uppfylla detta krav måste alla specialmetoder som stöds av denna klass åsidosättas; se källorna för information om vilka metoder som måste tillhandahållas i så fall.

UserString-objekt

Klassen UserString fungerar som ett omslag runt strängobjekt. Behovet av denna klass har delvis ersatts av möjligheten att subklassa direkt från str; denna klass kan dock vara lättare att arbeta med eftersom den underliggande strängen är tillgänglig som ett attribut.

class collections.UserString(seq)

Klass som simulerar ett strängobjekt. Instansens innehåll förvaras i ett vanligt strängobjekt, som är tillgängligt via attributet data i UserString-instanser. Instansens innehåll sätts initialt till en kopia av seq. Argumentet seq kan vara vilket objekt som helst som kan konverteras till en sträng med hjälp av den inbyggda funktionen str().

Förutom att stödja metoder och operationer för strängar, ger UserString-instanser följande attribut:

data

Ett verkligt str-objekt som används för att lagra innehållet i UserString-klassen.

Ändrad i version 3.5: Nya metoder __getnewargs__, __rmod__, casefold, format_map, isprintable och maketrans.