Loggen Sie sich auf hopper ein. Erzeugen Sie ein Arbeitsverzeichnis python-project und schreiben Sie dort Ihr erstes Python-Programm:
$ touch simple.py
$ chmod +x simple.py
$ vim simple.py
Geben Sie langsam und mit korrekter Formatierung den folgenden ersten
Programmcode ein:
#!/usr/bin/python
# ein Kommentar
print("Moin")
mylist = ["moin", "tach", "hi"]
print(mylist)
for el in mylist:
if el == "moin":
print("moin moin")
else:
print(el)
Dann können Sie - wie immer - direkt aus dem vim heraus mit :!./simple.py das Programm starten.
Es lassen sich auf den ersten Blick einige Besonderheiten in Python erkennen:
Assoziative Arrays - in Python dict bzw. dictionary - sind ähnlich gut integriert wie Listen:
mydict = {"age" : 30}
mydict["name"] = "paul"
print(mydict)
Neben Listen und Dictionaries gibt es noch Tuple und Sets. Besonders Tuple sind interessant. Sie ähneln Listen, sind aber unveränderbar. Etwas eigenartig mutet an, dass ein Tuple mit einem Element dennoch ein abschließendes Komma benötigt. Bisweilen geben Funktionen Tuple zurück - dann lassen sie sich elegant in Variablen aufsplitten.
mytuple = (1,2)
singletuple = (1,)
def myfunction():
return "string", 7
s, num = myfunction()
print(s+"..."+str(num))
Sowohl Listen als auch Tuple und Strings lassen sich slicen.
lst = [1,2,3,4,5,6]
print(lst)
#[1, 2, 3, 4, 5, 6]
print(lst[2:5])
#[3, 4, 5]
Die Formatierung von Strings ist recht ausgereift (siehe: guru99). Mit der format-Methode von Strings werden Argumente angegeben, die nacheinander in die Platzhalter {} eingesetzt werden. Innerhalb des Platzhalters können Ausrichtung und Formatierungen angegeben werden.
print("|{:<10}|{:^10}|{:>10}|".format("str1","str2","str3"))
#|str1 | str2 | str3|
print("|{:10.4f}|".format(3/2))
#| 0.6667|
Noch etwas moderner sind die f-Strings (siehe:realpython):
name='paul'
num=3/2
print(f"{name} {num:.4f}")
Module werden mit import importiert - danach kann über modulname.fct() auf Funktionen des Moduls zugegriffen werden. Funktionen werden mit def function_name(): deklariert und mit function_name() aufgerufen. Mit try/except wird Exception-Handling betrieben.
#!/usr/bin/python
import signal,sys
def signal_handler(sig, frame):
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
while True:
try:
s=input()
print("["+s+"]")
except EOFError:
break
Obiges Listing entspricht dem Standardverhalten eines Unix-kompatiblen Programmes, das mit Strg-C abgebrochen werden kann und dem ein EndOfFile-Signal mit Strg-D gesandt werden kann, ohne dass auf dem Standardfehlerkanal störende Fehlermeldungen ausgegeben werden.
Dateien lassen sich recht einfach ganz lesen und schreiben.
#!/usr/bin/python
content = """das ist ein String
der über zwei Zeilen geht"""
with open('datei.txt','w') as file:
file.write(content)
with open('datei.txt','r') as file:
content = file.read()
print(content)
Besonders hier lohnt sich das with-Statement, weil damit auf initialisierten Variablen sowohl am Ende close (wenn möglich) aufgerufen wird, als auch das Exception-Handling übernommen wird.
Neben diesem typischen Pythonweg gibt es aber auch das traditionelle Line by Line Lesen - in Python gerne mit einer for-Schleife. Beachte das strip bei jeder Zeile, um das Zeilenendezeichen abzuschneiden ...
file = open('datei.txt', 'r')
print("Using for loop")
for line in file:
print(line.rstrip())
# sys.stdout.flush()
file1.close()
Das geht auch mit stdin:
import sys
for line in sys.stdin:
print(line.strip())
Hier der Server:
#!/usr/bin/python
import socket
addrinfo=socket.getaddrinfo("0.0.0.0",7000)
seso=socket.socket()
seso.bind(addrinfo[0][-1])
seso.listen()
while True:
conn, address = seso.accept()
print("connect:"+str(address))
socketfile = conn.makefile("rw")
while True:
line = socketfile.readline()
if not line:
break
line=line.rstrip("\n")
print(line)
socketfile.write(f"[{line}]\n")
#darf in micropython nicht aufgerufen werden
socketfile.flush()
socketfile.close()
conn.close()
Und hier der passende Client:
#!/usr/bin/python
import socket
addrinfo=socket.getaddrinfo("localhost",7000)
sock=socket.socket()
sock.connect(addrinfo[0][-1])
socketfile = sock.makefile("rw")
print("connected")
for i in range(3):
socketfile.write(f"message {i}\n")
#darf in micropython nicht aufgerufen werden
socketfile.flush()
line = socketfile.readline().rstrip("\n")
if not line:
break
print("got:"+line)
Das json-Modul bietet Möglichkeiten, aus Python-Strukturen mit dumps ein json-Objekt zu erzeugen oder mit loads umgekehrt aus einem String eine Python-Struktur zu erzeugen. Mit load und dump lässt sich direkt mit Dateien arbeiten.
#!/usr/bin/python
obj={
"name" : "raspberry",
"type" : "fruit"
}
print(obj)
jsonstr = json.dumps(obj)
print(jsonstr)
print(json.loads(jsonstr)["name"])
with open('config.json') as f:
config = json.load(f)
with open('config.json', 'w') as f:
json.dump(config, f)
Mit requests lassen sich recht einfach http-Requests durchführen.
#!/usr/bin/python
import requests
r = requests.get('https://informatik.hs-bremerhaven.de/oradfelder/demo.txt')
print(r.status_code)
print(r.text)
Mit multiprocessing können mehrere Prozesse von Python aus koordiniert werden:
#!/usr/bin/python
import multiprocessing
import os
import time
def task(sleeptime):
for i in range(1,10):
time.sleep(sleeptime)
print(f"this is in ... {os.getpid()} ")
process = multiprocessing.Process(target=task,args=(0.0002,))
process.start()
for i in range(1,10):
time.sleep(0.002)
print(f"this is in ... {os.getpid()} ")
process.join()
#!/usr/bin/python
import os
print(os.getpid())
print(os.getcwd())
print(os.listdir())
os.chdir("/tmp")
os.mkdir("mytmp")
os.rename('mytmp','mytemp')
os.rmdir("mytemp")
Mit csv ist der Zugriff auf csv-Dateien möglich:
#!/usr/bin/python
import csv
with open('names.txt') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for row in csv_reader:
print(f'{row[0]} - {row[1]}.')
with open('newnames.csv', mode='w') as csv_file:
writer = csv.writer(csv_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
writer.writerow(['Peter', 'November'])
writer.writerow(['Erica', 'March'])
In Python findet sich das Schlüsselword yield recht häufig. Generatoren sind Funktionen, die als Iteratoren dienen. Bei jedem yield wird die Ausführung angehalten bis zum nächsten Aufruf der Funktion next(gen). Wenn der Generator in einer for-Schleife genutzt wird, wird next implizit aufgerufen.
def square_gen(n):
num = 0
while num < n:
num +=1
yield(num*num)
for i in square_gen(100):
print(i)
Häufig sieht man so etwas mit Funktionen, die ein Iterable erwarten - so wie z.B. sum():
def firstn(n):
num = 0
while num < n:
yield num
num += 1
thesum = sum(firstn(1000000))
print(thesum)
Die Funktion map erwartet eine Funktion und ein Iterable und wendet die Funktion auf jedes Element an und liefert einen Map-Iterator zurück.
prices = [1.09, 23.56, 57.84, 4.56, 6.78]
def get_price_with_tax(price):
return price * (1.21)
final_prices = map(get_price_with_tax, prices)
Als List Comprehension formuliert sieht es wie folgt aus:
squares = [price * 1.21 for price in prices]
Es gibt auch Set und Map Comprehensions:
elements=[2,4,5,7,2]
{e for e in elements}
{n:n*n for n in range(10)}
Python hat einiges aus der funktionalen Programmierung übernommen. In diesem Sinne können Funktionen an Funktionen als Argumente übergeben werden:
def mydecorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
def my_code():
print("my code!")
my_code = mydecorator(my_code)
@mydecorator
def sugar():
print("syntactic sugar")
Mit virtuellen Umgebungen lassen sich weitere Module lokal in einzelnen Projekten installieren. Dafür muss mit dem Modul venv ein Projekt angelegt werden und das Helfer-Script bin/activate jedes Mal aufgerufen werden, wenn man in dem Projekt arbeiten will. Zum Beenden ruft man deactive auf.
python -m venv myproject/venv
cd myproject
source venv/bin/activate
pip install scipy
...
deactivate
Dadurch, dass python nun im Unterverzeichnis venv (oder oft auch .venv) installiert ist, verliert der Prompt seine spezifische Bedeutung. Es lässt sich aber ein spezifischer Prompt angeben. Zudem möchte man insbesondere möglicherweise die aktuellste pip-Version:
python -m venv ~/mynewproject/venv --upgrade-deps --prompt=mynew
Denkt daran, das Verzeichnis venv in .gitignore aufzunehmen und gegebenenfalls mit pip freeze > requirements.txt jeweils dafür zu sorgen, dass die Umgebung von allen auf den je aktuellen Stand gebracht werden kann.
Anaconda und miniconda sind alternative Umgebungen, die nicht projektspezifisch sind. Anaconda ist ausgesprochen groß und eher nicht zu empfehlen. Miniconda hingegen könnte als Alternative eine Rolle spielen: miniconda getting startet.
Das Modul mariadb muss beispielsweise zunächst installiert werden, was am Besten innerhalb einer virtuellen Umgebung geschieht:
pip install mariadb
Dann lässt sich die Datenbankverbindung wie in anderen Programmiersprachen öffnen und mit einem Cursor über eine Ergebnismenge iterieren:
#!/usr/bin/python
import mariadb
import sys
try:
conn = mariadb.connect(
user="demo",
password="daspasswortinmycnf",
host="mysql-server",
port=3306,
database="demo_db",
autocommit=True
)
except mariadb.Error as e:
print(f"Error connecting to MariaDB: {e}")
sys.exit(1)
cur = conn.cursor()
cur.execute("INSERT INTO demo (name) VALUES (?)", ("karin",))
cur.execute(
"SELECT * FROM demo WHERE id > ? or name=?",
(1,"ulrike"))
for (id,name) in cur:
print(f"id: {id}, name: {name}")
conn.close()
Anleitung auf mariadb.com. Für die Anbindung an PostgreSQL ist der übliche Datenbanktreiber psycopg2.
Mit fcntl lassen sich ähnlich wie in C (flock) und in der Bash (flock) kompatible Locks erzeugen:
import os
import fcntl
import time
def acquire(lock_file):
open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC
fd = os.open(lock_file, open_mode)
fcntl.flock(fd, fcntl.LOCK_EX)
return fd
def release(lock_file_fd):
fcntl.flock(lock_file_fd, fcntl.LOCK_UN)
os.close(lock_file_fd)
return None
def main():
fd = acquire('myfile.lock')
if fd is None:
print(f'ERROR: {pid} lock NOT acquired')
return -1
print(f'acquired')
time.sleep(1.0)
release(fd)
print(f"lock released")
if __name__ == '__main__':
main()
Pandas sind die Grundlage für viele Operationen auf csv-artigen Daten ...
Das Modul redis muss ebenfalls installiert werden:
pip install redis
Dann lässt sich mit redis wie üblich arbeiten:
#!/usr/bin/python
import redis
rconn = redis.Redis(host='localhost', port=6379, decode_responses=True)
rconn.auth("daspasswortinmycnf")
rconn.set("foo","pythonbar")
print(rconn.get("foo"))
rconn.close()
Anleitung auf redis.io.
Mit PyInstaller lassen sich auf der jeweiligen Plattform ausführbare Binaries erstellen:
pip install -U pyinstaller
pyinstaller myprogram.py
Anleitung auf https://pyinstaller.org/.
Mit dem Modul websocket lässt sich zunächst ein recht einfacher Websocket-Client erzeugen:
import sys
import websocket
#websocket.enableTrace(True)
ws = websocket.WebSocket()
ws.connect("wss://informatik.hs-bremerhaven.de/docker-oradfelder-ws/")
for i in range(10000):
ws.send("moin"+str(i))
print(ws.recv())
sys.stdout.flush()
ws.close()
Hingegen ist ein vernünftiger Websocket-Server nur sinnvoll mit asyncio zu realisieren:
import asyncio
import websockets
async def echo(websocket):
async for message in websocket:
# print(message)
await websocket.send(message)
async def main():
async with websockets.serve(echo, "0.0.0.0", 7000):
# run forever
await asyncio.Future()
asyncio.run(main())
Mit playwright lassen sich Web-basierte automatische Tests erstellen:
python -m venv pyplay
cd pyplay
source bin/activate
pip install playwright
playwright install
echo '
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("http://playwright.dev")
print(page.title())
browser.close()
' > demo.py
python demo.py
Anleitung auf https://playwright.dev/python/docs/library.
from machine import Pin
led = Pin(2,Pin.OUT)
led.value(1)
import network
ssid="..."
password="..."
station=network.WLAN(network.STA_IF)
station.active(True)
station.connect(ssid,password)
while station.isconnected() == False:
pass
Flask ist ein kleines Web-Framework. Zunächst ist Flask eine WSGI-Anwendung:
from flask import Flask
app = Flask(__name__)
@app.route("/docker-oradfelder-http/")
def hello_world():
return "Hello, World!
"
Flask beinhaltet einen kleinen Entwicklungsserver:
flask --app hello run --host=0.0.0.0 --port=4000
gunicorn ist ein produktiver WSGI-Server:
from flask import Flask, session
app = Flask(__name__)
app.secret_key = "abc"
@app.route('/docker-oradfelder-http/')
def index():
session['response']='session#1'
return 'Application Deployed!
\n'
@app.route('/docker-oradfelder-http/get')
def getVariable():
if 'response' in session:
s = session['response'];
return f"{s}"
else:
return f"get\n"
if __name__ == '__main__':
app.run(debug=False)
gunicorn -D -p ~/var/gunicorn.pid -b 0.0.0.0:4000 -w 8 application:app
WSGI-Server sind synchron arbeitende Http-Server. Etwas moderner - da asynchron mit asyncio umgesetzt - sind ASGI-Server wie uvicorn, FastAPI, Starlette oder Quart.