Zephyrnet-logo

Python-gegevensstructuren vergeleken

Datum:

Python-gegevensstructuren vergeleken

Laten we eens kijken naar 5 verschillende Python-gegevensstructuren en zien hoe ze kunnen worden gebruikt om gegevens op te slaan die we in onze dagelijkse taken kunnen verwerken, evenals het relatieve geheugen dat ze gebruiken voor opslag en de tijd die ze nodig hebben om te creëren en toegang te krijgen.


Figuur
Foto door Hitesh Choudhary on Unsplash

 

Het kiezen van een structuur voor het opslaan van uw gegevens is een belangrijk onderdeel van het oplossen van programmeertaken en het implementeren van oplossingen, maar het krijgt vaak niet de aandacht die een keuze met een dergelijk potentieel gewicht verdient. Helaas zie ik in Python vaak dat de lijst wordt gebruikt als een allesomvattende datastructuur. De lijst heeft natuurlijk zijn voordelen, maar ook zijn nadelen. Er zijn ook tal van andere gegevensstructuuropties.

Laten we eens kijken naar 5 verschillende Python-gegevensstructuren en zien hoe ze kunnen worden gebruikt om gegevens op te slaan die we in onze dagelijkse taken kunnen verwerken, evenals het relatieve geheugen dat ze gebruiken voor opslag en de tijd die ze nodig hebben om te creëren en toegang te krijgen.

Soorten gegevensstructuren

 
Laten we eerst de 5 gegevensstructuren uiteenzetten die we hierin zullen beschouwen, en wat voorlopig inzicht geven.

 
Klasse

In dit geval hebben we het over vanilleklassen (in tegenstelling tot onderstaande dataklassen), die op hoog niveau worden beschreven in Python documentatie als volgt:

Klassen bieden een manier om data en functionaliteit te bundelen. Door een nieuwe klas aan te maken, wordt een nieuwe type dan: van object, waardoor nieuwe gevallen van dat type te maken. Aan elke klasse-instantie kunnen attributen worden gekoppeld om de status ervan te behouden. Klasse-instanties kunnen ook methoden hebben (gedefinieerd door de klasse) om de status ervan te wijzigen.

De voordelen van het gebruik van klassen is dat ze conventioneel zijn en goed worden gebruikt en begrepen. Of ze al dan niet overdreven zijn in termen van relatief vereist geheugen of tijd, is iets om naar te kijken.

 
Gegevensklasse

Toegevoegd in Python 3.7, de data klasse is een speciale klasse die voornamelijk bedoeld is voor het bewaren van gegevens, die standaard wordt geleverd met enkele freebie-methoden voor typische functionaliteit zoals het instantiëren en afdrukken van instantie-inhoud. Het maken van een gegevensklasse wordt bereikt met behulp van de @dataclass decorateur.

Hoewel ze een heel ander mechanisme gebruiken, kunnen gegevensklassen worden gezien als "veranderlijke benoemdetupels met standaardwaarden". Omdat gegevensklassen de normale syntaxis van klassendefinities gebruiken, staat het u vrij om overerving, metaklassen, docstrings, door de gebruiker gedefinieerde methoden, klassenfabrieken en andere Python-klassefuncties te gebruiken. Zo'n klasse wordt een Data Class genoemd, maar er is eigenlijk niets bijzonders aan de klasse: de decorateur voegt gegenereerde methoden toe aan de klasse en retourneert dezelfde klasse die hij heeft gekregen.

Zoals u kunt zien, de automatisch gegenereerde methoden en de daarmee samenhangende tijdsbesparing zijn de belangrijkste reden om dataklassen te overwegen.

 
genaamd Tuple Tu

Genoemde tupels zijn een elegante uitvoering van een nuttige gegevensstructuur, in wezen tuple-subklassen met benoemde velden.

Benoemde tupels geven betekenis aan elke positie in een tupel en zorgen voor een beter leesbare, zelfdocumenterende code. Ze kunnen overal worden gebruikt waar gewone tuples worden gebruikt, en ze voegen de mogelijkheid toe om velden op naam te openen in plaats van op positie-index.

Op het eerste gezicht lijken benoemde tupels het dichtst bij eenvoudige C-achtige structtypen die native beschikbaar zijn in Python, waardoor ze voor velen naïef aantrekkelijk zijn.

 
Woordenboek

