Grunder
Den här sidan skrivs som studiematerial för mig. Fler sidor kan byggas mer utförligt.
En bra princip i Python är att arbeta i virtuella miljöer. I en virtuell miljö installeras en specifik version av Python och tillhörande paket i en kombination som kan vara unik för just den här miljön.
Aktivera virtuell miljö (Linux) via:
python3 -m venv myenv
source myenv/bin/activate
Nu ska prompten visa (myenv)$.
Paket kan nu installeras i miljön via pip, Pythons pakethanterare. Ex. pip install paketnamn. Vill man alltid ha samma version av ett paketnamn slår man paketnamn==1.1.1, då installeas alltid version 1.1.1. Slår man paketnamn>=1.0 installeras 1.0 eller högre.
Paket kan man söka efter på https://pypi.org/search.
För att stänga av miljön slå deactivate.
Bra arbetssätt är att använda en requirements.txt fil. I den filen ska alla paket man önskar använda finnas, ex:
jmespath==1.0.1
jq==1.7.0
jsonpath-ng==1.5.3
lxml==4.9.3
markdown-it-py==3.0.0
Sedan kan man installera alla paket i miljön med pip install -r requirements.txt.
Om man vill spara de paket man för tillfället har installerade i en venv kan man göra det genom pip freeze > requirements.txt.
Datatyper
Ett objekt som är mutable kan förändras och ett objekt som är immutable kan ej förändras. En variabel kan fortfarande förändras genom att tilldela om den, men datatypen kan inte modifieras.
| Namn | Typ | Mutable | Beskrivning |
| Integer | int | Nej | Hela nummer utan decimaler, ex. 6, 600 och 1589 |
| Float | Ej hela nummer, ex. 1337.1337 | ||
| Boolean | bool | Nej | Ett jämförbart värde, kan bara vara True eller False |
| String | str | Nej | Sekvens av text avgränsad av citatttecken, såsom "Cisco, "Piper" och "2000" |
| List | list | Ja | Strukterad sekvens av objekt, ex. [10, "DNA", 19.8] |
| Tuple | tup | Nej | Strukterad sekvens av immutable objects, ex. (10, "DNS", 19.8) |
| Dictionary | dict | Ja | Ostrukterad key:value pairs, ex. {"key1":"value1","name":"Pip"[} |
| Set | set | Ja | Ostrukterad samling av unika object, ex. {"a","b"} |
Variabel
En variabel är ett värde i Python som är mappad till ett Pythonobjekt som är sparat i minne. Ex. supervariabel = 1337 är då en variabel där supervariabel matchar Integer 1337.
[jehrlander@bash python]python3
Python 3.12.13 (main, Jul 10 2026, 00:00:00) [GCC 14.3.1 20251022 (Red Hat 14.3.1-4)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> supervariabel = 1337
>>> print(supervariabel)
1337
>>> type(supervariabel)
<class 'int'>
Om man istället använder supervariabel = "1337" så blir det en String och inte en Integer.
>>> supervariabel = "1337"
>>> type(supervariabel)
<class 'str'>
En integer innehåller inte decimale: har den decimaler så blir det en float.
>>> supervariabel = 1337
>>> type(supervariabel)
<class 'int'>
>>> supervariabel = 1337.1337
>>> type(supervariabel)
<class 'float'>
Listor
Python har inte arrays. I Python kan man använda sig av listor. En lista kan innehålla alla typer av dataobjekt, även andra listor.
>>> switchar = ['Sw1', 'Sw2', 'Sw3']
>>> switchar
['Sw1', 'Sw2', 'Sw3']
>>> type(switchar)
<class 'list'>
>>> routrar = ['R1', 'R2']
>>> natvarksprylar = [switchar, routrar]
>>> natvarksprylar
[['Sw1', 'Sw2', 'Sw3'], ['R1', 'R2']]
>>> type(natvarksprylar)
<class 'list'>
Listor är att föredra över tuples när ett värde kan förändras, då listor är mutable.
Tuples
Tuples är lika listor, men de är inte skrivbara (immutable). Råkar man göra såhär så blir det en tuple istället:
>>> natvarksprylar = switchar,routrar
>>> natvarksprylar (['Sw1', 'Sw2', 'Sw3'], ['R1', 'R2'])
>>> type(natvarksprylar) <class 'tuple'>
Men regeln är att för att skapa en tuple använder man parantes istället för hakparantes. Så korrekt sätt att gskapa tuple är:
>>> natvarksprylar = (switchar, routrar)
>>> type(natvarksprylar)
<class 'tuple'>
En tuple är bra och effektiv att använda när värdet aldrig förändras, då tuple är immutable.
Dictionary
En dictionary är ett till sätt att skapa en samling av värden. Dictionary används när man behöver data som är ihopkopplat med ett visst värde, key:value.
>>> R1 = { "os":"Cisco IOS-XE", "hardware":"IR1101", "location":"Mordor" }
>>> type(R1)
<class 'dict'>
>>> R1["hardware"]
'IR1101'
>>> R1["location"]
'Mordor'
Det går att lägga till en dictionary till sin redan existerande dictionary:
>>> R1["installed_date"] = {"year":"2026", "month":"07", "day":"21"}
>>> R1["installed_date"]
{'year': '2026', 'month': '07', 'day': '21'}
>>> R1
{'os': 'Cisco IOS-XE', 'hardware': 'IR1101', 'location': 'Mordor', 'installed_date': {'year': '2026', 'month': '07', 'day': '21'}}
En bra tumregel för att hålla koll på listor/tuples/dictionary är:
[]→ skapar en list{}→ skapar ett dict (eller ett set om det bara innehåller värden)()används ofta för gruppering, men kommatecknet är det som faktiskt skapar en tuple.
Sets
Sets är mutable. Man kan göra sets till frozen sets vilket gör de immutable.
>>> nummer = {1, 2, 3, 4, 5}
>>> type(nummer)
<class 'set'>
>>> udda_nummer = {1, 3, 5, 7}
# Lägg ihop två sets
>>> nummer | udda_nummer
{1, 2, 3, 4, 5, 7}
# Se vilka värden som finns i båda sets
>>> nummer & udda_nummer
{1, 3, 5}
Input och output
input() är en funktion som tar det man skriver och gör det möjligt att spara det till en variabel. Med funktionen print kan man sedan visa det i terminalen. Exempel:
>>> inpt = input('Skriv ditt namn: ')
Skriv ditt namn: Jehrlander
>>> print(inpt)
Jehrlander
>>> type(inpt)
<class 'str'>
Det som skriv ut med print-funktionen har en implicit newline character (\n) på slutet.
print-funktionen använder en separera melan element. Det kan göra att en print inte ser jättesnygg ut, ex:
>>> numbs = {1, 2, 4, 5, 6, 7, 10 }
>>> print('Numbers in set', 1, ':', numbs )
Numbers in set 1 : {1, 2, 4, 5, 6, 7, 10}
Slänger man på en sep='' (två enkelcitattecken) så tas automatiska mellanrum bort och man kan lägga till egna på ett snyggt sätt:
>>> print('Numbers in set ', 1, ': ', numbs, sep='' )
Numbers in set 1: {1, 2, 4, 5, 6, 7, 10}
Från Python3.6 och senare kan man använda sig av fstrings, vilket gör formattering och användning av print-funktionen väldigt enkel:
>>> value1 = 'Jehrlander'
>>> value2 = 1337
>>> print(f'{value1} gillar {value2} väldigt mycket')
Jehrlander gillar 1337 väldigt mycket
Indenteringar
I Python används indenteringar för att dela upp kod. I exempelvis if statemens krävs detta för att koden ska fungera. Det går att göra lite hur man vill, bara man är konsekvent, exempelvis fungerar det att bara använda ett mellanslag. Rekommendationen/best practice är att använda fyra mellanslag.
Exempel på om man glömmer indentering:
>>> n = 20
>>> if n == 20:
... print('N är 20')
File "<stdin>", line 2
print('N är 20')
^^^^^
IndentationError: expected an indented block after 'if' statement on line 1
Vilkorssatser och loopar
Eller conditional and loops. Tre primära sätt finns:
- if - värden jämförs och beslut tas därefter
- for - en räknande loop som går igenom data ett specifikt antal gånger
- while - en loop som utförs så länge vissa förhållanden nås
if
Ett if-statement börjar med if och utför en jämförelse för att se om ett förhållande är sannt eller ej. Här är ett väldigt enkelt exempel:
>>> n = 20
>>> if n == 20:
... print('N är 20.')
...
N är 20.
Det är alltså booleansk logik, True eller False.
Om siffran är annorlunda, alltså att n inte är 20, kan man använda sig av anna logik för att hantera det fallet, elif (else if).
>>> n = 3
>>> if n == 17:
... print('N är 17.')
... elif n < 10:
... print('N är under 10.')
... elif n > 10:
... print('N är över 10.')
...
N är under 10.
Och om inget matchar if eller elif kan man avsluta med else.
n = 10
if n == 17:
print('N är 17.')
elif n < 10:
print('N är under 10.')
elif n > 10:
print('N är över 10.')
else:
print('Ingen match ovan, N måste vara 10.')
Ett praktiskt exempel, i Pythonjobb med Nornir jag har byggt appliceras viss konfiguration beroende på om switchen är med i en grupp. Då har jag använt if-statements såhär för att hoppa över de switchar som ej är med i gruppen:
if "leaves" not in task.host.groups:
log_step(f"=== {task.host} === Not a leaf - not applying leaf iBGP neighbor config")
return Result(host=task.host, result="Not in 'leaves' group")
return avslutar då jobbet för de switchar som ej är med i gruppen leaves.
for
Med foor kan man skapa en loop som iterar genom koden ett specifikt antal gånger. Kan även kallas för en counting loop. Används ofta för parsning av data.
>>> data=(1, 2, 3, 4, 5)
>>> type(data)
<class 'tuple'>
>>> for variable in data:
... print(variable)
...
1
2
3
4
5
variable är då en variabel som skapas av for loopen. Om man printar variable efter att loopen är kvar är det enbart det senaste värdet kvar:
>>> print(variable)
while
Med while kan man skapa en loop som loopar så länge ett värde stämmer med definitionen, som med if. Så man kan använda ex. while True och while False.
>>> count = 1
>>> while (count < 5):
... print("Loop count is:", count)
... count = count + 1
... else:
... print("Loop is finished.")
...
Loop count is: 1
Loop count is: 2
Loop count is: 3
Loop count is: 4
Loop is finished.
Man kan använda sig av break för att ta sig ur loopen.
Funktioner
En function i Python är en samlign kod som kan ta emot någon parameter, eller ingen alls, och returnera något typ av värde tillbaks till koden som anropade funktionen. Principen är Don't Repeat Yourself, DRY, ska något utföras flera gånger ska man anropa en funktion som gör det istället för att bygga samma sak flera gånger.
I Python finns det många färdiga funktioner via standardbiblioteket.
Man kan även bygga egna. En funktion definieras genom nyckelordet def, ett namn för funktionen, paranteser för eventuell data(argument) du vill skicka med till funktionen och ett kolon. En egen funktion får ej börja med en siffra, får ej vara ett reserverat Pyton-ord (ex. print()) och får innehålla vad som helst av följande: A-Z, a-z, 0-9, understreck (_) och Bindestreck-minus (-).
Information om en funktion kan man ta fram genom help(värde). I en egen funktion, om man i raden efter def placerar information i nom 6 citattecken indenterat ex. ``` Information om funktion``` så kan man använda help() även för egna funktioner.
def notify_users(task: Task, status: str = "start") -> Result:
"""
Skickar meddelande till inloggade användare på switchen.
"""
>>> help(notify_users)
Help on function notify_users in module tasks.notify_users:
notify_users(task: nornir.core.task.Task, status: str = 'start') -> nornir.core.task.Result
Skickar meddelande till inloggade användare på switchen.
För att få information tillbaka från en funktion ska funktionen avslutas med return.
>>> def sub(arg1, arg2):
... result = arg1 - arg2
... return result
...
>>> sub(37, 13)
24
Det går även att definiera när man åkallar funktionen vilket argument som är vilket. I exemplet ovan blev det först arg1 och den andra arg2, men definierar man såhär blir det tvärtom:
>>> sub(arg2=37, arg1=13)
-24
Classes
I Python använder man classes (klass) för att beskriva objekt. En class definieraras med nyckelordet class, ett namn och avslut med ett kolon. PEP-8 (stilguide för Pyton) rekommenderar att en class inleds med en stor bokstav för att särskilja från en variabel.
Klassen beskriver vilka egenskaper (attribut) och funktioner (methods/metoder) som objekten ska ha.
En klass är väldigt användbar när man har många värden. Tänk exempelvis en samling routrar, alla bör ha samma fält men olika i värden (key:value), då är det bra med en class.
Inheritance
Om man redan har en class som utför något kan en child class ärva attribut och metoder från den första klassen. För att ärva i en klass skapas klassen som vanligt men parantes läggs till som hänvisar till den första klassen. Om den första klassen definierades med class Router: så definieras den andra med class NotRouters(Router):. Den första klassen måste komma före den andra i koden.
Moduler
En modul kan importeras i ett Pythonjobb med import. Det gäller både egenskapade och fördefinierade moduler.
Egenskapade moduler importeras såhär: from tasks.configure_macsec import configure_macsec. Tasks är då en undermapp till mappen där Pythonjobbet finns.
Fördefinierade moduler kan importeras såhär:
from nornir.core.filter import F
import time
Om man bara vill ha en del av en modul så använder man from såsom i ovan.
För att använda en fördefinierad modul så måste paketet installeras via pip, som beskrevs längre upp, gärna i en virtuell miljö. Det finns även andra pakethanterare, exempelvis uv.
När en modul är importerad kan man kontrollera alla metor i modulen med dir().
Vill man av någon anledning kan man byta namn på en modul lokalt, ex. import calendar as cal, då anropar man cal i jobbet.
Arbeta med filer i Python
Textfiler
Att arbeta med textfiler i python är lätt. Två funktioner används, open() och close(). Nedan exempel innehåller en testfil i samma mapp som koden.
>>> readdata = open("testfil.txt", "r")
>>> print(readdata.read())
Jag är en testfil!
# Tar man inte med .read() så blir det såhär
>>> print(readdata)
<_io.TextIOWrapper name='testfil.txt' mode='r' encoding='UTF-8'>
De olika flaggorna efter "testfil.txt", ex. "r", gör olika saker:
- r: Öppna för att läsa (standard)
- w: Öppna för att skriva
- x: Öppna för exklusivt skapande, misslyckas om filen redan finns
- a: Öppna för att skriva, lägger till längst ned i filen om den finns
- b: Öppna i binärt läga
t: Öppna i textläge (standard) - +: Öppna för att uppdatera (läsa och skriva)
När en fil har öppnats med open() så kan den vara låst av Python från resten av operativsystemet. Så se till att stänga den när man är klar, ex. med readdata.close().
>>> readdata.close()
>>> print(readdata.read())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.
Istället för att öppna en fil genom att tilldela en variabel kan man använda with (context manager). with innehåller bättre undantagshantering och stänger automatiskt filen när man är klar med läsning eller skrivning. Här i exemplet nedan ser vi att printningen ej fungerar när funktionen är avslutad:
>>> with open("testfil.txt", "r") as data:
... print(data.read())
...
Jag är en testfil!
>>> print(data.read())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.
Lägg till text i filen (a för append):
>>> with open("testfil.txt", "a") as data:
... data.write('\nEn till rad till testfilen!')
...
28
>>> with open("testfil.txt", "r") as data:
... print(data.read())
...
Jag är en testfil!
En till rad till testfilen!
CSV
För att läsa CSV-filer behövs först csv-modulen, skapa ett reader objekt at läsa CSV filen till, läs filen till en filhanterare, kör sedan CSV läsfunktionen och skicka resutlatet till reader-objektet.
import csv
samplefile = open('routerlist.csv')
samplereader = csv.reader(samplefile)
sampledata = list (samplereader)
sampledata
Beroende på hur CSV-filen är uppdelad kan man behöver lägga till delimiter. Är den semikolonseparerade fungerar nedan kod:
>>> with open("export_2026-07-23.csv") as routerdata:
... routerlist = csv.reader(routerdata, delimiter=";")
... for row in routerlist:
... routernamn = row[1]
... print(routernamn)
Här är ett exempel på ett skript som hittar en fil som matchar ett visst mönster i samma mapp, tar informationen från en viss rad, lägger till fqdn och printar:
from pathlib import Path
import csv
script_dir = Path(__file__).parent
for fil in script_dir.iterdir():
if fil.is_file() and "router" in fil.name:
print(f"Hittade: {fil.name}")
with open(fil, "r") as routerdata:
routerlist = csv.reader(routerdata, delimiter=";")
for row in routerlist:
routernamn=row[10]
print(routernamn, ".jehrlander.net", sep='')
break
JSON
JavaScript Object Notation (JSON) är en datastruktur som kommer från programmeringsspråket Java. Väldigt använt och ganska trevligt i mitt tycke, lätt att läsa.
Det finns en inbyggd JSON modul till python. Med den kan man konvertera JSON till listor eller dictionaries. Fyra funktioner finns för att utföra detta:
- load(): Importera JSON och kovnertera till Python dictionary.
- loads(): Importera JSON data från en string för parsning och manipulering.
- dump(): Skriv JSON data från Pythonobjekt tll en fil.
- dumps(): Ta JSON dictionary data och konvertera till en serialiserad sträng för parsning och manipulering i Python.
s:et på slutet av loads och dumps står för string, dump string.
XML
Extensible Markup Language (XML) är ett annat vanligt dataformat. Ser ut lite som HTML då det desingades för att arbeta med HTML, så start taggar (<>) och sluttaggar </> används, ex. <name>GigabitEthernet0/0/1</name>.
En modul som heter xmltodict finns som kan konvertera XML till dictionary i Python. pretty=True gör läsbarheten mycket bättre.
import xmltodict
with open ("xml_sample.xml" as data:
xml_example = data.read()
xml_dict = xmltodict.parse
print(xmltodict.unparse(xml_dict, pretty=True))
YAML
YAML Ain't Markup Language är ett format för att bygga konfigurationsfiler och spara data. YAML har en enkel läsbar syntax och struktur. En YAML-fil börjar alltid med ---.
Ex:
---
device_hostname: c9300
snmp_location: Leetland
trunk_interfaces:
- name: Port-channel1337
description: c9500 .1q lacp Te1/1/1, Te2/1/1
För att jobba med YAML behövs pyyaml-modulen. För att konvertera mellan YAML och Python används yaml.load, för att konvertera från YAML till Python, och yaml.dump för att konvertera Python till YAML.