De Python woordenboek is een verzameling sleutel-waardeparen.

Woordenboeken zijn veranderlijke ongeordende verzamelingen (ze registreren geen elementpositie of volgorde van invoeging) van sleutel-waardeparen. Sleutels in het woordenboek moeten uniek zijn en hashbaar zijn. Dat omvat typen zoals getallen, strings en tupels. Lijsten en dictaten kunnen niet als sleutels worden gebruikt omdat ze veranderlijk zijn.

Het voordeel van woordenboeken is dat ze eenvoudig zijn, de gegevens erin gemakkelijk toegankelijk zijn en dat ze goed worden gebruikt en begrepen.

 
Lijst

Hier is het, de one-size-fits-all Python-gegevenssuperstructuur, of zo veel code wil je doen geloven. Hier is wat de lijst echt is:

Lijsten zijn veranderlijke geordende en geïndexeerde verzamelingen van objecten. De items van een lijst zijn willekeurige Python-objecten. Lijsten worden gevormd door een door komma's gescheiden lijst van uitdrukkingen tussen vierkante haken te plaatsen.

Waarom het wijdverbreide gebruik van de lijst? Het is heel eenvoudig te begrijpen en te implementeren, en is meestal de eerste structuur die je leert wanneer je Python oppakt. Zijn er nadelen aan snelheid en geheugengebruik? Laten we kijken.

implementaties

 
Laten we eerst eens kijken naar het creatieproces van elk van deze structuren en hoe ze zich tot elkaar verhouden.

De reden waarom we een van deze gegevensstructuren zouden kunnen gebruiken om onze gegevens op te slaan, zou sterk kunnen verschillen, maar voor de fantasieloze, laten we ons voorstellen dat we gegevens uit een SQL-database halen en elk record in een dergelijke structuur moeten opslaan om enige verwerking uit te voeren voordat we de gegevens verder in onze pijplijn verplaatsen.

Met dat in gedachten is hier de instantiecode voor het maken van elk van de vijf structuren.

""" class """ class CustomerClass: def __init__(self, cust_num:str, f_name:str, l_name:str, address:str, city:str, state:str, phone:str, age:int): self. cust_num = cust_num self.f_name = f_name self.l_name = l_name self.address = adres self.city = stad self.state = staat self.phone = phone self.age = leeftijd def to_string(self): return(f'{self .cust_num}, {self.f_name}, {self.l_name}, {self.age}, {self.address}, {self.city}, {self.state}, {self.phone}'stgrcutures) "" " data class """ van dataclasses import dataclass @dataclass class CustomerDataClass: cust_num: int f_name: str l_name: str adres: str stad: str staat: str telefoon: str age: int """ genaamd tuple """ van collecties import namedtuple CustomerNamedTuple = namedtuple('CustomerNamedTuple', 'cust_num f_name l_name adres stad staat telefoon leeftijd') """ dict """ def make_customer_dict(cust_num: int, f_name: str, l_name: str, adres: str, stad: str, staat: str, telefoon: str, leeftijd: int): return {'cust_num': cust_num, 'f_name': f_name, 'l_na me': l_name, 'address': address, 'city': city, 'state': state, 'phone': phone, 'age': age} """ list """ def make_customer_list(cust_num: int, f_name : str, l_name: str, adres: str, stad: str, staat: str, telefoon: str, leeftijd: int): return [cust_num, f_name, l_name, adres, stad, staat, telefoon, leeftijd]


Let op het volgende:

  • Het maken van een instantie van het ingebouwde typenwoordenboek en de lijst zijn in functies geplaatst
  • Het verschil tussen de klasse- en de dataklasse-implementaties, in het licht van de bovenstaande discussie
  • De (duidelijk subjectieve) elegantie en eenvoud van de genoemde tuple

Laten we eens kijken naar de oprichting van deze structuren en een vergelijking van de middelen die nodig zijn om dit te doen.

Testen en resultaten

 
We zullen een enkele instantie van elk van de 5 structuren maken, elk met een enkel gegevensrecord. We zullen dit proces herhalen met dezelfde gegevensvelden voor elke structuur 1,000,000 keer om een ​​beter idee te krijgen van de gemiddelde tijd, door dit proces uit te voeren op mijn bescheiden Dell-notebook, met behulp van een van Ubuntu afgeleid besturingssysteem.

Beeld

Vergelijk de code tussen de 5 structuurinstanties hieronder.

""" instantiëren van structuren """ van sys import getsizeof import time # class customer_1 = CustomerClass('EP90210', 'Edward', 'Perez', '123 Fake Street', 'Cityville', 'TX', '888-456 -1234', 56) print(f'Data: {customer_1.to_string()}') print(f'Type: {type(customer_1)}') print(f'Size: {getsizeof(customer_1)} bytes') t0 = time.time() for i in range(1000000): customer = CustomerClass('EP90210', 'Edward', 'Perez', '123 Fake Street', 'Cityville', 'TX', '888-456- 1234', 56) t1 = time.time() print('Time: {:.3f}sn'.format(t1-t0)) # data class customer_2 = CustomerDataClass('EP90210', 'Edward', 'Perez' , '123 Fake Street', 'Cityville', 'TX', '888-456-1234', 56) print(f'Data: {customer_2}') print(f'Type: {type(customer_2)}') print(f'Size: {getsizeof(customer_2)} bytes') t0 = time.time() for i in range(1000000): customer = CustomerDataClass('EP90210', 'Edward', 'Perez', '123 Fake Street ', 'Cityville', 'TX', '888-456-1234', 56) t1 = time.time() print('Time: {:.3f}sn'.format(t1-t0)) # genaamd tuple cust omer_3 = CustomerNamedTuple('EP90210', 'Edward', 'Perez', '123 Fake Street', 'Cityville', 'TX', '888-456-1234', 56) print(f'Data: {customer_3}' ) print(f'Type: {type(customer_3)}') print(f'Size: {getsizeof(customer_3)} bytes') t0 = time.time() for i in range(1000000): customer = CustomerNamedTuple(' EP90210', 'Edward', 'Perez', '123 Fake Street', 'Cityville', 'TX', '888-456-1234', 56) t1 = time.time() print('Time: {:. 3f}sn'.format(t1-t0)) # dict customer_4 = make_customer_dict('EP90210', 'Edward', 'Perez', '123 Fake Street', 'Cityville', 'TX', '888-456-1234 ', 56) print(f'Data: {customer_4}') print(f'Type: {type(customer_4)}') print(f'Size: {getsizeof(customer_4)} bytes') t0 = time.time( ) voor i binnen bereik (1000000): klant = make_customer_dict('EP90210', 'Edward', 'Perez', '123 Fake Street', 'Cityville', 'TX', '888-456-1234', 56) t1 = time.time() print('Time: {:.3f}sn'.format(t1-t0)) # list customer_5 = make_customer_list('EP90210', 'Edward', 'Perez', '123 Fake Street', 'Cityville', 'TX', '888-456-1234', 56) print(f'Data: {customer_5}') print(f'Type: {type(customer_5)}') print(f'Size: {getsizeof(customer_5)} bytes') t0 = time.time() for i in range(1000000): customer = make_customer_list('EP90210', 'Edward', 'Perez', '123 Fake Street', 'Cityville', 'TX', '888-456- 1234', 56) t1 = tijd.tijd() print('Tijd: {:.3f}sn'.format(t1-t0))


En hier is de output van het bovenstaande:

Gegevens: EP90210, Edward, Perez, 56, 123 Fake Street, Cityville, TX, 888-456-1234 Type: Grootte: 56 bytes Tijd: 0.657s Gegevens: CustomerDataClass(cust_num='EP90210', f_name='Edward', l_name='Perez', address='123 Fake Street', city='Cityville', state='TX', telefoon='888-456-1234', leeftijd=56) Type: Grootte: 56 bytes Tijd: 0.630s Gegevens: CustomerNamedTuple(cust_num='EP90210', f_name='Edward', l_name='Perez', address='123 Fake Street', city='Cityville', state='TX', telefoon='888-456-1234', leeftijd=56) Type: Grootte: 112 bytes Tijd: 0.447s Gegevens: {'cust_num': 'EP90210', 'f_name': 'Edward', 'l_name': 'Perez', 'address': '123 Fake Street', 'city': ' Cityville', 'staat': 'TX', 'telefoon': '888-456-1234', 'leeftijd': 56} Type: Grootte: 368 bytes Tijd: 0.318s Gegevens: ['EP90210', 'Edward', 'Perez', '123 Fake Street', 'Cityville', 'TX', '888-456-1234', 56] Type: Grootte: 128 bytes Tijd: 0.184s


Ten slotte zou een ander nuttig gegeven zijn om de relatieve toegangstijden te kennen van waarden die zijn opgeslagen in onze structuren (in het onderstaande geval het adres). Hetzelfde ophalen wordt 1,000,000 keer herhaald, en de gemiddelde tijd wordt hieronder vermeld.

""" toegang tot een element """ # class t0 = time.time() for i in range(1000000): address = customer_1.address t1 = time.time() print(f'Type: {type(customer_1)} ') print('Time: {:.3f}sn'.format(t1-t0)) # data class t0 = time.time() for i in range(1000000): address = customer_2.address t1 = time.time () print(f'Type: {type(customer_2)}') print('Time: {:.3f}sn'.format(t1-t0)) # genaamd tuple t0 = time.time() voor i binnen bereik (1000000): adres = klant_3.adres t1 = tijd.tijd() print(f'Type: {type(klant_3)}') print('Tijd: {:.3f}sn'.format(t1-t0)) # woordenboek t0 = time.time() for i in range(1000000): address = customer_4['address'] t1 = time.time() print(f'Type: {type(customer_4)}') print('Time : {:.3f}sn'.format(t1-t0)) # list t0 = time.time() for i in range(1000000): adres = klant_5[3] t1 = time.time() print(f' Type: {type(klant_5)}') print('Tijd: {:.3f}sn'.format(t1-t0))


En de output:

Type: Tijd: 0.098s Type: Tijd: 0.092s Type: Tijd: 0.134s Type: Tijd: 0.095s Type: Tijd: 0.117s


De bedoeling van dit artikel is niet om op de een of andere manier een aanbeveling te doen over de te gebruiken datastructuur, en evenmin om te suggereren dat er voor elk geval een universele beste structuur is. In plaats daarvan wilden we een aantal verschillende opties bekijken en hun relatieve sterkte en zwakte. Zoals met alle dingen, moeten er afwegingen worden gemaakt en moeten minder kwantitatieve overwegingen zoals begrijpelijkheid, gebruiksgemak, enz. In aanmerking worden genomen bij het nemen van dit soort beslissingen.

Dat gezegd hebbende, vallen een paar dingen op uit de bovenstaande analyse:

  1. Het woordenboek gebruikt de grootste hoeveelheid opslag van alle structuren, in ons geval bijna 3 keer zoveel als de volgende grootste - hoewel we voorzichtig moeten zijn met generaliseren totdat we kijken naar de effecten van schalen en interne veldgegevenstypen
  2. Het is niet verwonderlijk dat de lijst het snelst kan worden geïnstantieerd, maar niet de snelste om een ​​element op te halen (het is bijna het langzaamste)
  3. In ons geval is de genoemde tuple de langzaamste structuur om een ​​element uit te halen, maar is het midden in het pakket voor opslagruimte
  4. Beide klassen hebben relatief meer tijd nodig om te instantiëren (verwacht), maar het ophalen van elementen en de gebruikte ruimte zijn in beide gevallen zeer concurrerend met de andere structuren

Dus niet alleen willen we niet in alle gevallen een enkele structuur aanbevelen, er is geen duidelijke winnaar die in alle gevallen kan worden aanbevolen. Zelfs met de voorzichtigheid om te generaliseren op basis van ons kleine experiment, is het duidelijk dat er rekening moet worden gehouden met prioriteiten bij het nemen van een beslissing over welke structuur u voor een bepaalde taak gebruikt. Deze beperkte experimenten hebben op zijn minst enig inzicht gegeven in de prestaties van datastructuren die beschikbaar zijn in Python.

 
Verwant:


PlatoAi. Web3 opnieuw uitgevonden. Gegevensintelligentie versterkt.
Klik hier om toegang te krijgen.

Bron: https://www.kdnuggets.com/2021/07/python-data-structures-compared.html

spot_img

Laatste intelligentie

spot_img