Wikibooks
dewikibooks
https://de.wikibooks.org/wiki/Hauptseite
MediaWiki 1.47.0-wmf.22
first-letter
Medium
Spezial
Diskussion
Benutzer
Benutzer Diskussion
Wikibooks
Wikibooks Diskussion
Datei
Datei Diskussion
MediaWiki
MediaWiki Diskussion
Vorlage
Vorlage Diskussion
Hilfe
Hilfe Diskussion
Kategorie
Kategorie Diskussion
Regal
Regal Diskussion
TimedText
TimedText talk
Modul
Modul Diskussion
Veranstaltung
Veranstaltung Diskussion
Traktorenlexikon: Allis-Chalmers
0
7000
1091895
1090739
2026-10-03T17:41:57Z
Baupit
56622
/* Serie 7000 */
1091895
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation}}
Die 1901 gegründete Firma '''Allis-Chalmers''' hatte ihren Sitz in Milwaukee, USA.
==Geschichte==
1912 wurde der erste Benzintraktor vorgestellt.
In den 1920er Jahren kaufte Allis-Chalmers mehrere andere Firmen auf, u.a. auch Monarch Tractor.
1955 bot Allis Chalmers den ersten Radschlepper mit Dieselmotor an (Raupenschlepper gab es schon früher mit Dieselmotor). Im gleichen Jahr wurde auch die Firma Gleaner Harvester gekauft.
1960 kaufte man den französischen Traktorenhersteller [[Traktorenlexikon:_Vendeuvre|Vendeuvre]] auf.
1969 bis in die Mitte der 70er Jahre arbeitete [[Traktorenlexikon:_Renault|Renault]] mit diesem amerikanischen Hersteller zusammen.
1985 wurde Allis Chalmers von [[Traktorenlexikon: Deutz|Deutz]] übernommen, die Produktion der Allis-Chalmers-Traktoren wurden im gleichen Jahr beendet. Der neue Markenname war [[Traktorenlexikon: Deutz-Allis|Deutz-Allis]].
1990 übernahm der [[Traktorenlexikon: AGCO|AGCO-Corporation-Konzern]], einer der weltweit größten Anbieter von Traktoren und Landmaschinen, den Bereich Deutz-Allis von Kloeckner-Humboldt-Deutz. Es entstand nun die Traktorenmarke [[Traktorenlexikon: AGCO-Allis|AGCO-Allis]].
==Typen==
[[Datei:Allis Chalmers GDO 569-at Driffield-P8100559.JPG|thumb|[[Traktorenlexikon: Allis-Chalmers B|Allis-Chalmers B]]]]
Es wurden Schlepper mit folgenden Typenbezeichnungen vertrieben (''die Liste ist noch unvollständig''):
===1914 - 1926===
{{:Traktorenlexikon:_Create|Modell 10-18}}
{{:Traktorenlexikon:_Create|Modell 6-12}}
===Modell - E===
{{:Traktorenlexikon:_Create|Modell 15-30/18-30}}
{{:Traktorenlexikon:_Create|Modell 20-35}}
{{:Traktorenlexikon:_Create|Modell 25-40}}
===Modell - L===
{{:Traktorenlexikon:_Create|Modell L (12-20/15-25)}}
===Allis-Chalmers-Rumely===
{{:Traktorenlexikon:_Create|Modell DoAll}}
{{:Traktorenlexikon:_Create|Modell 6 A}}
===Letters-Serie===
{{:Traktorenlexikon:_Create|Modell U}}
{{:Traktorenlexikon:_Create|Modell UC}}
{{:Traktorenlexikon:_Create|Modell A}}
{{:Traktorenlexikon:_Create|Modell B}}
{{:Traktorenlexikon:_Create|Modell RC}}
{{:Traktorenlexikon:_Create|Modell C}}
{{:Traktorenlexikon:_Create|Modell CA}}
===W-Serie===
[[Datei:Allis-Chalmers WD45.jpg|thumb|Allis-Chalmers WD 45]]
{{:Traktorenlexikon:_Create|WC}}
{{:Traktorenlexikon:_Create|WD}}
{{:Traktorenlexikon:_Create|WD 45}}
{{:Traktorenlexikon:_Create|WF}}
===Baureihe-D===
[[Datei:Allis-Chalmers D21 series II tractor.jpg|thumb|Allis-Chalmers D 21]]
{{:Traktorenlexikon:_Create|D 10}}
{{:Traktorenlexikon:_Create|D 12}}
{{:Traktorenlexikon:_Create|D 14}}
{{:Traktorenlexikon:_Create|D 15}}
{{:Traktorenlexikon:_Create|D 17}}
{{:Traktorenlexikon:_Create|D 19}}
{{:Traktorenlexikon:_Create|D 21}}
===Englische Modelle===
{{:Traktorenlexikon:_Create|D 270}}
{{:Traktorenlexikon:_Create|D 272}}
[[Datei:Allis-Chalmers ED-40.jpg|thumb|Allis-Chalmers ED 40]]
{{:Traktorenlexikon:_Create|ED 40}}
===Allis-Chalmers/Vendeuvre===
{{:Traktorenlexikon:_Create|FD 3}}
{{:Traktorenlexikon:_Create|FD 4}}
{{:Traktorenlexikon:_Create|FD 5}}
===G===
{{:Traktorenlexikon:_Create|G}}
===Raupenschlepper===
[[Datei:A DEMONSTRATION OF A TRACTOR FOR STUDENTS OF THE RUPPIN AGRICULTURAL TRAINING CENTER. מכללת רופין לחקלאות. בצילום, סטודנטים לומדים כיצד לתפעל טרקטור שD592-079.jpg|thumb|Allis-Chalmers HD 5]]
{{:Traktorenlexikon:_Create|WK}}
{{:Traktorenlexikon:_Create|WS}}
{{:Traktorenlexikon:_Create|HD 3}}
{{:Traktorenlexikon:_Create|HD 5 B}}
{{:Traktorenlexikon:_Create|HD 6}}
{{:Traktorenlexikon:_Create|HD 7 W}}
{{:Traktorenlexikon:_Create|HD 9}}
{{:Traktorenlexikon:_Create|HD 10 W}}
{{:Traktorenlexikon:_Create|HD 11}}
{{:Traktorenlexikon:_Create|HD 14}}
{{:Traktorenlexikon:_Create|HD 15}}
{{:Traktorenlexikon:_Create|HD 16}}
{{:Traktorenlexikon:_Create|HD 19}}
{{:Traktorenlexikon:_Create|HD 20}}
{{:Traktorenlexikon:_Create|HD 21}}
===100er-Serie===
[[Datei:Allis-Chalmers 190 XT.jpg|thumb|Allis-Chalmers 190 XT]]
{{:Traktorenlexikon:_Create|160}}
{{:Traktorenlexikon:_Create|170}}
{{:Traktorenlexikon:_Create|175}}
{{:Traktorenlexikon:_Create|180}}
{{:Traktorenlexikon:_Create|185}}
{{:Traktorenlexikon:_Create|190}}
{{:Traktorenlexikon:_Create|190XT}}
{{:Traktorenlexikon:_Create|200}}
{{:Traktorenlexikon:_Create|210}}
{{:Traktorenlexikon:_Create|220}}
===Serie 4-WD===
[[Datei:AC 4W-305 4WD.jpg|thumb|Allis-Chalmers 4W-305]]
{{:Traktorenlexikon:_Create|440}}
{{:Traktorenlexikon:_Create|7580}}
{{:Traktorenlexikon:_Create|8550}}
{{:Traktorenlexikon:_Create|4-W 220}}
{{:Traktorenlexikon:_Create|4-W 305}}
===Serie 5000===
{{:Traktorenlexikon:_Create|5015}}
{{:Traktorenlexikon:_Create|5020}}
{{:Traktorenlexikon:_Create|5030}}
{{:Traktorenlexikon:_Create|5040}}
{{:Traktorenlexikon:_Create|5045}}
{{:Traktorenlexikon:_Create|5050}}
===Serie 6000===
{{:Traktorenlexikon:_Create|6040}}
{{:Traktorenlexikon:_Create|6060}}
{{:Traktorenlexikon:_Create|6070}}
{{:Traktorenlexikon:_Create|6080}}
{{:Traktorenlexikon:_Create|6140}}
===Serie 7000===
[[Datei:Allis-Chalmers 7030.jpg|thumb|Allis-Chalmers 7030]]
{{:Traktorenlexikon:_Create|7000}}
{{:Traktorenlexikon:_Create|7010}}
{{:Traktorenlexikon:_Create|7020}}
{{:Traktorenlexikon:_Create|7030}}
{{:Traktorenlexikon:_Create|7040}}
{{:Traktorenlexikon:_Create|7045}}
{{:Traktorenlexikon:_Create|7050}}
{{:Traktorenlexikon:_Create|7060}}
{{:Traktorenlexikon:_Create|7080}}
===Serie 8000===
{{:Traktorenlexikon:_Create|8010}}
{{:Traktorenlexikon:_Create|8030}}
{{:Traktorenlexikon:_Create|8050}}
{{:Traktorenlexikon:_Create|8070}}
== Weblinks ==
{{Commons|Category:Allis-Chalmers tractors|Allis-Chalmers-Traktoren}}
{{Wikipedia1|Allis-Chalmers}}
* [http://www.allischalmers.com www.allischalmers.com]
* [http://www.agcocorp.com www.agcocorp.com]
* http://www.tractordata.com/farm-tractors/tractor-brands/allischalmers/allischalmers-tractors.html
{{:Traktorenlexikon: Navigation}}
hw6aml0cv319jhsha55b7iqi8ntf0zk
Benutzer:Mjchael/Werkstatt
2
55243
1091898
1091087
2026-10-03T19:21:36Z
Mjchael
2222
/* Canon in D */
1091898
wikitext
text/x-wiki
<!-- BEGINN SEITE -->
{| width="100%" cellspacing="0" cellpadding="0" valign="top"|
|- <!-- SEITE:TABS -->
|<!-- BEGINN SEITE:TABS -->
{| border="0" cellspacing="0" cellpadding="0" height="30" width="100%"
|-
{{Benutzer:Mjchael/TabVoll|#dfefdf|User:Mjchael|Mjchael}}
{{Benutzer:Mjchael/TabVoll|#f0f0f8|User:Mjchael/Projekte|Projekte}}
{{Benutzer:Mjchael/TabOffen|#f0f0f8|User:Mjchael/Werkstatt|Werkstatt}}
{{Benutzer:Mjchael/TabVoll|#f0f0f8|User:Mjchael/ Hilfen|Hilfen}}
{{Benutzer:Mjchael/TabVoll|#f0f0f8|User:Mjchael/Sammlungen|Sammlungen}}
| style="background-color:#f8f8ff;border-bottom:1px solid #000" width="100"|
|}<!-- ENDE SEITE:TABS -->
{|width="100%" cellpadding="2" cellspacing="0" style="text-align:left; border:solid #000000; border-width:0px 1px 1px 1px;" valign="top"|
|-
|bgcolor="#dfefdf" valign="top"|<!-- Äußere Tabelle linke Spalte -->
<!-- Anfang Inhalt -->
*[[:Kategorie:todo Mjchael|meine Todo-Liste]]
=== Akut ===
{{:Gitarre/ Navi|Formen-Systematik|
{{:Gitarre: Formen-Systematik/ Navi}}|
img=Guitar 1.svg |bg=#F8f8f8|border=#666666|color=#333333|px=80|navi=Formen-Systematik}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Kadenzen in C"
subtitle="Dreiklänge auf den Diskantsaiten (6. Bund)"
arranger = "CC-BY-SA Wikibooks (mjchael)"
}
myKey = {
\tempo 4 = 120
%Tempo ausblenden
\set Score.tempoHideNote = ##t
\clef "G_8"
\time 4/4
\key c
\major
}
myDiskant = {
\repeat volta 4{
\repeat volta 2{
\set Staff.midiInstrument = #"electric guitar (jazz)"
\stemUp
< e'\3 g'\2 c''\1 >2 % C
< f'\3 a'\2 c''\1 > % F
< d'\3 g'\2 b'\1 >4 % G
< d'\3 f'\2 b'\1 >4 % B°
< e'\3 g'\2 c''\1 >2 % C
}
%
\repeat volta 2{
\set Staff.midiInstrument = #"electric guitar (clean)"
< e'\3 a'\2 c''\1 >2 % Am
< f'\3 a'\2 d''\1 > % Dm
< e'\3 g'\2 b'\1 >4 % Em
< e'\3 gis'\2 b'\1 > % E
< e'\3 a'\2 c''\1 >2 % Am
}
%
}
}
myFretBoards = {
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
% \override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
% \override FretBoard.fret-diagram-details.orientation =
#'landscape
\myDiskant
}
}
myChords = \chordmode {
c2 f g4 b:dim c2 | a2:m d:m e4:m e a2:m |
}
myGuitar = \myDiskant
%% Layout
\score {
<<
%% Griffbilder
\myFretBoards
%% Akkordnamen
\new ChordNames { \myChords }
%% Noten
\new Voice {
\myKey
\myGuitar
}
%% Tabulatur
\new TabStaff {
\tabFullNotation
\myGuitar
}
>>
\layout { \omit Voice.StringNumber }
}
%% Migiausgabe
\score {
<<
\unfoldRepeats {
\new Staff <<
\myKey
\myDiskant
>>
}
>>
\midi {}
}
%& unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
line-width=100\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
{{Todo|Cups (When I'm Gone) by Anna Kendrick<br>
Hello by Adele<br>Just The Way You Are by Bruno Mars<br>Someone You Loved by Lewis Capaldi|Mjchael}}
<poem>
Father Charles Goes Down And Ends Battle
3 times • 1st with b • 2nd natural • 3rd with #
Fb Cb Gb Db Ab Eb Bb F C G D A E B F# C# G# D# A# E# B#
You have to know or to learn
C G D A E
stands for
C D E _ G A _ C major pentatonic
A _ C D E _ G A minor pentatonic
Fb Cb Gb Db Ab
Cb Gb Db Ab Eb
Gb Db Ab Eb Bb
Db Ab Eb Bb F
Ab Eb Bb F C
Eb Bb F C G
Bb F C G D
F C G D A
C G D A E
G D A E B
D A E B F#
A E B F# C#
E B F# C# G#
B F# C# G# D#
F# C# G# D# A#
C# G# D# A# E#
The first note is the root of the major pentatonic
The 4th note is the root of the minor pentatonic.
One sentence
Father Charles Goes Down And Ends Battle
Less to lern, more benefits.
</poem>
<poem>
Strategie
Tonart runter • Capo rauf
C Dur [ F C G Dm Am Em ]
C - 3 = A
D - 5 = A
E - 7 = A
A Dur [ D A E Bm F#m C#m ]
A - 2 = G
C - 5 = G
D - 7 = G
G Dur [ C G D Am Em Bm ]
G - 3 = E
A - 5 = E
C - 8 = E
E Dur = [ A E B7 F#m C#m G#m ]
E - 2 = D
G - 5 = D
A - 7 = D
D Dur = [ G D A Em Bm F#m ]
D - 2 = C
E - 4 = C
G - 7 = C
C Dur [ F C G Dm Am Em ]
Hast du jetzt eine andere Tonart als Start, musst du nur einen Bund hinzufügen oder abziehen (Bb F B Eb Db...)
Zwei Grundlagen sind unverzichtbar
1) Der Quintenzirkel um die zusammengehörigen Akkorde zu kennen
Fähige Clevere Gitarristen Denken An Ein Barré
Father Charles Goes Down And Ends Battle
Fb Cb Gb Db Ab Eb Bb F C G D A E B F# C# G# D# A# E# B#
2) Das die Tonleiter (Das Alphabet) runter...
G F E D C B A G F E D C B A
... und die Halbtonschritte dazwischen um die Abstände abzuzählen...
Für Kreuztonarten
G F# F E D# D C# C B A# A G# G F# F E D# D C# C B A# A
Für die B-Tonarten
G Gb F E Eb D Db C B Bb A Ab G Gb F E Eb D Db C B Bb A Ab
Die Kreuz- und B-Tonarten wollen wir eigentlich ganz vermeiden
G _ F E _ D _ C B _ A _ G _ F E _ D _ C B _ A _ G
Hier siehst du, warum die meisten Capo-Positionen zwei Bünde entfernt sind.
Nun zählt auch F und B nicht zu den Lieblingstonarten der Gitarristen.
G _ _ E _ D _ C _ _ A _ G _ _ E _ D _ C _ _ A _ G
So kommen die Abstände von 3 Bünden zustande.
G - 3 = E ( übersprungenes F )
C - 3 = A ( übersprungenes B )
</poem>
== Vorübung Still got the Blues ==
<score sound="1" raw="1">
\version "2.20.0"
%{
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 d e f e d c4
b8 c d e d c b4
a8 b c d c b a \tweak color #red gis
a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c d e f e d c
b c d e d c b \break
a b c d c b a "g#"
a
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=90\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==Lilypond Version==
{{Regal:Musik/ Lilypond Version}}
=== Bonus Balladendiplom ===
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Basis-Pattern"
subtitles="My December (Linking Park)"
encoder="mjchael"
}
%Diskant- bzw. Melodiesaiten
myDiskant = {
d8 d' a f' d d' a f' | % 1
c8 c' g e' c c' g e' | % 1
d8 d' a f' d d' a f' | % 1
c8 c' g e' c c' g e' | % 1
}
%Basssaiten, die hier nur mit dem Daumen gespielt werden.
myBass = {
d4 a d a
c4 g c g
d4 a d a
c4 g c g
}
% Layout- bzw. Bildausgabe
\score {
<<
\new ChordNames {
\chordmode {
d1:m c d1:m c
}
}
{
%Noten
\new Staff <<
\tempo 4 = 120
%Tempo ausblenden
\set Score.tempoHideNote = ##t
\time 4/4
\key c \major
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8" \repeat volta 4
% Balken nur über viertel Noten, nicht über halbe Noten
\set Timing.beamExceptions = #'()
\set Timing.baseMoment = #(ly:make-moment 1/4)
\set Timing.beatStructure = #'(1 1 1 1)
% Noten im Diskant
\myDiskant
\\
% Noten im Bass - beachte: Wiederholungszeichen ist für Midi notwendig!
\repeat volta 4
\myBass
>>
}
% Tabulatur
\new TabStaff {
\tabFullNotation \repeat volta 4
<<
% Tabulatur im Diskant
\myDiskant
\\
% Tabulatur im Bass
\myBass
>>
}
>>
\layout {}
}
% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\key c \major
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8" \repeat volta 4
\myDiskant
\\
\repeat volta 4
\myBass
>>
}
>>
\midi {}
}
% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<div style="background-color:FFF;">
=== Danny Boy ===
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Danny Boy"
subtitle = "A Londonderry Air (before 1855)"
poet = "Lyrics: Frederic Weatherly (1910)"
% composer = "Komponist"
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myD = \chordmode { d,4 d d, d }
myA = \chordmode { a,,4 a, a,, a, }
myDA = \chordmode { d,4 d a,, a, }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
% \myD \myA \myDA \myD
% d,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c'{
\partial 4. fis8 g a |
b4. a8[ b] e[ d b] |
a( g) e4 r8 g b c |
d4. e8 d b g b |
a2 r8 fis8 g a |
b4. a8[ b] e[ d b] |
a( g) e4. fis8 g a |
b4. c8 b a g fis |
g2 r8 d' e fis |
g4. fis8 fis e d e |
\tweak color #red d( b) g4 r8 d'8 e fis |
\break % 11
g4. fis8 fis e d b |
a2 r8 d8 8 8 |
b'4. a8 8 g e g |
d( b) g4 r8 fis8 g a |
b e d b a g e fis |
g2~ 8 \bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Oh, Dan -- ny Boy, the pipes, the pipes are cal -- ling
From glen to glen, and down the moun -- tain side
The sum -- mer's gone and all the ro -- ses fal -- ling
It's you, it's you must go and I must bide.
But come ye back when sum -- mer's in the mea -- dow.
Or when the val -- ley's hushed and white with snow.
And I'll be here in sun -- shine or in sha -- dow.
Oh Dan -- ny Boy, oh, Dan -- ny Boy, I love you so.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Tom Dooley to Tabs ===
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myG = \chordmode { g,,4 g,8 4 8 4 }
myGAm = \chordmode { g,,4 g,8 a,4:m a,8:m a,4:m}
myD = \chordmode { d,4 d8 4 8 4 }
myDsept = \chordmode { d,4:7 d8:7 d4:7 d8:7 d4:7 }
myAm = \chordmode { a,,4:m a,8:m a,4:m a,8:m a,4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myG \myG \myGAm \myD
\myAm \myD \myDsept \myG
g,,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c'{
d8 4 8 e g4. | b4. b8( b2)|
d,8 4 8 e g4. | a1 |
d,8 4 e4 g4. | a4. a8~ a2|
a8 4 b8 a4 e4 | g1
\bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== Von G nach C ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key c\major
}
%% Akkorde
%% Lagerfeuer-Schlag
%% 1 . 2 + . + 4 .
myC = \chordmode { c,4 c8 4 8 4 }
myCDm = \chordmode { c,4 c8 d4:m d8:m d4:m}
myG = \chordmode { g,,4 g,8 4 8 4 }
myGsept = \chordmode { g,,4:7 g,8:7 g,4:7 g,8:7 g,4:7 }
myDm = \chordmode { d,4:m d8:m d4:m d8:m d4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myC \myC \myCDm \myG
\myDm \myG \myGsept \myC
c,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
g8 g8( g8) 8 a c4. | e4. e8( e2)|
g,8 g8~ g8 8 a c4. | d1 |
g,8 8~ 8 a4 c4. | d4. d8~ d2|
d8 d8~ d8 e8 d4 a4 | c1
\bar "|."
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== Von G nach C in den Bass ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key c\major
}
%% Akkorde
%% Lagerfeuer-Schlag
%% 1 . 2 + . + 4 .
myC = \chordmode { c,4 c8 4 8 4 }
myCDm = \chordmode { c,4 c8 d4:m d8:m d4:m}
myG = \chordmode { g,,4 g,8 4 8 4 }
myGsept = \chordmode { g,,4:7 g,8:7 g,4:7 g,8:7 g,4:7 }
myDm = \chordmode { d,4:m d8:m d4:m d8:m d4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myC \myC \myCDm \myG
\myDm \myG \myGsept \myC
c,1 %Schlusston
}
myMelody = \relative c' {
\myKey
\set Staff.midiInstrument = #"trombone"
g8 4 8 a c4. | e4. e8( e2)|
g,8 4 8 a c4. | d1 |
g,8 4 a4 c4. | d4. d8~ d2|
d8 4 e8 d4 a4 | c1
\bar "|."
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== bon G nach D ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myG = \chordmode { g,,4 g,8 4 8 4 }
myGAm = \chordmode { g,,4 g,8 a,4:m a,8:m a,4:m}
myD = \chordmode { d,4 d8 4 8 4 }
myDsept = \chordmode { d,4:7 d8:7 d4:7 d8:7 d4:7 }
myAm = \chordmode { a,,4:m a,8:m a,4:m a,8:m a,4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myG \myG \myGAm \myD
\myAm \myD \myDsept \myG
g,,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c'{
d8 d8( d8) 8 e g4. | b4. b8( b2)|
d,8 4 8 e g4. | a1 |
d,8 4 e4 g4. | a4. a8~ a2|
a8 4 b8 a4 e4 | g1
\bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Yes Sir That's my Baby ==
{{:Liederbuch/ Vorlage:Liedheader
|Liedtyp= Charleston (1924)
|Alternativtitel=
|Text= Gus Kahn (*1886 - † 1941)
|Melodie= Walter Donaldson (*1893 - † 1947)
|Urheber=
|Tonart=
|Bearbeiter= Mjchael
|Co-Bearbeiter=
}}
* {{w|Yes Sir, That’s My Baby}}
Der Protagonist (Mann oder Frau) bestätigt den Gesprächspartnern, nun verlobt zu sein, und läd diese zur Hochzeit ein.
<poem>
{{crd|C}} Who's that coming down the {{crd|C#dim}} street,
{{crd|G}} who's that looking so petite
{{crd|G7}} Who's that coming down to meet me {{crd|C}} here. {{crd|Dm7}} {{crd|G7}}
{{crd|C}} Who's that - you know who I {{crd|C#dim}} mean?
{{crd|G7}} Sweetest 'who' you've ever seen
{{crd|D7}} I {{crd|Am7}} could {{crd|D7}} tell {{crd|Am7}} her
{{crd|D7}} miles {{crd|Am7}} a-{{crd|D7}}way from {{crd|G7}} here. {{crd|Em}} {{crd|B7}} {{crd|G7}}
{{crd|C}} Yes, sir, that's my {{crd|C#dim}} baby,
{{crd|G}} no, sir, I don't mean maybe
{{crd|G7}} Yes, sir, that's my baby {{crd|C}} now. {{crd|G7}}
{{crd|C}} Yes, ma'am we've de-{{crd|C#dim}}cided,
{{crd|G}} no, ma'am we won't hide it
{{crd|G7}} Yes ma'am you're invited {{crd|C}} now.
By the {{crd|C7}} way, by the {{crd|F}} way,
when we {{crd|D7}} reach the preacher I'll {{crd|G7}} say {{crd|G7+5}}
{{crd|C}} Yes, sir, that's my {{crd|C#dim}} baby,
{{crd|G}} no, sir, I don't mean maybe
{{crd|G7}} Yes, sir, that's my baby {{crd|C}} now.
{{crd|C}} Well well, 'lookit' that {{crd|C#dim}} baby,
{{crd|G}} Do tell, don't say "maybe",
{{crd|G7}} Hell's bells, won't she cause some {{crd|C}} row?
Pretty {{crd|C7}} soon, Pretty {{crd|F}} soon,
We will {{crd|D7}} hear that Lohengrin {{crd|G7}} tune, (I'm sayin'){{crd|G7+5}}
{{crd|C}} Who for should she {{crd|C#dim}} be sir,
{{crd|G}} No one else but me sir,
{{crd|G7}} Yes sir, That's my Baby {{crd|C}} now. {{crd|C7}}
{{crd|C}} Yes sir, that's my {{crd|C#dim}} Baby
{{crd|G}} Yes sir, I don't mean maybe,
{{crd|G7}} Yes sir, That's my Baby {{crd|C}} now
</poem>
=== Yes Sir, That's My Baby (Var2) ===
<poem>
{{crd|C}} Yes {{crd|Am}} sir, {{crd|C}} that's my {{crd|Am}} baby
{{crd|G7}} No {{crd|Dm}} sir, {{crd|G7}} don't be {{crd|Dm}} maybe
{{crd|G7}} Yes {{crd|Am}} sir, {{crd|G7}} that's my {{crd|Dm}} baby {{crd|C}} now {{crd|G7}}
{{crd|C}} Yes {{crd|Am}} ma'am, {{crd|C}} we've de{{crd|Am}}cided
{{crd|G7}} No {{crd|Dm}} ma'am, {{crd|G7}} we won't {{crd|Dm}} hide it
{{crd|G7}} Yes {{crd|Am}} ma'am, {{crd|G7}} that's my {{crd|Dm}} baby {{crd|C}} now
By the way, {{crd|C7}} by the {{crd|F}} way
When we {{crd|D7}} meet that preacher
I'll {{crd|G7}} say with {{crd|G7sus2}} feel{{crd|G7}}ing
{{crd|C}} Yes {{crd|Am}} sir, {{crd|C}} that's my {{crd|Am}} baby
{{crd|G7}} No {{crd|Dm}} sir, {{crd|G7}} don't be {{crd|Dm}} maybe
<div>{{crd|G7}} Yes {{crd|Am}} sir, {{crd|G7}} that's my {{crd|Dm}} baby {{crd|C}} now.
</poem>
* {{Youtube-Suche|Yes+Sir+That's+My+Baby|Yes Sir, That's My Baby}}
===Early One Morning===
<poem>
;1
{{crd|D}}Early one morning, just {{crd|G}}as the sun was {{crd|A}}rising
I {{crd|D}}heard a maiden singing, from the {{crd|G}}va-{{crd|A}}lley be-{{crd|D}}low:
;Chorus
{{crd|A}}Oh, don't de-{{crd|D}}ceive me, {{crd|A}}Oh never {{crd|D}}leave me,
{{crd|D}}How could you {{crd|G}}use, a {{crd|D}}poor {{crd|A}}maiden {{crd|D}}so?
;2
Oh {{crd|D}}gay is garland, and {{crd|G}}fresh are the {{crd|A}}roses,
I've {{crd|D}}culled from the garden, to {{crd|G}}bind u-{{crd|A}}pon thy {{crd|D}}brow.
;3
Re-{{crd|D}}member the vows, that you {{crd|G}}made to your {{crd|A}}Mary
Re-{{crd|D}}member the bow'r, where you {{crd|G}}promised {{crd|A}}to be {{crd|D}}true.
;4
Thus {{crd|D}}sang the poor maid, her {{crd|G}}sorrows be{{crd|A}}wailing,
Thus, {{crd|D}}sang the poor maid, in the {{crd|G}}va-{{crd|A}}lley be-{{crd|D}}low.
</poem>
===Down In The River To Pray===
<poem>
As I went down in the river to pray
Studying about that good old way
And who shall wear the starry crown
Good Lord, show me the way!
O sisters let's go down,
Let's go down, come on down,
O sisters let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the robe and crown
Good Lord, show me the way!
O brothers let's go down,
Let's go down, come on down,
Come on brothers let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the starry crown
Good Lord, show me the way!
O fathers let's go down,
Let's go down, come on down,
O fathers let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the robe and crown
Good Lord, show me the way!
O mothers let's go down,
Let's go down, don't you want to go down,
Come on mothers let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the starry crown
Good Lord, show me the way!
O sinners let's go down,
Let's go down, come on down,
O sinners let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the robe and crown
Good Lord, show me the way!
</poem>
=== Wild Mountain Thyme ===
[[Datei:Wild mountain thyme - geograph.org.uk - 25029.jpg|mini]]
{{listen|filename=Christoph Nolte - The Rocky Road - The Wild Mountain Thyme.ogg|title=The Wild Mountain Thyme|description="Wild Mountain Thyme" performed by Christoph Nolte}}
<score lang="ABC" sound="1">
X: 5
T: Wild Mountain Thyme
R: barndance
M: 4/4
L: 1/8
K: Gmaj
GE|"G"D2 D2 "C"E<G-GA|"G"G6 Bd|"C"e3 e e3 d|"G"Bd-d4 Bd
"C"e4 "G"d3 B|"Em"A<G-G4AB|"Am"c3B A3G|"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|
"G"G6 Bd|"C"e3 e e3 d|"G"Bd-d4 Bd|"C"e4 "G"d3 B|"Em"A<G-G4AB|
"Am"c3B A3G|"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|"G"G6|
</score>
< !--
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Wild Mountain Thyme"
% subtitle = "MeinSubtitle"
% poet = "Texter"
% composer = "Komponist"
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myD = \chordmode { d,4 d d, d }
myA = \chordmode { a,,4 a, a,, a, }
myDA = \chordmode { d,4 d a,, a, }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
\partial 4 s4
\myD \myA \myDA \myD
d,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c''{
\partial 4 g8 e
d4 d e16 g8.~8 a | g2. b8 d | e4. e8 e4. d8 | b d8~2 b8 d |
% GE|"G"D2 D2 "C"E<G-GA|"G"G6 Bd|"C"e3 e e3 d|"G"Bd-d4 Bd
e2 d4. b8 | a16 g8.~2 a8 b | c4. b8 a4. g8 |e8 g8~2 g8 e | d4 4 e16 g8.~g8 a
% "C"e4 "G"d3 B|"Em"A<G-G4AB|"Am"c3B A3G |"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|
c4. b8 a4. g8 | e g8~2 8 e | d4 4 e16 g8.~8 a | g2.
% "Am"c3B A3G|"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|"G"G6|
\bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Häns -- chen klein | ging al -- lein | in das Haus hin | -- ein. |
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
-->
(also known as "Purple Heather" and "Will Ye Go, Lassie, Go?") is a Scottish/Irish folk song.
<poem>
;1
O the summer time has come
And the trees are sweetly blooming
And wild mountain thyme
Grows around the purple heather.
Will you go, lassie, go?
;Chorus
And we'll all go together,
To pull wild mountain thyme,
All around the purple heather.
Will you go, lassie, go?
;2
I will build my love a tower,
By yon clear crystal fountain,
And on it I will pile,
All the flowers of the mountain.
Will you go, lassie, go?
;3
I will range through the wilds
And the deep land so dreary
And return with the spoils
To the bower o' my dearie.
Will ye go lassie go ?
;4
If my true love she'll not come,
Then I'll surely find another,
To pull wild mountain thyme,
All around the purple heather.
Will you go, lassie, go?
</poem>
== Akkordfolge NEM ==
<score>
<<
\new ChordNames { \chordmode {
d1 c g b
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< d-1\5 a-2\4 d'-3\3 fis'-4\2 a'-1\1 > % d
< c-1\5 g-2\4 c'-3\3 e'-4\2 g'-1\1 > % C/B
< g,-1 d-3 g-4 b-2 d'-1 g'-1 > % G
< b,-1\5 fis-2\4 b-3\3 dis'-4\2 fis'-1\1 > % B
}
>>
</score>
<score>
<<
\new ChordNames { \chordmode {
c1 a g e d
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'blue
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< e\6 c'\5 e'\4 g'\3 c''\2 e''\1 > % C
< e\6 a\5 e'\4 a'\3 cis''\2 e''\1 > % A
< g\6 b\5 d'\4 g'\3 b'\2 g''\1 > % G
< e\6 b\5 e'\4 gis'\3 b'\2 e''\1 > % E
< d'\4 a'\3 d''\2 fis''\1 > % d
}
\new ChordNames { \chordmode {
c1:m a:m g:m e:m d:m
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'blue
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< es\6 c'\5 es'\4 g'\3 c''\2 es''\1 > % C
< e\6 a\5 e'\4 a'\3 c''\2 e''\1 > % A
< g\6 bes\5 d'\4 g'\3 bes'\2 g''\1 > % G
< e\6 b\5 e'\4 g'\3 b'\2 e''\1 > % E
< d'\4 a'\3 d''\2 f''\1 > % d
}
>>
</score>
== Umkehrung mit CAGED ==
<score>
<<
\new ChordNames { \chordmode {
a1 g:/b e e:/gis
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< a, e-1 a-2 cis'-3 > % A
< b, d-2 g d'-4 > % G/B
< e-1/5 b-2/4 e'-3/3 gis'-4/2 b'-1/1> % E
< gis-2/5 b-1/4 e'-1/3 gis'-4/2 > % E/G#
}
>>
</score>
== Canon in D ==
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Canon"
composer = "M: Johann Pachebel (1653-1706)"
key="D"
composer= "Pachelbel"
arranger = "arr.: ccbysa Wikibooks (mjchael)"
}
myKey = {
\language "deutsch"
\tempo 4 = 100
%Tempo ausblenden
\set Score.tempoHideNote = ##t
\clef "G_8" \time 4/4
\key d \major
\set Staff.midiInstrument = #"electric guitar (clean)"
}
myMelody = \relative c {
\myKey
\set minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\stemUp
\repeat volta 2{}
%^\markup { \bold {Em7} }
%\break
fis2 e d cis h a h cis
\voiceOne
fis' e d cis h a
h cis fis e d cis
h a h cis
d4 \oneVoice d e cis
d fis a a,
h g fis a g d' cis a
d8 cis d fis, a a cis4
d8 d fis4 a a8 h
g fis e g fis e d cis
\voiceOne
h cis d4~ d8 cis16 d cis4
d8 cis d fis, a4 cis d fis a a8 h
g fis e g fis e d cis
h a d4 ~ d8 cis16 d cis4\trill
\oneVoice
\set Timing.beatStructure = #'(1 1 1 1)
d8 fis16 g a8 fis16 g a a, h cis d e fis g
fis8 d16 e fis8 fis,16 g a h a g a fis g a
d8 h16 a g8 fis16 e fis e d e fis g a h
d8 h16a h8 e16 d cis h cis d e fis g e
fis8 d16 cis d8 fis, e cis'16 d e8 cis
% fis d16 cis d8 fis, e cis'16 d e8 cis
d h16 a h8 d, cis fis16 g a8 fis
h g16 fis g8 h a fis'16 e fis8 d
h d16 cis d8 fis, e a d cis
\voiceOne
\set Timing.beatStructure = #'(2 2)
d4. fis8 fis g fis e
d4. d8 d e d cis
h4. h8 a4 d
d8 c h c a2
\oneVoice
d4 fis8 a a h a g
\voiceOne
s1 s
h,2 a ~ a4 \oneVoice d e cis
d fis, a4. h8
g4 d fis a
\voiceOne
g fis e a
fis1\fermata
\bar "||."
% \bar "|." |
}
Gitarre = \myMelody
%% Layout = Noten mit Tab
\score {
<<
%% Noten
\new Voice {
\myKey
\Gitarre
}
%% Tabulatur
\new TabStaff {
\tabFullNotation
\Gitarre
}
>>
\layout {}
}
%% Midiausgabe
\score {
<<
\unfoldRepeats {
\new Staff <<
\myKey
\Gitarre
>>
}
>>
\midi {}
}
%& unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%& DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Takte auszählen ==
GEMISCHTE TAKTE AUSZÄHLEN
Speziell ein Tutorial für Kerstin Jentzsch
Ich gehe mal davon aus, das du dich ganz grob mit den Notenwerten auskennst, und eine Methode suchst, wie du sie beim täglichen Üben einsetzen kannst.
Versuche es mal mit Zahlen.
Die Idee hab ich von
Mike Schönmehl "Jazz und Pop Musiklehre"
Atlantis-Schott-Musikverlag
Alle viertel-Noten werden mit einfachen Zahlen ausgesprochen
1 . 2 . 3 . 4 .
Eins zwei drei vier
oder
fünf sechs sieben acht
oder
neun zehn elf zwölf
Es ist egal welche dieser Zahlenfolgen du nimmst es ist für jede Zahl nur eine Silbe.
Jetzt komme die Achtel:
1 + 2 + 3 + 4 +
Drei-zehn, vier-zehn, fünf-zehn, sech-zehn
sieb-zehn, ach-zehn, neun-zehn, zwan-zig
Was auch gut geht ist
Ein-er, Zwei-er, Drei-er, vier-er
Hier haben alle Zahlen zwei Silben und teilen sich wie zwei Achtel auf.
Jetzt kommen die Sechzehntel
1 e + e 2 e + e 3 e + e 4 e + e
Ein-und-zwan-zig, Zwei-und-zwan-zig, Drei-und-zwan-zig, Vier-und-zwan-zig
Fünf-und-zwan-zig, Sechs-und-zwan-zieg, sieben-und-zwan-zieg, Acht-und-zwan-zig
Hier haben alle Zahlen vier Silben und teilen sich wie vier Sechzentel auf.
Jetzt die Triolen:
1-er-lei 2-er-lei 3-er-lei 4-er-lei
Ein-hun-dert, Zwei-hun-dert, Drei-hun-dert, Vier-hun-dert
Hier haben alle Zahlen drei Silben und teilen sich wie drei Triolen auf.
Wir sind es beim Zählen gewöhnt, in bestimmten Schritten zu zählen, so das wir 1-12 meist genau so langsam bzw. schnell zählen wie 13-20 oder wie 21-29. Und auch die Hunderter werden im gleichen Schritt gezählt.
Man macht ganz automatisch zwei-Achtel, vier-Sechzentel oder 3-Triolen.
Man kann versuchen, sich für viele Rhyhtmen einfach eine Zahlenfolge aufschreiben, und sich auch neue Kombinationen einfallen lassen.
Wie wäre es wenn man viertel, triolen und Sechzentel miteiander übt?
Eins | Zwei-hund-dert | drei | vier-und-zwan-zig
Ein-und-zwan-zig| zwei | drei-hun-dert | vier
Zehner-Zahlen könnten sich sogar für einen Schuffle eignen
1 . + 2 . + 3 . + 4 . +
Bei der Zehn muss man sich was einfallen lassen, aber dann kann man gut im Shuffle zählen
Zehn---tel, Zwan---zig, Drei---ßig, Vier---zig
Zehn---tel, Zwei-hund-dert, Drei---ßig, Vier---zig
So in etwa
Die Methode ist nicht der Weisheit letzter Schluss, aber vielleicht hilft es dem einen oder anderen beim Üben.
Gruß Mjchael
===Gallerie von Red_Rooster===
Die meisten Gifs und JPG wurden von Red_Rooster hochgeladen. Die müssen nach SVG umgestaltet werden.
<!-- Bilder durch SVG ersetzen -->
{{Klappbox|style=border:1px solid grey; margin:6px 0 6px 0;|bg1=#EAEAEA|verborgen=true|ta1=left|fw1=bold
|Titel= Bilder durch SVG ersetzen
|Inhalt=
{{rot|Bilder nicht löschen!!!!!!!!! Sie müssen weltweit durch SVG ausgetauscht werden, und dann erst auf den Commons für die Schnelllöschung vorgeschlagen werden, und dann erst dürfen sie entfernt werden. Und das mache ich selbst!}}
<gallery>
Image:00.01.D.1.png|
Image:00.01.D.2.png|
Image:01.01.D_A1.png|
Image:01.01.D_A2.png|
Image:01.01.D_A3.png|
Image:01.01.D_A4.png|
Image:01.01.D_A5.png|
Image:01.01.D_A6.png|
Image:01.01.D_A7.png|
Image:01.01.D_A8.png|
Image:01.01.D_A91.png|
Image:01.01.D_A92.png|
Image:02.01.D.gif|
Image:02.01.DG1.gif|
Image:02.01.DG2.gif|
Image:02.01.DG3.gif|
Image:02.01.G.gif|
Image:02.01.G_Schluessel.png|
Image:%03.01.C.gif|
Image:03.01.D_C.gif|
Image:03.01.G C.png|
Image:Druck_mittig.png|
Image:Druck_zu_dicht.png|
Image:Druck_zu_weit.png|
Image:%Durstellung.gif|
Image:Durstellung1_4.gif|
Image:EADGHE.gif|
Image:%G_Langsam.gif|
Image:Halbtonschritte_I.gif|
Image:HCF.gif|
Image:Mollstellung1_3.gif|
Image:MR_Durstellung.gif|
Image:MR_Mollstellung.gif|
</gallery>
}}
<pre>
{{duplicate|Crd_Form_C.svg}}
*replaced by [[image:Crd Form C.svg]]
*original is unused or replaced
--~~~~
</pre>
== Spielwiese ==
*[[Benutzer:Mjchael/ Spielweise | Spielweise (Tests für meine Projekte)]]
== Zeichnen und Schreiben ==
*[[Gitarre: Grifftabelle einfach | einfache Grifftabelle]]
*[[Liederbuch]] (weitere Übungsbeispiele für die "Diplome"
== Eigendichtungen ==
*[[Benutzer:Mjchael/ Eigendichtungen | Lob und Kritik und Ideen für selbstkomponierte Lieder]]
==Lieder==
[[Liederbuch/ Pläne und Wünsche]]
== Seitenüberblick ==
<!-- Alle Gitarrenseiten -->
{{Klappbox|style=border:1px solid grey; margin:6px 0 6px 0;|bg1=#EAEAEA|verborgen=true|ta1=left|fw1=bold
|Titel= Alle Gitarrenseiten
|Inhalt={{Spezial:Prefixindex/Gitarre}}
}}
<!-- Alle Liederbuchseiten -->
{{Klappbox|style=border:1px solid grey; margin:6px 0 6px 0;|bg1=#EAEAEA|verborgen=true|ta1=left|fw1=bold
|Titel= Alle Liederbuchseiten
|Inhalt={{Spezial:Prefixindex/Liederbuch}}
}}
<!-- Ende Inhalt -->
|}
<!-- Ende Äußere Tabelle -->
monpu2krl438mshvwd7g0ar4j3q73hm
1091900
1091898
2026-10-03T19:35:59Z
Mjchael
2222
/* Umkehrung mit CAGED */
1091900
wikitext
text/x-wiki
<!-- BEGINN SEITE -->
{| width="100%" cellspacing="0" cellpadding="0" valign="top"|
|- <!-- SEITE:TABS -->
|<!-- BEGINN SEITE:TABS -->
{| border="0" cellspacing="0" cellpadding="0" height="30" width="100%"
|-
{{Benutzer:Mjchael/TabVoll|#dfefdf|User:Mjchael|Mjchael}}
{{Benutzer:Mjchael/TabVoll|#f0f0f8|User:Mjchael/Projekte|Projekte}}
{{Benutzer:Mjchael/TabOffen|#f0f0f8|User:Mjchael/Werkstatt|Werkstatt}}
{{Benutzer:Mjchael/TabVoll|#f0f0f8|User:Mjchael/ Hilfen|Hilfen}}
{{Benutzer:Mjchael/TabVoll|#f0f0f8|User:Mjchael/Sammlungen|Sammlungen}}
| style="background-color:#f8f8ff;border-bottom:1px solid #000" width="100"|
|}<!-- ENDE SEITE:TABS -->
{|width="100%" cellpadding="2" cellspacing="0" style="text-align:left; border:solid #000000; border-width:0px 1px 1px 1px;" valign="top"|
|-
|bgcolor="#dfefdf" valign="top"|<!-- Äußere Tabelle linke Spalte -->
<!-- Anfang Inhalt -->
*[[:Kategorie:todo Mjchael|meine Todo-Liste]]
=== Akut ===
{{:Gitarre/ Navi|Formen-Systematik|
{{:Gitarre: Formen-Systematik/ Navi}}|
img=Guitar 1.svg |bg=#F8f8f8|border=#666666|color=#333333|px=80|navi=Formen-Systematik}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Kadenzen in C"
subtitle="Dreiklänge auf den Diskantsaiten (6. Bund)"
arranger = "CC-BY-SA Wikibooks (mjchael)"
}
myKey = {
\tempo 4 = 120
%Tempo ausblenden
\set Score.tempoHideNote = ##t
\clef "G_8"
\time 4/4
\key c
\major
}
myDiskant = {
\repeat volta 4{
\repeat volta 2{
\set Staff.midiInstrument = #"electric guitar (jazz)"
\stemUp
< e'\3 g'\2 c''\1 >2 % C
< f'\3 a'\2 c''\1 > % F
< d'\3 g'\2 b'\1 >4 % G
< d'\3 f'\2 b'\1 >4 % B°
< e'\3 g'\2 c''\1 >2 % C
}
%
\repeat volta 2{
\set Staff.midiInstrument = #"electric guitar (clean)"
< e'\3 a'\2 c''\1 >2 % Am
< f'\3 a'\2 d''\1 > % Dm
< e'\3 g'\2 b'\1 >4 % Em
< e'\3 gis'\2 b'\1 > % E
< e'\3 a'\2 c''\1 >2 % Am
}
%
}
}
myFretBoards = {
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
% \override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
% \override FretBoard.fret-diagram-details.orientation =
#'landscape
\myDiskant
}
}
myChords = \chordmode {
c2 f g4 b:dim c2 | a2:m d:m e4:m e a2:m |
}
myGuitar = \myDiskant
%% Layout
\score {
<<
%% Griffbilder
\myFretBoards
%% Akkordnamen
\new ChordNames { \myChords }
%% Noten
\new Voice {
\myKey
\myGuitar
}
%% Tabulatur
\new TabStaff {
\tabFullNotation
\myGuitar
}
>>
\layout { \omit Voice.StringNumber }
}
%% Migiausgabe
\score {
<<
\unfoldRepeats {
\new Staff <<
\myKey
\myDiskant
>>
}
>>
\midi {}
}
%& unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
line-width=100\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
{{Todo|Cups (When I'm Gone) by Anna Kendrick<br>
Hello by Adele<br>Just The Way You Are by Bruno Mars<br>Someone You Loved by Lewis Capaldi|Mjchael}}
<poem>
Father Charles Goes Down And Ends Battle
3 times • 1st with b • 2nd natural • 3rd with #
Fb Cb Gb Db Ab Eb Bb F C G D A E B F# C# G# D# A# E# B#
You have to know or to learn
C G D A E
stands for
C D E _ G A _ C major pentatonic
A _ C D E _ G A minor pentatonic
Fb Cb Gb Db Ab
Cb Gb Db Ab Eb
Gb Db Ab Eb Bb
Db Ab Eb Bb F
Ab Eb Bb F C
Eb Bb F C G
Bb F C G D
F C G D A
C G D A E
G D A E B
D A E B F#
A E B F# C#
E B F# C# G#
B F# C# G# D#
F# C# G# D# A#
C# G# D# A# E#
The first note is the root of the major pentatonic
The 4th note is the root of the minor pentatonic.
One sentence
Father Charles Goes Down And Ends Battle
Less to lern, more benefits.
</poem>
<poem>
Strategie
Tonart runter • Capo rauf
C Dur [ F C G Dm Am Em ]
C - 3 = A
D - 5 = A
E - 7 = A
A Dur [ D A E Bm F#m C#m ]
A - 2 = G
C - 5 = G
D - 7 = G
G Dur [ C G D Am Em Bm ]
G - 3 = E
A - 5 = E
C - 8 = E
E Dur = [ A E B7 F#m C#m G#m ]
E - 2 = D
G - 5 = D
A - 7 = D
D Dur = [ G D A Em Bm F#m ]
D - 2 = C
E - 4 = C
G - 7 = C
C Dur [ F C G Dm Am Em ]
Hast du jetzt eine andere Tonart als Start, musst du nur einen Bund hinzufügen oder abziehen (Bb F B Eb Db...)
Zwei Grundlagen sind unverzichtbar
1) Der Quintenzirkel um die zusammengehörigen Akkorde zu kennen
Fähige Clevere Gitarristen Denken An Ein Barré
Father Charles Goes Down And Ends Battle
Fb Cb Gb Db Ab Eb Bb F C G D A E B F# C# G# D# A# E# B#
2) Das die Tonleiter (Das Alphabet) runter...
G F E D C B A G F E D C B A
... und die Halbtonschritte dazwischen um die Abstände abzuzählen...
Für Kreuztonarten
G F# F E D# D C# C B A# A G# G F# F E D# D C# C B A# A
Für die B-Tonarten
G Gb F E Eb D Db C B Bb A Ab G Gb F E Eb D Db C B Bb A Ab
Die Kreuz- und B-Tonarten wollen wir eigentlich ganz vermeiden
G _ F E _ D _ C B _ A _ G _ F E _ D _ C B _ A _ G
Hier siehst du, warum die meisten Capo-Positionen zwei Bünde entfernt sind.
Nun zählt auch F und B nicht zu den Lieblingstonarten der Gitarristen.
G _ _ E _ D _ C _ _ A _ G _ _ E _ D _ C _ _ A _ G
So kommen die Abstände von 3 Bünden zustande.
G - 3 = E ( übersprungenes F )
C - 3 = A ( übersprungenes B )
</poem>
== Vorübung Still got the Blues ==
<score sound="1" raw="1">
\version "2.20.0"
%{
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 d e f e d c4
b8 c d e d c b4
a8 b c d c b a \tweak color #red gis
a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c d e f e d c
b c d e d c b \break
a b c d c b a "g#"
a
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=90\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==Lilypond Version==
{{Regal:Musik/ Lilypond Version}}
=== Bonus Balladendiplom ===
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Basis-Pattern"
subtitles="My December (Linking Park)"
encoder="mjchael"
}
%Diskant- bzw. Melodiesaiten
myDiskant = {
d8 d' a f' d d' a f' | % 1
c8 c' g e' c c' g e' | % 1
d8 d' a f' d d' a f' | % 1
c8 c' g e' c c' g e' | % 1
}
%Basssaiten, die hier nur mit dem Daumen gespielt werden.
myBass = {
d4 a d a
c4 g c g
d4 a d a
c4 g c g
}
% Layout- bzw. Bildausgabe
\score {
<<
\new ChordNames {
\chordmode {
d1:m c d1:m c
}
}
{
%Noten
\new Staff <<
\tempo 4 = 120
%Tempo ausblenden
\set Score.tempoHideNote = ##t
\time 4/4
\key c \major
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8" \repeat volta 4
% Balken nur über viertel Noten, nicht über halbe Noten
\set Timing.beamExceptions = #'()
\set Timing.baseMoment = #(ly:make-moment 1/4)
\set Timing.beatStructure = #'(1 1 1 1)
% Noten im Diskant
\myDiskant
\\
% Noten im Bass - beachte: Wiederholungszeichen ist für Midi notwendig!
\repeat volta 4
\myBass
>>
}
% Tabulatur
\new TabStaff {
\tabFullNotation \repeat volta 4
<<
% Tabulatur im Diskant
\myDiskant
\\
% Tabulatur im Bass
\myBass
>>
}
>>
\layout {}
}
% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\key c \major
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8" \repeat volta 4
\myDiskant
\\
\repeat volta 4
\myBass
>>
}
>>
\midi {}
}
% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<div style="background-color:FFF;">
=== Danny Boy ===
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Danny Boy"
subtitle = "A Londonderry Air (before 1855)"
poet = "Lyrics: Frederic Weatherly (1910)"
% composer = "Komponist"
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myD = \chordmode { d,4 d d, d }
myA = \chordmode { a,,4 a, a,, a, }
myDA = \chordmode { d,4 d a,, a, }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
% \myD \myA \myDA \myD
% d,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c'{
\partial 4. fis8 g a |
b4. a8[ b] e[ d b] |
a( g) e4 r8 g b c |
d4. e8 d b g b |
a2 r8 fis8 g a |
b4. a8[ b] e[ d b] |
a( g) e4. fis8 g a |
b4. c8 b a g fis |
g2 r8 d' e fis |
g4. fis8 fis e d e |
\tweak color #red d( b) g4 r8 d'8 e fis |
\break % 11
g4. fis8 fis e d b |
a2 r8 d8 8 8 |
b'4. a8 8 g e g |
d( b) g4 r8 fis8 g a |
b e d b a g e fis |
g2~ 8 \bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Oh, Dan -- ny Boy, the pipes, the pipes are cal -- ling
From glen to glen, and down the moun -- tain side
The sum -- mer's gone and all the ro -- ses fal -- ling
It's you, it's you must go and I must bide.
But come ye back when sum -- mer's in the mea -- dow.
Or when the val -- ley's hushed and white with snow.
And I'll be here in sun -- shine or in sha -- dow.
Oh Dan -- ny Boy, oh, Dan -- ny Boy, I love you so.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Tom Dooley to Tabs ===
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myG = \chordmode { g,,4 g,8 4 8 4 }
myGAm = \chordmode { g,,4 g,8 a,4:m a,8:m a,4:m}
myD = \chordmode { d,4 d8 4 8 4 }
myDsept = \chordmode { d,4:7 d8:7 d4:7 d8:7 d4:7 }
myAm = \chordmode { a,,4:m a,8:m a,4:m a,8:m a,4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myG \myG \myGAm \myD
\myAm \myD \myDsept \myG
g,,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c'{
d8 4 8 e g4. | b4. b8( b2)|
d,8 4 8 e g4. | a1 |
d,8 4 e4 g4. | a4. a8~ a2|
a8 4 b8 a4 e4 | g1
\bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== Von G nach C ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key c\major
}
%% Akkorde
%% Lagerfeuer-Schlag
%% 1 . 2 + . + 4 .
myC = \chordmode { c,4 c8 4 8 4 }
myCDm = \chordmode { c,4 c8 d4:m d8:m d4:m}
myG = \chordmode { g,,4 g,8 4 8 4 }
myGsept = \chordmode { g,,4:7 g,8:7 g,4:7 g,8:7 g,4:7 }
myDm = \chordmode { d,4:m d8:m d4:m d8:m d4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myC \myC \myCDm \myG
\myDm \myG \myGsept \myC
c,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
g8 g8( g8) 8 a c4. | e4. e8( e2)|
g,8 g8~ g8 8 a c4. | d1 |
g,8 8~ 8 a4 c4. | d4. d8~ d2|
d8 d8~ d8 e8 d4 a4 | c1
\bar "|."
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== Von G nach C in den Bass ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key c\major
}
%% Akkorde
%% Lagerfeuer-Schlag
%% 1 . 2 + . + 4 .
myC = \chordmode { c,4 c8 4 8 4 }
myCDm = \chordmode { c,4 c8 d4:m d8:m d4:m}
myG = \chordmode { g,,4 g,8 4 8 4 }
myGsept = \chordmode { g,,4:7 g,8:7 g,4:7 g,8:7 g,4:7 }
myDm = \chordmode { d,4:m d8:m d4:m d8:m d4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myC \myC \myCDm \myG
\myDm \myG \myGsept \myC
c,1 %Schlusston
}
myMelody = \relative c' {
\myKey
\set Staff.midiInstrument = #"trombone"
g8 4 8 a c4. | e4. e8( e2)|
g,8 4 8 a c4. | d1 |
g,8 4 a4 c4. | d4. d8~ d2|
d8 4 e8 d4 a4 | c1
\bar "|."
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== bon G nach D ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myG = \chordmode { g,,4 g,8 4 8 4 }
myGAm = \chordmode { g,,4 g,8 a,4:m a,8:m a,4:m}
myD = \chordmode { d,4 d8 4 8 4 }
myDsept = \chordmode { d,4:7 d8:7 d4:7 d8:7 d4:7 }
myAm = \chordmode { a,,4:m a,8:m a,4:m a,8:m a,4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myG \myG \myGAm \myD
\myAm \myD \myDsept \myG
g,,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c'{
d8 d8( d8) 8 e g4. | b4. b8( b2)|
d,8 4 8 e g4. | a1 |
d,8 4 e4 g4. | a4. a8~ a2|
a8 4 b8 a4 e4 | g1
\bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Yes Sir That's my Baby ==
{{:Liederbuch/ Vorlage:Liedheader
|Liedtyp= Charleston (1924)
|Alternativtitel=
|Text= Gus Kahn (*1886 - † 1941)
|Melodie= Walter Donaldson (*1893 - † 1947)
|Urheber=
|Tonart=
|Bearbeiter= Mjchael
|Co-Bearbeiter=
}}
* {{w|Yes Sir, That’s My Baby}}
Der Protagonist (Mann oder Frau) bestätigt den Gesprächspartnern, nun verlobt zu sein, und läd diese zur Hochzeit ein.
<poem>
{{crd|C}} Who's that coming down the {{crd|C#dim}} street,
{{crd|G}} who's that looking so petite
{{crd|G7}} Who's that coming down to meet me {{crd|C}} here. {{crd|Dm7}} {{crd|G7}}
{{crd|C}} Who's that - you know who I {{crd|C#dim}} mean?
{{crd|G7}} Sweetest 'who' you've ever seen
{{crd|D7}} I {{crd|Am7}} could {{crd|D7}} tell {{crd|Am7}} her
{{crd|D7}} miles {{crd|Am7}} a-{{crd|D7}}way from {{crd|G7}} here. {{crd|Em}} {{crd|B7}} {{crd|G7}}
{{crd|C}} Yes, sir, that's my {{crd|C#dim}} baby,
{{crd|G}} no, sir, I don't mean maybe
{{crd|G7}} Yes, sir, that's my baby {{crd|C}} now. {{crd|G7}}
{{crd|C}} Yes, ma'am we've de-{{crd|C#dim}}cided,
{{crd|G}} no, ma'am we won't hide it
{{crd|G7}} Yes ma'am you're invited {{crd|C}} now.
By the {{crd|C7}} way, by the {{crd|F}} way,
when we {{crd|D7}} reach the preacher I'll {{crd|G7}} say {{crd|G7+5}}
{{crd|C}} Yes, sir, that's my {{crd|C#dim}} baby,
{{crd|G}} no, sir, I don't mean maybe
{{crd|G7}} Yes, sir, that's my baby {{crd|C}} now.
{{crd|C}} Well well, 'lookit' that {{crd|C#dim}} baby,
{{crd|G}} Do tell, don't say "maybe",
{{crd|G7}} Hell's bells, won't she cause some {{crd|C}} row?
Pretty {{crd|C7}} soon, Pretty {{crd|F}} soon,
We will {{crd|D7}} hear that Lohengrin {{crd|G7}} tune, (I'm sayin'){{crd|G7+5}}
{{crd|C}} Who for should she {{crd|C#dim}} be sir,
{{crd|G}} No one else but me sir,
{{crd|G7}} Yes sir, That's my Baby {{crd|C}} now. {{crd|C7}}
{{crd|C}} Yes sir, that's my {{crd|C#dim}} Baby
{{crd|G}} Yes sir, I don't mean maybe,
{{crd|G7}} Yes sir, That's my Baby {{crd|C}} now
</poem>
=== Yes Sir, That's My Baby (Var2) ===
<poem>
{{crd|C}} Yes {{crd|Am}} sir, {{crd|C}} that's my {{crd|Am}} baby
{{crd|G7}} No {{crd|Dm}} sir, {{crd|G7}} don't be {{crd|Dm}} maybe
{{crd|G7}} Yes {{crd|Am}} sir, {{crd|G7}} that's my {{crd|Dm}} baby {{crd|C}} now {{crd|G7}}
{{crd|C}} Yes {{crd|Am}} ma'am, {{crd|C}} we've de{{crd|Am}}cided
{{crd|G7}} No {{crd|Dm}} ma'am, {{crd|G7}} we won't {{crd|Dm}} hide it
{{crd|G7}} Yes {{crd|Am}} ma'am, {{crd|G7}} that's my {{crd|Dm}} baby {{crd|C}} now
By the way, {{crd|C7}} by the {{crd|F}} way
When we {{crd|D7}} meet that preacher
I'll {{crd|G7}} say with {{crd|G7sus2}} feel{{crd|G7}}ing
{{crd|C}} Yes {{crd|Am}} sir, {{crd|C}} that's my {{crd|Am}} baby
{{crd|G7}} No {{crd|Dm}} sir, {{crd|G7}} don't be {{crd|Dm}} maybe
<div>{{crd|G7}} Yes {{crd|Am}} sir, {{crd|G7}} that's my {{crd|Dm}} baby {{crd|C}} now.
</poem>
* {{Youtube-Suche|Yes+Sir+That's+My+Baby|Yes Sir, That's My Baby}}
===Early One Morning===
<poem>
;1
{{crd|D}}Early one morning, just {{crd|G}}as the sun was {{crd|A}}rising
I {{crd|D}}heard a maiden singing, from the {{crd|G}}va-{{crd|A}}lley be-{{crd|D}}low:
;Chorus
{{crd|A}}Oh, don't de-{{crd|D}}ceive me, {{crd|A}}Oh never {{crd|D}}leave me,
{{crd|D}}How could you {{crd|G}}use, a {{crd|D}}poor {{crd|A}}maiden {{crd|D}}so?
;2
Oh {{crd|D}}gay is garland, and {{crd|G}}fresh are the {{crd|A}}roses,
I've {{crd|D}}culled from the garden, to {{crd|G}}bind u-{{crd|A}}pon thy {{crd|D}}brow.
;3
Re-{{crd|D}}member the vows, that you {{crd|G}}made to your {{crd|A}}Mary
Re-{{crd|D}}member the bow'r, where you {{crd|G}}promised {{crd|A}}to be {{crd|D}}true.
;4
Thus {{crd|D}}sang the poor maid, her {{crd|G}}sorrows be{{crd|A}}wailing,
Thus, {{crd|D}}sang the poor maid, in the {{crd|G}}va-{{crd|A}}lley be-{{crd|D}}low.
</poem>
===Down In The River To Pray===
<poem>
As I went down in the river to pray
Studying about that good old way
And who shall wear the starry crown
Good Lord, show me the way!
O sisters let's go down,
Let's go down, come on down,
O sisters let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the robe and crown
Good Lord, show me the way!
O brothers let's go down,
Let's go down, come on down,
Come on brothers let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the starry crown
Good Lord, show me the way!
O fathers let's go down,
Let's go down, come on down,
O fathers let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the robe and crown
Good Lord, show me the way!
O mothers let's go down,
Let's go down, don't you want to go down,
Come on mothers let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the starry crown
Good Lord, show me the way!
O sinners let's go down,
Let's go down, come on down,
O sinners let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the robe and crown
Good Lord, show me the way!
</poem>
=== Wild Mountain Thyme ===
[[Datei:Wild mountain thyme - geograph.org.uk - 25029.jpg|mini]]
{{listen|filename=Christoph Nolte - The Rocky Road - The Wild Mountain Thyme.ogg|title=The Wild Mountain Thyme|description="Wild Mountain Thyme" performed by Christoph Nolte}}
<score lang="ABC" sound="1">
X: 5
T: Wild Mountain Thyme
R: barndance
M: 4/4
L: 1/8
K: Gmaj
GE|"G"D2 D2 "C"E<G-GA|"G"G6 Bd|"C"e3 e e3 d|"G"Bd-d4 Bd
"C"e4 "G"d3 B|"Em"A<G-G4AB|"Am"c3B A3G|"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|
"G"G6 Bd|"C"e3 e e3 d|"G"Bd-d4 Bd|"C"e4 "G"d3 B|"Em"A<G-G4AB|
"Am"c3B A3G|"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|"G"G6|
</score>
< !--
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Wild Mountain Thyme"
% subtitle = "MeinSubtitle"
% poet = "Texter"
% composer = "Komponist"
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myD = \chordmode { d,4 d d, d }
myA = \chordmode { a,,4 a, a,, a, }
myDA = \chordmode { d,4 d a,, a, }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
\partial 4 s4
\myD \myA \myDA \myD
d,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c''{
\partial 4 g8 e
d4 d e16 g8.~8 a | g2. b8 d | e4. e8 e4. d8 | b d8~2 b8 d |
% GE|"G"D2 D2 "C"E<G-GA|"G"G6 Bd|"C"e3 e e3 d|"G"Bd-d4 Bd
e2 d4. b8 | a16 g8.~2 a8 b | c4. b8 a4. g8 |e8 g8~2 g8 e | d4 4 e16 g8.~g8 a
% "C"e4 "G"d3 B|"Em"A<G-G4AB|"Am"c3B A3G |"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|
c4. b8 a4. g8 | e g8~2 8 e | d4 4 e16 g8.~8 a | g2.
% "Am"c3B A3G|"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|"G"G6|
\bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Häns -- chen klein | ging al -- lein | in das Haus hin | -- ein. |
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
-->
(also known as "Purple Heather" and "Will Ye Go, Lassie, Go?") is a Scottish/Irish folk song.
<poem>
;1
O the summer time has come
And the trees are sweetly blooming
And wild mountain thyme
Grows around the purple heather.
Will you go, lassie, go?
;Chorus
And we'll all go together,
To pull wild mountain thyme,
All around the purple heather.
Will you go, lassie, go?
;2
I will build my love a tower,
By yon clear crystal fountain,
And on it I will pile,
All the flowers of the mountain.
Will you go, lassie, go?
;3
I will range through the wilds
And the deep land so dreary
And return with the spoils
To the bower o' my dearie.
Will ye go lassie go ?
;4
If my true love she'll not come,
Then I'll surely find another,
To pull wild mountain thyme,
All around the purple heather.
Will you go, lassie, go?
</poem>
== Akkordfolge NEM ==
<score>
<<
\new ChordNames { \chordmode {
d1 c g b
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< d-1\5 a-2\4 d'-3\3 fis'-4\2 a'-1\1 > % d
< c-1\5 g-2\4 c'-3\3 e'-4\2 g'-1\1 > % C/B
< g,-1 d-3 g-4 b-2 d'-1 g'-1 > % G
< b,-1\5 fis-2\4 b-3\3 dis'-4\2 fis'-1\1 > % B
}
>>
</score>
<score>
<<
\new ChordNames { \chordmode {
c1 a g e d
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'blue
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< e\6 c'\5 e'\4 g'\3 c''\2 e''\1 > % C
< e\6 a\5 e'\4 a'\3 cis''\2 e''\1 > % A
< g\6 b\5 d'\4 g'\3 b'\2 g''\1 > % G
< e\6 b\5 e'\4 gis'\3 b'\2 e''\1 > % E
< d'\4 a'\3 d''\2 fis''\1 > % d
}
\new ChordNames { \chordmode {
c1:m a:m g:m e:m d:m
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'blue
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< es\6 c'\5 es'\4 g'\3 c''\2 es''\1 > % C
< e\6 a\5 e'\4 a'\3 c''\2 e''\1 > % A
< g\6 bes\5 d'\4 g'\3 bes'\2 g''\1 > % G
< e\6 b\5 e'\4 g'\3 b'\2 e''\1 > % E
< d'\4 a'\3 d''\2 f''\1 > % d
}
>>
</score>
== Umkehrung mit CAGED ==
<score>
<<
\new ChordNames { \chordmode {
a1 g:/b e e:/gis
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< a, e-1 a-2 cis'-3 > % A
< b,-2 d g d'-4 > % G/B
< e-1\5 b-2\4 e'-3\3 gis'-4\2 b'-1\1> % E
< gis-2\5 b-1\4 e'-1\3 b'-4\2 > % E/G#
}
>>
</score>
<score>
<<
\new ChordNames { \chordmode {
e1 d:/fis a a:/cis
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< e, b,-2 e-3 gis-4 b e'> % A
< f#,-2 a d a'-3 d'-4 > % D/F#
< a,-1\6 e-3\5 a'-4\4 cis'-2\3 e'-1\2 a'-1\1> % A
< cis-2\6 e-1\5 a'-1\4 e'-3\3 cis''-4\2 > % A/C#
}
>>
</score>
== Canon in D ==
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Canon"
composer = "M: Johann Pachebel (1653-1706)"
key="D"
composer= "Pachelbel"
arranger = "arr.: ccbysa Wikibooks (mjchael)"
}
myKey = {
\language "deutsch"
\tempo 4 = 100
%Tempo ausblenden
\set Score.tempoHideNote = ##t
\clef "G_8" \time 4/4
\key d \major
\set Staff.midiInstrument = #"electric guitar (clean)"
}
myMelody = \relative c {
\myKey
\set minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\stemUp
\repeat volta 2{}
%^\markup { \bold {Em7} }
%\break
fis2 e d cis h a h cis
\voiceOne
fis' e d cis h a
h cis fis e d cis
h a h cis
d4 \oneVoice d e cis
d fis a a,
h g fis a g d' cis a
d8 cis d fis, a a cis4
d8 d fis4 a a8 h
g fis e g fis e d cis
\voiceOne
h cis d4~ d8 cis16 d cis4
d8 cis d fis, a4 cis d fis a a8 h
g fis e g fis e d cis
h a d4 ~ d8 cis16 d cis4\trill
\oneVoice
\set Timing.beatStructure = #'(1 1 1 1)
d8 fis16 g a8 fis16 g a a, h cis d e fis g
fis8 d16 e fis8 fis,16 g a h a g a fis g a
d8 h16 a g8 fis16 e fis e d e fis g a h
d8 h16a h8 e16 d cis h cis d e fis g e
fis8 d16 cis d8 fis, e cis'16 d e8 cis
% fis d16 cis d8 fis, e cis'16 d e8 cis
d h16 a h8 d, cis fis16 g a8 fis
h g16 fis g8 h a fis'16 e fis8 d
h d16 cis d8 fis, e a d cis
\voiceOne
\set Timing.beatStructure = #'(2 2)
d4. fis8 fis g fis e
d4. d8 d e d cis
h4. h8 a4 d
d8 c h c a2
\oneVoice
d4 fis8 a a h a g
\voiceOne
s1 s
h,2 a ~ a4 \oneVoice d e cis
d fis, a4. h8
g4 d fis a
\voiceOne
g fis e a
fis1\fermata
\bar "||."
% \bar "|." |
}
Gitarre = \myMelody
%% Layout = Noten mit Tab
\score {
<<
%% Noten
\new Voice {
\myKey
\Gitarre
}
%% Tabulatur
\new TabStaff {
\tabFullNotation
\Gitarre
}
>>
\layout {}
}
%% Midiausgabe
\score {
<<
\unfoldRepeats {
\new Staff <<
\myKey
\Gitarre
>>
}
>>
\midi {}
}
%& unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%& DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Takte auszählen ==
GEMISCHTE TAKTE AUSZÄHLEN
Speziell ein Tutorial für Kerstin Jentzsch
Ich gehe mal davon aus, das du dich ganz grob mit den Notenwerten auskennst, und eine Methode suchst, wie du sie beim täglichen Üben einsetzen kannst.
Versuche es mal mit Zahlen.
Die Idee hab ich von
Mike Schönmehl "Jazz und Pop Musiklehre"
Atlantis-Schott-Musikverlag
Alle viertel-Noten werden mit einfachen Zahlen ausgesprochen
1 . 2 . 3 . 4 .
Eins zwei drei vier
oder
fünf sechs sieben acht
oder
neun zehn elf zwölf
Es ist egal welche dieser Zahlenfolgen du nimmst es ist für jede Zahl nur eine Silbe.
Jetzt komme die Achtel:
1 + 2 + 3 + 4 +
Drei-zehn, vier-zehn, fünf-zehn, sech-zehn
sieb-zehn, ach-zehn, neun-zehn, zwan-zig
Was auch gut geht ist
Ein-er, Zwei-er, Drei-er, vier-er
Hier haben alle Zahlen zwei Silben und teilen sich wie zwei Achtel auf.
Jetzt kommen die Sechzehntel
1 e + e 2 e + e 3 e + e 4 e + e
Ein-und-zwan-zig, Zwei-und-zwan-zig, Drei-und-zwan-zig, Vier-und-zwan-zig
Fünf-und-zwan-zig, Sechs-und-zwan-zieg, sieben-und-zwan-zieg, Acht-und-zwan-zig
Hier haben alle Zahlen vier Silben und teilen sich wie vier Sechzentel auf.
Jetzt die Triolen:
1-er-lei 2-er-lei 3-er-lei 4-er-lei
Ein-hun-dert, Zwei-hun-dert, Drei-hun-dert, Vier-hun-dert
Hier haben alle Zahlen drei Silben und teilen sich wie drei Triolen auf.
Wir sind es beim Zählen gewöhnt, in bestimmten Schritten zu zählen, so das wir 1-12 meist genau so langsam bzw. schnell zählen wie 13-20 oder wie 21-29. Und auch die Hunderter werden im gleichen Schritt gezählt.
Man macht ganz automatisch zwei-Achtel, vier-Sechzentel oder 3-Triolen.
Man kann versuchen, sich für viele Rhyhtmen einfach eine Zahlenfolge aufschreiben, und sich auch neue Kombinationen einfallen lassen.
Wie wäre es wenn man viertel, triolen und Sechzentel miteiander übt?
Eins | Zwei-hund-dert | drei | vier-und-zwan-zig
Ein-und-zwan-zig| zwei | drei-hun-dert | vier
Zehner-Zahlen könnten sich sogar für einen Schuffle eignen
1 . + 2 . + 3 . + 4 . +
Bei der Zehn muss man sich was einfallen lassen, aber dann kann man gut im Shuffle zählen
Zehn---tel, Zwan---zig, Drei---ßig, Vier---zig
Zehn---tel, Zwei-hund-dert, Drei---ßig, Vier---zig
So in etwa
Die Methode ist nicht der Weisheit letzter Schluss, aber vielleicht hilft es dem einen oder anderen beim Üben.
Gruß Mjchael
===Gallerie von Red_Rooster===
Die meisten Gifs und JPG wurden von Red_Rooster hochgeladen. Die müssen nach SVG umgestaltet werden.
<!-- Bilder durch SVG ersetzen -->
{{Klappbox|style=border:1px solid grey; margin:6px 0 6px 0;|bg1=#EAEAEA|verborgen=true|ta1=left|fw1=bold
|Titel= Bilder durch SVG ersetzen
|Inhalt=
{{rot|Bilder nicht löschen!!!!!!!!! Sie müssen weltweit durch SVG ausgetauscht werden, und dann erst auf den Commons für die Schnelllöschung vorgeschlagen werden, und dann erst dürfen sie entfernt werden. Und das mache ich selbst!}}
<gallery>
Image:00.01.D.1.png|
Image:00.01.D.2.png|
Image:01.01.D_A1.png|
Image:01.01.D_A2.png|
Image:01.01.D_A3.png|
Image:01.01.D_A4.png|
Image:01.01.D_A5.png|
Image:01.01.D_A6.png|
Image:01.01.D_A7.png|
Image:01.01.D_A8.png|
Image:01.01.D_A91.png|
Image:01.01.D_A92.png|
Image:02.01.D.gif|
Image:02.01.DG1.gif|
Image:02.01.DG2.gif|
Image:02.01.DG3.gif|
Image:02.01.G.gif|
Image:02.01.G_Schluessel.png|
Image:%03.01.C.gif|
Image:03.01.D_C.gif|
Image:03.01.G C.png|
Image:Druck_mittig.png|
Image:Druck_zu_dicht.png|
Image:Druck_zu_weit.png|
Image:%Durstellung.gif|
Image:Durstellung1_4.gif|
Image:EADGHE.gif|
Image:%G_Langsam.gif|
Image:Halbtonschritte_I.gif|
Image:HCF.gif|
Image:Mollstellung1_3.gif|
Image:MR_Durstellung.gif|
Image:MR_Mollstellung.gif|
</gallery>
}}
<pre>
{{duplicate|Crd_Form_C.svg}}
*replaced by [[image:Crd Form C.svg]]
*original is unused or replaced
--~~~~
</pre>
== Spielwiese ==
*[[Benutzer:Mjchael/ Spielweise | Spielweise (Tests für meine Projekte)]]
== Zeichnen und Schreiben ==
*[[Gitarre: Grifftabelle einfach | einfache Grifftabelle]]
*[[Liederbuch]] (weitere Übungsbeispiele für die "Diplome"
== Eigendichtungen ==
*[[Benutzer:Mjchael/ Eigendichtungen | Lob und Kritik und Ideen für selbstkomponierte Lieder]]
==Lieder==
[[Liederbuch/ Pläne und Wünsche]]
== Seitenüberblick ==
<!-- Alle Gitarrenseiten -->
{{Klappbox|style=border:1px solid grey; margin:6px 0 6px 0;|bg1=#EAEAEA|verborgen=true|ta1=left|fw1=bold
|Titel= Alle Gitarrenseiten
|Inhalt={{Spezial:Prefixindex/Gitarre}}
}}
<!-- Alle Liederbuchseiten -->
{{Klappbox|style=border:1px solid grey; margin:6px 0 6px 0;|bg1=#EAEAEA|verborgen=true|ta1=left|fw1=bold
|Titel= Alle Liederbuchseiten
|Inhalt={{Spezial:Prefixindex/Liederbuch}}
}}
<!-- Ende Inhalt -->
|}
<!-- Ende Äußere Tabelle -->
sxo7r11rl6gkpkhusvy6oxryzj954xy
1091901
1091900
2026-10-03T19:41:26Z
Mjchael
2222
/* Umkehrung mit CAGED */
1091901
wikitext
text/x-wiki
<!-- BEGINN SEITE -->
{| width="100%" cellspacing="0" cellpadding="0" valign="top"|
|- <!-- SEITE:TABS -->
|<!-- BEGINN SEITE:TABS -->
{| border="0" cellspacing="0" cellpadding="0" height="30" width="100%"
|-
{{Benutzer:Mjchael/TabVoll|#dfefdf|User:Mjchael|Mjchael}}
{{Benutzer:Mjchael/TabVoll|#f0f0f8|User:Mjchael/Projekte|Projekte}}
{{Benutzer:Mjchael/TabOffen|#f0f0f8|User:Mjchael/Werkstatt|Werkstatt}}
{{Benutzer:Mjchael/TabVoll|#f0f0f8|User:Mjchael/ Hilfen|Hilfen}}
{{Benutzer:Mjchael/TabVoll|#f0f0f8|User:Mjchael/Sammlungen|Sammlungen}}
| style="background-color:#f8f8ff;border-bottom:1px solid #000" width="100"|
|}<!-- ENDE SEITE:TABS -->
{|width="100%" cellpadding="2" cellspacing="0" style="text-align:left; border:solid #000000; border-width:0px 1px 1px 1px;" valign="top"|
|-
|bgcolor="#dfefdf" valign="top"|<!-- Äußere Tabelle linke Spalte -->
<!-- Anfang Inhalt -->
*[[:Kategorie:todo Mjchael|meine Todo-Liste]]
=== Akut ===
{{:Gitarre/ Navi|Formen-Systematik|
{{:Gitarre: Formen-Systematik/ Navi}}|
img=Guitar 1.svg |bg=#F8f8f8|border=#666666|color=#333333|px=80|navi=Formen-Systematik}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Kadenzen in C"
subtitle="Dreiklänge auf den Diskantsaiten (6. Bund)"
arranger = "CC-BY-SA Wikibooks (mjchael)"
}
myKey = {
\tempo 4 = 120
%Tempo ausblenden
\set Score.tempoHideNote = ##t
\clef "G_8"
\time 4/4
\key c
\major
}
myDiskant = {
\repeat volta 4{
\repeat volta 2{
\set Staff.midiInstrument = #"electric guitar (jazz)"
\stemUp
< e'\3 g'\2 c''\1 >2 % C
< f'\3 a'\2 c''\1 > % F
< d'\3 g'\2 b'\1 >4 % G
< d'\3 f'\2 b'\1 >4 % B°
< e'\3 g'\2 c''\1 >2 % C
}
%
\repeat volta 2{
\set Staff.midiInstrument = #"electric guitar (clean)"
< e'\3 a'\2 c''\1 >2 % Am
< f'\3 a'\2 d''\1 > % Dm
< e'\3 g'\2 b'\1 >4 % Em
< e'\3 gis'\2 b'\1 > % E
< e'\3 a'\2 c''\1 >2 % Am
}
%
}
}
myFretBoards = {
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
% \override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
% \override FretBoard.fret-diagram-details.orientation =
#'landscape
\myDiskant
}
}
myChords = \chordmode {
c2 f g4 b:dim c2 | a2:m d:m e4:m e a2:m |
}
myGuitar = \myDiskant
%% Layout
\score {
<<
%% Griffbilder
\myFretBoards
%% Akkordnamen
\new ChordNames { \myChords }
%% Noten
\new Voice {
\myKey
\myGuitar
}
%% Tabulatur
\new TabStaff {
\tabFullNotation
\myGuitar
}
>>
\layout { \omit Voice.StringNumber }
}
%% Migiausgabe
\score {
<<
\unfoldRepeats {
\new Staff <<
\myKey
\myDiskant
>>
}
>>
\midi {}
}
%& unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
line-width=100\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
{{Todo|Cups (When I'm Gone) by Anna Kendrick<br>
Hello by Adele<br>Just The Way You Are by Bruno Mars<br>Someone You Loved by Lewis Capaldi|Mjchael}}
<poem>
Father Charles Goes Down And Ends Battle
3 times • 1st with b • 2nd natural • 3rd with #
Fb Cb Gb Db Ab Eb Bb F C G D A E B F# C# G# D# A# E# B#
You have to know or to learn
C G D A E
stands for
C D E _ G A _ C major pentatonic
A _ C D E _ G A minor pentatonic
Fb Cb Gb Db Ab
Cb Gb Db Ab Eb
Gb Db Ab Eb Bb
Db Ab Eb Bb F
Ab Eb Bb F C
Eb Bb F C G
Bb F C G D
F C G D A
C G D A E
G D A E B
D A E B F#
A E B F# C#
E B F# C# G#
B F# C# G# D#
F# C# G# D# A#
C# G# D# A# E#
The first note is the root of the major pentatonic
The 4th note is the root of the minor pentatonic.
One sentence
Father Charles Goes Down And Ends Battle
Less to lern, more benefits.
</poem>
<poem>
Strategie
Tonart runter • Capo rauf
C Dur [ F C G Dm Am Em ]
C - 3 = A
D - 5 = A
E - 7 = A
A Dur [ D A E Bm F#m C#m ]
A - 2 = G
C - 5 = G
D - 7 = G
G Dur [ C G D Am Em Bm ]
G - 3 = E
A - 5 = E
C - 8 = E
E Dur = [ A E B7 F#m C#m G#m ]
E - 2 = D
G - 5 = D
A - 7 = D
D Dur = [ G D A Em Bm F#m ]
D - 2 = C
E - 4 = C
G - 7 = C
C Dur [ F C G Dm Am Em ]
Hast du jetzt eine andere Tonart als Start, musst du nur einen Bund hinzufügen oder abziehen (Bb F B Eb Db...)
Zwei Grundlagen sind unverzichtbar
1) Der Quintenzirkel um die zusammengehörigen Akkorde zu kennen
Fähige Clevere Gitarristen Denken An Ein Barré
Father Charles Goes Down And Ends Battle
Fb Cb Gb Db Ab Eb Bb F C G D A E B F# C# G# D# A# E# B#
2) Das die Tonleiter (Das Alphabet) runter...
G F E D C B A G F E D C B A
... und die Halbtonschritte dazwischen um die Abstände abzuzählen...
Für Kreuztonarten
G F# F E D# D C# C B A# A G# G F# F E D# D C# C B A# A
Für die B-Tonarten
G Gb F E Eb D Db C B Bb A Ab G Gb F E Eb D Db C B Bb A Ab
Die Kreuz- und B-Tonarten wollen wir eigentlich ganz vermeiden
G _ F E _ D _ C B _ A _ G _ F E _ D _ C B _ A _ G
Hier siehst du, warum die meisten Capo-Positionen zwei Bünde entfernt sind.
Nun zählt auch F und B nicht zu den Lieblingstonarten der Gitarristen.
G _ _ E _ D _ C _ _ A _ G _ _ E _ D _ C _ _ A _ G
So kommen die Abstände von 3 Bünden zustande.
G - 3 = E ( übersprungenes F )
C - 3 = A ( übersprungenes B )
</poem>
== Vorübung Still got the Blues ==
<score sound="1" raw="1">
\version "2.20.0"
%{
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 d e f e d c4
b8 c d e d c b4
a8 b c d c b a \tweak color #red gis
a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c d e f e d c
b c d e d c b \break
a b c d c b a "g#"
a
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=90\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==Lilypond Version==
{{Regal:Musik/ Lilypond Version}}
=== Bonus Balladendiplom ===
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Basis-Pattern"
subtitles="My December (Linking Park)"
encoder="mjchael"
}
%Diskant- bzw. Melodiesaiten
myDiskant = {
d8 d' a f' d d' a f' | % 1
c8 c' g e' c c' g e' | % 1
d8 d' a f' d d' a f' | % 1
c8 c' g e' c c' g e' | % 1
}
%Basssaiten, die hier nur mit dem Daumen gespielt werden.
myBass = {
d4 a d a
c4 g c g
d4 a d a
c4 g c g
}
% Layout- bzw. Bildausgabe
\score {
<<
\new ChordNames {
\chordmode {
d1:m c d1:m c
}
}
{
%Noten
\new Staff <<
\tempo 4 = 120
%Tempo ausblenden
\set Score.tempoHideNote = ##t
\time 4/4
\key c \major
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8" \repeat volta 4
% Balken nur über viertel Noten, nicht über halbe Noten
\set Timing.beamExceptions = #'()
\set Timing.baseMoment = #(ly:make-moment 1/4)
\set Timing.beatStructure = #'(1 1 1 1)
% Noten im Diskant
\myDiskant
\\
% Noten im Bass - beachte: Wiederholungszeichen ist für Midi notwendig!
\repeat volta 4
\myBass
>>
}
% Tabulatur
\new TabStaff {
\tabFullNotation \repeat volta 4
<<
% Tabulatur im Diskant
\myDiskant
\\
% Tabulatur im Bass
\myBass
>>
}
>>
\layout {}
}
% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\key c \major
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8" \repeat volta 4
\myDiskant
\\
\repeat volta 4
\myBass
>>
}
>>
\midi {}
}
% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<div style="background-color:FFF;">
=== Danny Boy ===
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Danny Boy"
subtitle = "A Londonderry Air (before 1855)"
poet = "Lyrics: Frederic Weatherly (1910)"
% composer = "Komponist"
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myD = \chordmode { d,4 d d, d }
myA = \chordmode { a,,4 a, a,, a, }
myDA = \chordmode { d,4 d a,, a, }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
% \myD \myA \myDA \myD
% d,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c'{
\partial 4. fis8 g a |
b4. a8[ b] e[ d b] |
a( g) e4 r8 g b c |
d4. e8 d b g b |
a2 r8 fis8 g a |
b4. a8[ b] e[ d b] |
a( g) e4. fis8 g a |
b4. c8 b a g fis |
g2 r8 d' e fis |
g4. fis8 fis e d e |
\tweak color #red d( b) g4 r8 d'8 e fis |
\break % 11
g4. fis8 fis e d b |
a2 r8 d8 8 8 |
b'4. a8 8 g e g |
d( b) g4 r8 fis8 g a |
b e d b a g e fis |
g2~ 8 \bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Oh, Dan -- ny Boy, the pipes, the pipes are cal -- ling
From glen to glen, and down the moun -- tain side
The sum -- mer's gone and all the ro -- ses fal -- ling
It's you, it's you must go and I must bide.
But come ye back when sum -- mer's in the mea -- dow.
Or when the val -- ley's hushed and white with snow.
And I'll be here in sun -- shine or in sha -- dow.
Oh Dan -- ny Boy, oh, Dan -- ny Boy, I love you so.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Tom Dooley to Tabs ===
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myG = \chordmode { g,,4 g,8 4 8 4 }
myGAm = \chordmode { g,,4 g,8 a,4:m a,8:m a,4:m}
myD = \chordmode { d,4 d8 4 8 4 }
myDsept = \chordmode { d,4:7 d8:7 d4:7 d8:7 d4:7 }
myAm = \chordmode { a,,4:m a,8:m a,4:m a,8:m a,4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myG \myG \myGAm \myD
\myAm \myD \myDsept \myG
g,,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c'{
d8 4 8 e g4. | b4. b8( b2)|
d,8 4 8 e g4. | a1 |
d,8 4 e4 g4. | a4. a8~ a2|
a8 4 b8 a4 e4 | g1
\bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== Von G nach C ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key c\major
}
%% Akkorde
%% Lagerfeuer-Schlag
%% 1 . 2 + . + 4 .
myC = \chordmode { c,4 c8 4 8 4 }
myCDm = \chordmode { c,4 c8 d4:m d8:m d4:m}
myG = \chordmode { g,,4 g,8 4 8 4 }
myGsept = \chordmode { g,,4:7 g,8:7 g,4:7 g,8:7 g,4:7 }
myDm = \chordmode { d,4:m d8:m d4:m d8:m d4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myC \myC \myCDm \myG
\myDm \myG \myGsept \myC
c,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
g8 g8( g8) 8 a c4. | e4. e8( e2)|
g,8 g8~ g8 8 a c4. | d1 |
g,8 8~ 8 a4 c4. | d4. d8~ d2|
d8 d8~ d8 e8 d4 a4 | c1
\bar "|."
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== Von G nach C in den Bass ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key c\major
}
%% Akkorde
%% Lagerfeuer-Schlag
%% 1 . 2 + . + 4 .
myC = \chordmode { c,4 c8 4 8 4 }
myCDm = \chordmode { c,4 c8 d4:m d8:m d4:m}
myG = \chordmode { g,,4 g,8 4 8 4 }
myGsept = \chordmode { g,,4:7 g,8:7 g,4:7 g,8:7 g,4:7 }
myDm = \chordmode { d,4:m d8:m d4:m d8:m d4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myC \myC \myCDm \myG
\myDm \myG \myGsept \myC
c,1 %Schlusston
}
myMelody = \relative c' {
\myKey
\set Staff.midiInstrument = #"trombone"
g8 4 8 a c4. | e4. e8( e2)|
g,8 4 8 a c4. | d1 |
g,8 4 a4 c4. | d4. d8~ d2|
d8 4 e8 d4 a4 | c1
\bar "|."
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== bon G nach D ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Tom Dooley"
% subtitle = "MeinSubtitle"
% poet = "Texter"
composer = "trad."
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myG = \chordmode { g,,4 g,8 4 8 4 }
myGAm = \chordmode { g,,4 g,8 a,4:m a,8:m a,4:m}
myD = \chordmode { d,4 d8 4 8 4 }
myDsept = \chordmode { d,4:7 d8:7 d4:7 d8:7 d4:7 }
myAm = \chordmode { a,,4:m a,8:m a,4:m a,8:m a,4:m }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
% \partial 4 s4
\myG \myG \myGAm \myD
\myAm \myD \myDsept \myG
g,,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c'{
d8 d8( d8) 8 e g4. | b4. b8( b2)|
d,8 4 8 e g4. | a1 |
d,8 4 e4 g4. | a4. a8~ a2|
a8 4 b8 a4 e4 | g1
\bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Hang down your head, Tom Doo -- ley.
Hang down your head and cry
Killed poor Lau -- ra Fos -- ter.
You know you're bound to die.
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Yes Sir That's my Baby ==
{{:Liederbuch/ Vorlage:Liedheader
|Liedtyp= Charleston (1924)
|Alternativtitel=
|Text= Gus Kahn (*1886 - † 1941)
|Melodie= Walter Donaldson (*1893 - † 1947)
|Urheber=
|Tonart=
|Bearbeiter= Mjchael
|Co-Bearbeiter=
}}
* {{w|Yes Sir, That’s My Baby}}
Der Protagonist (Mann oder Frau) bestätigt den Gesprächspartnern, nun verlobt zu sein, und läd diese zur Hochzeit ein.
<poem>
{{crd|C}} Who's that coming down the {{crd|C#dim}} street,
{{crd|G}} who's that looking so petite
{{crd|G7}} Who's that coming down to meet me {{crd|C}} here. {{crd|Dm7}} {{crd|G7}}
{{crd|C}} Who's that - you know who I {{crd|C#dim}} mean?
{{crd|G7}} Sweetest 'who' you've ever seen
{{crd|D7}} I {{crd|Am7}} could {{crd|D7}} tell {{crd|Am7}} her
{{crd|D7}} miles {{crd|Am7}} a-{{crd|D7}}way from {{crd|G7}} here. {{crd|Em}} {{crd|B7}} {{crd|G7}}
{{crd|C}} Yes, sir, that's my {{crd|C#dim}} baby,
{{crd|G}} no, sir, I don't mean maybe
{{crd|G7}} Yes, sir, that's my baby {{crd|C}} now. {{crd|G7}}
{{crd|C}} Yes, ma'am we've de-{{crd|C#dim}}cided,
{{crd|G}} no, ma'am we won't hide it
{{crd|G7}} Yes ma'am you're invited {{crd|C}} now.
By the {{crd|C7}} way, by the {{crd|F}} way,
when we {{crd|D7}} reach the preacher I'll {{crd|G7}} say {{crd|G7+5}}
{{crd|C}} Yes, sir, that's my {{crd|C#dim}} baby,
{{crd|G}} no, sir, I don't mean maybe
{{crd|G7}} Yes, sir, that's my baby {{crd|C}} now.
{{crd|C}} Well well, 'lookit' that {{crd|C#dim}} baby,
{{crd|G}} Do tell, don't say "maybe",
{{crd|G7}} Hell's bells, won't she cause some {{crd|C}} row?
Pretty {{crd|C7}} soon, Pretty {{crd|F}} soon,
We will {{crd|D7}} hear that Lohengrin {{crd|G7}} tune, (I'm sayin'){{crd|G7+5}}
{{crd|C}} Who for should she {{crd|C#dim}} be sir,
{{crd|G}} No one else but me sir,
{{crd|G7}} Yes sir, That's my Baby {{crd|C}} now. {{crd|C7}}
{{crd|C}} Yes sir, that's my {{crd|C#dim}} Baby
{{crd|G}} Yes sir, I don't mean maybe,
{{crd|G7}} Yes sir, That's my Baby {{crd|C}} now
</poem>
=== Yes Sir, That's My Baby (Var2) ===
<poem>
{{crd|C}} Yes {{crd|Am}} sir, {{crd|C}} that's my {{crd|Am}} baby
{{crd|G7}} No {{crd|Dm}} sir, {{crd|G7}} don't be {{crd|Dm}} maybe
{{crd|G7}} Yes {{crd|Am}} sir, {{crd|G7}} that's my {{crd|Dm}} baby {{crd|C}} now {{crd|G7}}
{{crd|C}} Yes {{crd|Am}} ma'am, {{crd|C}} we've de{{crd|Am}}cided
{{crd|G7}} No {{crd|Dm}} ma'am, {{crd|G7}} we won't {{crd|Dm}} hide it
{{crd|G7}} Yes {{crd|Am}} ma'am, {{crd|G7}} that's my {{crd|Dm}} baby {{crd|C}} now
By the way, {{crd|C7}} by the {{crd|F}} way
When we {{crd|D7}} meet that preacher
I'll {{crd|G7}} say with {{crd|G7sus2}} feel{{crd|G7}}ing
{{crd|C}} Yes {{crd|Am}} sir, {{crd|C}} that's my {{crd|Am}} baby
{{crd|G7}} No {{crd|Dm}} sir, {{crd|G7}} don't be {{crd|Dm}} maybe
<div>{{crd|G7}} Yes {{crd|Am}} sir, {{crd|G7}} that's my {{crd|Dm}} baby {{crd|C}} now.
</poem>
* {{Youtube-Suche|Yes+Sir+That's+My+Baby|Yes Sir, That's My Baby}}
===Early One Morning===
<poem>
;1
{{crd|D}}Early one morning, just {{crd|G}}as the sun was {{crd|A}}rising
I {{crd|D}}heard a maiden singing, from the {{crd|G}}va-{{crd|A}}lley be-{{crd|D}}low:
;Chorus
{{crd|A}}Oh, don't de-{{crd|D}}ceive me, {{crd|A}}Oh never {{crd|D}}leave me,
{{crd|D}}How could you {{crd|G}}use, a {{crd|D}}poor {{crd|A}}maiden {{crd|D}}so?
;2
Oh {{crd|D}}gay is garland, and {{crd|G}}fresh are the {{crd|A}}roses,
I've {{crd|D}}culled from the garden, to {{crd|G}}bind u-{{crd|A}}pon thy {{crd|D}}brow.
;3
Re-{{crd|D}}member the vows, that you {{crd|G}}made to your {{crd|A}}Mary
Re-{{crd|D}}member the bow'r, where you {{crd|G}}promised {{crd|A}}to be {{crd|D}}true.
;4
Thus {{crd|D}}sang the poor maid, her {{crd|G}}sorrows be{{crd|A}}wailing,
Thus, {{crd|D}}sang the poor maid, in the {{crd|G}}va-{{crd|A}}lley be-{{crd|D}}low.
</poem>
===Down In The River To Pray===
<poem>
As I went down in the river to pray
Studying about that good old way
And who shall wear the starry crown
Good Lord, show me the way!
O sisters let's go down,
Let's go down, come on down,
O sisters let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the robe and crown
Good Lord, show me the way!
O brothers let's go down,
Let's go down, come on down,
Come on brothers let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the starry crown
Good Lord, show me the way!
O fathers let's go down,
Let's go down, come on down,
O fathers let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the robe and crown
Good Lord, show me the way!
O mothers let's go down,
Let's go down, don't you want to go down,
Come on mothers let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the starry crown
Good Lord, show me the way!
O sinners let's go down,
Let's go down, come on down,
O sinners let's go down,
Down in the river to pray.
As I went down in the river to pray
Studying about that good old way
And who shall wear the robe and crown
Good Lord, show me the way!
</poem>
=== Wild Mountain Thyme ===
[[Datei:Wild mountain thyme - geograph.org.uk - 25029.jpg|mini]]
{{listen|filename=Christoph Nolte - The Rocky Road - The Wild Mountain Thyme.ogg|title=The Wild Mountain Thyme|description="Wild Mountain Thyme" performed by Christoph Nolte}}
<score lang="ABC" sound="1">
X: 5
T: Wild Mountain Thyme
R: barndance
M: 4/4
L: 1/8
K: Gmaj
GE|"G"D2 D2 "C"E<G-GA|"G"G6 Bd|"C"e3 e e3 d|"G"Bd-d4 Bd
"C"e4 "G"d3 B|"Em"A<G-G4AB|"Am"c3B A3G|"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|
"G"G6 Bd|"C"e3 e e3 d|"G"Bd-d4 Bd|"C"e4 "G"d3 B|"Em"A<G-G4AB|
"Am"c3B A3G|"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|"G"G6|
</score>
< !--
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Wild Mountain Thyme"
% subtitle = "MeinSubtitle"
% poet = "Texter"
% composer = "Komponist"
% arranger = "arr: ccbysa: Wikibooks (mjchael)"
}
myKey = {
\clef "treble"
\time 4/4
\tempo 4 = 100
%%Tempo ausblenden
\set Score.tempoHideNote = ##t
\key g\major
}
%% Akkorde
%% 4/4-Schlag
%% 1 . 2 . 3 . 4 .
myD = \chordmode { d,4 d d, d }
myA = \chordmode { a,,4 a, a,, a, }
myDA = \chordmode { d,4 d a,, a, }
myChords = \chordmode {
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
%% Akkorde nur beim Wechsel notieren
\set chordChanges = ##t
\partial 4 s4
\myD \myA \myDA \myD
d,1 %Schlusston
}
myMelody = \relative c'' {
\myKey
\set Staff.midiInstrument = #"trombone"
\relative c''{
\partial 4 g8 e
d4 d e16 g8.~8 a | g2. b8 d | e4. e8 e4. d8 | b d8~2 b8 d |
% GE|"G"D2 D2 "C"E<G-GA|"G"G6 Bd|"C"e3 e e3 d|"G"Bd-d4 Bd
e2 d4. b8 | a16 g8.~2 a8 b | c4. b8 a4. g8 |e8 g8~2 g8 e | d4 4 e16 g8.~g8 a
% "C"e4 "G"d3 B|"Em"A<G-G4AB|"Am"c3B A3G |"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|
c4. b8 a4. g8 | e g8~2 8 e | d4 4 e16 g8.~8 a | g2.
% "Am"c3B A3G|"C"EG-G4 GE|"G"D2 D2 "C"E<G-GA|"G"G6|
\bar "|."
}
}
myLyrics = \lyricmode {
\set stanza = "1."
Häns -- chen klein | ging al -- lein | in das Haus hin | -- ein. |
}
\score {
<<
\new ChordNames { \myChords }
\new Voice = "mySong" { \myMelody }
\new Lyrics \lyricsto "mySong" { \myLyrics }
% \new TabStaff { \myChords } %% Check
>>
\midi { }
\layout { }
}
%% unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
-->
(also known as "Purple Heather" and "Will Ye Go, Lassie, Go?") is a Scottish/Irish folk song.
<poem>
;1
O the summer time has come
And the trees are sweetly blooming
And wild mountain thyme
Grows around the purple heather.
Will you go, lassie, go?
;Chorus
And we'll all go together,
To pull wild mountain thyme,
All around the purple heather.
Will you go, lassie, go?
;2
I will build my love a tower,
By yon clear crystal fountain,
And on it I will pile,
All the flowers of the mountain.
Will you go, lassie, go?
;3
I will range through the wilds
And the deep land so dreary
And return with the spoils
To the bower o' my dearie.
Will ye go lassie go ?
;4
If my true love she'll not come,
Then I'll surely find another,
To pull wild mountain thyme,
All around the purple heather.
Will you go, lassie, go?
</poem>
== Akkordfolge NEM ==
<score>
<<
\new ChordNames { \chordmode {
d1 c g b
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< d-1\5 a-2\4 d'-3\3 fis'-4\2 a'-1\1 > % d
< c-1\5 g-2\4 c'-3\3 e'-4\2 g'-1\1 > % C/B
< g,-1 d-3 g-4 b-2 d'-1 g'-1 > % G
< b,-1\5 fis-2\4 b-3\3 dis'-4\2 fis'-1\1 > % B
}
>>
</score>
<score>
<<
\new ChordNames { \chordmode {
c1 a g e d
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'blue
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< e\6 c'\5 e'\4 g'\3 c''\2 e''\1 > % C
< e\6 a\5 e'\4 a'\3 cis''\2 e''\1 > % A
< g\6 b\5 d'\4 g'\3 b'\2 g''\1 > % G
< e\6 b\5 e'\4 gis'\3 b'\2 e''\1 > % E
< d'\4 a'\3 d''\2 fis''\1 > % d
}
\new ChordNames { \chordmode {
c1:m a:m g:m e:m d:m
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'blue
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< es\6 c'\5 es'\4 g'\3 c''\2 es''\1 > % C
< e\6 a\5 e'\4 a'\3 c''\2 e''\1 > % A
< g\6 bes\5 d'\4 g'\3 bes'\2 g''\1 > % G
< e\6 b\5 e'\4 g'\3 b'\2 e''\1 > % E
< d'\4 a'\3 d''\2 f''\1 > % d
}
>>
</score>
== Umkehrung mit CAGED ==
<score>
<<
\new ChordNames { \chordmode {
a1 g:/b e e:/gis
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< a, e-1 a-2 cis'-3 > % A
< b,-2 d g d'-4 > % G/B
< e-1\5 b-2\4 e'-3\3 gis'-4\2 b'-1\1> % E
< gis-2\5 b-1\4 e'-1\3 b'-4\2 > % E/G#
}
>>
</score>
<score>
<<
\new ChordNames { \chordmode {
e1 d:/fis a a:/cis
}}
\new FretBoards {
\override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
\override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< e, b,-2 e-3 gis-4 b e'> % A
< fis,-2 a, d a-3 d'-4 > % D/F#
< a,-1\6 e-3\5 a-4\4 cis'-2\3 e'-1\2 a'-1\1> % A
< cis-2\6 e-1\5 a-1\4 e'-3\3 a'-4\2 > % A/C#
}
>>
</score>
== Canon in D ==
<score sound="1" raw="1">
\version "2.20.0"
\header {
title = "Canon"
composer = "M: Johann Pachebel (1653-1706)"
key="D"
composer= "Pachelbel"
arranger = "arr.: ccbysa Wikibooks (mjchael)"
}
myKey = {
\language "deutsch"
\tempo 4 = 100
%Tempo ausblenden
\set Score.tempoHideNote = ##t
\clef "G_8" \time 4/4
\key d \major
\set Staff.midiInstrument = #"electric guitar (clean)"
}
myMelody = \relative c {
\myKey
\set minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\stemUp
\repeat volta 2{}
%^\markup { \bold {Em7} }
%\break
fis2 e d cis h a h cis
\voiceOne
fis' e d cis h a
h cis fis e d cis
h a h cis
d4 \oneVoice d e cis
d fis a a,
h g fis a g d' cis a
d8 cis d fis, a a cis4
d8 d fis4 a a8 h
g fis e g fis e d cis
\voiceOne
h cis d4~ d8 cis16 d cis4
d8 cis d fis, a4 cis d fis a a8 h
g fis e g fis e d cis
h a d4 ~ d8 cis16 d cis4\trill
\oneVoice
\set Timing.beatStructure = #'(1 1 1 1)
d8 fis16 g a8 fis16 g a a, h cis d e fis g
fis8 d16 e fis8 fis,16 g a h a g a fis g a
d8 h16 a g8 fis16 e fis e d e fis g a h
d8 h16a h8 e16 d cis h cis d e fis g e
fis8 d16 cis d8 fis, e cis'16 d e8 cis
% fis d16 cis d8 fis, e cis'16 d e8 cis
d h16 a h8 d, cis fis16 g a8 fis
h g16 fis g8 h a fis'16 e fis8 d
h d16 cis d8 fis, e a d cis
\voiceOne
\set Timing.beatStructure = #'(2 2)
d4. fis8 fis g fis e
d4. d8 d e d cis
h4. h8 a4 d
d8 c h c a2
\oneVoice
d4 fis8 a a h a g
\voiceOne
s1 s
h,2 a ~ a4 \oneVoice d e cis
d fis, a4. h8
g4 d fis a
\voiceOne
g fis e a
fis1\fermata
\bar "||."
% \bar "|." |
}
Gitarre = \myMelody
%% Layout = Noten mit Tab
\score {
<<
%% Noten
\new Voice {
\myKey
\Gitarre
}
%% Tabulatur
\new TabStaff {
\tabFullNotation
\Gitarre
}
>>
\layout {}
}
%% Midiausgabe
\score {
<<
\unfoldRepeats {
\new Staff <<
\myKey
\Gitarre
>>
}
>>
\midi {}
}
%& unterdrückt im raw="1"-Modus das DinA4-Format.
\paper {
indent=0\mm
%& DinA4 0 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Takte auszählen ==
GEMISCHTE TAKTE AUSZÄHLEN
Speziell ein Tutorial für Kerstin Jentzsch
Ich gehe mal davon aus, das du dich ganz grob mit den Notenwerten auskennst, und eine Methode suchst, wie du sie beim täglichen Üben einsetzen kannst.
Versuche es mal mit Zahlen.
Die Idee hab ich von
Mike Schönmehl "Jazz und Pop Musiklehre"
Atlantis-Schott-Musikverlag
Alle viertel-Noten werden mit einfachen Zahlen ausgesprochen
1 . 2 . 3 . 4 .
Eins zwei drei vier
oder
fünf sechs sieben acht
oder
neun zehn elf zwölf
Es ist egal welche dieser Zahlenfolgen du nimmst es ist für jede Zahl nur eine Silbe.
Jetzt komme die Achtel:
1 + 2 + 3 + 4 +
Drei-zehn, vier-zehn, fünf-zehn, sech-zehn
sieb-zehn, ach-zehn, neun-zehn, zwan-zig
Was auch gut geht ist
Ein-er, Zwei-er, Drei-er, vier-er
Hier haben alle Zahlen zwei Silben und teilen sich wie zwei Achtel auf.
Jetzt kommen die Sechzehntel
1 e + e 2 e + e 3 e + e 4 e + e
Ein-und-zwan-zig, Zwei-und-zwan-zig, Drei-und-zwan-zig, Vier-und-zwan-zig
Fünf-und-zwan-zig, Sechs-und-zwan-zieg, sieben-und-zwan-zieg, Acht-und-zwan-zig
Hier haben alle Zahlen vier Silben und teilen sich wie vier Sechzentel auf.
Jetzt die Triolen:
1-er-lei 2-er-lei 3-er-lei 4-er-lei
Ein-hun-dert, Zwei-hun-dert, Drei-hun-dert, Vier-hun-dert
Hier haben alle Zahlen drei Silben und teilen sich wie drei Triolen auf.
Wir sind es beim Zählen gewöhnt, in bestimmten Schritten zu zählen, so das wir 1-12 meist genau so langsam bzw. schnell zählen wie 13-20 oder wie 21-29. Und auch die Hunderter werden im gleichen Schritt gezählt.
Man macht ganz automatisch zwei-Achtel, vier-Sechzentel oder 3-Triolen.
Man kann versuchen, sich für viele Rhyhtmen einfach eine Zahlenfolge aufschreiben, und sich auch neue Kombinationen einfallen lassen.
Wie wäre es wenn man viertel, triolen und Sechzentel miteiander übt?
Eins | Zwei-hund-dert | drei | vier-und-zwan-zig
Ein-und-zwan-zig| zwei | drei-hun-dert | vier
Zehner-Zahlen könnten sich sogar für einen Schuffle eignen
1 . + 2 . + 3 . + 4 . +
Bei der Zehn muss man sich was einfallen lassen, aber dann kann man gut im Shuffle zählen
Zehn---tel, Zwan---zig, Drei---ßig, Vier---zig
Zehn---tel, Zwei-hund-dert, Drei---ßig, Vier---zig
So in etwa
Die Methode ist nicht der Weisheit letzter Schluss, aber vielleicht hilft es dem einen oder anderen beim Üben.
Gruß Mjchael
===Gallerie von Red_Rooster===
Die meisten Gifs und JPG wurden von Red_Rooster hochgeladen. Die müssen nach SVG umgestaltet werden.
<!-- Bilder durch SVG ersetzen -->
{{Klappbox|style=border:1px solid grey; margin:6px 0 6px 0;|bg1=#EAEAEA|verborgen=true|ta1=left|fw1=bold
|Titel= Bilder durch SVG ersetzen
|Inhalt=
{{rot|Bilder nicht löschen!!!!!!!!! Sie müssen weltweit durch SVG ausgetauscht werden, und dann erst auf den Commons für die Schnelllöschung vorgeschlagen werden, und dann erst dürfen sie entfernt werden. Und das mache ich selbst!}}
<gallery>
Image:00.01.D.1.png|
Image:00.01.D.2.png|
Image:01.01.D_A1.png|
Image:01.01.D_A2.png|
Image:01.01.D_A3.png|
Image:01.01.D_A4.png|
Image:01.01.D_A5.png|
Image:01.01.D_A6.png|
Image:01.01.D_A7.png|
Image:01.01.D_A8.png|
Image:01.01.D_A91.png|
Image:01.01.D_A92.png|
Image:02.01.D.gif|
Image:02.01.DG1.gif|
Image:02.01.DG2.gif|
Image:02.01.DG3.gif|
Image:02.01.G.gif|
Image:02.01.G_Schluessel.png|
Image:%03.01.C.gif|
Image:03.01.D_C.gif|
Image:03.01.G C.png|
Image:Druck_mittig.png|
Image:Druck_zu_dicht.png|
Image:Druck_zu_weit.png|
Image:%Durstellung.gif|
Image:Durstellung1_4.gif|
Image:EADGHE.gif|
Image:%G_Langsam.gif|
Image:Halbtonschritte_I.gif|
Image:HCF.gif|
Image:Mollstellung1_3.gif|
Image:MR_Durstellung.gif|
Image:MR_Mollstellung.gif|
</gallery>
}}
<pre>
{{duplicate|Crd_Form_C.svg}}
*replaced by [[image:Crd Form C.svg]]
*original is unused or replaced
--~~~~
</pre>
== Spielwiese ==
*[[Benutzer:Mjchael/ Spielweise | Spielweise (Tests für meine Projekte)]]
== Zeichnen und Schreiben ==
*[[Gitarre: Grifftabelle einfach | einfache Grifftabelle]]
*[[Liederbuch]] (weitere Übungsbeispiele für die "Diplome"
== Eigendichtungen ==
*[[Benutzer:Mjchael/ Eigendichtungen | Lob und Kritik und Ideen für selbstkomponierte Lieder]]
==Lieder==
[[Liederbuch/ Pläne und Wünsche]]
== Seitenüberblick ==
<!-- Alle Gitarrenseiten -->
{{Klappbox|style=border:1px solid grey; margin:6px 0 6px 0;|bg1=#EAEAEA|verborgen=true|ta1=left|fw1=bold
|Titel= Alle Gitarrenseiten
|Inhalt={{Spezial:Prefixindex/Gitarre}}
}}
<!-- Alle Liederbuchseiten -->
{{Klappbox|style=border:1px solid grey; margin:6px 0 6px 0;|bg1=#EAEAEA|verborgen=true|ta1=left|fw1=bold
|Titel= Alle Liederbuchseiten
|Inhalt={{Spezial:Prefixindex/Liederbuch}}
}}
<!-- Ende Inhalt -->
|}
<!-- Ende Äußere Tabelle -->
8yjhxjbcraurumt29ks99q3iwimld2e
Ing Mathematik: Python
0
117969
1091890
1091888
2026-10-03T13:35:18Z
Intruder
1513
/* Py5 */
1091890
wikitext
text/x-wiki
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
= Hallo Welt und allgemeine Hinweise =
== Was ist Python ==
* Python ist eine universelle höhere Programmiersprache.
* Python ist objektorientiert.
* Python ist Open-Source (Python Software Foundation License).
* Python ist für viele Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
* Python ist ein Interpreter.
* Python ist durch Module fast beliebig erweiterbar.
* Python als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
* Python ist in etlichen Anwendungsprogrammen (z.B. {{W|FreeCAD}}, {{W|LibreOffice}}, {{W|GIMP}}, {{W|Blender (Software) | Blender}}) als Makrosprache verwendbar.
{{Wikipedia | Python (Programmiersprache)}}
== Python installieren ==
=== MS Windows ===
Laden Sie das aktuelle Python-Paket von der Webseite [https://www.python.org/] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.
=== Linux ===
Entweder ist Python bereits standardmäßig installiert, ansonsten ist die Installation mittels Paketmanagementsystem einfach möglich. Aber auch die Spyder-Entwicklungsumgebung ([https://www.spyder-ide.org]) bietet einen guten Einstieg mit Python (das gilt auch für MS Windows). Spyder bringt auch schon etliche wichtige Module standardmäßig mit.
== Python starten ==
=== MS Windows ===
Das Icon für das Python-Programm doppelklicken. Und schon startet das Programm.
[[Datei:PythonIng_start1.jpg]]
Python im interaktiven Modus präsentiert sich dann so:
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Alternativ kann das Programm auch über die Eingabeaufforderung oder die PowerShell gestartet werden:
c:\devel\Python>python.exe
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
=== Linux ===
Tippen Sie einfach das Wort „python“ (oder unter openSUSE Tumbleweed z.B. auch „python3.11“ oder „python3.13“) in einem Linux-Terminal ein, schließen den Befehl mit der RETURN-Taste ab, und schon startet Python im interaktiven Modus:
Python 3.13.12 (main, Feb 09 2026, 22:37:44) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Es gibt auch noch andere Möglichkeiten Python zwecks Programmausführung zu starten, z. B. den {{W|Shebang}} (<code>#!</code>) am Beginn eines Python-Scripts. Das Script sei als Script.py gespeichert. Dann kann das Script mit ./Script.py ausgeführt werden. Für openSUSE Tumbleweed sei nachfolgend ein lauffähiges "Hallo Welt!"-Script angegeben. Es wird in diesem Script der Python-Interpreter in der Version 3.13 verwendet :
#!/usr/bin/python3.13
print("Hallo Welt!")
Die Berechtigungen zum Ausführen der Datei müssen natürlich noch richtig gesetzt werden, z.B. mittels <code>chmod 777 Script.py</code>. <small><code>chmod</code> ist die Abkürzung für"'''ch'''ange file '''mod'''e bits".</small>
<small>Die "Maske" <code>777</code> ist nur für Testzwecke sinnvoll, weil sie leicht zu merken ist und für alle Benutzer alle Zugriffsberechtigungen ('''r'''ead/'''w'''rite/e'''x'''ecute für owner/group/others) setzt. Im richtigen Einsatz wird man das aus Sicherheitsgründen nicht so handhaben, sondern nur die Berechtigungen setzen, die unbedingt erforderlich sind. Welche Zugriffsberechtigungen gesetzt sind, kann man z.B. mit dem Befehl <code>ls -l</code> oder <code>ll</code> ('''l'''i'''s'''t directory contents) erfragen. Aber dazu im Moment genug. Erfahrene Linux-Nutzer kennen das ohnehin und Anfänger sollen jetzt nicht mit Linux-Interna überfordert werden. Bei Bedarf siehe die Linux-Man-Pages oder dezidierte Bücher zu Linux.</code></small>
<small>Oder das Script wird in einen Pfad verschoben, in dem sich ausführbare Programme generell befinden (welche Verzeichnisse im PATH liegen, kann bspw. mit <code>echo $PATH</code> abgefragt werden). Das Script kann dann wie ein normales Programm ohne weitere Angaben mit Script.py gestartet werden. Alternativ wird nicht das Script an sich verschoben, sondern nur ein symbolischer Link angelegt, z.B. mit <code>ln -s ~/tmp/Script.py ~/.local/bin/Script.py</code>. <code>~/.local/bin</code> sei ein im PATH gelegenes Verzeichnis. Dies sind aber schon Features für fortgeschrittene Linux-Benutzer und werden am Anfang eher selten benötigt.</small>
== Ein paar Worte zur Erklärung ==
=== Tests ===
Getestet wurden die Beispiele unter den Betriebssystemen
* MS Windows 10 mit der Python-Version 3.12.0 (teilweise auch mit 3.12.2 und 3.13.1; nur die Inhalte die bis spätestens Juli 2025 erstellt wurden)
* MS Windows 11 ab der Python-Version 3.13.4 (nur zum Teil; ab Juli 2025)
* openSUSE Leap 15.6 mit der Python-Version 3.11.12 (Spyder, nur vereinzelt) und zum Teil mit 3.12.11 (ab Juli 2025 bis November 2025).
* openSUSE Tumbleweed ab der Python-Version 3.13.9 (nur vereinzelt, ab November 2025)
=== Popularität ===
* An Beliebtheit rangiert Python mit Stand September 2026 mit einem Rating von 17,76% an 1. Stelle vor C und C++ (lt. [https://www.tiobe.com/tiobe-index/ TPCI - TIOBE Programming Community Index]).
* Lt. [https://innovationgraph.github.com/global-metrics/programming-languages GitHub Top 50 Programming Languages Globally] lag Python im Q1/2026 auf Rang 2, vor TypeScript und hinter JavaScript.
* [https://pypl.github.io/PYPL.html PYPL] (Popularity of Programming Language Index) ist ein anderer Popularitätsindex für Programmiersprachen. Auch hier liegt Python mit großem Vorsprung auf dem ersten Platz (52,08%), gefolgt von Java (13,34%) und C/C++ (7,99%) (Stand September 2026).
=== Namensgebung ===
Der Name "Python" rührt von der Komikertruppe {{W|Monty Python}} her. Die Icons für Python (z.B. Python selbst, Eric IDE, IDLE) sind aber durch die Python-Schlangenart symbolisiert.
<gallery>
Python-logo-notext.svg|Python-Logo
Guido van Rossum in PyConUS24.jpg|{{W|Guido van Rossum}} (geb. 1956), der Erfinder von Python
</gallery>
== Ein erstes Programm ==
Kommentare werden in Python mit der Raute (#) eingeleitet. Sie werden vom Python-Interpreter ignoriert. Text kann mit der print-Funktion ausgegeben werden. Starten Sie Python und geben sie folgende Anweisungen zeilenweise ein
>>> # Das ist ein Kommentar
>>> print("Hallo Welt!")
Als Ergebnis erhalten Sie
Hallo Welt!
Der Prompt (>>>) ist selbstverständlich nicht einzutippen, sondern wird vom Python-System geliefert.
Strings können in Python entweder in Anführungszeichen (") gesetzt werden oder in Hochkommatas('). In diesem Text wird die erste Variante bevorzugt eingesetzt.
Im Gegensatz zu Julia ist es hier egal, ob zwischen <code>print</code> und der öffnenden Klammer Leerzeichen stehen.
= Python als Taschenrechner =
== Allgemeines ==
Wir wollen 3 * 5 berechnen. Dazu starten wir Python im interaktiven Modus. Geben Sie dann die Formel
>>> 3 * 5
ein, drücken die Taste ENTER/RETURN ({{Taste|↵}}) und erhalten als Ergebnis
15
Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck <math>\sin\sqrt{15}</math> berechnen :
>>> import math
>>> math.sin(math.sqrt(15))
-0.6679052983383519
Als erstes wird das math-Modul importiert. Dann wird der mathematische Ausdruck berechnet.
Eine andere Variante, die dasselbe Ergebnis liefert, ist
>>> from math import *
>>> sin(sqrt(15))
-0.6679052983383519
Es wird also aus dem Modul <code>math</code> alles importiert (erkennbar am <code>*</code>). Will man nicht alles importieren, so kann man das auch einschränken:
>>> from math import sin, sqrt
Beenden lässt sich das Python-Programm durch Eingabe von <code>exit()</code> (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken).
== Die Hilfefunktion von Python ==
Bei Eingabe der Anweisung <code>help</code> oder <code>help()</code> springt Python in den Hilfemodus.
Eingabe:
>>> help()
Eingabe:
help> math.sin
Ausgabe:
Help on built-in function sin in math:
math.sin = sin(x, /)
Return the sine of x (measured in radians).
Für die komplette Python-Dokumentation siehe [https://docs.python.org/3/]. Verlassen kann man den Hilfemodus durch das Drücken von STRG-C, bzw. der Eingabe von q, quit oder exit mit anschließendem Drücken der RETURN-Taste.
== Aufgaben ==
* Erkunden Sie die Tangensfunktion "tan" mittels Python-Hilfe (vergessen Sie nicht das math-Modul zu importieren und das <code>math.</code> vor <code>tan</code>)
* Berechnen Sie mit Python den Ausdruck <math>\frac{1}{2}\cdot \text{e}^2 \cdot \tan(\pi/3)</math>. Siehe für die Exponentialfunktion im Python-Hilfesystem auch den Befehl <code>math.exp</code>. Alternativ kann auch die Konstante <code>math.e</code> eingesetzt werden. Potenzieren kann man bei Python mit dem **-Operator (z.B. 2**3 = 8). Für <math>\pi</math> gibt es <code>math.pi</code>.
= Python als Scriptsprache =
Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.py
# Das ist ein Kommentar
print("Hallo Welt!")
Python-Dateien werden mit der Dateiendung .py versehen. Achten Sie darauf, dass vor dem print keine Leerzeichen vorhanden sind. Das ist eine Python-Eigenheit. Wie wir später sehen werden, nutzt Python Einrückungen als syntaktisches Mittel, z.B. um bei Schleifen den Schleifenkörper zu kennzeichnen.
Danach bringen Sie die Skriptdatei test1.py (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:
1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ auch die Windows PowerShell). Das sieht dann etwa so aus:
Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\xyz>
: <small>Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol ([[Image:Windows_logo_-_2021_(Black).svg|10px]]) mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell unter Windows 10 den Eintrag "Windows PowerShell", unter Windows 11 den Eintrag "Terminal"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort <code>cmd</code> ein und mit "OK" wird das Ganze bestätigt.</small>
2) Wechseln Sie mittels <code>cd c:\tmp</code> in das Verzeichnis c:\tmp
3) Angenommen, Sie haben Python unter dem Pfad <code>c:\devel\Python\</code> installiert. Starten Sie das Programm so (der Prompt <code>c:\tmp></code>ist natürlich nicht mit einzutippen):
c:\tmp>c:\devel\Python\python.exe test1.py
4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm
Hallo Welt!
Die Vorgehensweise unter Linux ist prinzipiell gleich. Die kleinen Unterschiede, wie z.B. der Slash statt dem Backslash in Pfadangaben, sollten für Linux-Benutzer keine Hürde darstellen.
== Variablen ==
Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9) und Underscores (_) bestehen, dürfen aber nicht mit einer Zahl beginnen. Führende Underscores haben u.a. im Kontext mit der Objektorientierten Programmierung eine spezielle Bedeutung und sollten nicht für "normale" Variablenbezeichner verwendet werden.
Gültige Variablenbezeichner wären also:
xyz
x1
_wert
name_anzahl
Theoretisch kann man auch Umlaute, griechische Buchstaben u.ä. in Variablenbezeichnern nutzen, z.B.
ößÜ = 16
α = 134
print(ößÜ)
print(α)
Ausgabe:
16
134
Davon wird aber aus offensichtlichen Gründen ({{W|Englisch als Lingua franca}}) abgeraten. Das Eurozeichen (€) etc. darf man ohnehin nicht in Variablenbezeichnern verwenden, dies ergäbe einen Syntaxfehler. Siehe dazu auch [https://peps.python.org/pep-3131/].
Es gibt in Python etliche Schlüsselwörter (z.B. for, if oder return). Diese dürfen nicht als eigene Variablenbezeichner verwendet werden. Eine Liste aller Schlüsselwörter liefert das Script
import keyword
print(keyword.kwlist)
<small>Übung: Speichern Sie dieses Script in eine Datei, z.B. in c:\tmp\test1.py. Führen Sie diese Datei aus, um die Liste der Schlüsselwörter auszugeben.</small>
Da Python case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:
xyz
XYZ
xYz
Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.py gespeichert.
x = 5
y = 10
z = x*y
print(z)
Bringen Sie die Datei test1.py zur Ausführung, so erhalten Sie folgende Bildschirmausgabe
50
Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben. Dies führt aber zu unübersichtlichem Code.
x = 5; y = 10; z = x*y; print(z)
Ausgabe:
50
Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.
x = 5
# x = x - 2
x -= 2
print(x)
Bildschirmausgabe:
3
Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Den Inkrement-/Dekrementoperator (z.B. x++ oder x--) aus C/C++ oder Java kennt Python aber nicht.
Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Python problemlos möglich:
import math
wert = 10
print(wert)
wert = 35.5
print(wert)
wert = "Hallo"
print(wert)
wert = math.pi
print(wert)
Ausgabe:
10
35.5
Hallo
3.141592653589793
== Physische und logische Zeilen ==
In Python muss eine Anweisung in einer logischen Zeile Platz finden. Wird eine Anweisung aber zu lang für eine Zeile, dann kann sie in mehrere physische Zeilen unterteilt werden. Dies kann einerseits durch einen Backslash am Ende einer Zeile geschehen, z.B.
a = 2 + \
5
Dies stellt eine logische Zeile dar, die in zwei physische Zeilen unterbrochen ist.
Geklammerte Ausdrücke werden automatisch zu einer logischen Zeile verbunden, z.B.
a = (2 +
5)
Achtung: Im ersten Beispiel darf nach dem Backslash nichts mehr stehen, auch kein Kommentar. Dies trifft im zweiten Bespiel nicht zu, hier könnte noch ein Kommentar folgen, z.B.
a = (2 + # Kommentar
5)
Auch für Strings gibt es Möglichkeiten, diese auf mehrere Zeilen aufzuspalten.
# Kurzer String
str1 = "ABC"
# Langer String
str2 = """Hallo Welt,
Grüetzi Schwyzer,
Servus an alle"""
# Backslash
str3 = "UVW\
XYZ"
# Mit Klammern
str4 = ("Sehr langer Text, der automatisch .............. "
"in einer einzigen Variable zusammengefügt wird."
)
print(str1)
print(str2)
print(str3)
print(str4)
Ausgabe:
ABC
Hallo Welt,
Grüetzi Schwyzer,
Servus an alle
UVWXYZ
Sehr langer Text, der automatisch .............. in einer einzigen Variable zusammengefügt wird.
==Hexadezimale, oktale, binäre und andere Zahlen==
d = 1050 # Dezimalzahl
h = 0xAA2 # Hexadezimalzahl
o = 0o12 # Oktalzahl
b = 0b100001101 # Binärzahl
print(d)
print(h)
print(o)
print(b)
Ausgabe:
1050
2722
10
269
Groß- und Kleinbuchstaben sind in obigen Literalen übrigens egal. So kann man z.B. statt <code>0b1001</code> auch <code>0B1001</code> schreiben (siehe dazu [https://docs.python.org/3/reference/lexical_analysis.html#integer-literals]).
Sie können auch dezimale in hexadezimale Zahlen umwandeln, usw.:
h = hex(1050) # Dezimalzahl -> Hexadezimalzahl
b = bin(1050) # Dezimalzahl -> Binärzahl
o = oct(1050) # Dezimalzahl -> Oktalzahl
print(h)
print(b)
print(o)
Ausgabe:
0x41a
0b10000011010
0o2032
Gegeben sei die Zahl 121 zur Basis 3. Diese soll in eine Dezimalzahl umgewandelt werden. Das kann so geschehen:
z = int("121", 3)
print(z)
Ausgabe:
16
Dass dies richtig ist, davon kann man sich folgendermaßen überzeugen:
<math> 1 \cdot 3^2 + 2 \cdot 3^1 + 1 \cdot 3^0 = 9 + 6+ 1 = 16 </math>
Zahlen übersichtlicher schreiben kann man auch mittels Underscore, z.B.:
print("Eine Million (Variante 1) =", 1000000)
print("Eine Million (Variante 2) =", 1_000_000)
print("Eine Rechnung:", 2_000 * 400_000);
Es ergibt sich bei beiden Varianten die gleiche Ausgabe. Variante 2 ist aber im Sourcecode leichter lesbar, detto die Zahlen in der Rechnung:
Eine Million (Variante 1) = 1000000
Eine Million (Variante 2) = 1000000
Eine Rechnung: 800000000
== Strings und Platzhalter==
Ein paar einfache Beispiele:
print("Hallo {}" . format("Hugo"))
print("Hallo {:s}" . format("Hugo"))
print("Hallo %s" % "Hugo")
Ausgabe:
Hallo Hugo
Hallo Hugo
Hallo Hugo
Python-Code (formatted string literals, Beispiel 1):
str1 = "Hallo"
str2 = "Hugo"
print(f"{str1} {str2}")
Ausgabe:
Hallo Hugo
Python-Code (formatted string literals, Beispiel 2):
wert = 11.567
print(f"Ausgabe: {wert:.5f}")
Ausgabe:
Ausgabe: 11.56700
Komplexere Beispiele:
print("Hallo {} und {}" . format("Hugo", "Mike"))
print("Hallo {name1} und {name2}" . format(name2="Hugo", name1="Mike"))
# Füllzeichen: *
# Bündigkeit: > (=rechts), < (=links), ^ (=zentriert)
# Feldweite: 10
# Typ: s (=String), f (=Gleitkommazahl), d (=Dezimalzahl) etc.
print("Hallo {:*>10s}" . format("Hugo"))
print("Hallo {:*<10s}" . format("Hugo"))
Ausgabe:
Hallo Hugo und Mike
Hallo Mike und Hugo
Hallo ******Hugo
Hallo Hugo******
Python-Code:
str = "Hallo\t%s\t%7.2f\t%10.2e\t%i" % ("Hugo", 12.34567, 34.567, 264)
print(str)
Ausgabe:
Hallo Hugo 12.35 3.46e+01 264
== Unicode ==
Neben den bekannten ASCII-Zeichen lassen sich Zeichen auch mittels Unicode beschreiben. Griechische Buchstaben oder komplexere mathematische Operatoren - all das sollte kein Problem sein. Siehe auch {{W|Unicode}}, {{W|Liste der Unicodeblöcke}} und {{W|Unicodeblock Mathematische Operatoren}}. Im Folgenden werden ein paar Zeichen (Allquantor, Nabla-Operator, Existenzquantor), die man aus der Mathematik kennt, erzeugt.
ch1 = "\N{FOR ALL}"
ch2 = "\N{NABLA}"
ch3 = "\u2203"
print(ch1, ch2, ch3)
Ausgabe:
∀ ∇ ∃
<small>Diese Ausgabe ergibt sich z.B. mit der IDLE-Shell oder mit Cygwin. Beim Ausführen über die Windows-Eingabeaufforderung oder Windows PowerShell unter MS Windows 10 erfolgt keine korrekte Darstellung. IDLE ist die mit Python mitgelieferte IDE ('''I'''ntegrated '''D'''evelopment '''E'''nvironment, Integrierte Entwicklungsumgebung). Gegen Ende dieses Textes wird IDLE kurz beschrieben.
Das Problem mit der Windows Eingabeaufforderung lässt sich aber umgehen. Man muss nur eine Schriftart auswählen, die die Zeichen kennt, z.B. "DejaVu Sans Mono". Dazu klicken Sie einfach bei der Eingabeaufforderung mit der rechten Maustaste oben auf die weiße Leiste und wählen im aufpoppenden Fenster den Menüpunkt "Eigenschaften". Es öffnet sich ein Dialogfenster. Über den Reiter "Schriftart" lässt sich nun die Schriftart einstellen. Unter MS Windows 11 oder openSUSE Leap 15.6 (bash-Konsole) gibt es dieses Problem ohnehin nicht.</small>
== Reguläre Ausdrücke ==
Python kennt auch {{W|Regulärer Ausdruck|reguläre Ausdrücke}}. Dazu gibt es in Python das Modul <code>re</code>. Beipielsweise sollen alle Zahlen (<math>\text{zahl}\in\mathbb{N}_0</math>) in einem String gesucht und ausgegeben werden. Als String sei gegeben: <code>3x Grüße und 100 Kekse.</code> Das Muster (Pattern) ist <code>\d+</code>. <code>\d</code> steht für eine Dezimalziffer 0-9. Das Plus-Zeichen (+) steht symbolisch für ein oder mehrere Zeichen des vorherigen Ausdrucks. Hier also ein oder mehrere Dezimalziffern. Es wird die Funktion <code>findall</code> aus dem Modul <code>re</code>verwendet.
Python-Code:
from re import findall
str = "3x Grüße und 100 Kekse."
pat = "\\d+" # Doppel-Backslashes müssen verwendet werden, sonst gibt Python eine Warnung aus!
# alternativ: pat = r"\d+"
# oder: pat = "[0-9]+"
numb = findall(pat, str)
print(numb)
Ausgabe:
['3', '100']
Python kennt noch viele weitere Möglichkeiten mittels regulärer Ausdrücke zu hantieren. Dies soll hier aber nicht vertieft werden, da das Thema schon ziemlich speziell und komplex ist. Bei Bedarf siehe aber z.B. die Bücher ''Weigend, Seite 380ff'' und ''Ernesti, Kaiser'' [https://openbook.rheinwerk-verlag.de/python/28_001.html] oder die Python-Dokumentation [https://docs.python.org/3/library/re.html]. Auch [[Python unter Linux: Reguläre Ausdrücke]] liefert ein umfangreiches und brauchbares Python-2-Kapitel zu den regulären Ausdrücken. Die dort gelisteten Beispiele müssten ggf. vor Verwendung auf Python-3 umgeschrieben werden. <small>Wie macht man das? Dazu siehe z.B. [https://openbook.rheinwerk-verlag.de/python/43_001.html], [https://portingguide.readthedocs.io/en/latest/] oder [https://www.digitalocean.com/community/tutorials/how-to-port-python-2-code-to-python-3]</small>
<small>Es gibt auch ein externes Modul ''regex'', das bei Bedarf extra installiert werden muss ([https://pypi.org/project/regex/]). Es bietet zusätzliche Funktionalität und gründlicheren Unicode-Support. Dies sei hier aber nur der Vollständigkeit halber erwähnt.</small>
== Verzweigungen ==
=== if ===
Die IF-Verzweigung sei aus anderen Programmiersprachen bereits bekannt. In {{W|Pseudocode}} lässt sie sich folgendermaßen darstellen:
WENN bedingung TRUE
führe block1 aus
SONST
führe block2 aus
ENDE
Als {{W|Aktivitätsdiagramm|UML-Aktivitätsdiagramm}} sieht das in etwa so aus:
[[File:If-Then-Else-diagram.svg|200px]]
Und als {{W|Nassi-Shneiderman-Diagramm|Nassi-Shneiderman-Struktogramm}} so:
[[File:Zweiseitige Auswahl.png|250px]]
In Python gibt es keinen expliziten ENDE-Kennzeichner. Stattdessen wird der Code durch Einrückungen strukturiert. Alles mit der gleichen Einrückungstiefe gehört zum selben Block. Dies zeichnet Python vor anderen Programmiersprachen aus.
Die test1.py-Datei laute also wie folgt:
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4
Man achte auch auf die Doppelpunkte in der if- und else-Zeile. Darauf vergisst man gerne, wenn man von anderen Programmiersprachen kommt.
Folgendes wäre in Python ein Fehler (genauer gesagt ein IndentationError).
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Auch Nachstehendes würde nicht zum gewünschten Ergebnis führen (löst aber keine Fehlermeldung aus). Der letzte print-Befehl ist schon außerhalb der IF-ELSE-Verzweigung.
x = 3
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
x ist kleiner als 4
x ist groesser oder gleich 4
Python kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:
<, <= ... kleiner (gleich)
>, >= ... größer (gleich)
== ... gleich
!= ... ungleich
is ... identisch
is not ... nicht identisch
and ... AND
or ... OR
not ... NOT
Beispielsweise:
a = 5
b = 9
if a<=10 and b!=7:
print("OK")
else
print("Nicht OK")
Ausgabe:
OK
Der else-Block kann übrigens auch ersatzlos entfallen. Als Pseudocode sieht das so aus
WENN bedingung TRUE
führe block aus
ENDE
Mehrfache Verzweigungen werden durch das elif-Konstrukt erstellt. In Pseudocode:
WENN bedingung1 TRUE
führe block1 aus
SONST WENN bedingung2 TRUE
führe block2 aus
SONST WENN bedingung3 TRUE
führe block3 aus
SONST
führe block4 aus
ENDE
Ein Python-Beispiel:
a = 14
if a<=10:
print("<=5")
elif a>11 and a<15:
print("11 bis 15")
elif a>16 and a<20:
print("16 bis 20")
else:
print(">=20")
Ausgabe:
11 bis 15
In Python gibt es auch die Schlüsselwörter <code>True</code> (für wahr) und <code>False</code> (für falsch). Man beachte, dass sie mit Großbuchstaben beginnen. Andere Schreibweisen wären ein Fehler. Sie gehören zum Datentyp <code>bool</code>. Ihnen sind auch die Zahlen <code>1</code> und <code>0</code> zugewiesen.
Man beachte, dass {{W|Rundungsfehler}} auftreten können. D.h. man sollte bei der Verwendung von {{W|Gleitkommazahl|Gleitpunktzahlen}} niemals auf absolute Genauigkeit prüfen, sondern eine Toleranz (einen <math>\varepsilon</math>-Wert) vorgeben.
Ein klassisches Beispiel, das ein falsches Ergebnis liefert, ist:
i = 0.1 + 0.2
print(i)
if i == 0.3:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
NOK
Und das, obwohl man schon in der Volksschule lernt, dass 0.1 + 0.2 gleich 0.3 ist.
Korrekt muss das obige Beispiel z.B. so umgeschrieben werden:
ist = 0.1 + 0.2
soll = 0.3
epsilon = 0.000001
print(ist)
if abs(ist-soll) < epsilon:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
OK
Alternativ kann auch die <code>math.isclose()</code>-Funktion verwendet werden. Das sei aber hier nur erwähnt und nicht konkret ausgeführt.
<u>Aufgabe:</u> Recherchieren Sie im Internet zum Thema <code>math.isclose()</code>-Funktion.
=== match ===
Ab Python 3.10 gibt es auch die match-Anweisung. Dies ist das Python-Pendant für die switch-Anweisung in anderen Programmiersprachen, geht aber bei näherer Betrachtung weit darüber hinaus. Hier nur ein einfaches Beispiel:
x = "Hello"
match x:
case "Servus" | "Ciao": # or
print("Servus an alle")
case "Grüetzi":
print("Grüetzi Schwyzer")
case _: # other, default, sonstiges ...
print("Hallo Welt")
Ausgabe:
Hallo Welt
Als Struktogramm sieht das in etwa so aus:
[[File:Mehrseitige Auswahl.png|250px]]
Für nähere Details siehe z.B. [https://www.geeksforgeeks.org/python-match-case-statement/], [https://learnpython.com/blog/python-match-case-statement/], [https://docs.python.org/3/tutorial/controlflow.html#match-statements] und das Python Enhancement Proposal (PEP) 636 – Structural Pattern Matching: Tutorial [https://peps.python.org/pep-0636] und dort insbesondere den Anhang A - Quick Intro.
<small><code>match, case, _</code> etc. sind sogenannte ''soft keywords''. Im Gegensatz zu den normalen Schlüsselwörtern dürfen ihnen auch Werte zugewiesen werden. Eine Liste der weichen Schlüsselwörter lässt sich durch <code>keyword.softkwlist</code> erstellen (die Anweisung gibt es seit Python 3.9). Siehe dazu auch [https://stackoverflow.com/questions/65800344/what-are-soft-keywords] und [https://docs.python.org/3/library/keyword.html#keyword.softkwlist].</small>
== Schleifen ==
Kopfgesteuerte Schleife, Endlosschleife und fußgesteuerte Schleife:
[[File:Programmingloops.svg|450px]]
=== while ===
Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert wie aus anderen Programmiersprachen bekannt.
In Pseudocode:
SOLANGE bedingung TRUE
führe block aus
ENDE
In Python:
x = 0
while x <= 10:
print(x)
x += 1
Ausgabe:
0
1
2
3
4
5
6
7
8
9
10
Eine Endlosschleife ergibt sich z.B. so:
i = 5
while True:
print(i)
i-=1
Beendet werden kann sie mit der Tastenkombination STRG-C.
Eine fußgesteuerte Schleife kann so simuliert werden:
i = 5
while True:
print(i)
i-=1
if i<=0:
print("Fire")
break
Ausgabe:
5
4
3
2
1
Fire
Der <code>break</code>-Befehl wird etwas später noch einmal kurz thematisiert.
=== for ===
Struktogramm einer for-Schleife:
[[File:Zählschleife.png|200px]]
In Python bspw. so:
for x in range(6):
print(x*2)
Ausgabe:
0
2
4
6
8
10
Die Schleife läuft von 0 bis 5. Ausgegeben wird jeweils der Wert x*2. Aquivalent kann diese Schleife auch so geschrieben werden:
for x in range(0, 11, 2):
print(x)
Die Ausgabe ist wie oben. Der Startwert sei 0, der Endwert ist 11-1 und die Schrittweite ist 2.
Ein anderes Beispiel sei
for x in "text":
print(x)
Ausgabe:
t
e
x
t
== Schleifen abbrechen ==
=== break ===
<code>break</code> bricht die Schleife ab und setzt mit dem nächsten Befehl außerhalb der Schleife fort.
for var in range(100):
print(var)
if var == 5:
break
Ausgabe:
0
1
2
3
4
5
=== continue ===
<code>continue</code> bricht den aktuellen Schleifendurchlauf ab und setzt mit dem nächsten Schleifendurchlauf fort.
for var in range (11):
if var == 5:
continue
print(var)
Ausgabe:
0
1
2
3
4
6
7
8
9
10
== try - except ==
try:
z1 = 12 / 0
print(z1)
except ZeroDivisionError:
print("Das Ergebnis ist unendlich")
except:
print("Kann nicht berechnet werden!")
print("Bitte die Formel korrigieren!")
print("Setze Programm fort!")
Ausgabe:
Das Ergebnis ist unendlich
Setze Programm fort!
Es wird versucht, eine Zahl durch Null zu dividieren. Das ist nicht möglich, es wird eine Ausnahme ausgelöst. Das Programm springt daher in den except-ZeroDivisionError-Block und führt die dort gelisteten Anweisungen aus (in unserem Fall eine print-Anweisung). Danach wird das Programm fortgesetzt. Würden wir dieses Programm ohne try-except ausführen, so ergibt sich aus
z1 = 12 / 0
print(z1)
folgende Fehlermeldung und ein unmittelbarer Programmabbruch
Traceback (most recent call last):
File "C:\tmp\test1.py", line 1, in <module>
z1 = 12 / 0
ZeroDivisionError: division by zero
Mit dem try-except-Mechanismus können also Ausnahmen oder Fehler aufgefangen und behandelt werden. In unserem Beispiel ist das eher trivial, aber bei größeren Programmen kann das durchaus Sinn machen.
Neu in Python 3.14 ist, dass mehrere Ausnahmen auch ohne Klammern angegeben werden können, z.B.:
bis inkl. Python 3.13 nur:
except (ZeroDivisionError, ValueError):
ab Python 3.14 auch:
except ZeroDivisionError, ValueError:
== pass ==
Ein leerer Block muss in Python mittels dem Schlüsselwort <code>pass</code> dargestellt werden. Z.B.
x = 2
if x == 1:
print("Wert ist ", x)
else:
pass
Würde man das <code>pass</code> im else-Block weglassen, so würde man eine Fehlermeldung erhalten:
IndentationError: expected an indented block after 'else' statement on line 5
= Funktionen =
== Aufrufen von Funktionen ==
Funktionen sind uns im Rahmen dieses Kurses schon zuhauf begegnet. Sei es die print()-, die math.sin()- oder die hex()-Funktion. All diese Funktionen werden von Python zur Verfügung gestellt, ohne dass man sie explizit programmieren müsste. Aufgerufen werden diese Funktionen, indem man ihren Namen eintippt, gefolgt von runden Klammern. In diesen Klammern können noch Argumente übergeben werden. Auch Rückgabewerte sind möglich.
== Funktionen selber schreiben ==
Funktionen werden mit dem def-Schlüsselwort (man definiert die Funktion) eingeleitet, danach folgt der Funktionsname, danach wiederum runde Klammern, in denen formale Argumente stehen können. Abgeschlossen wird die def-Zeile mit einem Doppelpunkt. Danach folgt der Funktionskörper. Dieser Funktionskörper muss wiederum eingerückt werden (wie von den Verzweigungen und Schleifen bekannt). Aufgerufen wird diese Funktion, indem man ihren Funktionsnamen eingibt, gefolgt von runden Klammern (ggf. mit den aktuellen Parametern). Z.B.
# Funktion definieren
def halloWelt(i):
# i ... beliebige Ganzzahl
print("Hallo " * i, end="")
print("Welt!")
# Funktion aufrufen
halloWelt(3)
Ausgabe:
Hallo Hallo Hallo Welt!
Unterschied zwischen formalen und aktuellen Parametern:
[[Datei:PythonIng_func1.jpg]]
<small>Aktuelle Parameter werden auch Argumente genannt.</small>
Rückgabe von Funktionswerten:
# Funktion definieren
def mathFunc(a, b):
r1 = a + b
r2 = a * b
return r1, r2
# Funktion aufrufen
c, d = mathFunc(3, 5)
# Ausgabe der zurückgegebenen Werte
print(c)
print(d)
Ausgabe:
8
15
Es werden r1 und r2 zurückgegeben und den Variablen c und d zugewiesen. (r1, r2) und (c, d) sind Tupel. Was Tupel konkret sind, siehe etwas später in diesem Kapitel. 3 und 5 sind die aktuellen Parameter (die Argumente). a und b sind die formalen Parameter. Die Zuweisung der aktuellen zu den formalen Parametern erfolgt in der gegebenen Reihenfolge, also die Zahl 3 wird an a übergeben und die Zahl 5 an b.
Vorgabeparameter, z.B.:
def mathFunc(a=10, b=20):
r1 = a + b
r2 = a * b
return r1, r2
c, d = mathFunc(3, 5)
print(c)
print(d)
e, f = mathFunc(5)
print(e)
print(f)
g, h = mathFunc(b=6)
print(g)
print(h)
Ausgabe:
8
15
25
100
16
60
Erklärung:
* Erster <code>mathFunc</code>-Aufruf: Es werden, wie weiter oben, die Argumente 3 und 5 an die formalen Parameter a und b übergeben. Die Rückgabewerte r1 und r2 werden an c und d übergeben. Somit ist c=8 und d=15.
* Zweiter <code>mathFunc</code>-Aufruf: Es wird nur das Argment 5 an a übergeben. b behält den Vorgabewert 20. D.h. e= 25 und f=100.
* Dritter <code>mathFunc</code>-Aufruf: Es wird nur die Zahl 6 an b übergeben, a behält seinen Vorgabewert 10. Somit ergibt sich g=16 und h=60.
Beispiel (Schlüsselwortargumente vs. Positionsargumente):
def mathFunc(a, b):
r1 = a - b
r2 = a / b
return r1, r2
c, d = mathFunc(b=3, a=5) # Schlüsselwortargumente
e, f = mathFunc(3, 5) # Positionsargumente
print(c)
print(d)
print(e)
print(f)
Ausgabe:
2
1.6666666666666667
-2
0.6
Durch die Verwendung von Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge angegeben werden. Bei den Positionsargumenten ist die Reihenfolge vorgegeben. Daraus resultiert auch der Unterschied bei den obigen Ausgaben. Werden beide Arten in einem Aufruf gemischt, so müssen die Positionsargumente zuerst angegeben werden. Den Unterschied zwischen beiden Argumentarten zu kennen ist wichtig, nicht nur bei selbst erstellten Funktionen. Auch beim Aufruf von Python-Funktionen verfolgt einen die Mischung von Schlüsselwort- und Positionsargumenten auf Schritt und Tritt, z.B. beim etwas später folgenden Abschnitt über "Grafiken zeichnen":
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
Bei dieser <code>plot</code>-Funktion aus dem Modul <code>matplotlib.pyplot</code> sind <code>x</code> und <code>y1</code> Positionsargumente. <code>label, lw</code> und <code>ls</code> sind die Namen der Schlüsselwortargumente. Die Schlüsselwortargumente könnten auch in anderer Reihenfolge angeschrieben werden, nicht jedoch die Positionsargumente!
Siehe zu <code>matplotlib.pyplot.plot</code> auch die Seite [https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html].
== Lambda-Funktionen ==
print((lambda a, b: a*b) (3, 5))
Ausgabe:
15
Eingeleitet wird eine Lambda-Funktion (auch Lambda-Form, Lambda-Operator oder anonyme Funktion genannt) mit dem Schlüsselwort <code>lambda</code>. Es folgen die formalen Argumente, danach ein Doppelpunkt, die Berechnungsvorschrift und ggf. abschliessend in Klammern die aktuellen Parameter.
Man kann einer Lambda-Funktion auch einen Funktionsnamen geben und die Funktion über diesen Namen aufrufen, z.B.
prod = lambda a, b: a*b
print(prod(3, 5))
Als Ausgabe wird wieder die Zahl 15 geliefert.
== Rekursive Funktionen ==
Funktionen können wiederum andere Funktionen aufrufen. Von einem rekursiven Funktionsaufruf spricht man, wenn die aufgerufene Funktion gleich der aufrufenden ist.
def printFunc(i):
if (i >= 5):
return
else:
print("Hallo Welt")
printFunc(i+1)
printFunc(1)
Ausgabe:
Hallo Welt
Hallo Welt
Hallo Welt
Hallo Welt
== Funktionsannotationen ==
Python ist sehr flexibel, was Typen angeht. Im Vorhergehenden haben wir generell keine Typangaben gemacht. Will man Typen angeben, so bietet Python das Konzept der Funktionsannotation.
def calcFunc(a: int, b: int) -> int:
return a+b
r1 = calcFunc(8, 9)
r2 = calcFunc(8.0, 9.0)
r3 = calcFunc("Hallo", "Welt")
print(r1)
print(r2)
print(r3)
Ausgabe:
17
17.0
HalloWelt
Jetzt sieht man auf den ersten Blick, welche Typen der Programmierer im Sinn hatte, als er die Funktion erstellte. Das Problem dabei ist nur, dass es Python ziemlich egal ist, welche Typen man im Endeffekt eingibt. Im obigen Beispiel können statt Integer-Typen u.a. auch Float- oder String-Typen eingegeben werden.
<small>
Siehe zum Thema "Type Checking" aber auch den später folgenden Abschnitt [[Ing_Mathematik:_Python#Type_Checker]].
</small>
== Variadische Funktionen ==
Python-Code:
def test1(a, *b):
print(a);
for c in b:
print(c);
test1("Hallo", "Welt", "Schweizer", "und alle anderen")
Ausgabe:
Hallo
Welt
Schweizer
und alle anderen
Mit dem Stern (auch als Splat-Operator bezeichnet) in der formalen Parameterliste bei der Funktion <code>test1</code> wird angezeigt, dass eine beliebige Anzahl von Argumenten übergeben wird. <small> Dies entspricht in etwa dem, was in anderen Programmiersprachen (PHP etc.) mittels Ellipse (<code>...</code>) angezeigt wird.</small>
= Tupel, Listen und andere =
[[Datei:Python 3. The standard type hierarchy.png|mini|hochkant=1.7|Datentypen und Strukturen]]
== Tupel und Listen ==
Tupel, Listen und einige andere sind Datenstrukturen oder Sequenzen.
Listen (z.B. eine Einkaufsliste) sind veränderbar (mutable). Ein Tupel kann dagegen nicht verändert werden (immutable). Listen werden beim Anlegen in eckige Klammern eingeschlossen, Tupel in runde Klammern. Beim Tupel können die Klammern auch weggelassen werden. Ein Tupel mit nur einem Element muss mit einem Beistrich abgeschlossen werden. Der Grund ist, dass Python sonst nicht entscheiden kann, ob ein Tupel angelegt werden soll, oder nur ein geklammerter Wert.
Als Gedächtnisstütze kann man sich den Unterschied zwischen Tupel und Liste ev. so leichter merken:
: T'''u'''pel ... r'''u'''nde Klammern, '''u'''nveränderlich
: L'''i'''ste ... eck'''i'''ge Klammern, veränderl'''i'''ch.
Nachfolgend werden einige Operationen mit Listen und Tupel dargestellt.
# Liste und Tupel
liste = [1, 2, "Hallo"]
tupel = (1, 2, "Hallo")
# Ausgabe von liste und tupel
print(liste)
print(tupel)
# Ausgabe von Einzelelementen
print(liste[1])
print(tupel[2])
# Element an Liste anhängen und einfügen
liste.append(55)
liste.insert(4, "Welt")
print(liste)
# Element aus Liste entfernen
liste.remove(1)
print(liste)
# einige weitere Beispiele
liste2 = [1,]
tupel2 = 1, 2
tupel3 = (1,)
print(liste2)
print(tupel2)
print(tupel3)
Ausgabe:
[1, 2, 'Hallo']
(1, 2, 'Hallo')
2
Hallo
[1, 2, 'Hallo', 55, 'Welt']
[2, 'Hallo', 55, 'Welt']
[1]
(1, 2)
(1,)
Beispiel (eine Liste von Wörtern zu einem einzigen zusammenhängenden Text verbinden):
woerter = ["Hallo", "Welt"]
satz = " ".join(woerter)
print(satz)
Ausgabe:
Hallo Welt
== Dictionaries und Mengen ==
Zu den Datenstrukturen gehören weiters auch Mengen und Dictionaries. Mengen sind von der Mathematik bekannt, sie sind ungeordnet und es kommen keine mehrfachen Elemente vor. Dictionaries sind durch Schlüssel :Wert-Paare gekennzeichnet. Mengen werden beim Anlegen wie Dictionaries in geschweifte Klammern eingeschlossen.
dict = {"vorname":"Hugo", "nachname":"Meister" }
menge = {1, 1, 3, 4, 4, 4, "Hallo"}
print(dict)
print(menge)
print(dict["vorname"])
Ausgabe:
{'vorname': 'Hugo', 'nachname': 'Meister'}
{1, 3, 4, 'Hallo'}
Hugo
Geschweifte Klammern ohne Inhalt stellen Dictionaries dar und keine Mengen:
di = {}
print(type(di))
Ausgabe:
<class 'dict'>
Leere Mengen lassen sich mit <code>set()</code> erzeugen:
menge = set() # leere Menge
print(menge)
menge.add("Hallo") # Element hinzufügen
print(menge)
Ausgabe:
set()
{'Hallo'}
Beispiel (einige Mengenoperationen):
mengeA = {"Hallo", "Welt"}
mengeB = {1, 2, "Welt", 3}
# Vereinigung
print(mengeA | mengeB)
print(mengeA.union(mengeB))
# Durchschnitt
print(mengeA & mengeB)
print(mengeA.intersection(mengeB))
# Differenz
print(mengeA - mengeB)
print(mengeA.difference(mengeB))
# Symmetrische Differenz
print(mengeA ^ mengeB)
print(mengeA.symmetric_difference(mengeB))
# Teilmenge
print(mengeA.issubset(mengeB))
# Mehrere Elemente hinzu
mengeA.update(["Super", 67, 125])
print(mengeA)
# Element löschen
mengeA.discard("Hallo")
print(mengeA)
Ausgabe:
{1, 2, 3, 'Welt', 'Hallo'}
{1, 2, 3, 'Welt', 'Hallo'}
{'Welt'}
{'Welt'}
{'Hallo'}
{'Hallo'}
{1, 2, 3, 'Hallo'}
{1, 2, 3, 'Hallo'}
False
{67, 'Super', 'Welt', 'Hallo', 125}
{67, 'Super', 'Welt', 125}
Es gibt schon seit "ewigen" Zeiten unveränderbare Mengen, die mittels <code>frozenset</code> eingeleitet werden. Neu ab Python 3.15 ist dagegen das Pendant <code>frozendict</code>, das unveränderbare Dictionaries darstellt.
fdict = frozendict({"vorname":"Hugo", "nachname":"Meister"})
fset = frozenset({"A", 1, "A"})
print(fdict)
print(fdict["vorname"])
print (fset)
try:
fdict["vorname"] = "Max"
print(fdict["vorname"])
except TypeError as e:
print(f"Fehler: {e}")
try:
fset.add("B")
print(fset)
except AttributeError as e:
print(f"Fehler: {e}")
Ausgabe:
frozendict({'vorname': 'Hugo', 'nachname': 'Meister'})
Hugo
frozenset({1, 'A'})
Fehler: 'frozendict' object does not support item assignment
Fehler: 'frozenset' object has no attribute 'add'
== List Comprehensions ==
Aus einer Eingabeliste soll eine Ausgabeliste erzeugt werden. Das kann folgendermaßen geschehen.
Mathematische Schreibweise: <math>lc = \{2x|x\in\ \mathbb{N}, 1\le x < 11\}</math>
Python-Code:
lc = [x*2 for x in range(1,11)]
print(lc)
Ausgabe:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Mathematische Schreibweise: <math>lc = \{2x | x \in \mathbb{N}, 1\le x < 11, x \bmod 2 = 0 \}</math>
Python-Code:
lc = [x*2 for x in range(1,11) if x%2 == 0]
print(lc)
Ausgabe:
[4, 8, 12, 16, 20]
Siehe auch {{W|List Comprehension}}.
== Set Comprehensions ==
Dies ist sehr ähnlich wie im vorigen Abschnitt beschrieben. Es wird aber keine Liste, sondern eine Menge erzeugt.
sc = {x*2 for x in range(1,11)}
print(sc)
Ausgabe:
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
== Listen zusammenführen - zip() ==
li1 = ["A", "B", "C", "D"]
li2 = [1, 2, 3, 4]
li3 = [5.5, 6.6, 7.7, 8.8]
z = zip(li1, li2, li3)
print(z)
li4 = list(z)
print(li4)
Ausgabe:
<zip object at 0x00000283B6C6AC80>
[('A', 1, 5.5), ('B', 2, 6.6), ('C', 3, 7.7), ('D', 4, 8.8)]
== Generatorausdruck ==
g = (i*2 for i in range(1,11))
print(g)
t = tuple(g)
print(t)
print(t[1:3])
Ausgabe:
<generator object <genexpr> at 0x00000241D2A4A5A0>
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
(4, 6)
== Slicing ==
slice ... Scheibe, Teil, in Scheiben schneiden
Beispiel: Zugriff auf Elemente eines geordneten sequentiellen Objekttyps (Liste, Tupel oder String):
str1 = "Hallo"
# Das erste Element wird mit dem Index 0 angesprochen
# [start (inkl.) : stop (exkl.) : step (default=1)]
str2 = str1[0:2]
# Alternativ auch: str2 = str1[:2]
print(str2)
tup1 = (0,1,2,3)
# Das letzte Element hat auch den Index -1, das vorletzte den Index -2 usw.
tup2 = tup1[-3:-1]
print(tup2)
lst1 = [[1, 5, 10, 20],
[30, 40, 50, 60]]
lst2 = lst1[1][1]
print(lst2)
Ausgabe:
Ha
(1, 2)
40
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2])
print(x[-3])
print(x)
print(x[:])
print(x[2:])
print(x[:2])
print(x[::-1])
Ausgabe:
c
c
('a', 'b', 'c', 'd', 'e')
('a', 'b', 'c', 'd', 'e')
('c', 'd', 'e')
('a', 'b')
('e', 'd', 'c', 'b', 'a')
Visualisierung:
'''a''' '''b''' '''c''' '''d''' '''e'''
+-----------------------------+
| 0 | 1 |//'''2'''//| 3 | 4 |
+-----------------------------+
| -5 | -4 |/'''-3'''//| -2 | -1 |
+-----------------------------+
|/////////////////////////////|
+-----------------------------+
|/////////////''':'''///////////////|
+-----------------------------+
| | |///////'''2:'''////////|
+-----------------------------+
|////''':2'''/////| | | |
+-----------------------------+
|\\\\\<--\\\\\'''::-1'''\\\\<--\\\\\|
+-----------------------------+
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2::2])
print(x[2::-1])
print(x[2:0:-1])
Ausgabe:
('c', 'e')
('c', 'b', 'a')
('c', 'b')
Hier sieht man sehr schön, dass beim letzen <code>print</code>-Befehl die 0, die in diesem Fall den Buchstaben "a" repräsentiert, als letzer Wert nicht mehr dazugehört (wie weiter oben angedeutet ist der End- oder Stoppwert exklusiv). Will man den Buchstaben "a" dazunehmen, so ist die vorletzte Zeile die richtige.
Beispiel: Umdrehen von Strings
str1 = "Hallo"
str2 = str1[::-1]
print(str2)
Ausgabe:
ollaH
Mit zweidimensionalen Listen/Tupels wird das Ganze schon bedeutend komplexer.
Beispiel: Verkettetes Slicing
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
print(A[2::][::2])
Ausgabe:
[['20', '21', '22', '23'], ['40', '41', '42', '43']]
Das erste Slicing erstellt folgenden Slice:
[["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
Das zweite Slicing wird dann auf diesen Slice angewendet und ergibt das genannte Endergebnis. Will man Spalten statt Zeilen, so funktioniert dieser direkte Weg nicht. Man verwendet dann List Comprehensions oder die NumPy-Bibliothek. Diese Bibliothek erlaubt zweidimensionales Slicing. Sie wird erst später bei den Grafiken eingeführt. Deshalb wird hier dazu noch kein Beispiel gezeigt.
= Objektorientierte Programmierung =
{{Wikipedia|Objektorientierte Programmierung}}
* {{W|Klasse (Objektorientierung)|Klasse}} ... die Schablone oder der Bauplan, enthält Methoden und Attribute
* {{W|Objekt (Programmierung)|Objekt}} ... eine Klasseninstanz (die konkrete Ausprägung der Klasse)
* {{W|Attribut (Programmierung)|Attribute}} ... die Eigenschaften eines Objekts
* {{W|Methode (Programmierung)|Methoden}} ... die Aktionen (Operationen), die ein Objekt ausführen kann
* {{W|Vererbung (Programmierung)|Vererbung}} ... neue Klassen (Subklassen, Unterklassen, abgeleitete Klassen) aus vorhandenen Klassen (Superklassen, Oberklassen, Basisklassen, Elternklassen) ableiten. Ermöglicht den Aufbau von Klassenhierarchien. Die Subklasse "erbt" Attribute und Methoden von der Superklasse. Python unterstützt (so wie C++, aber im Gegensatz zu Java) Mehrfachvererbung.
== UML ==
* {{W|Unified Modeling Language|UML}} ... '''U'''nified '''M'''odeling '''L'''anguage, eine Modellierungssprache. Die UML enthält zahlreiche Diagrammarten, um Programme zu modellieren. Im Nachfolgenden wird nur das {{W|Klassendiagramm}} verwendet.
[[File:UmlCd Klasse-3.svg|300px]]
* {{W|Sichtbarkeit (Programmierung)|Sichtbarkeit}}:
** + ... public (öffentlich)
** - ... private
** # ... protected
* {{W|Attribut_(UML)#Attribute_für_Instanzen_und_für_Klassen|Klassenattribute}} (statische Attribute): Werden nur einmal pro Klasse angelegt. Im Klassendiagramm werden sie unterstrichen.
[[File:Attribute-3.png|200px]]
* Vererbung:
<gallery>
InheritancePgmUML.svg | Abgeleitete Klasse erbt von Basisklasse (Einfachvererbung)
Diamond inheritance.svg | D erbt von B und C (Mehrfachvererbung). B und C erben von A (Einfachvererbung)
</gallery>
Für weitergehende Betrachtungen zur UML wird auf Spezialliteratur verwiesen, z.B.:
* Seidl et al.: UML@Classroom. dpunkt, 2012, ISBN 978-3-89864-776-2
* Rupp et al.: UML 2 glasklar. Hanser, 4. Aufl., 2012, ISBN 978-3-446-43057-0
== Eine einfache Klasse ==
[[Datei:PythonIng_uml1.svg | 200px]]
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
fahr = Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die Klasse Fahrzeug wird durch das class-Schlüsselwort eingeleitet. raeder ist ein Klassenattribut und public. __init__ wird bei der Objekterzeugung automatisch aufgerufen (ist der sogenannte Konstruktor). Man achte darauf, dass diese Methode immer mit zwei Unterstrichen eingeleitet und abgeschlossen wird. Instanzattributen wird das Wort self vorangestellt. Wir sehen uns z.B. das Attribut self.__geschwind an. Auch hier werden zwei Unterstriche verwendet. Das bedeutet, dass dieses Attribut strikt/stark private ist. Wird nur ein Unterstrich verwendet, so deutet dies auf schwach/weakly private hin. Letzteres wird in Python deutlich häufiger verwendet. Bei den Methoden wird immer self als erster Parameter angegeben. Beim Aufruf der entsprechenden Funktion wird das self aber nicht berücksichtigt.
Besonderheiten bei stark und schwach private:
* '''stark private''':
** zwei führende Unterstriche
** Name Mangling: Name wird zu <code>_Klassenname__variablenname</code>
** Schutz vor Namenskollisionen bei Vererbung
** am Ende des Namens dürfen keine zwei Unterstriche verwendet werden. Das wären dann Magic Methods oder Dunder-Methods (z.B. __init__). Diese sind public.
* '''schwach private''':
** ein führender Unterstrich
** Name bleibt gleich
** ist nur ein Hinweis an die Programmierer, kein starker Schutz
** <code>from modul import *</code>: Objekte mit einem führenden Unterstrich werden standardmäßig nicht importiert
** Standard für die Kapselung bei Python. Schätzung: Weit mehr als 80% der nicht-öffentlichen Attribute/Methoden werden als schwach private deklariert. Weniger als 5-10% als stark private (Quelle: Google KI)
== Klassen importieren ==
Häufig ist es sinnvoll und übersichtlicher Klassen in eigenen Dateien zu speichern. Das sind dann eigene Module. Abgespeichert werden Sie mit der Endung py, wie bisher auch praktiziert. Aufgerufen werden Sie mit der import-Anweisung. Dann ist aber nur der Dateiname ohne Endung py zu verwenden. Klarer wird das mit einem Beispiel.
Datei c:\tmp\fahrzeug.py
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
Datei c:\tmp\test1.py
import fahrzeug
fahr = fahrzeug.Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die üblichen import-Anweisungen lauten wie folgt:
{| {{prettytable}}
! import-Befehl
! Instanz
|-
| import xyz || xyz.Klasse
|-
| import xyz as x || x.Klasse
|-
| from xyz import Klasse || Klasse
|-
| from xyz import * || Klasse
|}
Der Vorteil der ersten beiden import-Anweisungen ist, dass es kaum zu Namenskollisionen kommen kann. Dafür hat man bei den letzten beiden Varianten weniger Tipparbeit.
== Vererbung ==
=== Einfachvererbung ===
[[Datei:PythonIng_uml2.svg | 200px]]
Datei fahrzeug.py:
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
class Luftfahrzeug(Fahrzeug):
def __init__(self, geschwindigkeit, leistung, fluegel):
super().__init__(geschwindigkeit, leistung)
self.__flueg = fluegel
def getFlueg(self):
return self.__flueg
Datei test1.py:
import fahrzeug
fahr = fahrzeug.Luftfahrzeug(150, 90, 4)
print(fahr.getFlueg())
Ausgabe:
4
=== Mehrfachvererbung ===
Mit Python ist auch Mehrfachvererbung möglich, z.B.:
class A:
def _printA(self):
print("Klasse A")
class B:
def _printB(self):
print("Klasse B")
class C(A,B):
def __init__(self):
self._printA()
self._printB()
c = C()
Ausgabe:
Klasse A
Klasse B
Die Klasse C erbt von A und B. In UML sieht das in etwa so aus:
+-----------------------------+ +-------------------------+
| A | | B |
+-----------------------------+ +-------------------------+
| | | |
+-----------------------------+ +-------------------------+
| # printA() | | # printB() |
+-----------------------------+ +-------------------------+
. .
/ \ / \
--- ---
| |
| |
+---------------------+
| C |
+---------------------+
| |
+---------------------+
| |
+---------------------+
<code>printA()</code> und <code>printB()</code> sind schwach private (in UML als <code>protected</code> mit einem # dargestellt). Es ist aber zu beachten, dass schwach private nur Konvention ist. Praktisch könnte man auch von außerhalb auf diese Methoden zugreifen. Das soll man aber nicht tun, und das wird in Python durch einen Unterstrich angedeutet.
= Grafiken zeichnen =
Für das Zeichnen von Grafiken wird hier das Modul <code>matplotlib</code> verwendet. <code>matplotlib</code> ist ein externes Modul und muss vor der ersten Verwendung installiert werden. Das geht so:
# Starten Sie ein Terminal (bei Windows die Eingabeaufforderung).
# Führen Sie darin folgenden Befehl aus <code>c:\devel\Python\Scripts\pip.exe install matplotlib</code>
pip ist übrigens der Paketmanager von Python ({{W|Pip_(Python)}}).
Optimalerweise installieren wir auch gleich das Modul <code>numpy</code> (Numerical Python). Wir werden es im Folgenden oft benötigen (nicht nur bei den Grafiken). Das funktioniert vom Prinzip her genauso, wie für <code>matplotlib</code> gezeigt.
<small>Verwenden Sie Spyder, so sind diese Schritte nicht nötig. Spyder inkludiert diese Pakete standardmäßig. Unter openSUSE Tumbleweed lassen sich diese Pakete mittels YaST oder zypper installieren.</small>
== 2D ==
=== Graph einer Funktion ===
Es soll die cosh-Funktion im Intervall <math>x\in[-3,3]</math> gezeichnet werden. Der Programmcode lautet in der einfachsten Form:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x)
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh1.jpg]]
Der Code ist quasi selbsterklärend. Das Untermodul pyplot des matplotlib-Moduls und das numpy-Modul werden importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plt.plot()" ist der Zeichenbefehl. "plt.show" ist notwendig, um das Fenster mit der Grafik anzuzeigen.
Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen. "plt.grid()" zeichnet ein Gitter in die Grafik (kann auch weggelassen werden).
Die Bezeichnungen plt und np könnten auch anders gewählt werden. Es ist aber Konvention, diese so wie hier gezeigt zu wählen. Die "arange"-Funktion aus der NumPy-Bibliothek wird später ein bisschen genauer behandelt (siehe [[Ing_Mathematik:_Python#Zahlenfolgen|Zahlenfolgen]]).
<small>Mit der im obigen Bild gezeigten Menüleiste kann die dargestellte Grafik nachträglich noch geändert werden (Zoom, Pan, Achsenparameter, Kurvenparameter etc.). Natürlich kann man das alles auch direkt programmieren. Wie das funktioniert wird ansatzweise etwas später gezeigt.</small>
Ein etwas komplexeres Beispiel ist Folgendes:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x) + 2**x
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh4.png]]
Man beachte, dass im Gegensatz zu Octave und Julia der ominöse Punkt (.) bei 2**x mit Python nicht benötigt wird. Das macht das Programmiererleben etwas einfacher.
Die Farbe des Graphen kann man über den <code>color</code>-Schalter einstellen, z.B. auf rot setzen:
plt.plot(x, y, color="red")
Das ist nur eine Möglichkeit, es gibt auch andere, z.B. mittels
* hexadezimaler Zahl, z.B. <code>color="#ff0000"</code>
* Kurzform, z.B. <code>"r"</code>
Statt <code>color</code> kann auch die Kurzform <code>c</code> verwendet werden.
<u>Kleine Aufgabe:</u> Probieren Sie diese "Farbspielereien" am Computer aus.
=== Graphen mehrerer Funktionen und weiteres ===
==== Mehrere Funktionen in einen Plot zeichnen ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x")
plt.plot(x, y2, label = "sin(x) * cos(x)")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh2.png]]
Um die Linienstile etwas individueller zu gestalten, ist folgender Programmcode gedacht:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
plt.plot(x, y2, label = "sin(x) * cos(x)", lw=3, ls="--")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh3.png]]
Einige weitere Bespiele zu <code>ls</code></code>:
* - ... durchgezogene Linie
* -. ... Strichpunkt-Linie
* dashed ... gestrichelte Linie
==== Marker ====
Desweiteren kann man Marker verwenden.
Beispiel:
import matplotlib.pyplot as plt
plt.plot(10, 10, "ob", markersize=30)
plt.plot(20,20, ".r")
plt.plot(30,30, "Dg", ms=15)
plt.plot(40, 40, "ok", ms=20, mec="#FF5733", mew=3)
plt.plot(50, 50, "vk", ms=20, mec="yellow", mew=3)
plt.grid()
plt.show()
Das erste Zeichen im String nach den Koordinaten im plot-Befehl symbolisiert die Form (z.B. o für einen Kreis). Das zweite Zeichen steht für die Farbe (z.B. b für blue). <code>markersize</code> oder <code>ms</code> setzt die Größe des Markers.
Ausgabe:
[[Bild:PythonIng_formatpara1.svg|200px]]
Einige weitere Marker:
* * ... Stern
* + ... Plus
* h oder H ... Sechseck
Man kann mit den Parametern
* <code>markeredgecolor</code> oder kurz <code>mec</code> die Farbe des Markerrandes
* <code>markeredgewidth</code> oder kurz <code>mew</code> die Dicke des Randes
* <code>markerfacecolor</code> oder kurz <code>mfc</code> die Innenfarbe des Markers
bestimmen.
=== Funktion in Parameterdarstellung ===
Es soll die archimedische Spirale <math>x = t \cos(t), y = t \sin(t)</math> im Intervall <math>[0, 6\pi[</math> gezeichnet werden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.show()
[[Datei:PythonIng_spirale1.png]]
Diese Darstellung erscheint verzerrt. Will man gleiche Achsenskalierungen, so kann man den plt.axis()-Befehl verwenden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.axis("equal")
plt.show()
[[Datei:PythonIng_spirale2.png]]
=== Funktion in Polardarstellung ===
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
r = np.arange(0, 1, 0.01)
theta = r**3
line = ax.plot(theta, r)
plt.show()
[[Datei:PythonIng_polar1.png]]
=== Logarithmische Achsenskalierung ===
==== Semilog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.semilogy()
plt.show()
Ausgabe:
[[Datei:PythonIng_semilog1.png]]
==== LogLog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.loglog()
plt.show()
[[Datei:PythonIng_loglog1.png]]
=== Gefüllte Fläche ===
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 3, 0.1)
y1 = 3*x - 1
y2 = x**2
plt.plot(x, y1, x, y2, color='black')
plt.fill_between(x, y1, y2, where=y1>=y2)
plt.show()
[[Datei:PythonIng_gefuellt.png]]
=== Linien, Pfeile, Rechtecke, Kreise und Texte ===
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
r = mpl.patches.Rectangle((0, 0), 3, 3, angle=30, fill=False)
c = mpl.patches.Circle((4, 4), 2, fill=False)
ax.add_patch(r)
ax.add_patch(c)
ax.plot([-2, 7], [-2, 0], color="black")
ax.arrow(0, 7, 5, 0, length_includes_head=True, head_width=0.5, head_length=1.5,
color="black")
ax.set_aspect("equal")
plt.axis([-3, 8, -3, 8])
plt.show()
[[Datei:PythonIng_linien_pfeile_etc.png]]
Text kann mit <code>ax.text(x, y, "Text")</code> hinzugefügt werden, bspw.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
ax.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
Oder einfacher auch ohne <code>subplots</code>
import matplotlib.pyplot as plt
plt.text(0.1, 0.1, "Hallo")
plt.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text1.png]]
Auch Sonderzeichen (griechische Buchstaben etc.) können verwendet werden (siehe dazu auch [https://matplotlib.org/stable/users/explain/text/mathtext.html]).
import matplotlib.pyplot as plt
plt.text(.3, .5,
r'$\Omega\ \psi\ \oint\ \nabla\ \dot a\ \frac{a}{b}\ a_b$',
size="20")
plt.show()
[[Datei:PythonIng_text20.svg]]
Jetzt wird noch gezeigt, wofür <code>subplots</code> sinnvoll eingesetzt werden können.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(0.1, 0.1, "Hallo")
ax[1].text(0.1, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text2.png]]
=== Anmerkungen hinzufügen ===
Anmerkungen (engl. annotations) lassen sich mit matplotlib einfach hinzufügen. Unter Anmerkung wird hier ein Pfeil mit Text verstanden.
Beispiel:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1,10], [1,10])
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0))
plt.show()
Ausgabe:
[[Datei: PythonIng_ann1.svg|400px]]
<code>shrink</code> verkürzt den Pfeil. Sinnvoll sind beim obigen Beispiel Werte irgendwo zwischen 0.0 und 0.3.
<u>Kleine Aufgabe:</u> Probieren Sie verschiedene Pfeillängen aus.
Die Schriftgröße verändern können Sie übrigens mit <code>fontsize</code> oder <code>size</code>, z.B.
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0), fontsize=25)
Eine andere Schreibweise für Dictionaries, die wir weiter oben schon kennengelernt haben, die wir aber nochmals explizit aufschreiben wollen, ist
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops={"facecolor":"red", "shrink":0.0})
=== Figure, Axes etc.===
[[Bild:PythonIng_figure33.svg|350px]]
* fig (figure) ... das übergeordnete Fenster
* ax (axes) ... "Plot", das eigentliche Zeichenfenster
* axis ... die Koordinatenachsen
* spine ... Begrenzungslinien des Zeichenfensters
* tick ... Markierung an den Achsen des Zeichenfensters
Beispiel (eine figure mit 6 axes, ax-Titel, y-axis-Titel):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=3, ncols=2)
ax[0][0].text(0.1, 0.5, "11")
ax[0][1].text(0.1, 0.5, "12")
ax[1][0].text(0.1, 0.5, "21")
ax[1][1].text(0.1, 0.5, "22")
ax[2][0].text(0.1, 0.5, "31")
ax[2][1].text(0.1, 0.5, "32")
ax[0][0].set(ylabel="y-label", title="axes 1")
plt.show()
[[Bild:PythonIng_figure34.png|350px]]
Beispiel (Achsenbereiche setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-1, 10, 1, 12))
plt.show()
[[Bild:PythonIng_figure35.svg|350px]]
Beispiel (Gitter einschalten):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-5, 10, 1, 12))
ax[0].minorticks_on()
ax[0].grid(which='minor')
ax[1].grid(which='major')
plt.show()
[[Bild:PythonIng_figure36.svg|350px]]
Beispiel (ticks setzen)
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
pos = [0, .2, .5]
lab = ["a", "b", "c"]
ax.xaxis.set_major_locator(tick.FixedLocator(pos))
ax.xaxis.set_major_formatter(tick.FixedFormatter(lab))
plt.show()
[[Bild:PythonIng_figure37.svg|350px]]
Beispiel (Achsenkreuz beliebig setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position(('data', 0.3))
ax.spines['left'].set_position(('data', 0.5))
plt.show()
[[Bild:PythonIng_figure38.svg|350px]]
Beispiel (Inset):
import matplotlib.pyplot as plt
# Hauptplot erstellen
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
# Inset hinzu:
axin = ax.inset_axes([0.4, 0.4, 0.3, 0.3])
axin.text(0, 0, "Servus")
axin.plot()
plt.show()
[[Bild:PythonIng_figure40.svg|350px]]
Beispiel (Hintergrundfarben setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_facecolor("green")
fig.set_facecolor("yellow")
plt.plot([1, 3], [6, 8])
plt.show()
[[Bild:PythonIng_figure39.svg|300px]]
=== GridSpec ===
Mit figures und axes lassen sich schon jede Menge an Grafikdetails einstellen. GridSpec ist dann der Turbo oder Raketenantrieb den matplotlib eingebaut hat. Naja, vielleicht ist das etwas übertrieben, aber GridSpec ist sozusagen ein flexibler Layout-Manager. Bisher haben wir immer gleich große axes gezeichnet. Mit GridSpec können wir Subplots über mehrere Zeilen und Spalten ziehen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(3, 3)
ax1 = fig.add_subplot(gs[0, :])
ax1.set_title("Bereich 1: gs[0, :]")
ax2 = fig.add_subplot(gs[1:, 0])
ax2.set_title("Bereich 2: gs[1:, 0]")
ax3 = fig.add_subplot(gs[1, 1:])
ax3.set_title("Bereich 3: gs[1, 1:]")
ax4 = fig.add_subplot(gs[2, 1:])
ax4.set_title("Bereich 4: gs[2, 1:]")
plt.show()
[[Bild:PythonIng_gridspec1.svg|350px]]
Erklärung zu <code>(gs[zeile, spalte])</code>: Slicing; damit legen Sie fest, welche Zellen ein Subplot belegt. Achtung! Die Indizes beginnen bei 0 und nicht bei 1 (d.h., die erste Zeile/Spalte hat den Index 0)
* : ... alle
* 1: ... 1 bis Ende
* etc.
<code>constrained_layout=True</code> sorgt dafür, dass sich die Subplots nicht überlappen.
Aber auch die Spaltenbreiten und Zeilenhöhen lassen sich anpassen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
# Verhältnis erste zu zweite Zeile = 1.5:1
# Verhältnis erste zu zweite Spalte = 1:4
gs = fig.add_gridspec(2, 2, figure=fig, height_ratios=[1.5, 1], width_ratios=[1, 4])
ax1 = fig.add_subplot(gs[0, 0])
ax1.set_title("Bereich 1: gs[0, 0]")
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_title("Bereich 2: gs[0, 0]")
ax3 = fig.add_subplot(gs[1, 0])
ax3.set_title("Bereich 3: gs[1, 0]")
ax4 = fig.add_subplot(gs[1, 1:])
ax4.set_title("Bereich 4: gs[1, 1]")
plt.show()
[[Bild:PythonIng_gridspec2.svg|350px]]
Auch die Ränder lassen sich einstellen.
Beispiel 1:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.1, right=0.9, bottom=0.1,
top=0.9, wspace=0.2, hspace=0.2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec3.svg|300px]]
* hspace ... height space, vertikaler Abstand zwischen den Zeilen
* wspace ... width space, horizontaler Abstand zwischen den Spalten
Und im Vergleich dazu Beispiel 2:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.3, right=0.7, bottom=0.3,
top=0.7, wspace=0.3, hspace=0.3)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec4.svg|300px]]
Es gibt noch einige weitere Details, die sich mit GridSpec variieren lassen (z.B. SubGridSpec ... verschachtelte Grid-Layouts). Aber wir belassen es vorerst dabei. Das bisher Gezeigte sollte für die meisten Probleme ausreichend sein.
=== Aufgaben ===
* Zeichnen Sie die Strophoide <math>x = \frac{a(t^2-1)}{t^2+1}, y = \frac{at(t^2-1)}{t^2+1}, a = 2, -3 \leq t \leq 3</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_strophoide.jpg|300px|center]]
* Zeichnen Sie die verschlungene Hypozykloide <math>x = (R-r)\cos t + c\cos\frac{R-r}{r}t, y = (R-r)\sin t - c\sin\frac{R-r}{r}t, c = 3, r = 2, R = 6, -15 \leq t \leq 15</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_hypozykloide.jpg|300px|center]]
* Testen Sie bei den obigen Übungsaufgaben verschiedene Linienstile und Farben. Farben können mit dem plt.plot()-Parameter color gewählt werden.
* Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.
* Zeichnen Sie folgendes Bild (die Achsenbeschriftungen positionieren Sie z.B. mit den Befehlen <code>ax.set_xlabel("x", loc="right"); ax.set_ylabel("y", loc="top")</code>):
[[Bild:PythonIng_aufgabe24.svg|400px|center]]
* Zeichnen Sie mit Python, matplotlib und NumPy folgendes Bild:
[[Bild:PythonIng_figure41.svg|400px|center]]
* Zeichnen Sie mit GridSpec ein Layout, das in etwa wie folgendes aussieht (<code>height_ratios=[1, 2], width_ratios=[2, 1]</code>):
[[Bild:PythonIng_aufgabe23.svg|300px|center]]
== 3D ==
=== Räumliche Kurven ===
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0, 6*np.pi, 0.1)
x = t * np.cos(t)
y = t * np.sin(t)
z = t
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot(x, y, z)
plt.show()
[[Datei:PythonIng_raumkurve1.png]]
=== Flächen ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z)
plt.show()
[[Datei:PythonIng_fläche1.png]]
Das Ganze in Netzdarstellung läßt sich so programmieren:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = np.arange(0, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_wireframe(x, y, z)
plt.show()
[[Datei:PythonIng_fläche2.png]]
Ein etwas komplexeres Beispiel:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.1, 10, 0.1)
y = np.arange(0.1, 10, 0.1)
x, y = np.meshgrid(x, y)
z1 = np.sin(x) + 3 * np.cos(y)
z2 = np.sin(x) + np.log(y)
z3 = x + np.cos(y)
z4 = x**2 - y
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, nrows=2, ncols=2)
ax[0][0].plot_surface(x, y, z1)
ax[0][1].plot_surface(x, y, z2)
ax[1][0].plot_surface(x, y, z3)
ax[1][1].plot_surface(x, y, z4)
plt.show()
[[Datei:PythonIng_subplot1.png]]
Man beachte, dass man die Unterbilder im Bild nach dem Ausführen des Scripts z.B. mit der mittleren Maustaste einzeln drehen, oder über die Einträge in der Menüzeile einzeln bearbeiten kann. Mit ein paar Zeilen Programmtext lässt sich also eine Menge an Funktionalität generieren.
Die Farbgebung lässt sich über <code>colormaps</code> variieren.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm)
plt.show()
[[Datei:PythonIng_colormap1.png]]
Es gibt eine Menge an Colormaps, z.B. <code>plasma, Greys, Dark2, ocean</code>. Zwecks detaillierterer Infos siehe die matplotlib-Dokumentation. <small>Verwendet man die IDE namens IDLE, so gibt es dort auch die automatische Codevervollständigung. D.h. es werden alle Möglichkeiten (in unserem Fall nach dem Eintippen von <code>cm.</code> alle verfügbaren Colormaps) angezeigt.</small>
Die "edgecolor" und Linienbreite können auch frei gewählt werden:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm, edgecolor="black", linewidth=1.0)
plt.show()
[[Datei:PythonIng_colormap2.png]]
=== Höhenlinien ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
ax.contour(x, y, z)
plt.show()
[[Datei:PythonIng_höhenlinien1.png|400px]]
Etwas abgewandelt sieht das so aus:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contour(x, y, z)
ax.clabel(hl, inline = True)
plt.show()
[[Datei:PythonIng_höhenlinien2.png|400px]]
Und noch eine Variante (mit einem Farbbalken) sei gezeigt.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contourf(x, y, z)
fig.colorbar(hl)
plt.show()
[[Datei:PythonIng_höhenlinien5.svg|400px]]
=== Aufgaben ===
* Zeichnen Sie die räumliche Kurve <math>x = 2 \cdot \cosh(t)</math>, <math>y = 5 \cdot \sin(t)</math>, <math> z = t^{2} - t</math>, <math>0 \leq t \leq 3\pi</math>.
* Zeichnen Sie die Fläche <math>z = \log(x) + \cos(y)</math>.
== Animationen und fortgeschrittenes 3D ==
=== Mit matplotlib ===
Auch mit matplotlib sind Animationen möglich. Das ist ein bisschen komplizierter und wird deshalb hier nur mit einem sehr einfachen Beispiel dargestellt (bei Interesse siehe z.B. auch das [https://matplotlib.org/stable/users/explain/animations/animations.html#animations Animations using Matplotlib-Tutorial]).
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib
import numpy as np
def update(frame):
line.set_xdata(x[:frame])
line.set_ydata(y[:frame])
return (line)
fig, ax = plt.subplots()
x = np.arange(0, 10, .1)
y = np.sin(x)
line, = ax.plot(x[0], y[0])
ax.set(xlim=[0, 10], ylim=[-1, 1])
a = ani.FuncAnimation(fig=fig, func=update, frames=100, interval=20)
plt.show()
# Speichere die Animation in einem animierten GIF (optional)
a.save(filename="c:/tmp/PythonIng_anim5.gif", writer="pillow")
[[Datei:PythonIng_anim5.gif]]
Es wird eine Sinuskurve auf den Bildschirm gezeichnet. In der letzten Zeile wird diese Animation in ein animiertes GIF gespeichert. Das ist natürlich optional und kann auch weggelassen werden.
=== Mit VPython ===
Aber auch mit dem Modul VPython lassen sich einfache 3D-Animationen erstellen. VPython ist ein externes Modul, das vorab installiert werden muss. Unter openSUSE Tumbleweed gibt es dzt. kein entsprechendes rpm-Paket. Die übliche Methode der Installation mittels YaST oder zypper ist somit nicht möglich. Auch eine direkte Verwendung von pip führt nur zu einer Fehlermeldung (<code>error: externally-managed-environment</code>). Es empfiehlt sich dort folgende Vorgehensweise:
# Erstelle zuerst eine virtuelle Umgebung, z.B.: <code>python3.11 -m venv ~/tmp/venv1</code>
# Wechsle das Verzeichnis: <code>cd ~/tmp/venv1/bin</code>
# Installiere das entsprechende Paket: <code>./pip install vpython</code>
# Führe das entsprechende Skript aus: <code>./python ~/tmp/test1.py</code>
Aktuell (März 2026) ist dieses Programmpaket lt. der [https://vpython.org/presentation2018/install.html VPython-Homepage] nur für die Python-Versionen 3.8 bis 3.12 verfügbar.
Ein Beispiel zu einer einfachen Animation wird nachfolgend geliefert.
from vpython import *
scene.width = 1200
scene.height = 600
scene.center = vector(20,0,0)
scene.background = color.white
cylinder(pos=vector(0,0,0), axis=vector(20,0,0), radius=5,
color=color.blue)
cone(pos=vector(0,0,0), axis=vector(-10,0,0), radius=5,
color=color.blue)
helix(pos=vector(20,0,0), axis=vector(40,0,0), radius=2,
coils=10, thickness=0.5, color=color.blue)
ball = sphere(pos=vector(20,0,0), color = color.green, radius = 1)
ball.p = vector(0.15, 0, 0)
toc = True
while True:
rate(200)
if(ball.pos.x <= 60 and toc == True):
ball.pos += ball.p
else:
toc = False
ball.pos -= ball.p
if(ball.pos.x <= 20 and toc == False):
toc = True
[[Datei:PythonIng_vpython_anim.JPG]]
Idealerweise öffnet sich beim Ausführen des Scripts ein Browserfenster. Darin wird die programmierte Animation gezeigt (siehe auch den obigen Screenshot). Eine Größenänderung können Sie mit der mittleren Maustaste initiieren. Die Szenerie drehen können Sie mit der rechten Maustaste.
=== Mit build123d ===
Hiermit lassen sich einfach 3D-Modelle für CAD-Systeme erstellen. [https://build123d.readthedocs.io/en/latest/ build123d] ist ein externes Modul und muss vorab, wie schon für mehrere andere Module gezeigt, installiert werden (pip, venv etc.).
Beispielcode:
from build123d import *
# Bauteil
with BuildPart() as bauteil:
# Zylinder erstellen
Cylinder(100, 60)
# Bohrung
with BuildSketch(bauteil.faces().sort_by(Axis.Z)[-1]) as loch:
Circle(radius=10)
# negativ extrudieren
extrude(amount=-60, mode=Mode.SUBTRACT)
# Dem Bauteil z.B. die Farbe rot zuweisen
# bauteil.part.color = Color("red", alpha=1.0)
# Fertiges Modell exportieren
export_step(bauteil.part, "bauteil.step")
Ausgabe ({{W|Standard for the exchange of product model data | STEP}}-Datei, z.B. in {{W|FreeCAD}} importiert, Screenshot):
[[Datei:PythonIng_build123d.jpg | 300px]]
FreeCAD ist ein freies 3D-CAD-System. Die [[Ing_Mathematik:_Python#FreeCAD | Makroprogrammierung]] in diesem System wird später noch gezeigt. STEP steht für "'''St'''andard for the '''e'''xchange of '''p'''roduct model data" und ist ein Datenaustauschformat.
=== Mit VTK ===
Komplexer, aber auch mächtiger als VPython ist die Verwendung von VTK ('''V'''isualization '''T'''ool'''k'''it). Genauer gesagt des Python-Wrappers von VTK. Dieses externe Python-Modul muss vorab installiert werden (z.B. mittels YaST, pip oder in eine virtuelle Umgebung). VTK ist eine Softwarebibliothek zur 3D-Visualisierung und wurde ursprünglich in C++ geschrieben. Verbreitet eingesetzt wird diese Bibliothek in der Wissenschaft und Forschung, z.B.
* in der medizinischen Bildgebung
* für Strömungssimulationen
* für Klimadaten
VTK funktioniert nach dem {{W|Grafikpipeline|Pipeline-Prinzip}}:
Source (Quellen) -> Filter -> Mapper (Senken) -> Actor/Renderer
Daten fließen von den Quellen zu den Senken.
Als einfaches Beispiel wird die Darstellung eines Zylinders gezeigt, der mit den Maustasten gedreht oder in der Größe geändert werden kann:
import vtk
# Zylinder erzeugen
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
# Geometrie in darstellbare Daten umwandeln
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
# Objekt in der Szene
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Szene verwalten
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# Render-Fenster
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
# Maus/Tastatur-Steuerung
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Starten
render_window.Render()
interactor.Start()
Ausgabe:
[[Datei:PythonIng_VTK_1.png]]
Gleiches Beispiel wie oben, aber mit einer Animationssequenz:
import vtk
import time
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
render_window.Render()
time.sleep(0.01)
Das Grafikfenster schließt sich nach Ablauf der Schleife. Das Fenster bleibt geöffnet, wenn Sie am Programmende folgenden Befehl hinschreiben
interactor.Start()
Um den animierten Zylinder grün einzufärben, müssen Sie Folgendes im obigen Programm ergänzen (Farbnamen):
colors = vtk.vtkNamedColors()
actor.GetProperty().SetColor(colors.GetColor3d("Green"))
Als Namen können Sie u.a. die CSS3 Web-Farben verwenden (siehe z.B. [https://wiki.selfhtml.org/wiki/Farbe/Farbangaben] und {{W|Webfarbe#CSS_3}}).
Alternativ funktioniert auch das ({{W|RGB-Farbraum|RGB}}):
actor.GetProperty().SetColor(0.0, 0.6, 0.0)
Wie der Zylinder mit einer Textur versehen wird, zeigt folgendes Programm:
import vtk
import time
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(30)
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.CappingOn()
texture_coords = vtk.vtkTextureMapToCylinder()
texture_coords.SetInputConnection(cylinder.GetOutputPort())
texture_coords.PreventSeamOn()
reader = vtk.vtkJPEGReader()
reader.SetFileName("PythonIng_textur.jpg")
texture = vtk.vtkTexture()
texture.SetInputConnection(reader.GetOutputPort())
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(texture_coords.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.SetTexture(texture)
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
renderWindow.Render()
time.sleep(0.01)
interactor.Start()
<gallery>
PythonIng_textur.jpg | Textur-Datei
PythonIng_VTK_2.png | Ausgabe (Screenshot)
</gallery>
== Sonstige Grafikbibliotheken ==
=== Py5 ===
Im Buch ''Iacono et al.: Programmieren trainieren, mit über 150 Workouts in Java und Python; 3. Aufl., Hanser, 2023'' werden zahlreiche Aufgaben gestellt, die u.a. mit Processing zu lösen sind. Processing ist eine einfache Programmiersprache und Entwicklungsumgebung. Warum ich das erwähne? Weil in älteren Processing-Versionen auch die Programmiersprache Python abgedeckt war. Bei neueren Versionen gibt es keine Python-Anbindung mehr. Somit funktioniert der Python-Teil im genannten Buch nicht mehr. Ist das tragisch, oder kann das Buch weggeschmissen werden? Nein! Es gibt Alternativen zu Processing. Zum einen die im Buch selbst genannten Bibliotheken tkinter oder pygame. Pygame wird dort auch kurz anhand eines Beispiels thematisiert. Aber noch besser ist es, die py5-Bibliothek zu verwenden (lt. Google KI vom 30. Sept. 2026: ''Der echte, moderne „spirituelle Nachfolger“''). Damit ist die Funktionalität von Processing gewährleistet. Man kann aber beliebige Editoren oder IDEs zur Programmerstellung verwenden, ohne an Processing als IDE gebunden zu sein. Nachfolgend werden ein paar Beispiele zu dieser externen Bibliothek gegeben. Der erste Schritt ist wieder, die py5-Bibliothek zu installieren (z.B. mittels pip in eine virtuelle Umgebung). Dann kann es schon mit dem Programmieren losgehen.
Beispiel (angelehnt an die ''Aufgabe W.2.3 Haus'' des genannten Buchs, jedoch etwas erweitert):
import py5
def setup():
py5.size(600, 600) # Fenstergröße 600px x 600px
py5.background(255, 255, 255) # Hintergrundfarbe ... weiss
def draw():
# Haus zeichnen
py5.fill(255, 255, 255) # Hintergrundfarbe ... weiss
py5.stroke(255, 0, 0) # Linienfarbe ... rot
py5.stroke_weight(3) # Linienbreite ... 3px
py5.rect(150, 200, 300, 300) # Rechteck zeichnen (x, y, b, h)
py5.triangle(150, 200, 300, 100, 450, 200) # Dreieck zeichnen
py5.circle(250, 300, 70) # Kreis zeichnen (x, y, d)
# Bemassung zeichnen
py5.stroke(0, 255, 0)
py5.stroke_weight(1)
py5.line(300, 100, 550, 100) # Linie zeichnen
py5.line(450, 200, 550, 200)
py5.line(450, 500, 550, 500)
py5.line(150, 500, 150, 550)
py5.line(450, 500, 450, 550)
py5.text_size(20) # Textgroesse
py5.fill(0, 255, 0) # Textfarbe
py5.text("300", 280, 550) # Text zeichnen
py5.text("100", 500, 150)
py5.text("300", 500, 350)
# Gedrehtes Rechteck zeichnen
py5.stroke(255, 255, 0)
py5.stroke_weight(3)
py5.fill(200, 200, 200)
py5.translate(320, 260)
py5.rotate(0.3) # Drehung (in Radiant)
py5.rect(0, 0, 100, 50)
# Startet den Sketch
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_1.png|300px]]
Das skizzierte Haus ist mit einer rudimentären Bemaßung versehen und hat zwei Fenster, ein rundes und ein gedrehtes, trübes rechteckiges.
Beispiel (Mausoperationen):
import py5
def setup():
py5.size(600, 600)
py5.background(255, 255, 255)
def draw():
pass
def mouse_pressed():
py5.text_size(15)
py5.fill(0, 0, 255)
x = py5.mouse_x
y = py5.mouse_y
py5.text("(%d, %d)" %(x, y), x, y) # Positionsdaten bei Maus-Klick schreiben
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_2.png|300px]]
Obiges Bild zeigt das Resultat nach einigen Mausklicks. Man erkennt, dass links-oben der Koordinatennullpunkt ist. Die x-Achse zeigt nach rechts, die y-Achse nach unten.
Beispiel (Fünfeck):
import py5
import random
def setup():
py5.size(400, 400)
py5.no_loop() # statisches Bild (schont die Ressourcen)
def draw():
py5.translate(py5.width / 2, py5.height / 2) # KS setzen
radius = 150
eck_anzahl = 5
py5.fill(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255)) # Füllfarbe auf Zufallswert setzen
py5.stroke(155, 0, 0)
py5.stroke_weight(5)
# Fünfeck als Polygon zeichnen
py5.begin_shape()
for i in range(eck_anzahl):
winkel = i * py5.TWO_PI / eck_anzahl - py5.HALF_PI
x = py5.cos(winkel) * radius
y = py5.sin(winkel) * radius
py5.vertex(x, y)
py5.end_shape(py5.CLOSE)
py5.run_sketch()
Ausgabe, bspw.:
[[Datei:PythonIng_py5_5.png|200px]]
<u>Kleine Aufgaben:</u>
* Um die Funktionsweise von <code>py5.no_loop()</code> zu verstehen, kommentieren Sie die Anweisung im Beispiel einfach aus, und starten Sie das Programm erneut.
* Zeichnen Sie ein Siebeneck.
* Was passiert, wenn man <code>py5.CLOSE</code> im <code>py5.end_shape()</code>-Befehl weglässt?
Beispiel (Grafik laden und zeichnen):
import py5
image1 = None
def setup():
global image1
py5.size(600, 600)
py5.no_loop()
image1 = py5.load_image("PythonIng_py5_1.png")
def draw():
py5.image(image1, 0, 0)
py5.run_sketch()
Hier wird einfach das Bild vom Haus-Beispiel (Screenshot von weiter oben) geladen und gezeichnet.
Hiermit belassen wir es mit der py5-Bibliothek und wenden uns wieder "mathematischeren" Themen zu.
= Vektoren und Matrizen =
== Zahlenfolgen ==
Für das Erstellen von Zahlenfolgen bieten sich die Funktionen <code>arange</code> und <code>linspace</code> aus dem <code>numpy</code>-Modul an.
from numpy import *
start = 0
stop = 10
step = 2
num = 10
r = arange(start, stop, step) # step ... Schrittweite
l = linspace(start, stop, num) # num ... Anzahl der Werte
print("r = ", r)
print("l = ", l)
Ausgabe:
r = [0 2 4 6 8]
l = [ 0. 1.11111111 2.22222222 3.33333333 4.44444444 5.55555556
6.66666667 7.77777778 8.88888889 10. ]
Bei <code>arange</code> ist der <code>stop</code>-Wert nicht im Ergebnis enthalten, bei <code>linspace</code> standardmäßig aber sehr wohl. Jedoch kann man das bei <code>linspace</code> auch ändern. Dann ist der Stoppwert nicht mehr enthalten:
linspace(start, stop, num, endpoint=False)
== Vektoren ==
Vektoren sollten jedem aus der Linearen Algebra bekannt sein.
=== Arrays ===
In Python mit NumPy kann man Vektoren durch die Funktion array erzeugen.
import numpy as np
l1 = (-5, 3, 2)
l2 = (1, 1, 4)
a1 = np.array(l1)
a2 = np.array(l2)
a3 = a1 + a2
a4 = 2 * a2
print(a1)
print(a2)
print(a3)
print(a3[2])
print(a4)
Ausgabe:
[-5 3 2]
[1 1 4]
[-4 4 6]
6
[2 2 8]
=== Zeilen- und Spaltenvektoren ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
print(z)
print(s)
Ausgabe:
[ [-5 3 2] ]
[[1]
[1]
[4]]
=== Skalarprodukt ===
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
skalarprodukt = np.dot(a1, a2)
print(skalarprodukt)
Ausgabe:
6
=== Vektorprodukt ===
<math>a\ast b=\left(\begin{array}{c}
a_{1}\\
a_{2}\\
a_{3}
\end{array}\right)\ast\left(\begin{array}{c}
b_{1}\\
b_{2}\\
b_{3}
\end{array}\right)=\left(\begin{array}{c}
a_{2}b_{3}-a_{3}b_{2}\\
a_{3}b_{1}-a_{1}b_{3}\\
a_{1}b_{2}-a_{2}b_{1}
\end{array}\right)
</math>
Python-Code:
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
vektorprodukt = np.cross(a1, a2)
print(vektorprodukt)
Ausgabe:
[10 22 -8]
=== Transponierter Vektor ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
# transponierter Vektor
z_tp = np.transpose(z)
# transponierter Vektor
s_tp = np.transpose(s)
print(z_tp)
print(s_tp)
Ausgabe:
[[-5]
[ 3]
[ 2]]
[ [1 1 4] ]
=== Vektorfelder visualisieren ===
import matplotlib.pyplot as plt
import numpy as np
# Daten generieren
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
X, Y = np.meshgrid(x, y)
U = X * Y
V = Y + X
# Plotten
fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='xy')
plt.show()
Ausgabe:
[[Datei:PythonIng_quiver1.png]]
== Matrizen==
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
print(m1)
Ausgabe:
[[1 2 3]
[4 5 6]]
=== Zugriff auf Matrizenelemente ===
Beispiel:
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
# Element aus Zeile 2 und Spalte 3 (Achtung! Index startet bei Null)
print(m1[1,2])
Ausgabe:
6
Visualisierung:
0 1 2
+-----------+
0 | 1 | 2 | 3 |
+-----------+
1 | 4 | 5 | '''6''' |
+-----------+
Beispiel:
import numpy as np
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
B = np.matrix(A)
print(B[2::, ::2])
Ausgabe:
[['20' '22']
['30' '32']
['40' '42']]
Mit der NumPy-Bibliothek funktioniert das zweidimensionale Slicing. Mit normalen Listen/Tupels geht das nicht, was wir schon früher thematisiert haben.
=== Addition und Subtraktion von Matrizen ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
m2 = np.matrix([[0, 0, 2], [1, 3, 2]])
print(m1 + m2)
print(m1 - m2)
Ausgabe:
[[1 2 5]
[5 8 8]]
[[1 2 1]
[3 2 4]]
=== Transponierte Matrix ===
import numpy as np
m = np.matrix([[1, 2, 3], [4, 5, 6]])
mt = np.transpose(m)
print(m)
print(mt)
Ausgabe:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]
=== Rang einer Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
rg = np.linalg.matrix_rank(m)
print(rg)
Ausgabe:
2
=== Inverse Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
mi = np.linalg.inv(m)
print(mi)
Ausgabe:
[[ 1. 0.6]
[-0. -0.2]]
=== Multiplikation von Matrizen (falksches Schema) ===
import numpy as np
m1 = np.matrix([[1, 3, 4], [0, -5, 1]])
m2 = np.matrix([[1, 2], [2, 3], [0, 2]])
print(m1 @ m2)
Ausgabe:
[[ 7 19]
[-10 -13]]
=== Eigenwerte und Eigenvektoren ===
import numpy as np
m = np.matrix([[5, 8], [1, 3]])
D,V = np.linalg.eig(m)
# Eigenwerte
print(D)
# Eigenvektoren
print(V)
Ausgabe:
[7. 1.]
[[ 0.9701425 -0.89442719]
[ 0.24253563 0.4472136 ]]
=== Teilmatrizen ===
import numpy as np
m = np.matrix([[1, 3, 4], [0, -5, 1]])
print("m = ", m)
# Erste Zeile extrahieren
m1 = m[0,:]
print("m1 = ", m1)
# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
m2 = m[0,1]
print("m2 = ", m2)
# Zweite Spalte extrahieren
m3 = m[:, 1]
print("m3 = ", m3)
Ausgabe:
m = [[ 1 3 4]
[ 0 -5 1]]
m1 = [ [1 3 4] ]
m2 = 3
m3 = [[ 3]
[-5]]
=== Spezielle Matrizen ===
==== Nullmatrix ====
import numpy as np
z = np.zeros((3, 2))
print(z)
Ausgabe:
[[0. 0.]
[0. 0.]
[0. 0.]]
==== Einheitsmatrix ====
import numpy as np
z = np.eye(3)
print(z)
Ausgabe:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
==== Matrix mit lauter Einsen ====
import numpy as np
z = np.ones((3, 2))
print(z)
Ausgabe:
[[1. 1.]
[1. 1.]
[1. 1.]]
=== Spärlich besetzte Matrizen ===
Das Thema spärlich besetzter Matrizen wird hier nur kurz angerissen. Nähere Details siehe unter dem Weblink [https://docs.scipy.org/doc/scipy/reference/sparse.html#module-scipy.sparse].
Beispiel:
import numpy as np
import scipy
A = scipy.sparse.csr_array(np.eye(5))
print(A)
Ausgabe:
<Compressed Sparse Row sparse array of dtype 'float64'
with 5 stored elements and shape (5, 5)>
Coords Values
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
(4, 4) 1.0
csr steht für '''c'''ompressed '''s'''parse '''r'''ow.
Andere Möglichkeiten:
* coo-Format ('''coo'''rdinate Format): <code>scipy.sparse.coo_array()</code>
* lil-Format ('''li'''st of '''l'''ists): <code>scipy.sparse.lil_array()</code>
* csc-Format ('''c'''ompressed '''s'''parse '''c'''olumn): <code>scipy.sparse.csc_array()</code>
Es gibt auch <code>scipy.sparse.csr_matrix()</code> etc. Diese Befehle sind aber veraltet und es wird empfohlen, statt dessen die <code>..._array()</code>-Funktionen zu verwenden.
<u>Aufgaben:</u>
Recherchieren Sie im Internet
* generell zum Thema "spärlich besetzte Matrizen mit Python".
* Was sind die Vor-/Nachteile von csr-arrays gegenüber coo- und lil-arrays?
* Wann verwendet man sinnvollerweise csr- und wann csc-arrays?
* Wie wandelt man coo-arrays in csr-arrays um?
= Lineare Gleichungssysteme =
Sei <math>Ax = b</math> ein lineares Gleichungssystem. <math>A</math> sei die Koeffizientenmatrix, <math>x</math> der Lösungsvektor und <math>b</math> ein bekannter Vektor.
Beispiel:
import numpy as np
A = np.array([[5, 1], [0, 2]])
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)
Ausgabe:
[0. 1.]
Siehe dazu auch das Kapitel [[Ing Mathematik: Numerisches Lösen von linearen Gleichungssystemen]]. Dort wird dieses Themengebiet u.a. mit weitergehenden Python-Skripten vertieft.
== Aufgabe ==
* Lösen Sie folgendes Gleichungssystem mittels Python (und zur Kontrolle auch händisch):
5x + 6y - 2z = 12
3x - y - 3z = 6
2x + 2y + 4z = 5
= Polynome =
== Ein erstes einfaches Beispiel ==
Gegeben sei das Polynom <math>7x^3+5x^2+1</math>. In Python:
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p)
Ausgabe:
3 2
7 x + 5 x + 1
== Einzelne Polynomwerte berechnen ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p(1.5))
Ausgabe:
35.875
== Polynome integrieren und differenzieren ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
# 1. Ableitung
p1 = p.deriv()
p2 = p.deriv(1)
# 2. Ableitung
p3 = p.deriv(2)
# Integral
p4 = p.integ()
print(p1)
print(p2)
print(p3)
print(p4)
Ausgabe:
2
21 x + 10 x
2
21 x + 10 x
42 x + 10
4 3
1.75 x + 1.667 x + 1 x
== Nullstellen bestimmen ==
import numpy as np
p = np.poly1d([2, 5, 0, 4])
r = np.roots(p)
print(r)
Ausgabe:
[-2.7621427 +0.j 0.13107135+0.84077099j 0.13107135-0.84077099j]
== Aufgaben ==
* Berechnen Sie den Wert für x = 3 des Polynoms <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Differenzieren und integrieren Sie das Polynom <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Berechnen Sie die Nullstellen von <math>y = 7x^5 - 3x^2 + 12</math>.
= Nichtlineare Gleichungen und Gleichungssysteme =
== Nullstellenbestimmung ==
Löse eine beliebige Gleichung f(x) = 0, z.B. <math> f(x) = x^2 - 5\cos(x) - 10 = 0 </math>:
import scipy
import numpy as np
def f(x):
return x**2 - 5*np.cos(x) - 10
xstart = [-1, 1] # Startwerte
xn = scipy.optimize.root(f, xstart)
print(xn.x)
Ausgabe:
[-2.46813009 2.46813009]
Funktionsgraph:
[[Datei:octave_nichtlin2.jpg]]
== Gleichungssysteme ==
SymPy ist ein externes Modul, das symbolisches Rechnen ('''Sym'''bolic '''Py'''thon) ermöglicht.
Folgende Aufgabe ist dem Buch "Knorrenschild: Numerische Mathematik, Hanser, 2017, Seite 72" entnommen. Zu lösen ist das nichtlineare Gleichungssystem
<math>f_1 = 2x_1 + 4x_2 = 0 </math>
<math>f_2 = 4x_1 + 8x_2^3 = 0</math>
Mit Python ist das so möglich:
import sympy
x1, x2 = sympy.symbols("x1 x2")
f1 = 2*x1 + 4*x2
f2 = 4*x1 + 8*x2**3
s = sympy.solve((f1, f2), x1, x2)
print(s)
Ausgabe:
[(-2, 1), (0, 0), (2, -1)]
Plot:
[[Datei:IngPython_nl_gleichung1.svg|500px]]
= Komplexe Zahlen =
Die imaginäre Einheit wird in Python durch den Buchstaben <code>j</code> symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:
* Kartesische Darstellung <math>z = \Re(z) + j \cdot \Im(z)</math>
* Polardarstellungen <math>z = r \cdot (\cos(\phi) + j \cdot \sin(\phi)) = r \cdot e^{j\cdot \phi}</math>
Die konjugiert komplexe Zahl ist <math>z^* = \Re(z) - j \cdot \Im(z)</math>
Nachfolgend einige mathematische Operationen mit Python und NumPy.
import numpy as np
z1 = 2 + 5j # kartesische Darstellung
z2 = 3 * np.exp(3j) # Polardarstellung
# Addition
res = z1 + z2
print("z1 + z2 = ", res)
# Multiplikation
res = z1 * z2
print("z1 * z2 = ", res)
# Realteil
res = np.real(z2)
print("Realteil von z2 = ", res)
# Imaginärteil
res = np.imag(z2)
print("Imaginaerteil von z2 = ", res)
# Betrag
res = np.abs(z1)
print("Betrag von z1 = ", res)
# Argument
res = np.angle(z1)
print("Argument von z1 = ", res)
# Konjugiert komplexe Zahl
res = np.conj(z1)
print("Konjugiert komplexe Zahl von z1 = ", res)
Ausgabe:
z1 + z2 = (-0.9699774898013365+5.423360024179601j)
z1 * z2 = (-8.05675510050068-14.003167400647481j)
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = (2-5j)
= Interpolation =
import numpy as np
import scipy
import matplotlib.pyplot as plt
# Stützpunkte
xp = np.arange(1, 6)
yp = (0, -5, 2, 7, 6)
ti = np.arange(1, 5, 0.01)
i1 = scipy.interpolate.interp1d(xp, yp, kind = "linear")
i2 = scipy.interpolate.interp1d(xp, yp, kind = "cubic")
plt.plot(xp, yp, "rx")
plt.plot(xp, i1(xp))
plt.plot(ti, i2(ti))
plt.show()
Ausgabe:
[[Datei:PythonIng_interpol1.png]]
= Differenzialrechnung =
== Numerisches Differenzieren ==
Als Beispiel differenzieren wir <math>y = 5x\sin{x}</math> und stellen das Ganze grafisch dar.
from findiff import Diff
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
f = 5 * x * np.sin(x)
dx = x[1] - x[0]
# Ableitung
d_dx = Diff(0, dx)
df_dx = d_dx(f)
# Grafik
plt.plot(x, f, label = "y")
plt.plot(x, df_dx, label = "y'")
plt.grid()
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:octave_diff1.jpg]]
<small>findiff ist ein externes Modul. Dieses muss installiert werden (z.B. so: ...\Python\Scripts\pip.exe install --upgrade findiff). Für die Vorgehensweise unter openSUSE Tumbleweed siehe das Kapitel [[Ing_Mathematik:_Python#Mit_VPython | VPython]], nur dass das Ganze mit einer aktuelleren Python-Version exekutiert wird, z.B. mit Python 3.13. Das im Buch "Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler, Rheinwerk" verwendete Modul "scipy.misc" ist veraltet (deprecated ... missbilligt). Lt. [https://docs.scipy.org/doc/scipy-1.17.0/dev/roadmap-detailed.html#misc SciPy-Dokumentation für die Version 1.17.0] wurden alle entsprechenden Features schon entfernt.</small>
== Symbolisches Differenzieren ==
Differenzieren Sie die Funktionen <math>f_1(x) = x^2</math> und <math>f_2(x) = \sin(x)\cos\left(\frac{x}{2}\right)</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2;
f2 = sympy.sin(x) * sympy.cos(x/2.)
d1 = sympy.diff(f1, x)
d2 = sympy.diff(f2, x)
print(d1)
print(d2)
Ausgabe:
2*x
-0.5*sin(0.5*x)*sin(x) + cos(0.5*x)*cos(x)
== Aufgaben ==
* Differenzieren Sie die Funktion <math>y = \log(x) + 10x</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
* Differenzieren Sie die Funktion <math>y = \frac{\sinh(x)}{(1+x)}</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
= Integralrechnung =
== Numerisches Integrieren ==
Berechnen Sie das Integral <math>\int_{0}^{3}x^2 dx</math>.
import scipy
def f(x):
return x**2
i = scipy.integrate.quad(f, 0, 3)
print(i)
Ausgabe:
(9.000000000000002, 9.992007221626411e-14)
Das trifft den exakten Wert 9.0 ziemlich genau.
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} dx</math>.
import scipy
import numpy as np
def f(x):
return 2**(-x)
i = scipy.integrate.quad(f, 0, np.inf)
print(i)
Ausgabe:
(1.4426950408889556, 4.486558477977586e-09)
== Symbolisches Integrieren ==
Berechnen Sie <math>\int x^2 \text{d}x</math> und <math>\int \sin{x}\cos{\frac{x}{2}} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2
f2 = sympy.sin(x) * sympy.cos(x/2.)
i1 = sympy.integrate(f1, x)
i2 = sympy.integrate(f2, x)
print(i1)
print(i2)
Ausgabe:
x**3/3
-0.666666666666667*sin(0.5*x)*sin(x) - 1.33333333333333*cos(0.5*x)*cos(x)
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f = 2**(-x)
i = sympy.integrate(f, (x, 0, sympy.oo))
print(i)
Ausgabe:
1/log(2)
<code>sympy.oo</code> steht für das {{W|Unendlichzeichen}} <math>\infty</math> (die liegende Acht oder das Möbiusband). Mit <code>sympy.pprint(i)</code> ließe sich letzere Ausgabe etwas schöner schreiben:
1
──────
log(2)
Man beachtete, <code>log</code> steht hier für den natürlichen Logarithmus <code>ln</code>.
== Aufgaben ==
* Integrieren Sie die Funktion <math>y = \log(x) + 10x</math> von 1 bis 5.
* Integrieren Sie die Funktion <math>y = x^3</math> von 0 bis 4.
* Integrieren Sie <math>\int x^x(\log (x) + 1)\mathrm dx</math> symbolisch.
= Gewöhnliche Differenzialgleichungen =
== DGL numerisch lösen ==
Für die Lösung von Differenzialgleichungen steht u.a. die Funktion scipy.integrate.solve_ivp() zur Verfügung. Diese Funktion implementiert auch das Runge-Kutta-Verfahren (RK45).
{{Wikipedia | Runge-Kutta-Verfahren}}
Beispiel <math>y' = x^2 + y^3</math>:
import scipy
import numpy as np
import matplotlib.pyplot as plt
def dy_dx(x, y):
return x**2 + y**3
y0 = [1]
xi = [0, 1]
x = np.arange(0, 1, 0.01)
z = scipy.integrate.solve_ivp(dy_dx, xi, y0, method="RK45", dense_output=True)
y = z.sol(x)
plt.plot(x, y.T)
plt.grid()
plt.show()
[[Datei:PythonIng_dgl1.png]]
== DGL symbolisch lösen ==
Beispiel <math>y' = x^2 + y^3</math>:
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
print(lsg)
Ausgabe:
[Eq(f(x), (-x**2)**(1/3)), Eq(f(x), (-x**2)**(1/3)*(-1 - sqrt(3)*I)/2), Eq(f(x), (-x**2)**(1/3)*(-1 + sqrt(3)*I)/2)]
Mit <code>sympy.pprint</code> (pretty print) lässt sich die Ausgabe etwas übersichtlicher darstellen.
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
sympy.pprint(lsg)
Ausgabe:
⎡ _____ _____ ⎤
⎢ _____ 3 ╱ 2 3 ╱ 2 ⎥
⎢ 3 ╱ 2 ╲╱ -x ⋅(-1 - √3⋅ⅈ) ╲╱ -x ⋅(-1 + √3⋅ⅈ)⎥
⎢f(x) = ╲╱ -x , f(x) = ────────────────────, f(x) = ────────────────────⎥
⎣ 2 2 ⎦
== Aufgaben ==
* Lösen Sie die Differenzialgleichung <math>y' = \frac{1}{x\cdot y}</math> mit Python. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>m' = -k\cdot m</math>. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>y' = \sqrt{|y|}</math>.
=Laplace-Transformation=
Laplace-Transformation:
<math>F(s) =\mathcal{L} \left\{f\right\}(s) = \int_{0}^{\infty} f(t) \mathrm e^{-st} \,\mathrm{d}t, \qquad s\in\mathbb{C}
</math>
Inverse Laplace-Transformation:
<math>\mathcal{L}^{-1} \left\{F\right\}(t)
= \frac{1}{2 \pi \mathrm j} \int_{ \gamma - \mathrm j \infty}^{ \gamma + \mathrm j \infty} \mathrm e^{st} F(s)\,\mathrm ds
= \begin{cases}
f(t) & \text{für } t \geq 0 \\
0 & \text{für } t < 0
\end{cases}
</math>
Siehe auch [[Ing_Mathematik:_Laplace-Transformation]]
Code:
import sympy
from sympy.abc import t, s
# Laplace-Transformation der Funktion f(t) = 1 (Heaviside-Fkt.)
f = 1
# alternativ: f = sympy.Heaviside(t)
F = sympy.laplace_transform(f, t, s, noconds=True)
print("Laplace-Transformierte F(s):", F)
# Inverse Laplace-Transformation zurück in den Zeitbereich
f_inv = sympy.inverse_laplace_transform(F, s, t)
print("Inverse Transformation f(t):", f_inv)
Ausgabe:
Laplace-Transformierte F(s): 1/s
Inverse Transformation f(t): Heaviside(t)
Die Zeile
from sympy.abc import t, s
steht alternativ für
t = sympy.symbols("t")
s = sympy.symbols("s")
<u>Aufgaben</u>: Ermitteln Sie mittels SymPy die <math>\mathcal{L}</math>-Transformierten und dann wieder die <math>\mathcal{L}^{-1}</math>-Transformationen (ähnlich wie beim obigen Beispiel):
* <math>\sin(t) \circ\! -\! \bullet \ ?</math>
* <math>t^3 \circ\! -\! \bullet \ ?</math>
* <math>\text{e}^{\omega t} \circ\! -\! \bullet \ ?</math>
=Fourier-Reihen=
<math>
f(x)\approx \frac{a_{0}}{2}+\sum_{k=1}^{\infty}\left(a_{k}\cos\left(kx\right)+b_{k}\sin\left(kx\right)\right)
</math>
<math>
a_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\cos\left(kx\right)\mathrm dx\quad\text{für }k\geq0
</math>
<math>
b_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\sin\left(kx\right)\mathrm dx\quad\text{für }k\geq1
</math>
Für die Sägezahnfunktion <math>y=x;\, 0 < x < 2\pi</math> sei die Fourierreihe mit einem Python-Programm (unter Mithilfe von sympy) hergeleitet.
Code:
from sympy import fourier_series, pi, symbols, pprint
x = symbols('x')
f = x
s = fourier_series(f, (x, 0, 2*pi))
pprint(s.truncate(n=4))
Ausgabe:
2⋅sin(3⋅x)
-2⋅sin(x) - sin(2⋅x) - ────────── + π
3
Siehe auch [[Ing Mathematik: Fourierreihen]].
Ein komplizierteres Beispiel:
[[Datei:IngMath fourier bsp13.svg | 300px]]
<math>0\le t < T/2\text{:}\quad f(t) = H</math>
<math>T/2 \le t \le T\text{:}\quad f(t) = \frac{2H}{T}\left( t-\frac{T}{2}\right)</math>
Code:
import sympy as sp
H = sp.Symbol('H', positive=True)
T = sp.Symbol('T', positive=True)
t = sp.Symbol('t')
f = sp.Piecewise(
(H, (t > 0) & (t < T/2)),
(2*H/T*(t-T/2), (t > T/2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Ausgabe:
⎛2⋅π⋅t⎞ ⎛4⋅π⋅t⎞ ⎛6⋅π⋅t⎞ ⎛2⋅π⋅t⎞ ⎛6⋅π⋅t⎞
H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ 2⋅H⋅cos⎜─────⎟ 2⋅H⋅cos⎜─────⎟
⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ 3⋅H
──────────── - ──────────── + ──────────── + ────────────── + ────────────── + ───
π 2⋅π 3⋅π 2 2 4
π 9⋅π
=Rechnen mit wirklich großen Zahlen=
Bekannt ist, dass Python kaum Einschränkungen beim Wertebereich von Ganzzahlen hat, z.B.
print(10**300)
Ausgabe (gekürzt):
100000000000000000000...00000000000000000000000000000000000000000000000000000000000000000000000
Ähnliches geht auch mit Gleitpunktzahlen, z.B. durch die Verwendung des Moduls [https://mpmath.org/ mpmath]:
import mpmath
print(mpmath.mpf(1500.4)**mpmath.mpf(300))
Ausgabe:
7.27975299218612e+952
Anderes Beispiel:
from mpmath import mp, pi
mp.dps = 100
print(pi)
Ausgabe:
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
mpmath kann noch einiges mehr, dazu sei aber auf die entsprechende Dokumentation auf der mpmath-Homepage verwiesen. mpmath ist Bestandteil von SymPy, kann aber auch separat installiert werden.
Aber auch Python selbst besitzt eine Möglichkeit, um mit großen bzw. exakten Gleitpunktzahlen zu rechnen, nämlich das interne Modul decimal. Dieses hat einige Vorteile gegenüber mpmath, aber auch gravierende Nachteile. Diese seien hier nicht detailliert aufgezählt. Grob gesagt hat decimal im Finanzwesen seine Berechtigung. Für wissenschaftliche Anwendungen wird aber mpmath vorzuziehen sein, da es u.a. vielfältige mathematische Funktionen bereit stellt. Nachfolgend ein einfaches Beispiel mit decimal:
import decimal
print("Potenzierung:", decimal.Decimal(1500.4) ** decimal.Decimal(300.0))
print("Einfache Addition:", 0.1 + 0.2)
decimal.getcontext().prec = 50
print("Addition mit decimal:", decimal.Decimal("0.1") + decimal.Decimal("0.2"))
Ausgabe:
Potenzierung: 7.279752992186121551039839134E+952
Einfache Addition: 0.30000000000000004
Addition mit decimal: 0.3
<u>Aufgabe:</u> Recherchieren Sie im Internet die genauen Vor- und Nachteile von decimal und mpmath. Verwenden Sie dazu auch KI (z.B. von Google, chatgpt).
= pint - mit physikalischen Größen rechnen =
[[File:Pint-Glas_UK.jpg|right|100px]]
pint ist ein externes Python-Paket zur Manipulation von physikalischen Einheiten. Es muss vor der ersten Benutzung installiert werden (Vorgehensweise wie immer: pip, YaST, via venv etc.).
Beispiel:
import pint
import numpy as np
ureg = pint.UnitRegistry()
# Einfache Berechnung
print(3 * ureg.meter + 4 * ureg.cm)
# Mit NumPy
npeinzel = [3, 4] * ureg.meter + [2, 5] * ureg.cm
print(npeinzel)
npsum = np.sum(npeinzel)
print(npsum)
# Konvertierung von Einheiten
npsum_inch = npsum.to(ureg.inch)
print(npsum_inch)
print(npeinzel.magnitude)
print(npeinzel.units)
print(npeinzel.dimensionality)
Ausgabe:
3.04 meter
[3.02 4.05] meter
7.07 meter
278.3464566929134 inch
[3.02 4.05]
meter
[length]
Die Dokumentation zu pint findet sich auf [https://pint.readthedocs.io/en/stable/].
=Regelungstechnische Aufgabenstellungen=
Für regelungstechnische Aufgaben gibt es u.a. das externe Paket <code>control</code>. Hier soll nicht detailliert darauf eingegangen werden. Anhand eines Beispiels soll anschließend nur die Visualisierung in Form eines Bode-Diagramms und der Sprungantwort gezeigt werden. Gegeben sei ein P-Regler mit <math>R = \frac{5}{2}</math> und eine Strecke <math>S= \frac{1}{30s^3+20s^2+10s+1,5}</math>. Gesucht sei vorerst ein Bode-Diagramm für den offenen Regelkreis und das Führungsverhalten.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke # oder: G0 = ct.series(regler, strecke)
Gw = ct.feedback(G0)
ct.bode_plot(G0, label='G0')
ct.bode_plot(Gw, label='Gw')
plt.show()
[[Datei:PythonIng_bode1.svg]]
Nun noch für obiges Beispiel die Sprungantwort. Diese zeigt einige große Überschwinger, d.h. der Regler kann sicher noch optimiert werden.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke
Gw = ct.feedback(G0)
t, y = ct.step_response(Gw)
plt.plot(t,y)
plt.title('Sprungantwort')
plt.xlabel('t')
plt.ylabel('h(t)')
plt.grid()
plt.show()
[[Datei:PythonIng_bode3.svg]]
Einige weitere wichtige Daten (Phasenreserve, Amplitudenreserve, Durchtrittsfrequenz) lassen sich mittels der <code>control</code>-Funktion <code>margin()</code> ermitteln. Die Ortskurve lässt sich mit der Funktion <code>nyquist_plot()</code> zeichnen. Dies sei hier aber nicht weiter ausgeführt.
==Aufgaben==
* Zeichen Sie mit Python die Ortskurve für obiges Beispiel.
* Was passiert, wenn man die Reglerverstärkung weiter aufdreht (z.B. auf <math>R = \frac{25}{2}</math>)?
* Wie sehen das Bode-Diagramm und die Sprungantwort aus, wenn ein PI-Regler verwendet wird?
= Stereostatik etc. =
Das Modul SymPy bietet einige Möglichkeiten einfache Bauwerke zu berechnen, z.B. Balken oder Fachwerke. Nachfolgend wird ein einfaches Fachwerk berechnet und gezeichnet.
Python-Code:
from sympy.physics.continuum_mechanics.truss import Truss
t = Truss()
# Knoten
t.add_node(("A", -3, 0), ("B", 0, 0), ("C", 4, 0), ("D", 7, 0),
("E", 6, 1.5), ("F", 2, 3), ("G", -2, 1.5))
# Stäbe
t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D"))
t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F"))
t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E"))
t.add_member(("FE","F","E"), ("DE","D","E"))
# Auflager; roller ... Loslager, pinned ... Festlager
t.apply_support(("A","roller"), ("D","pinned"))
# Einwirkende Kräfte
t.apply_load(("G", 5, 270), ("E", 3, 90))
# Berechnung
t.solve()
print("Reaction Forces: ", t.reaction_loads)
print("Internal Forces: ", t.internal_forces)
# Fachwerk zeichnen
p = t.draw()
p.show()
Ausgabe auf der Konsole:
Reaction Forces: {'R_A_y': 4.20000000000000, 'R_D_x': 0, 'R_D_y': -2.20000000000000}
Internal Forces: {'AB': 2.80000000000000, 'BC': 0.333333333333333, 'CD': -1.46666666666667,
'AG': -5.04777178564958, 'GB': -2.05555555555556, 'GF': -1.23413387432364,
'BF': 0.411111111111111*sqrt(13), 'FC': -0.3*sqrt(13), 'CE': 1.50000000000000,
'FE': 0.284800124843917, 'DE': 2.64407093534026}
Zeichnung:
[[File:PythonIng_fachwerk1.svg|300px]]
Details zu diesem Thema siehe z.B. [https://docs.sympy.org/latest/modules/physics/continuum_mechanics/index.html Continuum Mechanics] oder [https://docs.sympy.org/latest/tutorials/physics/continuum_mechanics/index.html Continuum Mechanics Tutorials]. Auch andere mechanische Probleme werden von SymPy abgehandelt ([https://docs.sympy.org/latest/tutorials/physics/index.html Physics Tutorials]).
== Aufgabe ==
Gegeben sei ein einseitig eingespannter Kragträger. Belastet wird er durch eine Einzellast am Trägerende. Für die Daten siehe folgende ASCII-Skizze:
| 20 kN
//|---> x |
//| V
//|----------------------
//| 10 m |
Elastizitätsmodul E = 2,1*10⁵ N/mm²
Flächenträgheitsmoment I = 0.001 m⁴
Berechnen Sie die Auflagerreaktionen, den Querkraft- und Biegemomentenverlauf, sowie die Verformungen.
Stellen Sie dies mit Hilfe von SymPy graphisch und auch mittels Formeln dar. Verwenden Sie dazu auch pprint (pretty print) aus dem SymPy-Modul. Zwecks Lösungsansatz siehe die oben aufgeführte Seite "Continuum Mechanics Tutorials". Achten Sie auch auf die Einheiten! Kontrollieren Sie das Ganze mittels händischer Rechnung. In dem genannten Tutorial ist von "Singularity Functions" die Rede. Gemeint ist damit in diesem Kontext die {{W|Föppl-Klammer}}.
Einige Python-Programme, vorrangig zu Maschinenelementen, finden sich auf [https://baymp.de/download_python.html BayMP für Python] (Balken, Zahnräder, Stabknickung usw.).
=Thermodynamik=
== PYroMat ==
Für thermodynamische Aufgabenstellungen gibt es verschiedene externe Module. Eines davon ist PYroMat (siehe auch [http://pyromat.org]). Damit lassen sich thermodynamische Stoffdaten für viele Substanzen berechnen.
Beispiel (einige Stoffdaten für Wasser bei 400°C und 20 bar berechnen):
import pyromat as pm
# Wasserdaten laden:
H2O = pm.get('mp.H2O')
# Stoffdaten berechnen:
T = 673.15 # Temperatur in Kelvin
p = 20 # Druck in bar
v = H2O.v(T, p)
h = H2O.h(T, p)
s = H2O.s(T, p)
print(f"Spezifisches Volumen: {v} m³/kg")
print(f"Spezifische Enthalpie: {h} kJ/kg")
print(f"Spezifische Entropie: {s} kJ/(kg K)")
Ausgabe:
Spezifisches Volumen: [0.1512163] m³/kg
Spezifische Enthalpie: [3248.3789473] kJ/kg
Spezifische Entropie: [7.12924142] kJ/(kg K)
<small>
PYroMat muss vorab installiert werden (z.B. mittels pip, in eine virtuelle Umgebung)
</small>
<code>mp</code> steht für "multi phase". Für ein ideales Gas wäre <code>ig</code> zuständig, z.B. <code>'ig.O2'</code>.
Beispiel (T-s-Diagramm für Wasser zeichnen):
import numpy as np
import matplotlib.pyplot as plt
import pyromat as pm
# Konfigurieren
pm.config["unit_pressure"] = "bar"
pm.config["unit_temperature"] = "K"
fluid = pm.get("mp.H2O")
# Temperaturbereich für das Nassdampfgebiet
T_tripel = 273.16
T_crit = 647.096
T = np.linspace(T_tripel, T_crit - 0.1, 200)
# Sättigungslinien berechnen und zeichnen
for x in np.linspace(0.0, 1.0, 5):
s = fluid.s(T=T, x=x)
if(x<=0.0):
plt.plot(s, T, label="Siedelinie x=%3.1f" % x, linewidth=2.0)
elif(x>=1.0):
plt.plot(s, T, label="Taulinie x=%3.1f" % x, linewidth=2.0)
else:
plt.plot(s, T, label="x=%3.1f" % x, linewidth=1.0)
# Isobaren zeichnen
p_values = [0.1, 1, 10, 50, 100]
T_isobar = np.linspace(T_tripel, 1000, 200)
t = 0.7
for p in p_values:
s_iso = fluid.s(T=T_isobar, p=p)
plt.plot(s_iso, T_isobar, 'k-', alpha=0.8, linewidth=0.8)
t += .05
idx = int(len(s_iso) * t)
plt.text(s_iso[idx], T_isobar[idx], f"{p} bar", fontsize=9, alpha=0.8)
# Diagramm zeichnen
plt.title("T-s-Diagramm für Wasser")
plt.xlabel("Spezifische Entropie s in kJ/kg K", fontsize=10)
plt.ylabel("Temperatur T in K", fontsize=10)
plt.legend(loc="best")
plt.grid(True)
plt.show()
Ausgabe (in etwa so):
[[Datei:T-s-Diagramm fuer Wasser.svg|400px]]
== CoolProp ==
Auch mit CoolProp können Stoffdaten berechnet werden. Siehe auch [https://coolprop.org/coolprop/wrappers/Python/index.html]
Beispiel (Wasser bei 20bar und 400°C):
import CoolProp.CoolProp as CP
fluid = 'Water'
T = 673.15 # Temperatur in Kelvin
P = 20e5 # Druck in Pascal
dichte = CP.PropsSI('D', 'T', T, 'P', P, fluid)
enthalpie = CP.PropsSI('H', 'T', T, 'P', P, fluid)
entropie = CP.PropsSI('S', 'T', T, 'P', P, fluid)
print(f"Spez. Volumen: {1/dichte:.6f} m³/kg")
print(f"Spez. Enthalpie: {enthalpie:.2f} J/kg")
print(f"Spez. Entropie: {entropie:.2f} J/kgK")
Ausgabe:
Spez. Volumen: 0.151215 m³/kg
Spez. Enthalpie: 3248344.02 J/kg
Spez. Entropie: 7129.16 J/kgK
== iapws ==
Um Werte für Wasser(dampf) zu erhalten (IAPWS; '''I'''nternational '''A'''ssociation for the '''P'''roperties of '''W'''ater and '''S'''team) gibt es die Bibliothek iapws. Siehe auch [https://iapws.org/] und [https://pypi.org/project/iapws/]
Beispiel (Wasser für 20bar und 400°C):
from iapws import IAPWS97
dampf = IAPWS97(P=2.0, T=673.15)
print(f"Spezifisches Volumen: {dampf.v:.6f} m³/kg")
print(f"Spezifische Enthalpie: {dampf.h:.2f} kJ/kg")
print(f"Spezifische Entropie: {dampf.s:.4f} kJ/(kgK)")
print(f"Phase: {dampf.phase}")
Ausgabe:
Spezifisches Volumen: 0.151208 m³/kg
Spezifische Enthalpie: 3248.23 kJ/kg
Spezifische Entropie: 7.1290 kJ/(kgK)
Phase: Gas
== TESPy ==
Ein anderes Modul für einen anderen Aufgabenzweck ist TESPy ('''T'''hermal '''E'''ngineering '''S'''ystems in '''Py'''thon). Dieses Modul ist für die Anlagensimulation zuständig. Für nähere Informationen siehe [https://tespy.readthedocs.io/en/main/getting_started/introduction.html]. Als Beipiel sei hier vorerst Code, der von der Google KI generiert wurde, angeführt. Der Code wurde überarbeitet, damit keine Warnungen auftreten. Bitte aber den Code trotzdem mit Vorsicht genießen, auch KI-generierter Code kann Fehler aufweisen. Eine Pumpe wird berechnet:
from tespy.components import Sink, Source, Pump
from tespy.connections import Connection
from tespy.networks import Network
# 1. Netzwerk definieren (Zentrales Steuerungselement)
# Wir wählen Wasser als Fluid und bar/Celsius als Einheiten
nw = Network(fluids=["water"])
nw.units.set_defaults(pressure="bar", pressure_difference="bar",
temperature="°C", enthalpy="kJ / kg")
# 2. Komponenten erstellen
eingang = Source("Wasserquelle")
ausgang = Sink("Wasserspeicher")
pumpe = Pump("Speisewasserpumpe")
# 3. Verbindungen definieren (Komponenten miteinander verknüpfen)
c1 = Connection(eingang, "out1", pumpe, "in1")
c2 = Connection(pumpe, "out1", ausgang, "in1")
# Verbindungen dem Netzwerk hinzufügen
nw.add_conns(c1, c2)
# 4. Randbedingungen und Parameter festlegen
# Zustand am Eingang (Druck, Temperatur, Massenstrom, Fluid-Zusammensetzung)
c1.set_attr(
v=1, # Massenstrom: 1 kg/s
T=20, # Temperatur: 20 °C
p=1, # Druck: 1 bar
fluid={"water": 1}, # 100% Wasser
)
# Zustand am Ausgang / Zielwerte der Pumpe
c2.set_attr(p=10) # Ziel-Druck nach der Pumpe: 10 bar
# Pumpeneigenschaften festlegen
pumpe.set_attr(eta_s=0.8) # Isentroper Wirkungsgrad von 80%
# 5. Simulation ausführen
nw.solve(mode="design")
# 6. Ergebnisse ausgeben
nw.print_results()
# Spezifische Werte direkt auslesen
print("\n--- Auswertung ---")
print(f"Erforderliche Pumpenleistung: {pumpe.P.val / 1000:.2f} kW")
print(f"Temperatur nach der Pumpe: {c2.T.val:.2f} °C")
Ausgabe (gekürzt):
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 7.04e+04 | 12 % | 9.96e+02 | 0.00e+00 | 8.81e+04 | 0.00e+00 | 0.00e+00
2 | 5.91e-12 | 100 % | 1.11e-13 | 0.00e+00 | 7.39e-12 | 0.00e+00 | 0.00e+00
3 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
4 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.01 s, Iterations per second: 480.85
##### RESULTS (Pump) #####
+-------------------+----------+----------+-----------+----------+----------+----------+
| | P | pr | dp | eta | eta_s | head |
|-------------------+----------+----------+-----------+----------+----------+----------|
| Speisewasserpumpe | 1.12e+06 | 1.00e+01 | -9.00e+00 | 8.00e-01 | 8.00e-01 | 9.19e+01 |
+-------------------+----------+----------+-----------+----------+----------+----------+
...
...
--- Auswertung ---
Erforderliche Pumpenleistung: 1124.77 kW
Temperatur nach der Pumpe: 20.07 °C
= Stochastik =
Die {{W|Stochastik}} ist ein sehr weites Feld. Hier werden etliche wichtige Themen kurz angerissen. Python stellt mit den Moduln math und statistics Software zu diesem Zwecke bereit. math und statistics sind bereits im Lieferumfang von Python enthalten. Aber auch mit den externen Modulen NumPy, SciPy, stochastic und pandas kann man Stochastik in Python betreiben. Die Theorie der Wahrscheinlichkeitsrechnung und Statistik soll etwas später in Band 5 dieser Buchreihe behandelt werden.
== Lageparameter ==
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
m1 = statistics.mean(werte)
m2 = statistics.mode(werte)
m3 = statistics.median(werte)
print("Arithmetischer Mittelwert = ", m1)
print("Modalwert = ", m2)
print("Median = ", m3)
Ausgabe:
Arithmetischer Mittelwert = 3.5
Modalwert = 1
Median = 3.0
== Streuungsparameter ==
Beispiel (Berechnung der Standardabweichung):
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
s = statistics.stdev(werte)
print("Standardabweichung = ", s)
Ausgabe:
Standardabweichung = 2.6770630673681683
Beispiel (Berechnung des Variationskoeffizienten V = Standardabweichung/Mittelwert)
import numpy as np
from scipy import stats
import statistics
k = 50
dat1 = [14, 21, 18, 25, 30, 17, 20]
dat = np.array(dat1)
# Mit SciPy
v = stats.variation(dat)
vddof = stats.variation(dat, ddof=1)
print("V SciPy: ", v)
print("V DDOF SciPy: ", vddof)
print(k*"-")
# mit NumPy
mittelwert1 = np.mean(dat)
std_abw1 = np.std(dat)
std_abw1ddof = np.std(dat, ddof=1)
v1= std_abw1 / mittelwert1
v1ddof = std_abw1ddof / mittelwert1
print("Mittelwert NumPy: ", mittelwert1)
print("Std.abw. NumPy: ", std_abw1)
print("Std.abw. DDOF NumPy: ", std_abw1ddof)
print("V NumPy: ", v1)
print("V DDOF NumPy: ", v1ddof)
print(k*"-")
# nur mit reinem Python
mittelwert2 = statistics.mean(dat1)
std_abw2 = statistics.stdev(dat1)
v2 = std_abw2 / mittelwert2
print("Mittelwert Python: ", mittelwert2)
print("Std.abw. Python: ", std_abw2)
print("V Python:", v2)
print(k*"-")
Ausgabe:
V SciPy: 0.23890355966467272
V DDOF SciPy: 0.25804533701889254
--------------------------------------------------
Mittelwert NumPy: 20.714285714285715
Std.abw. NumPy: 4.948716593053935
Std.abw. DDOF NumPy: 5.3452248382484875
V NumPy: 0.23890355966467272
V DDOF NumPy: 0.2580453370188925
--------------------------------------------------
Mittelwert Python: 20.714285714285715
Std.abw. Python: 5.3452248382484875
V Python: 0.2580453370188925
--------------------------------------------------
Der Unterschied bei der Standardabweichung zwischen reinem Python und den externen Bibliotheken SciPy und NumPy entsteht dadurch, dass einmal durch (n-1) und das andere Mal nur durch n dividiert wird. Dies kann bei NumPy und SciPy dadurch entschärft werden, indem <code>ddof=1</code> gesetzt wird. ddof steht für '''D'''elta '''D'''egrees '''o'''f '''F'''reedom. <small>Je größer die Anzahl der Datensätze n wird, umso weniger spielt das eine Rolle.</small>
== Kombinatorik ==
Beispiel:
import math
n = 7
k = 5
print("n! = ", math.factorial(n))
print("Kombinationen (n über k) = ", math.comb(n, k))
Ausgabe:
n! = 5040
Kombinationen (n über k) = 21
Siehe zu diesem Thema auch [[Ing Mathematik: Permutationen, Kombinationen, binomischer Lehrsatz]]. Die Anzahlen lassen sich einfach aus den dortigen Formeln ermitteln, z.B. bei Permutationen mit <math>n!</math> oder Variationen mit Wiederholungen als <math>n^k</math>. Will man die Kombinationen oder Variationen aber auch als Liste ausgeben, so kann das Modul <code>itertools</code> nützlich sein.
Beispiel (Variationen ohne Wiederholung):
from itertools import permutations
menge = ["A", "B", "C", "D"] # n = 4
k = 3
variationen = list(permutations(menge, k))
for v in variationen:
print("".join(v))
print(50*"-")
print(len(variationen))
Ausgabe (gekürzt):
ABC
ABD
ACB
...
DCA
DCB
--------------------------------------------------
24
Siehe zum Modul <code>itertools</code> auch die Website [https://docs.python.org/3/library/itertools.html].
* Variationen mit Wiederholung: <code>itertools.product()</code>
* Kombinationen ohne Wiederholung: <code>itertools.combinations()</code>
* Kombinationen mit Wiederholung: <code>itertools.combinations_with_replacement()</code>
== Zufallszahlen ==
Beispiel:
import random
# Ganzzahlige Zufallszahl von 1 bis 10
zufallszahl1 = random.randint(1, 10)
# Gleitpunktzahlen
# zwischen 0.0 und 1.0
zufallszahl2 = random.random()
# Zahl zwischen 1.5 und 9.5
zufallszahl3 = random.uniform(1.5, 9.5)
# aus Liste auswählen
farbe = ["Rot", "Grün", "Blau"]
zufallswert = random.choice(farbe)
print(zufallszahl1)
print(zufallszahl2)
print(zufallszahl3)
print(zufallswert)
Ausgabe, z.B.:
5
0.14147945849015753
6.894003397570905
Rot
Benötigt man mehrere Zufallszahlen, so ist das Modul <code>numpy</code> zu bevorzugen, z.B.:
* Normalverteilung: <code>np.random.normal(...)</code>
* Gleichverteilung: <code>np.random.uniform(...)</code>
== Histogramm ==
Zum Thema Histogramm siehe {{W|Histogramm}}.
Beispiel (mit Matplotlib):
import matplotlib.pyplot as plt
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
plt.hist(daten, bins=25, edgecolor='darkgray')
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm.svg|300px]]
Beispiel (mit Seaborn):
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
sns.set_theme(style="darkgrid")
sns.histplot(data=daten)
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm2.svg|300px]]
Das Kürzel <code>sns</code> ist Konvention und steht für die fiktive Figur '''S'''amuel '''N'''orman '''S'''eaborn aus der US-Fernsehserie {{W|The West Wing – Im Zentrum der Macht | The West Wing}}.
== Box-Plot ==
[[File:Elements of a boxplot.svg|400px]]
Siehe auch {{W|Box-Plot}}.
Beispiel (mit Seaborn erstellt):
import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("tips")
sns.boxplot(data=df, x="day", y="tip", hue="day", legend=False)
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot.svg|400px]]
Beispiel (mit Matplotlib erstellt):
import matplotlib.pyplot as plt
daten = [12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25]
plt.boxplot(daten, patch_artist=True)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot2.svg|300px]]
Um mehrere Box-Plots unterschiedlicher Farbe mit Matplotlib in einem Diagramm zu zeichnen, können Sie folgendermaßen vorgehen:
import matplotlib.pyplot as plt
daten = [[12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25],
[10, 19, 20, 21, 20, 30, 19, 40, 11, 17, 19, 21]]
farben = ["green", "blue"]
boxplot = plt.boxplot(daten, patch_artist=True)
for patch, farbe in zip(boxplot['boxes'], farben):
patch.set_facecolor(farbe)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
== Regressionsrechnung ==
Beispiel:
import numpy as np
import matplotlib.pyplot as plt
# Messpunkte
x = np.array([1, 3, 5, 6, 8, 10, 20])
y = np.array([3, 4, 5, 5, 7, 9, 11])
# Regressionskurve (Grad 1 = lineare Regression, 2 = Polynom-Regression 2. Gr.)
# y = kx + d
k, d = np.polyfit(x, y, deg=1)
# y = ax**2 + bx + c
a, b, c = np.polyfit(x, y, deg=2)
x_l = np.linspace(1, 20, 100)
y_p = a * x_l**2 + b * x_l + c
# Zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.plot(x, k*x + d, color='blue', label='Regressionsgerade')
plt.plot(x_l, y_p, color='red', label='Regressionspolynom 2. Gr.')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:IngMath_regression.svg|400px]]
== Korrelationsrechnung ==
Beispiel:
import pandas as pd
import matplotlib.pyplot as plt
# Messdaten
x = [1, 3, 4, 5, 6]
y = [2, 4, 6, 8, 5]
daten = {'X': x, 'Y': y}
df = pd.DataFrame(daten)
# Korrelation
korr = df['X'].corr(df['Y'])
print(f"Korrelationskoeff.: {korr}")
# Messpunkte zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
Korrelationskoeff.: 0.7556096518348252
[[Datei:IngMath_korrelation.svg|300px]]
== Mengen und Venn-Diagramme ==
Beispiel:
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
menge_a = {1, 2, 3, 4, 5, 6}
menge_b = {4, 5, 6, 7, 8}
vereinigung = menge_a | menge_b
schnitt = menge_a & menge_b
print("Vereinigungsmenge = ", vereinigung)
print("Schnittmenge = ", schnitt)
venn2([menge_a, menge_b], set_labels=('Menge A', 'Menge B'))
plt.show()
Ausgabe:
Vereinigungsmenge = {1, 2, 3, 4, 5, 6, 7, 8}
Schnittmenge = {4, 5, 6}
[[Datei:IngMath_venn.svg|300px]]
Siehe auch {{W|Mengendiagramm#Venn-Diagramme}}.
== Verteilungs- und Dichtefunktion ==
* CDF ... '''C'''umulative '''D'''istribution '''F'''unction, Verteilungsfunktion
* PDF ... '''P'''robability '''D'''ensity '''F'''unction, Dichtefunktion
Beispiel (Normalverteilung):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
my, sigma = 0, 1
x = np.linspace(-4, 4, 50)
pdf = norm.pdf(x, my, sigma)
cdf = norm.cdf(x, my, sigma)
plt.plot(x, pdf, lw=2, label="Dichtefunktion")
plt.plot(x, cdf, lw=2, label="Verteilungsfunktion")
plt.legend()
plt.grid()
plt.show()
Ausgabe:
[[Datei:IngMath_cdf_pdf.svg|300px]]
Beispiel (<math>\chi^2</math>-Verteilung):
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
x = np.linspace(0, 20, 500)
# df ... degree of freedom, Freiheitsgrad
pdf = (stats.chi2.pdf(x, df=2), stats.chi2.pdf(x, df=5), stats.chi2.pdf(x, df=10))
for i in range(0,3):
if(i==0):
lab = "Freiheitsgrad 2"
elif(i==1):
lab = "Freiheitsgrad 5"
else:
lab = "Freiheitsgrad 10"
plt.plot(x, pdf[i], label=lab, lw=2)
plt.grid()
plt.legend()
plt.show()
Ausgabe:
[[Datei:IngMath_chi2.svg | 300px]]
== Schätzen und Testen ==
=== Intervallschätzung ===
Als Beispiel seien Daten gegeben, die von ''Dürr, Mayer: Wahrscheinlichkeitsrechnung und Schließende Statistik; 7. Aufl., Hanser, 2014, Seite 137'' stammen. Und zwar soll das 95%-Vertrauensintervall für den Mittelwert des Kaloriengehalts (kcal/100g) von Hähnchen ermittelt werden. Wir wollen das mit Python inkl. NumPy und SciPy durchführen. Die Stichprobe ist groß (50 Hähnchen):
Python-Code:
import numpy as np
import scipy.stats as stats
# Stichprobe
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203]
# Parameter definieren
konfidenzniveau = 0.95
mean = np.mean(daten)
std = np.std(daten, ddof=1)
stdfehler = stats.sem(daten)
intervall = stats.norm.interval(confidence=konfidenzniveau, loc=mean, scale=stdfehler)
print(f"Mittelwert: {mean}")
print(f"Standardabweichung: {std}")
print(f"Konfidenzintervall: {intervall}")
Ausgabe:
Mittelwert: 215.48
Standardabweichung: 33.14238915925757
Konfidenzintervall: (np.float64(206.29356722321992), np.float64(224.66643277678006))
Diese Werte stimmen gerundet mit denen im genannten Buch überein. Zum Code selbst:
* sem steht für '''s'''tandard '''e'''rror of the '''m'''ean.
* <code>scipy.stats.norm</code> ... Modul für die Normalverteilung.
=== Punktschätzung ===
Gleiche Daten wie oben bei der Intervallschätzung.
Python-Code:
import numpy as np
from scipy import stats
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203
]
mu_hat, sigma_hat = stats.norm.fit(daten)
print(f"Schätzer für den Erwartungswert (μ): {mu_hat:.4f}")
print(f"Schätzer für die Standardabweichung (σ): {sigma_hat:.4f}")
Ausgabe:
Schätzer für den Erwartungswert (μ): 215.4800
Schätzer für die Standardabweichung (σ): 32.8093
=== Hypothesentests ===
Beispiel:
import numpy as np
import scipy.stats as stats
x_quer = 12.075 # Stichproben-Mittelwert
var = 0.069 # Stichproben-Varianz
n = 90 # Stichprobengröße
my_0 = 12.0 # Nullhypothese
alpha = 0.05 # Signifikanzniveau
z_stat = (x_quer - my_0) / np.sqrt(var / n)
p_val = 2 * (1 - stats.norm.cdf(np.abs(z_stat)))
print(f"Z-Statistik: {z_stat:.4f}")
if p_val < alpha:
print(f"p-Wert: {p_val:.6f} < alpha:", alpha)
print("Die Nullhypothese wird verworfen.")
else:
print(f"p-Wert: {p_val:.6f} > alpha:", alpha)
print("Die Nullhypothese wird nicht verworfen.")
Ausgabe:
Z-Statistik: 2.7087
p-Wert: 0.006755 < alpha: 0.05
Die Nullhypothese wird verworfen.
== Statistische Qualitätskontrolle ==
Beispiel (Mittelwertkarte):
import numpy as np
import matplotlib.pyplot as plt
# Gegeben
sollwert = 50.0
varianz = 4.0
stichproben_umfang = 1
daten = [49.5, 50.2, 53.0, 48.1, 52.6, 53.4, 49.8]
# Berechnung
standardabweichung = np.sqrt(varianz)
streuung = standardabweichung / np.sqrt(stichproben_umfang)
cl = sollwert
ucl = cl + 3 * streuung
lcl = cl - 3 * streuung
# Darstellung
plt.plot(daten, marker='o', linestyle='-', color='b', label='Messdaten')
plt.axhline(cl, color='green', linestyle='-', label=f'CL: {cl}')
plt.axhline(ucl, color='red', linestyle='--', label=f'UCL: {ucl:.2f}')
plt.axhline(lcl, color='red', linestyle='--', label=f'LCL: {lcl:.2f}')
plt.title('Mittelwertkarte')
plt.xlabel('Stichprobe')
plt.ylabel('Wert')
plt.legend(loc='lower left')
plt.grid(True)
plt.show()
Ausgabe:
[[Datei:IngMath_mittelwertkarte.svg|300px]]
Siehe auch {{W|Shewhart-Regelkarte}} und {{W|Qualitätsregelkarte}}.
* UCL ... '''U'''pper '''C'''ontrol '''Limit''', Obere Eingriffsgrenze
* LCL ... '''L'''ower '''C'''ontrol '''Limit''', Untere Eingriffsgrenze
* CL ... '''C'''enter '''L'''ine, Mittellinie
= Ein- und Ausgabe =
== print ==
Die Anweisung print haben wir schon oft verwendet. Hier soll anhand von Beispielen kurz beschrieben werden, was der Befehl print leisten kann.
print("Hallo", "Welt", 1, sep="-")
print("Hallo", end=" ")
print("Welt")
Ausgabe:
Hallo-Welt-1
Hallo Welt
== input ==
a = int(input("Zahl 1: "))
b = int(input("Zahl 2: "))
print("a + b = ", a+b)
Ausgabe (nach Eingabe der beiden Ganzzahlen):
Zahl 1: 4
Zahl 2: 5
a + b = 9
== Aus Dateien lesen ==
Es seinen die datei.txt
Hallo Welt.
Wie geht es dir?
...
und test1.py
dat = open("datei.txt", mode = "r")
print(dat.read())
dat.close()
Ausgabe
Hallo Welt.
Wie geht es dir?
...
Mit dem open()-Befehl wird die Datei datei.txt im Lesemodus geöffnet (r ... read). Mit dem read()-Befehl wird die Datei eingelesen und mittels print ausgegeben.
== In Dateien schreiben ==
dat = open("datei.txt", mode = "a", encoding = "utf-8")
dat.write("Hänge Zeile an\n")
dat.close()
Die Datei datei.txt sieht nach Abarbeitung des obigen Skripts nun so aus
Hallo Welt.
Wie geht es dir?
...
Hänge Zeile an
Es wird die Datei im Schreibmodus geöffnet (a ... append (anhängend), w ... write (überschreibend)).
write() fügt hier also eine Zeile Text am Dateiende ein. close() schließt die Datei wieder.
Das close() kann man sich mit der with-Anweisung auch sparen.
with open("datei.txt", mode="a", encoding="utf-8") as dat:
dat.write("Hänge Zeile an\n")
= Benutzeroberflächen erstellen =
== tkinter ==
{{Wikipedia | Tkinter}}
Python bietet standardmäßig das Modul tkinter zur Programmierung von Benutzeroberflächen. Es müssen also bei der Verwendung von tkinter keine externen Module installiert werden. Hier wird eine (sehr) kurze Einführung in das Erstellen von grafischen Oberflächen mittels tkinter gegeben.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
win.minsize(300, 50)
but = tk.Button(win, text = "Push the button")
but.pack()
win.mainloop()
Ausgabe:
[[Datei:PythonIng_gui1.jpg]]
Ein etwas komplizierteres Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
def on_button_clicked():
str = ent1.get() + ent2.get()
lab2["text"] = str
ent1 = tk.Entry(win)
ent2 = tk.Entry(win)
lab1 = tk.Label(win, text="verknuepfen mit")
lab2 = tk.Label(win, text="")
but = tk.Button(win, text = "=", command=on_button_clicked)
ent1.pack(side="left")
lab1.pack(side="left")
ent2.pack(side="left")
but.pack(side="left")
ent2.pack(side="left")
lab2.pack(side="left")
win.mainloop()
Ausgabe (vor der Eingabe der Teilstrings):
[[Datei:PythonIng_gui2.jpg]]
Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):
[[Datei:PythonIng_gui3.jpg]]
== curses ==
{{Wikipedia | curses}}
Mit dem curses-Modul lassen sich u.a. TUIs ('''T'''ext '''U'''ser '''I'''nterfaces) erstellen. Ein sehr einfaches Beispiel zur allgemeinen Funktionsweise wird nachstehend geliefert.
import curses
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
stdscr.clear()
stdscr.addstr("Hallo Welt", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.endwin()
Als Ausgabe sollte <span style="color:#FF0000;">Hallo Welt</span> (rote Schrift auf weißem Hintergrund) auf dem Terminal/der Konsole erscheinen. Getestet wurde dies mit openSUSE Tumbleweed, Python-Version 3.13.12. Das entsprechende Python-curses-Package muss installiert sein.
Allgemeine Informationen zur Terminal-/Konsolengröße und Cursorposition liefert folgendes Programm:
import curses
stdscr = curses.initscr()
stdscr.addstr(3, 5, "LINES: %d" % curses.LINES)
stdscr.addstr(4, 5, "COLS: %d" % curses.COLS)
(y,x) = stdscr.getyx()
stdscr.addstr(5, 5, "Momentane Cursorposition: [%d, %d]" % (y, x))
(y,x) = stdscr.getbegyx()
stdscr.addstr(6, 5, "Koordinatenursprung: [%d, %d]" % (y, x))
(y,x) = stdscr.getmaxyx()
stdscr.addstr(7, 5, "Fenstergröße: [%d, %d]" % (y, x))
stdscr.addstr(11, 2, "Taste drücken -> Ende")
stdscr.refresh()
stdscr.getch()
curses.endwin()
Es sollte sich in etwa folgende Ausgabe ergeben:
LINES: 44
COLS: 110
Momentane Cursorposition: [4, 15]
Koordinatenursprung: [0, 0]
Fenstergröße: [44, 110]
Taste drücken -> Ende
Zur Funktionsweise von curses siehe auch das Wikibook [[ncurses]]. Zum Verständnis sind dort allerdings elementare Kenntnisse in der Programmiersprache C erforderlich.
== Qt ==
{{Wikipedia | Qt (Bibliothek)}}
Auch für das Qt-Framework gibt es eine Anbindung an Python. Nachfolgend ein einfaches Beispiel.
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hallo Welt!")
label.show()
sys.exit(app.exec())
Ausgabe:
[[Datei:PythonIng_gui10.png]]
== Gtk ==
{{Wikipedia | GTK (Programmbibliothek)}}
Eine idente Ausgabe, wie oben für Qt gezeigt, erzeugt z.B. folgendes Gtk-Programm:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
lab = Gtk.Label(label="Hallo Welt!")
win.set_child(lab)
win.present()
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
Auch für die Benutzung von Qt und Gtk müssen die jeweiligen Packages installiert sein. Getestet wurden die entsprechenden Python-Programme nur unter openSUSE Tumbleweed. Wie das GTK-Paket unter MS Windows 11 installiert wird, siehe z.B. [https://www.gtk.org/docs/installations/windows Setting up GTK for Windows].
Damit sei aber das Thema "Benutzeroberflächen erstellen" hier abgeschlossen, da dies schon ein sehr spezielles Aufgabengebiet ist, das eher Informatiker und nicht so sehr Ingenieure anspricht. Bei Bedarf siehe aber ggf. die entsprechenden Links unten in diesem Tutorial. Dort sind weiterführende Informationen zu finden.
= Pandas kurz erklärt =
Hier wird kurz auf das externe Modul Pandas eingegangen. Pandas steht für '''Pan'''el '''Da'''ta und ist ein Modul für die Datenanalyse und -manipulation.
== Series ==
Vorstellbar ist eine "Series" wie eine einzelne Spalte in einem Tabellenkalkulationsprogramm.
Beispiel (Index implizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5]) # Temperaturwerte
print(temp)
Ausgabe:
0 8.5
1 11.0
2 12.5
3 10.0
4 13.0
5 11.0
6 14.5
dtype: float64
Das Kürzel <code>pd</code> ist Konvention. Es seien Temperaturwerte gegeben. Die erste Spalte bei der Ausgabe ist der Index. Die zweite Spalte enthält die Werte.
Beispiel (separater Zugriff auf den Index und auf die Werte):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5])
print(temp.index)
print(temp.values)
Ausgabe:
RangeIndex(start=0, stop=7, step=1)
[ 8.5 11. 12.5 10. 13. 11. 14.5]
Beispiel (Index explizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
print("*** Die gesamte Series ***")
print(temp)
print("*** Temperatur am Donnerstag ***")
print(temp["Do"])
print("*** Tage wärmer als 12 Grad ***")
temp_gr_12 = temp[temp > 12]
print(temp_gr_12)
Ausgabe:
*** Die gesamte Series ***
Mo 8.5
Di 11.0
Mi 12.5
Do 10.0
Fr 13.0
Sa 11.0
So 14.5
dtype: float64
*** Temperatur am Donnerstag ***
10.0
*** Tage wärmer als 12 Grad ***
Mi 12.5
Fr 13.0
So 14.5
dtype: float64
== DataFrame ==
Ein DataFrame entspricht einer Tabelle.
Beispiel (Erzeugen eines DataFrames):
import pandas as pd
tag = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
v1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=tag)
v2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=tag)
v3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=tag)
tab = pd.concat([v1, v2, v3], axis=1)
tab.columns = stadt
print(tab)
print(type(tab))
Ausgabe:
Linz Salzburg Innsbruck
Mo 1 8 Hallo
Di 2 9 16
Mi 3 10 17
Do 4 11 18
Fr 5 12 19
Sa 6 13 20
So 7 14 21
<class 'pandas.core.frame.DataFrame'>
Wir haben hier drei Datenspalten (v1, v2, v3) mit den Spaltennamen "Linz", "Salzburg" und "Innsbruck", sowie sieben Zeilen "Mo" bis "So".
Beispiel (Zugriff auf eine Spalte):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab["Salzburg"])
Ausgabe:
Mo 8
Di 9
Mi 10
Do 11
Fr 12
Sa 13
So 14
Name: Salzburg, dtype: int64
Beispiel (Zugriff auf eine Zeile):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab.loc["Di"])
Ausgabe:
Linz 2
Salzburg 9
Innsbruck 16
Name: Di, dtype: object
== Grafiken erstellen ==
Hier sei nur ein Torten- oder Kreisdiagramm gezeichnet:
import pandas as pd
import matplotlib.pyplot as plt
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
expl = [0, 0.2, 0, 0, 0, 0, 0]
temp.plot.pie(figsize=(5,5), explode=expl)
plt.show()
Ausgabe:
[[Datei:IngPython_pandas1.svg|350px]]
Die <code>figsize</code> hat nichts mit der Spaltenanzahl zu tun, sondern setzt die Fenster- oder Diagrammgröße in Inches (Breite * Höhe).
Mit Pandas kann man auch noch andere Diagrammarten erstellen, z.B. Linien- oder Balkendiagramme. Dies wird hier aber nicht vorgeführt.
== Arbeiten mit CSV- und LibreOffice-Dateien ==
Gegeben sei eine CSV-Datei test1.csv:
Mai;Juni;Juli
12;17;45
15;65;65
16;32;23
4;14;7
23;17;Keine Daten verfügbar
67;Keine Daten verfügbar;45
15;24;12
Lesen von dieser CSV-Datei:
import pandas as pd
tab = pd.read_csv("test1.csv", sep=";")
print(tab)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Schreiben in eine CSV-Datei test2.csv:
import pandas as pd
val = pd.read_csv("test1.csv", sep=";")
val.to_csv("test2.csv", index=False)
Ausgabedatei:
Mai,Juni,Juli
12,17,45
15,65,65
16,32,23
4,14,7
23,17,Keine Daten verfügbar
67,Keine Daten verfügbar,45
15,24,12
Die Ausgabedatei ist beinahe gleich wie die Eingabedatei. Es werden aber Kommas statt Strichpunkten verwendet. Daher kommt auch der Name CSV ('''C'''omma '''S'''eparated '''V'''alue). Will man wieder Strichpunkte, so kann man dies über den Parameter <code>sep=";"</code> in der <code>to_csv</code>-Funktion machen.
Um direkt von einer ODS-Datei (LibreOffice Calc, '''O'''pen '''D'''ocument '''S'''preadsheet) zu lesen muss das Modul odfpy extra installiert sein (per YaST, pip etc.). Gelesen wird dann folgendermaßen:
import pandas as pd
df = pd.read_excel('test1.ods', engine='odf')
print(df)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Die Datei "test1.ods" sei die Datei, aus der das obige "test1.csv" generiert wurde. Schreiben kann man ebenfalls in eine ODS-Datei:
import pandas as pd
daten = {
"Name": ["Hugo", "Richie", "Wilhelmine"],
"Alter": [38, 30, 29],
"Ort": ["Linz", "Innsbruck", "Salzburg"]
}
tab = pd.DataFrame(daten)
with pd.ExcelWriter("test2.ods", engine="odf") as writer:
tab.to_excel(writer, sheet_name="Daten", index=False)
Es ergibt sich eine "test2.ods"-Datei (Screenshot):
[[Datei:IngPython_pandas2.png|250px]]
== Sonstiges ==
Hier seien stichpunktartig einige weitere Features von Pandas angeführt:
* {{W|Pivot-Tabelle|Pivot-Tabellen}} (pivot ... Dreh-, Angelpunkt): Zweck - große Datenmengen schnell zusammenfassen, filtern und analysieren.
* NaN ('''n'''ot '''a''' '''n'''umber): In einem Datensatz fehlt ein Wert oder ist nicht definiert.
* groupby-Funktion: Daten strukturieren, aggregieren oder Zwischensummen bilden.
* {{W|Binning#Datenverarbeitung_und_-analyse|Binning}}: Klassenbildung.
* Mehrstufige Indizierung (Hierarchical Indexing oder MultiIndex)
* Zeitreihen (Time Series)
Für tiefergehende und weiterführende Informationen wird auf das Buch von ''Klein: Numerisches Python; Hanser, 2023'' und [https://pandas.pydata.org/ pandas] verwiesen.
= Style Guide, flake8, pylint, Black etc. =
== Style Guide ==
Wie man schönen und richtigen Python-Code schreibt, erfahren Sie in
* [https://peps.python.org/pep-0008/ PEP 8 – Style Guide for Python Code]
== Formatter und Linter ==
Ein Modul, das prüft, ob die Richtlinien im Style Guide eingehalten wurden, ist ''flake8'':
* [https://flake8.pycqa.org/en/latest/ Flake8: Your Tool For Style Guide Enforcement]
Code formatieren kann man auch mit [https://pypi.org/project/black/ Black]. Z.B. übersetzt <code>black test1.py</code> die Datei <code>test1.py</code>
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)),
(2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
in
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)), (2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Die Programmausgabe ist
reformatted test1.py
All done! ✨ 🍰 ✨
1 file reformatted.
Der Unterschied zwischen Black und Flake8:
* Black ist ein Code-Formatter. Er formatiert Ihren Code um, sodass er im Einklang mit PEP 8 steht.
* Flake8 ist ein {{W|Lint (Programmierwerkzeug) | Code-Linter}}. Flake8 verändert Ihren Code nicht, sondern durchsucht ihn nach potenziellen Fehlern etc.
Am obigen Beispiel sieht man auch, dass flake8 und Black nicht immer einer Meinung sind. Flake8 (<code>flake8 test1.py</code>) würde standardmäßig den mit Black formatierten Code bemängeln:
test1.py:8:80: E501 line too long (80 > 79 characters)
Diese Diskrepanz kann beseitigt werden. Da 79 Zeichen auf modernen Bildschirmen meist als zu kurz empfunden werden, ist ein Limit von 88 Zeichen (Black-Standard) oder mehr empfehlenswert. Um dies zu implementieren, erstellen Sie in Ihrem Projektverzeichnis eine <code>.flake8</code>-Datei mit dem Inhalt
[flake8]
max-line-length = 88
Und schon ignoriert Flake8 dieses Problem.
Ein anderer Linter ist pylint. Der würde beim Abarbeiten des obigen Beispiels, z.B. mit <code>pylint test1.py</code> noch eine Kleinigkeit bemängeln:
************* Module test1
/home/hr/tmp/test1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)
Auch pylint muss vor der ersten Verwendung installiert werden (z.B. mittels pip, virtuelle Umgebung, YaST). Die Dokumentation zu pylint findet sich auf [https://pylint.readthedocs.io/en/latest/].
<u>Aufgabe:</u> Fügen Sie einen "module docstring" in die <code>test1.py</code>-Datei ein und testen Sie erneut mit flake8, Black und pylint. <small>Sehen Sie zum Thema docstrings auch [https://peps.python.org/pep-0257/#what-is-a-docstring PEP 257 – Docstring Conventions].</small>
Es gibt noch weitere Formatierungswerkzeuge für Python-Code. Z.B. [https://docs.astral.sh/ruff/ Ruff], ein moderner Code-Formatter und -Linter. Mittels <code>ruff check test1.py</code> würde obiger Code geprüft (Linter). <code>ruff format test1.py</code> formatiert den Code (Formatter).
== Type Checker ==
"Type Checker" sind z.B.
* mypy
* pyright
* ty
Diese prüfen die Datentypen, z.B. in folgendem Code
def greetings(name: str) -> str:
return "Hello, %s" % name
print(greetings(42))
Python selbst, flake8, ruff oder black würden diesen Code ohne zu murren akzeptieren. "Type Checker" würden aber sehr wohl Alarm schlagen, z.B. liefert <code>mypy</code> folgende Ausgabe
test1.py:5: error: Argument 1 to "greetings" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Das funktioniert übrigens nicht nur bei Funktionsannotationen, sondern auch mit Variablen etc.
from typing import Final
# "Konstante", ab Python 3.8
NUMBER: Final = 123
print(NUMBER)
NUMBER = 125
print(NUMBER)
# Variable
a: int = 345
print(a)
a = "Irgendwas"
print(a)
# Variable (Pipe-Symbol), ab Python 3.10
b : int|str = 567
print(b)
b = "sonstiges"
print(b)
Ausgabe mit python:
123
125
345
Irgendwas
567
sonstiges
Ausgabe mit mypy:
test3.py:6: error: Cannot assign to final name "NUMBER" [misc]
test3.py:12: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
Found 2 errors in 1 file (checked 1 source file)
Python kennt übrigens keine Konstanten. Man kann diese mittels Großbuchstaben andeuten. Das ist aber nur Konvention, hat aber keine sonstigen Auswirkungen. Oder man verwendet wie oben gezeigt <code>Final</code>. Dann werfen Typchecker Errors aus.
==pydoc==
pydoc ist ein Werkzeug, um Python-Module, -Funktionen und -Klassen zu dokumentieren.
Beispiel <code>test1.py</code>:
"""Rechen-Modul.
Funktionen die von pydoc gelesen werden.
"""
def multiply(a, b):
"""Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a * b
def add(a, b):
"""Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a + b
if __name__ == '__main__':
print(multiply(3, 5))
print(add(4, 6))
Ausgabe mit <code>python3.13 -m pydoc test1</code> auf der Konsole:
Help on module test1:
NAME
test1 - Rechen-Modul.
DESCRIPTION
Funktionen die von pydoc gelesen werden.
FUNCTIONS
add(a, b)
Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
multiply(a, b)
Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
FILE
/home/xyz/tmp/test1.py
Siehe zu diesem Thema z.B. auch [https://docs.python.org/3/library/pydoc.html]. Mittels <code>python3.13 -m pydoc -w test1</code> kann man auch eine HTML-Dokumentation erstellen.
Wofür <code>if __name__ == '__main__':</code> steht, siehe z.B. etwas später im Abschnitt [[Ing_Mathematik:_Python#Doctests]].
== Sonstige Tools ==
Andere Tools für die {{W|Statische Code-Analyse|statische Codeanalyse}}, die aber für Ingenieure weniger interessant sein dürften, sind z.B.
* Radon: Liefert verschiedene {{W|Softwaremetrik|Codemetriken}} (Komplexität, Wartbarkeitsindex ...)
* Bandit: Findet Sicherheitslücken
Tools für die {{W|Dynamisches Software-Testverfahren|dynamische Codeanalyse}}, z.B.:
* DynaPyt (Framework zur dynamischen Programmanalyse)
* cProfile (Profiler)
* Memory Profiler (Speicheranalyse)
* Memray (Speicheranalyse)
* tracemalloc (Speicheranalyse)
Paket- und Projektmanagement (pip-Ersatz etc.):
* uv
* Poetry
* Conda
* pipx
Packaging-Tools (Freezer) und {{W|Compiler#Sonderformen|Transpiler}} :
* pyinstaller
** erstellt eigenständige, ausführbare Binärdatei
** kein Cross-Compiler
** kein Schutz vor Reverse-Engineering
** langsam
** packt alles in eine Datei
** sehr große Datei
** Befehl, z.B.: <code>pyinstaller --onefile test1.py</code>
** GUI: <code>auto-py-to-exe</code>
* cx_Freeze
* nuitka
** Übersetzt Python-Code in C/C++-Code und weiter in eine ausführbare Datei
** kein Cross-Compiler
** Schutz vor Reverse-Engineering
** Befehl, z.B.: <code>nuitka --standalone --onefile test1.py</code>
* cython
= Einige Integrierte Entwicklungsumgebungen (IDEs)=
Werden Programmtexte größer und umfangreicher, so ist das Arbeiten mit der interaktiven Programmierumgebung bzw. das direkte Ausführen von Python-Skripten mühsam. Man wünscht sich z.B. Hilfen zum Debuggen oder die automatische Code-Vervollständigung. Zu diesem Zweck wurden IDEs (Integrated Development Environments) geschaffen. Von diesen seinen nachfolgend auszugsweise einige kurz beschrieben. Testen Sie einfach aus, welche davon für Sie bzw. für Ihr Python-Projekt geeignet sind.
== IDLE ==
IDLE ist die mit dem Python-Programmpaket mitgelieferte IDE. Der Name leitet sich einerseits ab vom Monty-Python-Mitglied Eric Idle, andererseits steht es als Abkürzung für "'''I'''ntegrated '''D'''evelopment and '''L'''earning '''E'''nvironment. IDLE ist einfach zu bedienen, bietet aber schon einen beachtlichen Leistungsumfang. Nachfolgend wird ein Screenshot zu IDLE geliefert. Rechts ist das Editor-Fenster zu sehen, links die interaktive Programmierumgebung. Um das Beispiel selbst nachvollziehen zu können, starten Sie IDLE. Das geht ähnlich, wie Sie die interaktive Programmierumgebung von Python starten (nur, dass Sie eben das IDLE-Icon doppelklicken und nicht das Python-Icon. Unter Linux geben Sie einfach in einem Terminal <code>idle3.13</code> o. Ä. ein). Weiter geht es mit "File - Open - ...". Die auszuführende Datei auswählen (im konkreten Fall ein "Hallo-Welt"-Programm). Es erscheint das rechte Fenster. Dort "Run - Run Module" auswählen. Und schon wird im linken Fenster "Hallo Welt!" ausgegeben.
[[Datei:PythonIng_idle1.jpg | 600px]]
Siehe auch {{W|IDLE}}.
== PyCharm ==
PyCharm ist ein kommerzielles Produkt. Es gab aber auch eine kostenlose Community Edition. Seit 2025 sind beide Varianten vereint. Für die ersten 30 Tage sind die Pro-Funktionen frei verfügbar, danach nur noch die Kernfunktionalitäten (oder man bezieht kostenpflichtig die Pro-Version). Zu beziehen ist PyCharm unter dem Weblink [https://www.jetbrains.com/pycharm/]. Nachfolgend ein etwas abgewandeltes "Hallo Welt"-Programm, editiert und ausgeführt mit PyCharm.
[[Datei:PyCharm_IDE_2023_screenshot.png | 600px]]
Siehe auch {{W|PyCharm}}.
== Eric ==
Auch eric ist Open Source und steht unter der GNU General Public License Version 3 oder später. Zu beziehen ist diese Software unter [https://eric-ide.python-projects.org/].
[[Datei:Screenshot_Eric_4.png | 600px]]
Siehe auch {{W|eric (Software)}}.
<small>
Unter openSUSE Tumbleweed sollte sich eric auch mit YaST installieren lassen. Bei mir gibt es aber dann beim Ausführen des eric-Programms eine Fehlermeldung (Stand März 2026):
...
ModuleNotFoundError: No module named 'PyQt6.QtPdfWidgets'
Umgehen kann man dieses Problem aber wieder mit dem Erstellen einer virtuellen Umgebung, in etwa so
python3.13 -m venv ~/tmp/venv1
cd ~/tmp/venv1/bin
./python3.13 -m pip install --upgrade --prefer-binary eric-ide
./eric7_ide
</small>
== PyScripter ==
Vom Funktionsumfang vergleichbar mit den vorherigen IDEs ist PyScripter. Auch PyScripter ist Open Source. Die Projekt-Homepage findet sich auf [https://sourceforge.net/projects/pyscripter/]. PyScripter ist nur für MS Windows verfügbar.
[[Datei:PythonIng_pyscripter1.jpg | 600px]]
== Spyder IDE ==
Spyder enthält bereits eine stabile Python-Version und etliche Module (z.B. matplotlib, numpy, control). Ansonsten kann dieses Softwarepaket vom Funktionsumfang her mit den anderen genannten IDEs locker mithalten. Spyder wurde unter der MIT-Lizenz veröffentlicht. Diese Software findet sich auf [https://www.spyder-ide.org].
[[Datei:Spyder-windows-screenshot.png | 600px]]
Siehe auch {{W|Spyder (Software)}}
== Eclipse IDE==
Die {{W|Eclipse_(IDE)|Eclipse-IDE}} kann für Python aufgerüstet werden. Dazu gibt es das PyDev-Plugin. Installiert wird es über
* Help > Eclipse Marketplace...
* Find - PyDev - Install
Danach muss noch der Pfad zum Python-Interpreter festgelegt werden
* Window > Preferences > PyDev > Interpreters > Python Interpreter > New ...
Das Ergebnis ist ähnlich wie im folgenden Bild, nur dass statt C/C++ Python Verwendung findet.
[[Datei:Setting Up Eclipse CDT helloout.png | 600px]]
== Sonstige ==
Die genannten IDEs sind nicht die Einzigen. Es gibt, um dem Image Pythons als beliebteste Programmiersprache gerecht zu werden, noch einige andere. Sowohl Open Source-Programme als auch kommerzielle Programme sind im Web zu finden, z.B. Thonny oder {{W|Visual Studio Code}}. Unter Linux kann man auch {{W|KDevelop}}, ausgestattet mit dem Python3-Plugin, einsetzen. Braucht man den Umfang von ausgewachsenen IDEs nicht, so kann man auch normale Texteditoren verwenden (z.B. {{W|Geany}} oder {{W|Kate_(Texteditor)|Kate}}).
= Debuggen und Testen =
Das Debuggen und Testen von Programmen sind wichtige Bestandteile der Programmierung. Syntaxfehler lassen sich i.A. leicht beheben. Schwieriger ist das Eingrenzen von logischen Fehlern, die ev. nur in bestimmten Situationen auftreten und keine explizite Fehlermeldung hervorrufen. Das Programm liefert falsche Ergebnisse oder es stürzt aus heiterem Himmel ab. Um das zu verhindern gibt es verschiedene Werkzeuge, die bei der Fehlersuche behilflich sein können. Vorerst siehe aber zwecks Begriffsklärung noch folgende Links:
* {{W|Debuggen}}
* {{W|Debugger}}
* {{W|Softwaretest}}
<gallery>
First Computer Bug, 1947.jpg
Test ganzheitlich.png
V-Modell.svg
</gallery>
== Das Modul pdb ==
Python bringt schon ein Modul zum Debuggen mit. Siehe z.B. [https://docs.python.org/3/library/pdb.html pdb — The Python Debugger].
Komfortabler lässt sich das aber mittels Integrierter Entwicklungsumgebungen (IDEs) angehen.
== Debuggen mit IDEs ==
Für die IDEs IDLE und Spyder sei kurz auf die entsprechenden Webseiten verwiesen:
* [https://www.cs.uky.edu/~keen/help/debug-tutorial/debug.html Debugging under IDLE].
* [https://docs.spyder-ide.org/current/panes/debugging.html Spyder Debugger]
Dort wird die Vorgehensweise auch mittels Screenshots erläutert.
== assert ==
assert ... behaupten, zusichern ({{W|Assertion (Informatik)}})
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10., 0.)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10., 0.)
File "/home/hr/Develop/test1.py", line 4, in print1
assert y != 0.0
^^^^^^^^
AssertionError
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1("10.", "5.")
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Aber auch bei nachfolgendem Code gibt es eine Fehlermeldung:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10, 5)
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Damit letzteres funktioniert, kann man den Programmcode so umschreiben:
def print1(x, y):
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
2.0
Und jetzt fangen wir den <code>AssertionError</code> auf:
def print1(x, y):
try:
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
except(AssertionError):
print("Hallo")
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Hallo
Ich hoffe, es ist wenigstens im Ansatz klar geworden, wofür <code>assert</code> gut sein kann. Ausschalten kann man die <code>assert</code>-Überprüfung übrigens mit dem Python-Schalter <code>-O</code>.
== Doctests ==
Innerhalb eines Docstrings kann die Arbeit im interaktiven Modus simuliert werden. Nach den Promptzeichen (>>>) erfolgen dann bei unserem Beispiel innerhalb des Docstrings simulierte Aufrufe der Funktion <code>print1()</code>. Danach folgen jeweils die Sollresultate. Wird das Modul oder die Datei als Hauptprogramm aufgerufen, so wird die Funktion <code>doctest.testmode()</code> aufgerufen und ein Bericht auf der Konsole ausgegeben. Wird das Modul nicht als Hauptprogramm aufgerufen, sondern importiert, dann wird diese <code>testmod</code>-Funktion nicht aufgerufen. D.h. dieser Code kann sowohl für Testzwecke als auch für den produktiven Einsatz verwendet werden. Das ist auch sinnvoll, weil wenn man Teile der Datei immer löschen bzw. einfügen müsste, so würden sich Fehlerquellen auftun. Das würde den Sinn und Zweck von Doctests konterkarieren.
def print1(x=0., y=1.):
""" Dividiere zwei Zahlen
Autor: Intruder
Datum: 12.08.2025
>>> print1(2., 1.)
2.0
>>> print1(5., 2.)
2.5
>>> print1(5.)
5.0
"""
print(x/y)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Ausgabe:
Trying:
print1(2., 1.)
Expecting:
2.0
ok
Trying:
print1(5., 2)
Expecting:
2.5
ok
Trying:
print1(5.)
Expecting:
5.0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.print1
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Das gezeigte Beispiel ist so ziemlich das einfachste, das es gibt. Für weiterführende Details siehe z.B.:
* [https://peps.python.org/pep-0257/ PEP 257 – Docstring Conventions]
* [https://docs.python.org/3/library/doctest.html doctest — Test interactive Python examples]
''Einschub:'' Ganz ähnlich kann man auch Klassen testen, z.B. in folgendem Code-Fragment
class Fahrzeug:
# siehe Abschnitt "Objektorientierte Programmierung"
# ...
if __name__ == "__main__":
vauweh = Fahrzeug(170, 90)
beemweh = Fahrzeug(200, 120)
print(vauweh.convertGeschw())
print(beemweh.convertGeschw())
Wird das Script als Hauptprogramm ausgeführt (z.B. zu Testzwecken), so erfolgt die Ausgabe der zwei, via <code>convertGeschw()</code>, umgerechneten Geschwindigkeiten. Wird es aber als Modul eingebunden, so wird der letzte Programmabschnitt nicht ausgeführt (<code>__name__ == "__main__"</code> ergibt <code>False</code>).
== pytest ==
Siehe zu diesem Thema auch {{W|Modultest}}.
pytest ist ein externes Modul und muss vorab installiert werden, z.B. mittels
pip install -U pytest
pip install -U pytest-html
Python-Code, Datei test1.py:
def add(x, y):
return x + y
def test_answer():
assert add(1, 1) == 3
Starten von pytest in der Konsole:
pytest test1.py
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py F [100%]
========================================================= FAILURES ==========================================================
________________________________________________________ test_answer ________________________________________________________
def test_answer():
> assert add(1, 1) == 3
E assert 2 == 3
E + where 2 = add(1, 1)
test1.py:6: AssertionError
================================================== short test summary info ==================================================
FAILED test1.py::test_answer - assert 2 == 3
===================================================== 1 failed in 0.09s =====================================================
Hier erhalten wir einen Fehler, da 1+1 eindeutig ungleich 3 ist. Aber aus irgendeinem Grund wollte der Programmierer oder Tester in diesem Fall, dass dies so ist. Testfälle werden übrigens mit dem Präfix <code>test_</code> eingeleitet.
Python-Code:
def add(x, y):
return x + y + 1
def test_answer():
assert add(1, 1) == 3
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py . [100%]
===================================================== 1 passed in 0.01s =====================================================
Jetzt ist alles in Ordnung. Weiterführendes siehe z.B.
* [https://docs.pytest.org/en/stable/ pytest: helps you write better programs]
== unittest ==
Auch unittest dient zur Durchführung von Testreihen, ist aber Bestandteil von Python. Hier wird vorerst nicht näher darauf eingegangen. Siehe z.B.
* [https://docs.python.org/3/library/unittest.html unittest — Unit testing framework]
Lt. ''Inden: Python Challenge; dpunkt, 2021, Seite 481'' soll unittest weniger komfortabel als pytest sein.
Einen Vergleich von unittest mit pytest findet man in
* [https://knapsackpro.com/testing_frameworks/difference_between/pytest/vs/unittest pytest vs unittest]
= Python und Anwendungsprogramme =
Bisher stand immer alleine die Programmiersprache Python (ev. unter Einbeziehung von Modulen) im Mittelpunkt der Betrachtungen. Aber Python kann auch als Makrosprache für Anwendungsprogramme auftreten. Als Beispiele seien {{W|FreeCAD}} und {{W|LibreOffice}} genannt.
== FreeCAD ==
FreeCAD ist ein freies 3D-CAD-Programm. Hier soll nicht auf die Bedienung dieses CAD-Pakets eingegangen werden, sondern nur auf die Möglichkeit, mittels Python Makros zu schreiben. Als einfacher Einstieg soll ein Makro erstellt werden, welches eine Kugel (rot) und einen Quader (blau) zeichnet. Folgende Vorbereitungsschritte sind erforderlich (es sei vorausgesetzt, dass FreeCAD schon am Rechner installiert ist. Downloaden können Sie das Programm von der Website [https://www.freecad.org/downloads.php?lang=en]):
* FreeCAD starten
* Leere Datei erstellen
* Makro > Makros > Erstellen ...
Es öffnet sich ein leeres Editorfenster, in das Sie folgenden Code eingeben können:
import FreeCAD
import Part
doc = FreeCAD.newDocument()
# Kugel
kugel = Part.makeSphere(10)
form_element = doc.addObject("Part::Feature", "Kugel")
form_element.Shape = kugel
kug = FreeCAD.ActiveDocument.getObject("Kugel")
kug.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
neuePosition = App.Vector(5, 2.5, 2.5)
kug.Placement = App.Placement(neuePosition, kug.Placement.Rotation)
# Quader
quader = Part.makeBox(5, 5, 50)
form_element = doc.addObject("Part::Feature", "Quader")
form_element.Shape = quader
quad = FreeCAD.ActiveDocument.getObject("Quader")
quad.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
doc.recompute()
Diesen Code können Sie nun ausführen:
* Makro > Makro ausführen
Es ergibt sich folgende Ausgabe (gedreht und gezoomt):
[[Datei: PythonIng_freecad1.png|500px]]
Siehe auch [https://wiki.freecad.org/Python_scripting_tutorial/de# Anleitung Skripterstellung mit Python]. Getestet wurde obiges Beispiel mit FreeCAD 1.1.3 unter Linux und 1.1.1 unter MS Windows.
== LibreOffice ==
LibreOffice ist ein freies Officepaket ([https://de.libreoffice.org/]). Hier soll nur das Tabellenkalkulationsprogramm Calc kurz betrachtet werden. Es seinen in den ersten 3 Zellen (A1 bis A3) Zahlen gegeben. Diese sollen mit einem Python-Makro addiert und das Resultat in der Zelle A5 ausgegeben werden. Auch hier sind Vorbereitungsarbeiten nötig:
* zuerst muss unter Linux das Verzeichnis <code>~/.config/libreoffice/4/user/Scripts/python</code> erstellt werden
* für MS Windows ist es das Verzeichnis <code>%APPDATA%\LibreOffice\4\user\Scripts\python</code>
** drücken Sie zuerst Win + R (es öffnet sich das Ausführen-Fenster)
** geben Sie <code>%appdata%</code> ein, danach drücken Sie Enter (es öffnet sich der Explorer)
** navigieren Sie zu dem genannten Verzeichnis bzw. erstellen Sie das Verzeichnis
* in diesem Verzeichnis wird dann mit einem beliebigen Texteditor das Python-Makro erstellt, in unserem Fall die Datei <code>summiere_zellen.py</code>:
import uno
def summiere_zellen(*args):
# Zugriff auf das aktuelle Dokument und das aktive Tabellenblatt
ctx = uno.getComponentContext()
smgr = ctx.getServiceManager()
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.getCurrentController().getActiveSheet()
# Werte aus den Zellen A1 bis A3 auslesen
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
# Addition der drei Werte
summe = w1 + w2 + w3
# Ergebnis in die Zelle A5 schreiben
sheet.getCellRangeByName("A5").Value = summe
* siehe dazu ggf. auch [https://help.libreoffice.org/latest/de/text/sbasic/python/python_locations.html?DbPAR=BASIC].
Weiter geht es in LibreOffice Calc mit dem Menü ''Extras > Makros > Makros verwalten > Python''. Dort wird das Makro <code>summiere_zellen</code> ausgeführt. Es ergibt sich z.B. folgendes Resultat
[[Datei:PythonIng_libreoffice1.png]]
Das Kürzel <code>uno</code> steht für '''U'''niversal '''N'''etwork '''O'''bjects. Etwas einfacher geht's auch so:
def summiere_zellen():
desktop = XSCRIPTCONTEXT.getDesktop()
model = desktop.getCurrentComponent()
sheets = model.getSheets()
sheet = sheets.getByIndex(0)
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
cell = sheet.getCellRangeByName("A5")
cell.setValue(w1 + w2 + w3)
Empfohlen wird auch, das Erweiterungspaket APSO ('''A'''lternative '''P'''ython '''S'''cript '''O'''rganizer, apso.oxt) zu installieren. Die Vorgehensweise wird hier nicht gezeigt, sondern nur darauf hingewiesen, dass man das einfach "googeln" kann. Siehe zur Python-Programmierung für LibreOffice auch [https://wiki.documentfoundation.org/Macros/Python_Guide/de Makros/Python-Handbuch]. Getestet wurden obige Beispiele mit LibreOffice 26.2.5.1 unter Linux und 26.2.1.2 unter MS Windows.
= Ausblick =
Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Python. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks, Bücher und die Python-Hilfefunktion verwiesen. Python kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Module fast beliebig erweiterbar.
= Weblinks=
== Python allgemein ==
* [https://www.python.org/ Python Homepage]
== Externe mathematische Module ==
* [https://numpy.org/ NumPy]
* [https://numpy.org/doc/stable/user/numpy-for-matlab-users.html NumPy for MATLAB users]
* [https://scipy.org/ SciPy]
* [https://www.sympy.org/en/index.html SymPy]
* [https://pandas.pydata.org/ pandas]
* [https://github.com/maroba/findiff findiff]
* [https://mpmath.org/ mpmath]
== Externe Module für Grafiken ==
* [https://matplotlib.org/ Matplotlib]
* [https://vpython.org/ VPython]
* [https://build123d.readthedocs.io/en/latest/ build123d]
* [https://docs.vtk.org/en/latest/api/python.html VTK]
* [https://docs.bokeh.org/en/latest/docs/first_steps.html bokeh]
* [https://py5coding.org/ py5]
== Erstellung von User Interfaces ==
* [https://docs.python.org/3/library/tkinter.html tkinter - Python interface to Tcl/Tk]
* [https://docs.python.org/3/library/curses.html curses - Terminal handling for character-cell displays]
* [https://wiki.qt.io/Qt_for_Python Qt for Python]
* [https://www.gtk.org/docs/language-bindings/python GTK and Python]
== Erstellen virtueller Umgebungen ==
* [https://docs.python.org/3/library/venv.html venv - Creation of virtual environments]
== Sonstige ==
* [https://python-control.readthedocs.io/en/stable/ Python Control Systems Library]
* [https://pypi.org/project/regex/ regex - Regular Expressions]
* [http://pyromat.org/ PYroMat]
* [https://coolprop.org/coolprop/wrappers/Python/index.html CoolProp]
* [https://pypi.org/project/iapws/ iapws]
* [https://tespy.readthedocs.io/en/main/getting_started/introduction.html TESPy - Thermal Engineering Systems in Python]
* [https://pint.readthedocs.io/en/stable/ pint]
= Bücher =
== Gedruckte Bücher, OpenBooks, Magazine ==
* Diverse: c't Python Lernen, Verstehen, Anwenden; Heise, 2022
* Ernesti, Kaiser: Python3 - das umfassende Handbuch; 5. Aufl., Rheinwerk, [https://openbook.rheinwerk-verlag.de/python/ OpenBook]
* Iacono et al.: Programmieren trainieren; 3. Aufl., Hanser, 2023, ISBN 978-3-446-47766-7
* Inden: Python Challenge; dpunkt, 2021, ISBN 978-3-86490-809-5
* Klein: Numerisches Python; 2. Aufl., Hanser, 2023, ISBN 978-3-446-47170-2
* Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler; Rheinwerk, 2021, ISBN 978-3-8362-7316-9
* Weigend: Python 3 - Das umfassende Praxisbuch; 9. Aufl., mitp, 2022, ISBN 978-3-7475-0544-1
* Woyand: Python für Ingenieure und Naturwissenschaftler; 4. Aufl., Hanser, 2021, ISBN 978-3-446-46483-4
== Andere Wikibooks ==
* [[:en:Subject:Python_programming_language | Englische Wikibooks zum Thema Python]]
* [[Python|Deutschsprachiges Python-Wikibook]] [[Bild:2von10.png|20%]]
* [[Python unter Linux|Python 2.7 unter Linux]] [[Bild:10von10.png|100%]]
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
7j4a9yw9dhdjtan238iqyufnubkncaw
1091891
1091890
2026-10-03T14:53:17Z
Intruder
1513
/* Py5 */
1091891
wikitext
text/x-wiki
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
= Hallo Welt und allgemeine Hinweise =
== Was ist Python ==
* Python ist eine universelle höhere Programmiersprache.
* Python ist objektorientiert.
* Python ist Open-Source (Python Software Foundation License).
* Python ist für viele Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
* Python ist ein Interpreter.
* Python ist durch Module fast beliebig erweiterbar.
* Python als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
* Python ist in etlichen Anwendungsprogrammen (z.B. {{W|FreeCAD}}, {{W|LibreOffice}}, {{W|GIMP}}, {{W|Blender (Software) | Blender}}) als Makrosprache verwendbar.
{{Wikipedia | Python (Programmiersprache)}}
== Python installieren ==
=== MS Windows ===
Laden Sie das aktuelle Python-Paket von der Webseite [https://www.python.org/] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.
=== Linux ===
Entweder ist Python bereits standardmäßig installiert, ansonsten ist die Installation mittels Paketmanagementsystem einfach möglich. Aber auch die Spyder-Entwicklungsumgebung ([https://www.spyder-ide.org]) bietet einen guten Einstieg mit Python (das gilt auch für MS Windows). Spyder bringt auch schon etliche wichtige Module standardmäßig mit.
== Python starten ==
=== MS Windows ===
Das Icon für das Python-Programm doppelklicken. Und schon startet das Programm.
[[Datei:PythonIng_start1.jpg]]
Python im interaktiven Modus präsentiert sich dann so:
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Alternativ kann das Programm auch über die Eingabeaufforderung oder die PowerShell gestartet werden:
c:\devel\Python>python.exe
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
=== Linux ===
Tippen Sie einfach das Wort „python“ (oder unter openSUSE Tumbleweed z.B. auch „python3.11“ oder „python3.13“) in einem Linux-Terminal ein, schließen den Befehl mit der RETURN-Taste ab, und schon startet Python im interaktiven Modus:
Python 3.13.12 (main, Feb 09 2026, 22:37:44) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Es gibt auch noch andere Möglichkeiten Python zwecks Programmausführung zu starten, z. B. den {{W|Shebang}} (<code>#!</code>) am Beginn eines Python-Scripts. Das Script sei als Script.py gespeichert. Dann kann das Script mit ./Script.py ausgeführt werden. Für openSUSE Tumbleweed sei nachfolgend ein lauffähiges "Hallo Welt!"-Script angegeben. Es wird in diesem Script der Python-Interpreter in der Version 3.13 verwendet :
#!/usr/bin/python3.13
print("Hallo Welt!")
Die Berechtigungen zum Ausführen der Datei müssen natürlich noch richtig gesetzt werden, z.B. mittels <code>chmod 777 Script.py</code>. <small><code>chmod</code> ist die Abkürzung für"'''ch'''ange file '''mod'''e bits".</small>
<small>Die "Maske" <code>777</code> ist nur für Testzwecke sinnvoll, weil sie leicht zu merken ist und für alle Benutzer alle Zugriffsberechtigungen ('''r'''ead/'''w'''rite/e'''x'''ecute für owner/group/others) setzt. Im richtigen Einsatz wird man das aus Sicherheitsgründen nicht so handhaben, sondern nur die Berechtigungen setzen, die unbedingt erforderlich sind. Welche Zugriffsberechtigungen gesetzt sind, kann man z.B. mit dem Befehl <code>ls -l</code> oder <code>ll</code> ('''l'''i'''s'''t directory contents) erfragen. Aber dazu im Moment genug. Erfahrene Linux-Nutzer kennen das ohnehin und Anfänger sollen jetzt nicht mit Linux-Interna überfordert werden. Bei Bedarf siehe die Linux-Man-Pages oder dezidierte Bücher zu Linux.</code></small>
<small>Oder das Script wird in einen Pfad verschoben, in dem sich ausführbare Programme generell befinden (welche Verzeichnisse im PATH liegen, kann bspw. mit <code>echo $PATH</code> abgefragt werden). Das Script kann dann wie ein normales Programm ohne weitere Angaben mit Script.py gestartet werden. Alternativ wird nicht das Script an sich verschoben, sondern nur ein symbolischer Link angelegt, z.B. mit <code>ln -s ~/tmp/Script.py ~/.local/bin/Script.py</code>. <code>~/.local/bin</code> sei ein im PATH gelegenes Verzeichnis. Dies sind aber schon Features für fortgeschrittene Linux-Benutzer und werden am Anfang eher selten benötigt.</small>
== Ein paar Worte zur Erklärung ==
=== Tests ===
Getestet wurden die Beispiele unter den Betriebssystemen
* MS Windows 10 mit der Python-Version 3.12.0 (teilweise auch mit 3.12.2 und 3.13.1; nur die Inhalte die bis spätestens Juli 2025 erstellt wurden)
* MS Windows 11 ab der Python-Version 3.13.4 (nur zum Teil; ab Juli 2025)
* openSUSE Leap 15.6 mit der Python-Version 3.11.12 (Spyder, nur vereinzelt) und zum Teil mit 3.12.11 (ab Juli 2025 bis November 2025).
* openSUSE Tumbleweed ab der Python-Version 3.13.9 (nur vereinzelt, ab November 2025)
=== Popularität ===
* An Beliebtheit rangiert Python mit Stand September 2026 mit einem Rating von 17,76% an 1. Stelle vor C und C++ (lt. [https://www.tiobe.com/tiobe-index/ TPCI - TIOBE Programming Community Index]).
* Lt. [https://innovationgraph.github.com/global-metrics/programming-languages GitHub Top 50 Programming Languages Globally] lag Python im Q1/2026 auf Rang 2, vor TypeScript und hinter JavaScript.
* [https://pypl.github.io/PYPL.html PYPL] (Popularity of Programming Language Index) ist ein anderer Popularitätsindex für Programmiersprachen. Auch hier liegt Python mit großem Vorsprung auf dem ersten Platz (52,08%), gefolgt von Java (13,34%) und C/C++ (7,99%) (Stand September 2026).
=== Namensgebung ===
Der Name "Python" rührt von der Komikertruppe {{W|Monty Python}} her. Die Icons für Python (z.B. Python selbst, Eric IDE, IDLE) sind aber durch die Python-Schlangenart symbolisiert.
<gallery>
Python-logo-notext.svg|Python-Logo
Guido van Rossum in PyConUS24.jpg|{{W|Guido van Rossum}} (geb. 1956), der Erfinder von Python
</gallery>
== Ein erstes Programm ==
Kommentare werden in Python mit der Raute (#) eingeleitet. Sie werden vom Python-Interpreter ignoriert. Text kann mit der print-Funktion ausgegeben werden. Starten Sie Python und geben sie folgende Anweisungen zeilenweise ein
>>> # Das ist ein Kommentar
>>> print("Hallo Welt!")
Als Ergebnis erhalten Sie
Hallo Welt!
Der Prompt (>>>) ist selbstverständlich nicht einzutippen, sondern wird vom Python-System geliefert.
Strings können in Python entweder in Anführungszeichen (") gesetzt werden oder in Hochkommatas('). In diesem Text wird die erste Variante bevorzugt eingesetzt.
Im Gegensatz zu Julia ist es hier egal, ob zwischen <code>print</code> und der öffnenden Klammer Leerzeichen stehen.
= Python als Taschenrechner =
== Allgemeines ==
Wir wollen 3 * 5 berechnen. Dazu starten wir Python im interaktiven Modus. Geben Sie dann die Formel
>>> 3 * 5
ein, drücken die Taste ENTER/RETURN ({{Taste|↵}}) und erhalten als Ergebnis
15
Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck <math>\sin\sqrt{15}</math> berechnen :
>>> import math
>>> math.sin(math.sqrt(15))
-0.6679052983383519
Als erstes wird das math-Modul importiert. Dann wird der mathematische Ausdruck berechnet.
Eine andere Variante, die dasselbe Ergebnis liefert, ist
>>> from math import *
>>> sin(sqrt(15))
-0.6679052983383519
Es wird also aus dem Modul <code>math</code> alles importiert (erkennbar am <code>*</code>). Will man nicht alles importieren, so kann man das auch einschränken:
>>> from math import sin, sqrt
Beenden lässt sich das Python-Programm durch Eingabe von <code>exit()</code> (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken).
== Die Hilfefunktion von Python ==
Bei Eingabe der Anweisung <code>help</code> oder <code>help()</code> springt Python in den Hilfemodus.
Eingabe:
>>> help()
Eingabe:
help> math.sin
Ausgabe:
Help on built-in function sin in math:
math.sin = sin(x, /)
Return the sine of x (measured in radians).
Für die komplette Python-Dokumentation siehe [https://docs.python.org/3/]. Verlassen kann man den Hilfemodus durch das Drücken von STRG-C, bzw. der Eingabe von q, quit oder exit mit anschließendem Drücken der RETURN-Taste.
== Aufgaben ==
* Erkunden Sie die Tangensfunktion "tan" mittels Python-Hilfe (vergessen Sie nicht das math-Modul zu importieren und das <code>math.</code> vor <code>tan</code>)
* Berechnen Sie mit Python den Ausdruck <math>\frac{1}{2}\cdot \text{e}^2 \cdot \tan(\pi/3)</math>. Siehe für die Exponentialfunktion im Python-Hilfesystem auch den Befehl <code>math.exp</code>. Alternativ kann auch die Konstante <code>math.e</code> eingesetzt werden. Potenzieren kann man bei Python mit dem **-Operator (z.B. 2**3 = 8). Für <math>\pi</math> gibt es <code>math.pi</code>.
= Python als Scriptsprache =
Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.py
# Das ist ein Kommentar
print("Hallo Welt!")
Python-Dateien werden mit der Dateiendung .py versehen. Achten Sie darauf, dass vor dem print keine Leerzeichen vorhanden sind. Das ist eine Python-Eigenheit. Wie wir später sehen werden, nutzt Python Einrückungen als syntaktisches Mittel, z.B. um bei Schleifen den Schleifenkörper zu kennzeichnen.
Danach bringen Sie die Skriptdatei test1.py (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:
1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ auch die Windows PowerShell). Das sieht dann etwa so aus:
Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\xyz>
: <small>Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol ([[Image:Windows_logo_-_2021_(Black).svg|10px]]) mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell unter Windows 10 den Eintrag "Windows PowerShell", unter Windows 11 den Eintrag "Terminal"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort <code>cmd</code> ein und mit "OK" wird das Ganze bestätigt.</small>
2) Wechseln Sie mittels <code>cd c:\tmp</code> in das Verzeichnis c:\tmp
3) Angenommen, Sie haben Python unter dem Pfad <code>c:\devel\Python\</code> installiert. Starten Sie das Programm so (der Prompt <code>c:\tmp></code>ist natürlich nicht mit einzutippen):
c:\tmp>c:\devel\Python\python.exe test1.py
4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm
Hallo Welt!
Die Vorgehensweise unter Linux ist prinzipiell gleich. Die kleinen Unterschiede, wie z.B. der Slash statt dem Backslash in Pfadangaben, sollten für Linux-Benutzer keine Hürde darstellen.
== Variablen ==
Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9) und Underscores (_) bestehen, dürfen aber nicht mit einer Zahl beginnen. Führende Underscores haben u.a. im Kontext mit der Objektorientierten Programmierung eine spezielle Bedeutung und sollten nicht für "normale" Variablenbezeichner verwendet werden.
Gültige Variablenbezeichner wären also:
xyz
x1
_wert
name_anzahl
Theoretisch kann man auch Umlaute, griechische Buchstaben u.ä. in Variablenbezeichnern nutzen, z.B.
ößÜ = 16
α = 134
print(ößÜ)
print(α)
Ausgabe:
16
134
Davon wird aber aus offensichtlichen Gründen ({{W|Englisch als Lingua franca}}) abgeraten. Das Eurozeichen (€) etc. darf man ohnehin nicht in Variablenbezeichnern verwenden, dies ergäbe einen Syntaxfehler. Siehe dazu auch [https://peps.python.org/pep-3131/].
Es gibt in Python etliche Schlüsselwörter (z.B. for, if oder return). Diese dürfen nicht als eigene Variablenbezeichner verwendet werden. Eine Liste aller Schlüsselwörter liefert das Script
import keyword
print(keyword.kwlist)
<small>Übung: Speichern Sie dieses Script in eine Datei, z.B. in c:\tmp\test1.py. Führen Sie diese Datei aus, um die Liste der Schlüsselwörter auszugeben.</small>
Da Python case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:
xyz
XYZ
xYz
Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.py gespeichert.
x = 5
y = 10
z = x*y
print(z)
Bringen Sie die Datei test1.py zur Ausführung, so erhalten Sie folgende Bildschirmausgabe
50
Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben. Dies führt aber zu unübersichtlichem Code.
x = 5; y = 10; z = x*y; print(z)
Ausgabe:
50
Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.
x = 5
# x = x - 2
x -= 2
print(x)
Bildschirmausgabe:
3
Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Den Inkrement-/Dekrementoperator (z.B. x++ oder x--) aus C/C++ oder Java kennt Python aber nicht.
Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Python problemlos möglich:
import math
wert = 10
print(wert)
wert = 35.5
print(wert)
wert = "Hallo"
print(wert)
wert = math.pi
print(wert)
Ausgabe:
10
35.5
Hallo
3.141592653589793
== Physische und logische Zeilen ==
In Python muss eine Anweisung in einer logischen Zeile Platz finden. Wird eine Anweisung aber zu lang für eine Zeile, dann kann sie in mehrere physische Zeilen unterteilt werden. Dies kann einerseits durch einen Backslash am Ende einer Zeile geschehen, z.B.
a = 2 + \
5
Dies stellt eine logische Zeile dar, die in zwei physische Zeilen unterbrochen ist.
Geklammerte Ausdrücke werden automatisch zu einer logischen Zeile verbunden, z.B.
a = (2 +
5)
Achtung: Im ersten Beispiel darf nach dem Backslash nichts mehr stehen, auch kein Kommentar. Dies trifft im zweiten Bespiel nicht zu, hier könnte noch ein Kommentar folgen, z.B.
a = (2 + # Kommentar
5)
Auch für Strings gibt es Möglichkeiten, diese auf mehrere Zeilen aufzuspalten.
# Kurzer String
str1 = "ABC"
# Langer String
str2 = """Hallo Welt,
Grüetzi Schwyzer,
Servus an alle"""
# Backslash
str3 = "UVW\
XYZ"
# Mit Klammern
str4 = ("Sehr langer Text, der automatisch .............. "
"in einer einzigen Variable zusammengefügt wird."
)
print(str1)
print(str2)
print(str3)
print(str4)
Ausgabe:
ABC
Hallo Welt,
Grüetzi Schwyzer,
Servus an alle
UVWXYZ
Sehr langer Text, der automatisch .............. in einer einzigen Variable zusammengefügt wird.
==Hexadezimale, oktale, binäre und andere Zahlen==
d = 1050 # Dezimalzahl
h = 0xAA2 # Hexadezimalzahl
o = 0o12 # Oktalzahl
b = 0b100001101 # Binärzahl
print(d)
print(h)
print(o)
print(b)
Ausgabe:
1050
2722
10
269
Groß- und Kleinbuchstaben sind in obigen Literalen übrigens egal. So kann man z.B. statt <code>0b1001</code> auch <code>0B1001</code> schreiben (siehe dazu [https://docs.python.org/3/reference/lexical_analysis.html#integer-literals]).
Sie können auch dezimale in hexadezimale Zahlen umwandeln, usw.:
h = hex(1050) # Dezimalzahl -> Hexadezimalzahl
b = bin(1050) # Dezimalzahl -> Binärzahl
o = oct(1050) # Dezimalzahl -> Oktalzahl
print(h)
print(b)
print(o)
Ausgabe:
0x41a
0b10000011010
0o2032
Gegeben sei die Zahl 121 zur Basis 3. Diese soll in eine Dezimalzahl umgewandelt werden. Das kann so geschehen:
z = int("121", 3)
print(z)
Ausgabe:
16
Dass dies richtig ist, davon kann man sich folgendermaßen überzeugen:
<math> 1 \cdot 3^2 + 2 \cdot 3^1 + 1 \cdot 3^0 = 9 + 6+ 1 = 16 </math>
Zahlen übersichtlicher schreiben kann man auch mittels Underscore, z.B.:
print("Eine Million (Variante 1) =", 1000000)
print("Eine Million (Variante 2) =", 1_000_000)
print("Eine Rechnung:", 2_000 * 400_000);
Es ergibt sich bei beiden Varianten die gleiche Ausgabe. Variante 2 ist aber im Sourcecode leichter lesbar, detto die Zahlen in der Rechnung:
Eine Million (Variante 1) = 1000000
Eine Million (Variante 2) = 1000000
Eine Rechnung: 800000000
== Strings und Platzhalter==
Ein paar einfache Beispiele:
print("Hallo {}" . format("Hugo"))
print("Hallo {:s}" . format("Hugo"))
print("Hallo %s" % "Hugo")
Ausgabe:
Hallo Hugo
Hallo Hugo
Hallo Hugo
Python-Code (formatted string literals, Beispiel 1):
str1 = "Hallo"
str2 = "Hugo"
print(f"{str1} {str2}")
Ausgabe:
Hallo Hugo
Python-Code (formatted string literals, Beispiel 2):
wert = 11.567
print(f"Ausgabe: {wert:.5f}")
Ausgabe:
Ausgabe: 11.56700
Komplexere Beispiele:
print("Hallo {} und {}" . format("Hugo", "Mike"))
print("Hallo {name1} und {name2}" . format(name2="Hugo", name1="Mike"))
# Füllzeichen: *
# Bündigkeit: > (=rechts), < (=links), ^ (=zentriert)
# Feldweite: 10
# Typ: s (=String), f (=Gleitkommazahl), d (=Dezimalzahl) etc.
print("Hallo {:*>10s}" . format("Hugo"))
print("Hallo {:*<10s}" . format("Hugo"))
Ausgabe:
Hallo Hugo und Mike
Hallo Mike und Hugo
Hallo ******Hugo
Hallo Hugo******
Python-Code:
str = "Hallo\t%s\t%7.2f\t%10.2e\t%i" % ("Hugo", 12.34567, 34.567, 264)
print(str)
Ausgabe:
Hallo Hugo 12.35 3.46e+01 264
== Unicode ==
Neben den bekannten ASCII-Zeichen lassen sich Zeichen auch mittels Unicode beschreiben. Griechische Buchstaben oder komplexere mathematische Operatoren - all das sollte kein Problem sein. Siehe auch {{W|Unicode}}, {{W|Liste der Unicodeblöcke}} und {{W|Unicodeblock Mathematische Operatoren}}. Im Folgenden werden ein paar Zeichen (Allquantor, Nabla-Operator, Existenzquantor), die man aus der Mathematik kennt, erzeugt.
ch1 = "\N{FOR ALL}"
ch2 = "\N{NABLA}"
ch3 = "\u2203"
print(ch1, ch2, ch3)
Ausgabe:
∀ ∇ ∃
<small>Diese Ausgabe ergibt sich z.B. mit der IDLE-Shell oder mit Cygwin. Beim Ausführen über die Windows-Eingabeaufforderung oder Windows PowerShell unter MS Windows 10 erfolgt keine korrekte Darstellung. IDLE ist die mit Python mitgelieferte IDE ('''I'''ntegrated '''D'''evelopment '''E'''nvironment, Integrierte Entwicklungsumgebung). Gegen Ende dieses Textes wird IDLE kurz beschrieben.
Das Problem mit der Windows Eingabeaufforderung lässt sich aber umgehen. Man muss nur eine Schriftart auswählen, die die Zeichen kennt, z.B. "DejaVu Sans Mono". Dazu klicken Sie einfach bei der Eingabeaufforderung mit der rechten Maustaste oben auf die weiße Leiste und wählen im aufpoppenden Fenster den Menüpunkt "Eigenschaften". Es öffnet sich ein Dialogfenster. Über den Reiter "Schriftart" lässt sich nun die Schriftart einstellen. Unter MS Windows 11 oder openSUSE Leap 15.6 (bash-Konsole) gibt es dieses Problem ohnehin nicht.</small>
== Reguläre Ausdrücke ==
Python kennt auch {{W|Regulärer Ausdruck|reguläre Ausdrücke}}. Dazu gibt es in Python das Modul <code>re</code>. Beipielsweise sollen alle Zahlen (<math>\text{zahl}\in\mathbb{N}_0</math>) in einem String gesucht und ausgegeben werden. Als String sei gegeben: <code>3x Grüße und 100 Kekse.</code> Das Muster (Pattern) ist <code>\d+</code>. <code>\d</code> steht für eine Dezimalziffer 0-9. Das Plus-Zeichen (+) steht symbolisch für ein oder mehrere Zeichen des vorherigen Ausdrucks. Hier also ein oder mehrere Dezimalziffern. Es wird die Funktion <code>findall</code> aus dem Modul <code>re</code>verwendet.
Python-Code:
from re import findall
str = "3x Grüße und 100 Kekse."
pat = "\\d+" # Doppel-Backslashes müssen verwendet werden, sonst gibt Python eine Warnung aus!
# alternativ: pat = r"\d+"
# oder: pat = "[0-9]+"
numb = findall(pat, str)
print(numb)
Ausgabe:
['3', '100']
Python kennt noch viele weitere Möglichkeiten mittels regulärer Ausdrücke zu hantieren. Dies soll hier aber nicht vertieft werden, da das Thema schon ziemlich speziell und komplex ist. Bei Bedarf siehe aber z.B. die Bücher ''Weigend, Seite 380ff'' und ''Ernesti, Kaiser'' [https://openbook.rheinwerk-verlag.de/python/28_001.html] oder die Python-Dokumentation [https://docs.python.org/3/library/re.html]. Auch [[Python unter Linux: Reguläre Ausdrücke]] liefert ein umfangreiches und brauchbares Python-2-Kapitel zu den regulären Ausdrücken. Die dort gelisteten Beispiele müssten ggf. vor Verwendung auf Python-3 umgeschrieben werden. <small>Wie macht man das? Dazu siehe z.B. [https://openbook.rheinwerk-verlag.de/python/43_001.html], [https://portingguide.readthedocs.io/en/latest/] oder [https://www.digitalocean.com/community/tutorials/how-to-port-python-2-code-to-python-3]</small>
<small>Es gibt auch ein externes Modul ''regex'', das bei Bedarf extra installiert werden muss ([https://pypi.org/project/regex/]). Es bietet zusätzliche Funktionalität und gründlicheren Unicode-Support. Dies sei hier aber nur der Vollständigkeit halber erwähnt.</small>
== Verzweigungen ==
=== if ===
Die IF-Verzweigung sei aus anderen Programmiersprachen bereits bekannt. In {{W|Pseudocode}} lässt sie sich folgendermaßen darstellen:
WENN bedingung TRUE
führe block1 aus
SONST
führe block2 aus
ENDE
Als {{W|Aktivitätsdiagramm|UML-Aktivitätsdiagramm}} sieht das in etwa so aus:
[[File:If-Then-Else-diagram.svg|200px]]
Und als {{W|Nassi-Shneiderman-Diagramm|Nassi-Shneiderman-Struktogramm}} so:
[[File:Zweiseitige Auswahl.png|250px]]
In Python gibt es keinen expliziten ENDE-Kennzeichner. Stattdessen wird der Code durch Einrückungen strukturiert. Alles mit der gleichen Einrückungstiefe gehört zum selben Block. Dies zeichnet Python vor anderen Programmiersprachen aus.
Die test1.py-Datei laute also wie folgt:
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4
Man achte auch auf die Doppelpunkte in der if- und else-Zeile. Darauf vergisst man gerne, wenn man von anderen Programmiersprachen kommt.
Folgendes wäre in Python ein Fehler (genauer gesagt ein IndentationError).
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Auch Nachstehendes würde nicht zum gewünschten Ergebnis führen (löst aber keine Fehlermeldung aus). Der letzte print-Befehl ist schon außerhalb der IF-ELSE-Verzweigung.
x = 3
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
x ist kleiner als 4
x ist groesser oder gleich 4
Python kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:
<, <= ... kleiner (gleich)
>, >= ... größer (gleich)
== ... gleich
!= ... ungleich
is ... identisch
is not ... nicht identisch
and ... AND
or ... OR
not ... NOT
Beispielsweise:
a = 5
b = 9
if a<=10 and b!=7:
print("OK")
else
print("Nicht OK")
Ausgabe:
OK
Der else-Block kann übrigens auch ersatzlos entfallen. Als Pseudocode sieht das so aus
WENN bedingung TRUE
führe block aus
ENDE
Mehrfache Verzweigungen werden durch das elif-Konstrukt erstellt. In Pseudocode:
WENN bedingung1 TRUE
führe block1 aus
SONST WENN bedingung2 TRUE
führe block2 aus
SONST WENN bedingung3 TRUE
führe block3 aus
SONST
führe block4 aus
ENDE
Ein Python-Beispiel:
a = 14
if a<=10:
print("<=5")
elif a>11 and a<15:
print("11 bis 15")
elif a>16 and a<20:
print("16 bis 20")
else:
print(">=20")
Ausgabe:
11 bis 15
In Python gibt es auch die Schlüsselwörter <code>True</code> (für wahr) und <code>False</code> (für falsch). Man beachte, dass sie mit Großbuchstaben beginnen. Andere Schreibweisen wären ein Fehler. Sie gehören zum Datentyp <code>bool</code>. Ihnen sind auch die Zahlen <code>1</code> und <code>0</code> zugewiesen.
Man beachte, dass {{W|Rundungsfehler}} auftreten können. D.h. man sollte bei der Verwendung von {{W|Gleitkommazahl|Gleitpunktzahlen}} niemals auf absolute Genauigkeit prüfen, sondern eine Toleranz (einen <math>\varepsilon</math>-Wert) vorgeben.
Ein klassisches Beispiel, das ein falsches Ergebnis liefert, ist:
i = 0.1 + 0.2
print(i)
if i == 0.3:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
NOK
Und das, obwohl man schon in der Volksschule lernt, dass 0.1 + 0.2 gleich 0.3 ist.
Korrekt muss das obige Beispiel z.B. so umgeschrieben werden:
ist = 0.1 + 0.2
soll = 0.3
epsilon = 0.000001
print(ist)
if abs(ist-soll) < epsilon:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
OK
Alternativ kann auch die <code>math.isclose()</code>-Funktion verwendet werden. Das sei aber hier nur erwähnt und nicht konkret ausgeführt.
<u>Aufgabe:</u> Recherchieren Sie im Internet zum Thema <code>math.isclose()</code>-Funktion.
=== match ===
Ab Python 3.10 gibt es auch die match-Anweisung. Dies ist das Python-Pendant für die switch-Anweisung in anderen Programmiersprachen, geht aber bei näherer Betrachtung weit darüber hinaus. Hier nur ein einfaches Beispiel:
x = "Hello"
match x:
case "Servus" | "Ciao": # or
print("Servus an alle")
case "Grüetzi":
print("Grüetzi Schwyzer")
case _: # other, default, sonstiges ...
print("Hallo Welt")
Ausgabe:
Hallo Welt
Als Struktogramm sieht das in etwa so aus:
[[File:Mehrseitige Auswahl.png|250px]]
Für nähere Details siehe z.B. [https://www.geeksforgeeks.org/python-match-case-statement/], [https://learnpython.com/blog/python-match-case-statement/], [https://docs.python.org/3/tutorial/controlflow.html#match-statements] und das Python Enhancement Proposal (PEP) 636 – Structural Pattern Matching: Tutorial [https://peps.python.org/pep-0636] und dort insbesondere den Anhang A - Quick Intro.
<small><code>match, case, _</code> etc. sind sogenannte ''soft keywords''. Im Gegensatz zu den normalen Schlüsselwörtern dürfen ihnen auch Werte zugewiesen werden. Eine Liste der weichen Schlüsselwörter lässt sich durch <code>keyword.softkwlist</code> erstellen (die Anweisung gibt es seit Python 3.9). Siehe dazu auch [https://stackoverflow.com/questions/65800344/what-are-soft-keywords] und [https://docs.python.org/3/library/keyword.html#keyword.softkwlist].</small>
== Schleifen ==
Kopfgesteuerte Schleife, Endlosschleife und fußgesteuerte Schleife:
[[File:Programmingloops.svg|450px]]
=== while ===
Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert wie aus anderen Programmiersprachen bekannt.
In Pseudocode:
SOLANGE bedingung TRUE
führe block aus
ENDE
In Python:
x = 0
while x <= 10:
print(x)
x += 1
Ausgabe:
0
1
2
3
4
5
6
7
8
9
10
Eine Endlosschleife ergibt sich z.B. so:
i = 5
while True:
print(i)
i-=1
Beendet werden kann sie mit der Tastenkombination STRG-C.
Eine fußgesteuerte Schleife kann so simuliert werden:
i = 5
while True:
print(i)
i-=1
if i<=0:
print("Fire")
break
Ausgabe:
5
4
3
2
1
Fire
Der <code>break</code>-Befehl wird etwas später noch einmal kurz thematisiert.
=== for ===
Struktogramm einer for-Schleife:
[[File:Zählschleife.png|200px]]
In Python bspw. so:
for x in range(6):
print(x*2)
Ausgabe:
0
2
4
6
8
10
Die Schleife läuft von 0 bis 5. Ausgegeben wird jeweils der Wert x*2. Aquivalent kann diese Schleife auch so geschrieben werden:
for x in range(0, 11, 2):
print(x)
Die Ausgabe ist wie oben. Der Startwert sei 0, der Endwert ist 11-1 und die Schrittweite ist 2.
Ein anderes Beispiel sei
for x in "text":
print(x)
Ausgabe:
t
e
x
t
== Schleifen abbrechen ==
=== break ===
<code>break</code> bricht die Schleife ab und setzt mit dem nächsten Befehl außerhalb der Schleife fort.
for var in range(100):
print(var)
if var == 5:
break
Ausgabe:
0
1
2
3
4
5
=== continue ===
<code>continue</code> bricht den aktuellen Schleifendurchlauf ab und setzt mit dem nächsten Schleifendurchlauf fort.
for var in range (11):
if var == 5:
continue
print(var)
Ausgabe:
0
1
2
3
4
6
7
8
9
10
== try - except ==
try:
z1 = 12 / 0
print(z1)
except ZeroDivisionError:
print("Das Ergebnis ist unendlich")
except:
print("Kann nicht berechnet werden!")
print("Bitte die Formel korrigieren!")
print("Setze Programm fort!")
Ausgabe:
Das Ergebnis ist unendlich
Setze Programm fort!
Es wird versucht, eine Zahl durch Null zu dividieren. Das ist nicht möglich, es wird eine Ausnahme ausgelöst. Das Programm springt daher in den except-ZeroDivisionError-Block und führt die dort gelisteten Anweisungen aus (in unserem Fall eine print-Anweisung). Danach wird das Programm fortgesetzt. Würden wir dieses Programm ohne try-except ausführen, so ergibt sich aus
z1 = 12 / 0
print(z1)
folgende Fehlermeldung und ein unmittelbarer Programmabbruch
Traceback (most recent call last):
File "C:\tmp\test1.py", line 1, in <module>
z1 = 12 / 0
ZeroDivisionError: division by zero
Mit dem try-except-Mechanismus können also Ausnahmen oder Fehler aufgefangen und behandelt werden. In unserem Beispiel ist das eher trivial, aber bei größeren Programmen kann das durchaus Sinn machen.
Neu in Python 3.14 ist, dass mehrere Ausnahmen auch ohne Klammern angegeben werden können, z.B.:
bis inkl. Python 3.13 nur:
except (ZeroDivisionError, ValueError):
ab Python 3.14 auch:
except ZeroDivisionError, ValueError:
== pass ==
Ein leerer Block muss in Python mittels dem Schlüsselwort <code>pass</code> dargestellt werden. Z.B.
x = 2
if x == 1:
print("Wert ist ", x)
else:
pass
Würde man das <code>pass</code> im else-Block weglassen, so würde man eine Fehlermeldung erhalten:
IndentationError: expected an indented block after 'else' statement on line 5
= Funktionen =
== Aufrufen von Funktionen ==
Funktionen sind uns im Rahmen dieses Kurses schon zuhauf begegnet. Sei es die print()-, die math.sin()- oder die hex()-Funktion. All diese Funktionen werden von Python zur Verfügung gestellt, ohne dass man sie explizit programmieren müsste. Aufgerufen werden diese Funktionen, indem man ihren Namen eintippt, gefolgt von runden Klammern. In diesen Klammern können noch Argumente übergeben werden. Auch Rückgabewerte sind möglich.
== Funktionen selber schreiben ==
Funktionen werden mit dem def-Schlüsselwort (man definiert die Funktion) eingeleitet, danach folgt der Funktionsname, danach wiederum runde Klammern, in denen formale Argumente stehen können. Abgeschlossen wird die def-Zeile mit einem Doppelpunkt. Danach folgt der Funktionskörper. Dieser Funktionskörper muss wiederum eingerückt werden (wie von den Verzweigungen und Schleifen bekannt). Aufgerufen wird diese Funktion, indem man ihren Funktionsnamen eingibt, gefolgt von runden Klammern (ggf. mit den aktuellen Parametern). Z.B.
# Funktion definieren
def halloWelt(i):
# i ... beliebige Ganzzahl
print("Hallo " * i, end="")
print("Welt!")
# Funktion aufrufen
halloWelt(3)
Ausgabe:
Hallo Hallo Hallo Welt!
Unterschied zwischen formalen und aktuellen Parametern:
[[Datei:PythonIng_func1.jpg]]
<small>Aktuelle Parameter werden auch Argumente genannt.</small>
Rückgabe von Funktionswerten:
# Funktion definieren
def mathFunc(a, b):
r1 = a + b
r2 = a * b
return r1, r2
# Funktion aufrufen
c, d = mathFunc(3, 5)
# Ausgabe der zurückgegebenen Werte
print(c)
print(d)
Ausgabe:
8
15
Es werden r1 und r2 zurückgegeben und den Variablen c und d zugewiesen. (r1, r2) und (c, d) sind Tupel. Was Tupel konkret sind, siehe etwas später in diesem Kapitel. 3 und 5 sind die aktuellen Parameter (die Argumente). a und b sind die formalen Parameter. Die Zuweisung der aktuellen zu den formalen Parametern erfolgt in der gegebenen Reihenfolge, also die Zahl 3 wird an a übergeben und die Zahl 5 an b.
Vorgabeparameter, z.B.:
def mathFunc(a=10, b=20):
r1 = a + b
r2 = a * b
return r1, r2
c, d = mathFunc(3, 5)
print(c)
print(d)
e, f = mathFunc(5)
print(e)
print(f)
g, h = mathFunc(b=6)
print(g)
print(h)
Ausgabe:
8
15
25
100
16
60
Erklärung:
* Erster <code>mathFunc</code>-Aufruf: Es werden, wie weiter oben, die Argumente 3 und 5 an die formalen Parameter a und b übergeben. Die Rückgabewerte r1 und r2 werden an c und d übergeben. Somit ist c=8 und d=15.
* Zweiter <code>mathFunc</code>-Aufruf: Es wird nur das Argment 5 an a übergeben. b behält den Vorgabewert 20. D.h. e= 25 und f=100.
* Dritter <code>mathFunc</code>-Aufruf: Es wird nur die Zahl 6 an b übergeben, a behält seinen Vorgabewert 10. Somit ergibt sich g=16 und h=60.
Beispiel (Schlüsselwortargumente vs. Positionsargumente):
def mathFunc(a, b):
r1 = a - b
r2 = a / b
return r1, r2
c, d = mathFunc(b=3, a=5) # Schlüsselwortargumente
e, f = mathFunc(3, 5) # Positionsargumente
print(c)
print(d)
print(e)
print(f)
Ausgabe:
2
1.6666666666666667
-2
0.6
Durch die Verwendung von Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge angegeben werden. Bei den Positionsargumenten ist die Reihenfolge vorgegeben. Daraus resultiert auch der Unterschied bei den obigen Ausgaben. Werden beide Arten in einem Aufruf gemischt, so müssen die Positionsargumente zuerst angegeben werden. Den Unterschied zwischen beiden Argumentarten zu kennen ist wichtig, nicht nur bei selbst erstellten Funktionen. Auch beim Aufruf von Python-Funktionen verfolgt einen die Mischung von Schlüsselwort- und Positionsargumenten auf Schritt und Tritt, z.B. beim etwas später folgenden Abschnitt über "Grafiken zeichnen":
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
Bei dieser <code>plot</code>-Funktion aus dem Modul <code>matplotlib.pyplot</code> sind <code>x</code> und <code>y1</code> Positionsargumente. <code>label, lw</code> und <code>ls</code> sind die Namen der Schlüsselwortargumente. Die Schlüsselwortargumente könnten auch in anderer Reihenfolge angeschrieben werden, nicht jedoch die Positionsargumente!
Siehe zu <code>matplotlib.pyplot.plot</code> auch die Seite [https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html].
== Lambda-Funktionen ==
print((lambda a, b: a*b) (3, 5))
Ausgabe:
15
Eingeleitet wird eine Lambda-Funktion (auch Lambda-Form, Lambda-Operator oder anonyme Funktion genannt) mit dem Schlüsselwort <code>lambda</code>. Es folgen die formalen Argumente, danach ein Doppelpunkt, die Berechnungsvorschrift und ggf. abschliessend in Klammern die aktuellen Parameter.
Man kann einer Lambda-Funktion auch einen Funktionsnamen geben und die Funktion über diesen Namen aufrufen, z.B.
prod = lambda a, b: a*b
print(prod(3, 5))
Als Ausgabe wird wieder die Zahl 15 geliefert.
== Rekursive Funktionen ==
Funktionen können wiederum andere Funktionen aufrufen. Von einem rekursiven Funktionsaufruf spricht man, wenn die aufgerufene Funktion gleich der aufrufenden ist.
def printFunc(i):
if (i >= 5):
return
else:
print("Hallo Welt")
printFunc(i+1)
printFunc(1)
Ausgabe:
Hallo Welt
Hallo Welt
Hallo Welt
Hallo Welt
== Funktionsannotationen ==
Python ist sehr flexibel, was Typen angeht. Im Vorhergehenden haben wir generell keine Typangaben gemacht. Will man Typen angeben, so bietet Python das Konzept der Funktionsannotation.
def calcFunc(a: int, b: int) -> int:
return a+b
r1 = calcFunc(8, 9)
r2 = calcFunc(8.0, 9.0)
r3 = calcFunc("Hallo", "Welt")
print(r1)
print(r2)
print(r3)
Ausgabe:
17
17.0
HalloWelt
Jetzt sieht man auf den ersten Blick, welche Typen der Programmierer im Sinn hatte, als er die Funktion erstellte. Das Problem dabei ist nur, dass es Python ziemlich egal ist, welche Typen man im Endeffekt eingibt. Im obigen Beispiel können statt Integer-Typen u.a. auch Float- oder String-Typen eingegeben werden.
<small>
Siehe zum Thema "Type Checking" aber auch den später folgenden Abschnitt [[Ing_Mathematik:_Python#Type_Checker]].
</small>
== Variadische Funktionen ==
Python-Code:
def test1(a, *b):
print(a);
for c in b:
print(c);
test1("Hallo", "Welt", "Schweizer", "und alle anderen")
Ausgabe:
Hallo
Welt
Schweizer
und alle anderen
Mit dem Stern (auch als Splat-Operator bezeichnet) in der formalen Parameterliste bei der Funktion <code>test1</code> wird angezeigt, dass eine beliebige Anzahl von Argumenten übergeben wird. <small> Dies entspricht in etwa dem, was in anderen Programmiersprachen (PHP etc.) mittels Ellipse (<code>...</code>) angezeigt wird.</small>
= Tupel, Listen und andere =
[[Datei:Python 3. The standard type hierarchy.png|mini|hochkant=1.7|Datentypen und Strukturen]]
== Tupel und Listen ==
Tupel, Listen und einige andere sind Datenstrukturen oder Sequenzen.
Listen (z.B. eine Einkaufsliste) sind veränderbar (mutable). Ein Tupel kann dagegen nicht verändert werden (immutable). Listen werden beim Anlegen in eckige Klammern eingeschlossen, Tupel in runde Klammern. Beim Tupel können die Klammern auch weggelassen werden. Ein Tupel mit nur einem Element muss mit einem Beistrich abgeschlossen werden. Der Grund ist, dass Python sonst nicht entscheiden kann, ob ein Tupel angelegt werden soll, oder nur ein geklammerter Wert.
Als Gedächtnisstütze kann man sich den Unterschied zwischen Tupel und Liste ev. so leichter merken:
: T'''u'''pel ... r'''u'''nde Klammern, '''u'''nveränderlich
: L'''i'''ste ... eck'''i'''ge Klammern, veränderl'''i'''ch.
Nachfolgend werden einige Operationen mit Listen und Tupel dargestellt.
# Liste und Tupel
liste = [1, 2, "Hallo"]
tupel = (1, 2, "Hallo")
# Ausgabe von liste und tupel
print(liste)
print(tupel)
# Ausgabe von Einzelelementen
print(liste[1])
print(tupel[2])
# Element an Liste anhängen und einfügen
liste.append(55)
liste.insert(4, "Welt")
print(liste)
# Element aus Liste entfernen
liste.remove(1)
print(liste)
# einige weitere Beispiele
liste2 = [1,]
tupel2 = 1, 2
tupel3 = (1,)
print(liste2)
print(tupel2)
print(tupel3)
Ausgabe:
[1, 2, 'Hallo']
(1, 2, 'Hallo')
2
Hallo
[1, 2, 'Hallo', 55, 'Welt']
[2, 'Hallo', 55, 'Welt']
[1]
(1, 2)
(1,)
Beispiel (eine Liste von Wörtern zu einem einzigen zusammenhängenden Text verbinden):
woerter = ["Hallo", "Welt"]
satz = " ".join(woerter)
print(satz)
Ausgabe:
Hallo Welt
== Dictionaries und Mengen ==
Zu den Datenstrukturen gehören weiters auch Mengen und Dictionaries. Mengen sind von der Mathematik bekannt, sie sind ungeordnet und es kommen keine mehrfachen Elemente vor. Dictionaries sind durch Schlüssel :Wert-Paare gekennzeichnet. Mengen werden beim Anlegen wie Dictionaries in geschweifte Klammern eingeschlossen.
dict = {"vorname":"Hugo", "nachname":"Meister" }
menge = {1, 1, 3, 4, 4, 4, "Hallo"}
print(dict)
print(menge)
print(dict["vorname"])
Ausgabe:
{'vorname': 'Hugo', 'nachname': 'Meister'}
{1, 3, 4, 'Hallo'}
Hugo
Geschweifte Klammern ohne Inhalt stellen Dictionaries dar und keine Mengen:
di = {}
print(type(di))
Ausgabe:
<class 'dict'>
Leere Mengen lassen sich mit <code>set()</code> erzeugen:
menge = set() # leere Menge
print(menge)
menge.add("Hallo") # Element hinzufügen
print(menge)
Ausgabe:
set()
{'Hallo'}
Beispiel (einige Mengenoperationen):
mengeA = {"Hallo", "Welt"}
mengeB = {1, 2, "Welt", 3}
# Vereinigung
print(mengeA | mengeB)
print(mengeA.union(mengeB))
# Durchschnitt
print(mengeA & mengeB)
print(mengeA.intersection(mengeB))
# Differenz
print(mengeA - mengeB)
print(mengeA.difference(mengeB))
# Symmetrische Differenz
print(mengeA ^ mengeB)
print(mengeA.symmetric_difference(mengeB))
# Teilmenge
print(mengeA.issubset(mengeB))
# Mehrere Elemente hinzu
mengeA.update(["Super", 67, 125])
print(mengeA)
# Element löschen
mengeA.discard("Hallo")
print(mengeA)
Ausgabe:
{1, 2, 3, 'Welt', 'Hallo'}
{1, 2, 3, 'Welt', 'Hallo'}
{'Welt'}
{'Welt'}
{'Hallo'}
{'Hallo'}
{1, 2, 3, 'Hallo'}
{1, 2, 3, 'Hallo'}
False
{67, 'Super', 'Welt', 'Hallo', 125}
{67, 'Super', 'Welt', 125}
Es gibt schon seit "ewigen" Zeiten unveränderbare Mengen, die mittels <code>frozenset</code> eingeleitet werden. Neu ab Python 3.15 ist dagegen das Pendant <code>frozendict</code>, das unveränderbare Dictionaries darstellt.
fdict = frozendict({"vorname":"Hugo", "nachname":"Meister"})
fset = frozenset({"A", 1, "A"})
print(fdict)
print(fdict["vorname"])
print (fset)
try:
fdict["vorname"] = "Max"
print(fdict["vorname"])
except TypeError as e:
print(f"Fehler: {e}")
try:
fset.add("B")
print(fset)
except AttributeError as e:
print(f"Fehler: {e}")
Ausgabe:
frozendict({'vorname': 'Hugo', 'nachname': 'Meister'})
Hugo
frozenset({1, 'A'})
Fehler: 'frozendict' object does not support item assignment
Fehler: 'frozenset' object has no attribute 'add'
== List Comprehensions ==
Aus einer Eingabeliste soll eine Ausgabeliste erzeugt werden. Das kann folgendermaßen geschehen.
Mathematische Schreibweise: <math>lc = \{2x|x\in\ \mathbb{N}, 1\le x < 11\}</math>
Python-Code:
lc = [x*2 for x in range(1,11)]
print(lc)
Ausgabe:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Mathematische Schreibweise: <math>lc = \{2x | x \in \mathbb{N}, 1\le x < 11, x \bmod 2 = 0 \}</math>
Python-Code:
lc = [x*2 for x in range(1,11) if x%2 == 0]
print(lc)
Ausgabe:
[4, 8, 12, 16, 20]
Siehe auch {{W|List Comprehension}}.
== Set Comprehensions ==
Dies ist sehr ähnlich wie im vorigen Abschnitt beschrieben. Es wird aber keine Liste, sondern eine Menge erzeugt.
sc = {x*2 for x in range(1,11)}
print(sc)
Ausgabe:
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
== Listen zusammenführen - zip() ==
li1 = ["A", "B", "C", "D"]
li2 = [1, 2, 3, 4]
li3 = [5.5, 6.6, 7.7, 8.8]
z = zip(li1, li2, li3)
print(z)
li4 = list(z)
print(li4)
Ausgabe:
<zip object at 0x00000283B6C6AC80>
[('A', 1, 5.5), ('B', 2, 6.6), ('C', 3, 7.7), ('D', 4, 8.8)]
== Generatorausdruck ==
g = (i*2 for i in range(1,11))
print(g)
t = tuple(g)
print(t)
print(t[1:3])
Ausgabe:
<generator object <genexpr> at 0x00000241D2A4A5A0>
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
(4, 6)
== Slicing ==
slice ... Scheibe, Teil, in Scheiben schneiden
Beispiel: Zugriff auf Elemente eines geordneten sequentiellen Objekttyps (Liste, Tupel oder String):
str1 = "Hallo"
# Das erste Element wird mit dem Index 0 angesprochen
# [start (inkl.) : stop (exkl.) : step (default=1)]
str2 = str1[0:2]
# Alternativ auch: str2 = str1[:2]
print(str2)
tup1 = (0,1,2,3)
# Das letzte Element hat auch den Index -1, das vorletzte den Index -2 usw.
tup2 = tup1[-3:-1]
print(tup2)
lst1 = [[1, 5, 10, 20],
[30, 40, 50, 60]]
lst2 = lst1[1][1]
print(lst2)
Ausgabe:
Ha
(1, 2)
40
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2])
print(x[-3])
print(x)
print(x[:])
print(x[2:])
print(x[:2])
print(x[::-1])
Ausgabe:
c
c
('a', 'b', 'c', 'd', 'e')
('a', 'b', 'c', 'd', 'e')
('c', 'd', 'e')
('a', 'b')
('e', 'd', 'c', 'b', 'a')
Visualisierung:
'''a''' '''b''' '''c''' '''d''' '''e'''
+-----------------------------+
| 0 | 1 |//'''2'''//| 3 | 4 |
+-----------------------------+
| -5 | -4 |/'''-3'''//| -2 | -1 |
+-----------------------------+
|/////////////////////////////|
+-----------------------------+
|/////////////''':'''///////////////|
+-----------------------------+
| | |///////'''2:'''////////|
+-----------------------------+
|////''':2'''/////| | | |
+-----------------------------+
|\\\\\<--\\\\\'''::-1'''\\\\<--\\\\\|
+-----------------------------+
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2::2])
print(x[2::-1])
print(x[2:0:-1])
Ausgabe:
('c', 'e')
('c', 'b', 'a')
('c', 'b')
Hier sieht man sehr schön, dass beim letzen <code>print</code>-Befehl die 0, die in diesem Fall den Buchstaben "a" repräsentiert, als letzer Wert nicht mehr dazugehört (wie weiter oben angedeutet ist der End- oder Stoppwert exklusiv). Will man den Buchstaben "a" dazunehmen, so ist die vorletzte Zeile die richtige.
Beispiel: Umdrehen von Strings
str1 = "Hallo"
str2 = str1[::-1]
print(str2)
Ausgabe:
ollaH
Mit zweidimensionalen Listen/Tupels wird das Ganze schon bedeutend komplexer.
Beispiel: Verkettetes Slicing
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
print(A[2::][::2])
Ausgabe:
[['20', '21', '22', '23'], ['40', '41', '42', '43']]
Das erste Slicing erstellt folgenden Slice:
[["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
Das zweite Slicing wird dann auf diesen Slice angewendet und ergibt das genannte Endergebnis. Will man Spalten statt Zeilen, so funktioniert dieser direkte Weg nicht. Man verwendet dann List Comprehensions oder die NumPy-Bibliothek. Diese Bibliothek erlaubt zweidimensionales Slicing. Sie wird erst später bei den Grafiken eingeführt. Deshalb wird hier dazu noch kein Beispiel gezeigt.
= Objektorientierte Programmierung =
{{Wikipedia|Objektorientierte Programmierung}}
* {{W|Klasse (Objektorientierung)|Klasse}} ... die Schablone oder der Bauplan, enthält Methoden und Attribute
* {{W|Objekt (Programmierung)|Objekt}} ... eine Klasseninstanz (die konkrete Ausprägung der Klasse)
* {{W|Attribut (Programmierung)|Attribute}} ... die Eigenschaften eines Objekts
* {{W|Methode (Programmierung)|Methoden}} ... die Aktionen (Operationen), die ein Objekt ausführen kann
* {{W|Vererbung (Programmierung)|Vererbung}} ... neue Klassen (Subklassen, Unterklassen, abgeleitete Klassen) aus vorhandenen Klassen (Superklassen, Oberklassen, Basisklassen, Elternklassen) ableiten. Ermöglicht den Aufbau von Klassenhierarchien. Die Subklasse "erbt" Attribute und Methoden von der Superklasse. Python unterstützt (so wie C++, aber im Gegensatz zu Java) Mehrfachvererbung.
== UML ==
* {{W|Unified Modeling Language|UML}} ... '''U'''nified '''M'''odeling '''L'''anguage, eine Modellierungssprache. Die UML enthält zahlreiche Diagrammarten, um Programme zu modellieren. Im Nachfolgenden wird nur das {{W|Klassendiagramm}} verwendet.
[[File:UmlCd Klasse-3.svg|300px]]
* {{W|Sichtbarkeit (Programmierung)|Sichtbarkeit}}:
** + ... public (öffentlich)
** - ... private
** # ... protected
* {{W|Attribut_(UML)#Attribute_für_Instanzen_und_für_Klassen|Klassenattribute}} (statische Attribute): Werden nur einmal pro Klasse angelegt. Im Klassendiagramm werden sie unterstrichen.
[[File:Attribute-3.png|200px]]
* Vererbung:
<gallery>
InheritancePgmUML.svg | Abgeleitete Klasse erbt von Basisklasse (Einfachvererbung)
Diamond inheritance.svg | D erbt von B und C (Mehrfachvererbung). B und C erben von A (Einfachvererbung)
</gallery>
Für weitergehende Betrachtungen zur UML wird auf Spezialliteratur verwiesen, z.B.:
* Seidl et al.: UML@Classroom. dpunkt, 2012, ISBN 978-3-89864-776-2
* Rupp et al.: UML 2 glasklar. Hanser, 4. Aufl., 2012, ISBN 978-3-446-43057-0
== Eine einfache Klasse ==
[[Datei:PythonIng_uml1.svg | 200px]]
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
fahr = Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die Klasse Fahrzeug wird durch das class-Schlüsselwort eingeleitet. raeder ist ein Klassenattribut und public. __init__ wird bei der Objekterzeugung automatisch aufgerufen (ist der sogenannte Konstruktor). Man achte darauf, dass diese Methode immer mit zwei Unterstrichen eingeleitet und abgeschlossen wird. Instanzattributen wird das Wort self vorangestellt. Wir sehen uns z.B. das Attribut self.__geschwind an. Auch hier werden zwei Unterstriche verwendet. Das bedeutet, dass dieses Attribut strikt/stark private ist. Wird nur ein Unterstrich verwendet, so deutet dies auf schwach/weakly private hin. Letzteres wird in Python deutlich häufiger verwendet. Bei den Methoden wird immer self als erster Parameter angegeben. Beim Aufruf der entsprechenden Funktion wird das self aber nicht berücksichtigt.
Besonderheiten bei stark und schwach private:
* '''stark private''':
** zwei führende Unterstriche
** Name Mangling: Name wird zu <code>_Klassenname__variablenname</code>
** Schutz vor Namenskollisionen bei Vererbung
** am Ende des Namens dürfen keine zwei Unterstriche verwendet werden. Das wären dann Magic Methods oder Dunder-Methods (z.B. __init__). Diese sind public.
* '''schwach private''':
** ein führender Unterstrich
** Name bleibt gleich
** ist nur ein Hinweis an die Programmierer, kein starker Schutz
** <code>from modul import *</code>: Objekte mit einem führenden Unterstrich werden standardmäßig nicht importiert
** Standard für die Kapselung bei Python. Schätzung: Weit mehr als 80% der nicht-öffentlichen Attribute/Methoden werden als schwach private deklariert. Weniger als 5-10% als stark private (Quelle: Google KI)
== Klassen importieren ==
Häufig ist es sinnvoll und übersichtlicher Klassen in eigenen Dateien zu speichern. Das sind dann eigene Module. Abgespeichert werden Sie mit der Endung py, wie bisher auch praktiziert. Aufgerufen werden Sie mit der import-Anweisung. Dann ist aber nur der Dateiname ohne Endung py zu verwenden. Klarer wird das mit einem Beispiel.
Datei c:\tmp\fahrzeug.py
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
Datei c:\tmp\test1.py
import fahrzeug
fahr = fahrzeug.Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die üblichen import-Anweisungen lauten wie folgt:
{| {{prettytable}}
! import-Befehl
! Instanz
|-
| import xyz || xyz.Klasse
|-
| import xyz as x || x.Klasse
|-
| from xyz import Klasse || Klasse
|-
| from xyz import * || Klasse
|}
Der Vorteil der ersten beiden import-Anweisungen ist, dass es kaum zu Namenskollisionen kommen kann. Dafür hat man bei den letzten beiden Varianten weniger Tipparbeit.
== Vererbung ==
=== Einfachvererbung ===
[[Datei:PythonIng_uml2.svg | 200px]]
Datei fahrzeug.py:
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
class Luftfahrzeug(Fahrzeug):
def __init__(self, geschwindigkeit, leistung, fluegel):
super().__init__(geschwindigkeit, leistung)
self.__flueg = fluegel
def getFlueg(self):
return self.__flueg
Datei test1.py:
import fahrzeug
fahr = fahrzeug.Luftfahrzeug(150, 90, 4)
print(fahr.getFlueg())
Ausgabe:
4
=== Mehrfachvererbung ===
Mit Python ist auch Mehrfachvererbung möglich, z.B.:
class A:
def _printA(self):
print("Klasse A")
class B:
def _printB(self):
print("Klasse B")
class C(A,B):
def __init__(self):
self._printA()
self._printB()
c = C()
Ausgabe:
Klasse A
Klasse B
Die Klasse C erbt von A und B. In UML sieht das in etwa so aus:
+-----------------------------+ +-------------------------+
| A | | B |
+-----------------------------+ +-------------------------+
| | | |
+-----------------------------+ +-------------------------+
| # printA() | | # printB() |
+-----------------------------+ +-------------------------+
. .
/ \ / \
--- ---
| |
| |
+---------------------+
| C |
+---------------------+
| |
+---------------------+
| |
+---------------------+
<code>printA()</code> und <code>printB()</code> sind schwach private (in UML als <code>protected</code> mit einem # dargestellt). Es ist aber zu beachten, dass schwach private nur Konvention ist. Praktisch könnte man auch von außerhalb auf diese Methoden zugreifen. Das soll man aber nicht tun, und das wird in Python durch einen Unterstrich angedeutet.
= Grafiken zeichnen =
Für das Zeichnen von Grafiken wird hier das Modul <code>matplotlib</code> verwendet. <code>matplotlib</code> ist ein externes Modul und muss vor der ersten Verwendung installiert werden. Das geht so:
# Starten Sie ein Terminal (bei Windows die Eingabeaufforderung).
# Führen Sie darin folgenden Befehl aus <code>c:\devel\Python\Scripts\pip.exe install matplotlib</code>
pip ist übrigens der Paketmanager von Python ({{W|Pip_(Python)}}).
Optimalerweise installieren wir auch gleich das Modul <code>numpy</code> (Numerical Python). Wir werden es im Folgenden oft benötigen (nicht nur bei den Grafiken). Das funktioniert vom Prinzip her genauso, wie für <code>matplotlib</code> gezeigt.
<small>Verwenden Sie Spyder, so sind diese Schritte nicht nötig. Spyder inkludiert diese Pakete standardmäßig. Unter openSUSE Tumbleweed lassen sich diese Pakete mittels YaST oder zypper installieren.</small>
== 2D ==
=== Graph einer Funktion ===
Es soll die cosh-Funktion im Intervall <math>x\in[-3,3]</math> gezeichnet werden. Der Programmcode lautet in der einfachsten Form:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x)
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh1.jpg]]
Der Code ist quasi selbsterklärend. Das Untermodul pyplot des matplotlib-Moduls und das numpy-Modul werden importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plt.plot()" ist der Zeichenbefehl. "plt.show" ist notwendig, um das Fenster mit der Grafik anzuzeigen.
Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen. "plt.grid()" zeichnet ein Gitter in die Grafik (kann auch weggelassen werden).
Die Bezeichnungen plt und np könnten auch anders gewählt werden. Es ist aber Konvention, diese so wie hier gezeigt zu wählen. Die "arange"-Funktion aus der NumPy-Bibliothek wird später ein bisschen genauer behandelt (siehe [[Ing_Mathematik:_Python#Zahlenfolgen|Zahlenfolgen]]).
<small>Mit der im obigen Bild gezeigten Menüleiste kann die dargestellte Grafik nachträglich noch geändert werden (Zoom, Pan, Achsenparameter, Kurvenparameter etc.). Natürlich kann man das alles auch direkt programmieren. Wie das funktioniert wird ansatzweise etwas später gezeigt.</small>
Ein etwas komplexeres Beispiel ist Folgendes:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x) + 2**x
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh4.png]]
Man beachte, dass im Gegensatz zu Octave und Julia der ominöse Punkt (.) bei 2**x mit Python nicht benötigt wird. Das macht das Programmiererleben etwas einfacher.
Die Farbe des Graphen kann man über den <code>color</code>-Schalter einstellen, z.B. auf rot setzen:
plt.plot(x, y, color="red")
Das ist nur eine Möglichkeit, es gibt auch andere, z.B. mittels
* hexadezimaler Zahl, z.B. <code>color="#ff0000"</code>
* Kurzform, z.B. <code>"r"</code>
Statt <code>color</code> kann auch die Kurzform <code>c</code> verwendet werden.
<u>Kleine Aufgabe:</u> Probieren Sie diese "Farbspielereien" am Computer aus.
=== Graphen mehrerer Funktionen und weiteres ===
==== Mehrere Funktionen in einen Plot zeichnen ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x")
plt.plot(x, y2, label = "sin(x) * cos(x)")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh2.png]]
Um die Linienstile etwas individueller zu gestalten, ist folgender Programmcode gedacht:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
plt.plot(x, y2, label = "sin(x) * cos(x)", lw=3, ls="--")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh3.png]]
Einige weitere Bespiele zu <code>ls</code></code>:
* - ... durchgezogene Linie
* -. ... Strichpunkt-Linie
* dashed ... gestrichelte Linie
==== Marker ====
Desweiteren kann man Marker verwenden.
Beispiel:
import matplotlib.pyplot as plt
plt.plot(10, 10, "ob", markersize=30)
plt.plot(20,20, ".r")
plt.plot(30,30, "Dg", ms=15)
plt.plot(40, 40, "ok", ms=20, mec="#FF5733", mew=3)
plt.plot(50, 50, "vk", ms=20, mec="yellow", mew=3)
plt.grid()
plt.show()
Das erste Zeichen im String nach den Koordinaten im plot-Befehl symbolisiert die Form (z.B. o für einen Kreis). Das zweite Zeichen steht für die Farbe (z.B. b für blue). <code>markersize</code> oder <code>ms</code> setzt die Größe des Markers.
Ausgabe:
[[Bild:PythonIng_formatpara1.svg|200px]]
Einige weitere Marker:
* * ... Stern
* + ... Plus
* h oder H ... Sechseck
Man kann mit den Parametern
* <code>markeredgecolor</code> oder kurz <code>mec</code> die Farbe des Markerrandes
* <code>markeredgewidth</code> oder kurz <code>mew</code> die Dicke des Randes
* <code>markerfacecolor</code> oder kurz <code>mfc</code> die Innenfarbe des Markers
bestimmen.
=== Funktion in Parameterdarstellung ===
Es soll die archimedische Spirale <math>x = t \cos(t), y = t \sin(t)</math> im Intervall <math>[0, 6\pi[</math> gezeichnet werden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.show()
[[Datei:PythonIng_spirale1.png]]
Diese Darstellung erscheint verzerrt. Will man gleiche Achsenskalierungen, so kann man den plt.axis()-Befehl verwenden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.axis("equal")
plt.show()
[[Datei:PythonIng_spirale2.png]]
=== Funktion in Polardarstellung ===
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
r = np.arange(0, 1, 0.01)
theta = r**3
line = ax.plot(theta, r)
plt.show()
[[Datei:PythonIng_polar1.png]]
=== Logarithmische Achsenskalierung ===
==== Semilog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.semilogy()
plt.show()
Ausgabe:
[[Datei:PythonIng_semilog1.png]]
==== LogLog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.loglog()
plt.show()
[[Datei:PythonIng_loglog1.png]]
=== Gefüllte Fläche ===
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 3, 0.1)
y1 = 3*x - 1
y2 = x**2
plt.plot(x, y1, x, y2, color='black')
plt.fill_between(x, y1, y2, where=y1>=y2)
plt.show()
[[Datei:PythonIng_gefuellt.png]]
=== Linien, Pfeile, Rechtecke, Kreise und Texte ===
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
r = mpl.patches.Rectangle((0, 0), 3, 3, angle=30, fill=False)
c = mpl.patches.Circle((4, 4), 2, fill=False)
ax.add_patch(r)
ax.add_patch(c)
ax.plot([-2, 7], [-2, 0], color="black")
ax.arrow(0, 7, 5, 0, length_includes_head=True, head_width=0.5, head_length=1.5,
color="black")
ax.set_aspect("equal")
plt.axis([-3, 8, -3, 8])
plt.show()
[[Datei:PythonIng_linien_pfeile_etc.png]]
Text kann mit <code>ax.text(x, y, "Text")</code> hinzugefügt werden, bspw.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
ax.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
Oder einfacher auch ohne <code>subplots</code>
import matplotlib.pyplot as plt
plt.text(0.1, 0.1, "Hallo")
plt.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text1.png]]
Auch Sonderzeichen (griechische Buchstaben etc.) können verwendet werden (siehe dazu auch [https://matplotlib.org/stable/users/explain/text/mathtext.html]).
import matplotlib.pyplot as plt
plt.text(.3, .5,
r'$\Omega\ \psi\ \oint\ \nabla\ \dot a\ \frac{a}{b}\ a_b$',
size="20")
plt.show()
[[Datei:PythonIng_text20.svg]]
Jetzt wird noch gezeigt, wofür <code>subplots</code> sinnvoll eingesetzt werden können.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(0.1, 0.1, "Hallo")
ax[1].text(0.1, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text2.png]]
=== Anmerkungen hinzufügen ===
Anmerkungen (engl. annotations) lassen sich mit matplotlib einfach hinzufügen. Unter Anmerkung wird hier ein Pfeil mit Text verstanden.
Beispiel:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1,10], [1,10])
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0))
plt.show()
Ausgabe:
[[Datei: PythonIng_ann1.svg|400px]]
<code>shrink</code> verkürzt den Pfeil. Sinnvoll sind beim obigen Beispiel Werte irgendwo zwischen 0.0 und 0.3.
<u>Kleine Aufgabe:</u> Probieren Sie verschiedene Pfeillängen aus.
Die Schriftgröße verändern können Sie übrigens mit <code>fontsize</code> oder <code>size</code>, z.B.
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0), fontsize=25)
Eine andere Schreibweise für Dictionaries, die wir weiter oben schon kennengelernt haben, die wir aber nochmals explizit aufschreiben wollen, ist
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops={"facecolor":"red", "shrink":0.0})
=== Figure, Axes etc.===
[[Bild:PythonIng_figure33.svg|350px]]
* fig (figure) ... das übergeordnete Fenster
* ax (axes) ... "Plot", das eigentliche Zeichenfenster
* axis ... die Koordinatenachsen
* spine ... Begrenzungslinien des Zeichenfensters
* tick ... Markierung an den Achsen des Zeichenfensters
Beispiel (eine figure mit 6 axes, ax-Titel, y-axis-Titel):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=3, ncols=2)
ax[0][0].text(0.1, 0.5, "11")
ax[0][1].text(0.1, 0.5, "12")
ax[1][0].text(0.1, 0.5, "21")
ax[1][1].text(0.1, 0.5, "22")
ax[2][0].text(0.1, 0.5, "31")
ax[2][1].text(0.1, 0.5, "32")
ax[0][0].set(ylabel="y-label", title="axes 1")
plt.show()
[[Bild:PythonIng_figure34.png|350px]]
Beispiel (Achsenbereiche setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-1, 10, 1, 12))
plt.show()
[[Bild:PythonIng_figure35.svg|350px]]
Beispiel (Gitter einschalten):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-5, 10, 1, 12))
ax[0].minorticks_on()
ax[0].grid(which='minor')
ax[1].grid(which='major')
plt.show()
[[Bild:PythonIng_figure36.svg|350px]]
Beispiel (ticks setzen)
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
pos = [0, .2, .5]
lab = ["a", "b", "c"]
ax.xaxis.set_major_locator(tick.FixedLocator(pos))
ax.xaxis.set_major_formatter(tick.FixedFormatter(lab))
plt.show()
[[Bild:PythonIng_figure37.svg|350px]]
Beispiel (Achsenkreuz beliebig setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position(('data', 0.3))
ax.spines['left'].set_position(('data', 0.5))
plt.show()
[[Bild:PythonIng_figure38.svg|350px]]
Beispiel (Inset):
import matplotlib.pyplot as plt
# Hauptplot erstellen
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
# Inset hinzu:
axin = ax.inset_axes([0.4, 0.4, 0.3, 0.3])
axin.text(0, 0, "Servus")
axin.plot()
plt.show()
[[Bild:PythonIng_figure40.svg|350px]]
Beispiel (Hintergrundfarben setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_facecolor("green")
fig.set_facecolor("yellow")
plt.plot([1, 3], [6, 8])
plt.show()
[[Bild:PythonIng_figure39.svg|300px]]
=== GridSpec ===
Mit figures und axes lassen sich schon jede Menge an Grafikdetails einstellen. GridSpec ist dann der Turbo oder Raketenantrieb den matplotlib eingebaut hat. Naja, vielleicht ist das etwas übertrieben, aber GridSpec ist sozusagen ein flexibler Layout-Manager. Bisher haben wir immer gleich große axes gezeichnet. Mit GridSpec können wir Subplots über mehrere Zeilen und Spalten ziehen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(3, 3)
ax1 = fig.add_subplot(gs[0, :])
ax1.set_title("Bereich 1: gs[0, :]")
ax2 = fig.add_subplot(gs[1:, 0])
ax2.set_title("Bereich 2: gs[1:, 0]")
ax3 = fig.add_subplot(gs[1, 1:])
ax3.set_title("Bereich 3: gs[1, 1:]")
ax4 = fig.add_subplot(gs[2, 1:])
ax4.set_title("Bereich 4: gs[2, 1:]")
plt.show()
[[Bild:PythonIng_gridspec1.svg|350px]]
Erklärung zu <code>(gs[zeile, spalte])</code>: Slicing; damit legen Sie fest, welche Zellen ein Subplot belegt. Achtung! Die Indizes beginnen bei 0 und nicht bei 1 (d.h., die erste Zeile/Spalte hat den Index 0)
* : ... alle
* 1: ... 1 bis Ende
* etc.
<code>constrained_layout=True</code> sorgt dafür, dass sich die Subplots nicht überlappen.
Aber auch die Spaltenbreiten und Zeilenhöhen lassen sich anpassen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
# Verhältnis erste zu zweite Zeile = 1.5:1
# Verhältnis erste zu zweite Spalte = 1:4
gs = fig.add_gridspec(2, 2, figure=fig, height_ratios=[1.5, 1], width_ratios=[1, 4])
ax1 = fig.add_subplot(gs[0, 0])
ax1.set_title("Bereich 1: gs[0, 0]")
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_title("Bereich 2: gs[0, 0]")
ax3 = fig.add_subplot(gs[1, 0])
ax3.set_title("Bereich 3: gs[1, 0]")
ax4 = fig.add_subplot(gs[1, 1:])
ax4.set_title("Bereich 4: gs[1, 1]")
plt.show()
[[Bild:PythonIng_gridspec2.svg|350px]]
Auch die Ränder lassen sich einstellen.
Beispiel 1:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.1, right=0.9, bottom=0.1,
top=0.9, wspace=0.2, hspace=0.2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec3.svg|300px]]
* hspace ... height space, vertikaler Abstand zwischen den Zeilen
* wspace ... width space, horizontaler Abstand zwischen den Spalten
Und im Vergleich dazu Beispiel 2:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.3, right=0.7, bottom=0.3,
top=0.7, wspace=0.3, hspace=0.3)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec4.svg|300px]]
Es gibt noch einige weitere Details, die sich mit GridSpec variieren lassen (z.B. SubGridSpec ... verschachtelte Grid-Layouts). Aber wir belassen es vorerst dabei. Das bisher Gezeigte sollte für die meisten Probleme ausreichend sein.
=== Aufgaben ===
* Zeichnen Sie die Strophoide <math>x = \frac{a(t^2-1)}{t^2+1}, y = \frac{at(t^2-1)}{t^2+1}, a = 2, -3 \leq t \leq 3</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_strophoide.jpg|300px|center]]
* Zeichnen Sie die verschlungene Hypozykloide <math>x = (R-r)\cos t + c\cos\frac{R-r}{r}t, y = (R-r)\sin t - c\sin\frac{R-r}{r}t, c = 3, r = 2, R = 6, -15 \leq t \leq 15</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_hypozykloide.jpg|300px|center]]
* Testen Sie bei den obigen Übungsaufgaben verschiedene Linienstile und Farben. Farben können mit dem plt.plot()-Parameter color gewählt werden.
* Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.
* Zeichnen Sie folgendes Bild (die Achsenbeschriftungen positionieren Sie z.B. mit den Befehlen <code>ax.set_xlabel("x", loc="right"); ax.set_ylabel("y", loc="top")</code>):
[[Bild:PythonIng_aufgabe24.svg|400px|center]]
* Zeichnen Sie mit Python, matplotlib und NumPy folgendes Bild:
[[Bild:PythonIng_figure41.svg|400px|center]]
* Zeichnen Sie mit GridSpec ein Layout, das in etwa wie folgendes aussieht (<code>height_ratios=[1, 2], width_ratios=[2, 1]</code>):
[[Bild:PythonIng_aufgabe23.svg|300px|center]]
== 3D ==
=== Räumliche Kurven ===
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0, 6*np.pi, 0.1)
x = t * np.cos(t)
y = t * np.sin(t)
z = t
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot(x, y, z)
plt.show()
[[Datei:PythonIng_raumkurve1.png]]
=== Flächen ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z)
plt.show()
[[Datei:PythonIng_fläche1.png]]
Das Ganze in Netzdarstellung läßt sich so programmieren:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = np.arange(0, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_wireframe(x, y, z)
plt.show()
[[Datei:PythonIng_fläche2.png]]
Ein etwas komplexeres Beispiel:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.1, 10, 0.1)
y = np.arange(0.1, 10, 0.1)
x, y = np.meshgrid(x, y)
z1 = np.sin(x) + 3 * np.cos(y)
z2 = np.sin(x) + np.log(y)
z3 = x + np.cos(y)
z4 = x**2 - y
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, nrows=2, ncols=2)
ax[0][0].plot_surface(x, y, z1)
ax[0][1].plot_surface(x, y, z2)
ax[1][0].plot_surface(x, y, z3)
ax[1][1].plot_surface(x, y, z4)
plt.show()
[[Datei:PythonIng_subplot1.png]]
Man beachte, dass man die Unterbilder im Bild nach dem Ausführen des Scripts z.B. mit der mittleren Maustaste einzeln drehen, oder über die Einträge in der Menüzeile einzeln bearbeiten kann. Mit ein paar Zeilen Programmtext lässt sich also eine Menge an Funktionalität generieren.
Die Farbgebung lässt sich über <code>colormaps</code> variieren.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm)
plt.show()
[[Datei:PythonIng_colormap1.png]]
Es gibt eine Menge an Colormaps, z.B. <code>plasma, Greys, Dark2, ocean</code>. Zwecks detaillierterer Infos siehe die matplotlib-Dokumentation. <small>Verwendet man die IDE namens IDLE, so gibt es dort auch die automatische Codevervollständigung. D.h. es werden alle Möglichkeiten (in unserem Fall nach dem Eintippen von <code>cm.</code> alle verfügbaren Colormaps) angezeigt.</small>
Die "edgecolor" und Linienbreite können auch frei gewählt werden:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm, edgecolor="black", linewidth=1.0)
plt.show()
[[Datei:PythonIng_colormap2.png]]
=== Höhenlinien ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
ax.contour(x, y, z)
plt.show()
[[Datei:PythonIng_höhenlinien1.png|400px]]
Etwas abgewandelt sieht das so aus:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contour(x, y, z)
ax.clabel(hl, inline = True)
plt.show()
[[Datei:PythonIng_höhenlinien2.png|400px]]
Und noch eine Variante (mit einem Farbbalken) sei gezeigt.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contourf(x, y, z)
fig.colorbar(hl)
plt.show()
[[Datei:PythonIng_höhenlinien5.svg|400px]]
=== Aufgaben ===
* Zeichnen Sie die räumliche Kurve <math>x = 2 \cdot \cosh(t)</math>, <math>y = 5 \cdot \sin(t)</math>, <math> z = t^{2} - t</math>, <math>0 \leq t \leq 3\pi</math>.
* Zeichnen Sie die Fläche <math>z = \log(x) + \cos(y)</math>.
== Animationen und fortgeschrittenes 3D ==
=== Mit matplotlib ===
Auch mit matplotlib sind Animationen möglich. Das ist ein bisschen komplizierter und wird deshalb hier nur mit einem sehr einfachen Beispiel dargestellt (bei Interesse siehe z.B. auch das [https://matplotlib.org/stable/users/explain/animations/animations.html#animations Animations using Matplotlib-Tutorial]).
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib
import numpy as np
def update(frame):
line.set_xdata(x[:frame])
line.set_ydata(y[:frame])
return (line)
fig, ax = plt.subplots()
x = np.arange(0, 10, .1)
y = np.sin(x)
line, = ax.plot(x[0], y[0])
ax.set(xlim=[0, 10], ylim=[-1, 1])
a = ani.FuncAnimation(fig=fig, func=update, frames=100, interval=20)
plt.show()
# Speichere die Animation in einem animierten GIF (optional)
a.save(filename="c:/tmp/PythonIng_anim5.gif", writer="pillow")
[[Datei:PythonIng_anim5.gif]]
Es wird eine Sinuskurve auf den Bildschirm gezeichnet. In der letzten Zeile wird diese Animation in ein animiertes GIF gespeichert. Das ist natürlich optional und kann auch weggelassen werden.
=== Mit VPython ===
Aber auch mit dem Modul VPython lassen sich einfache 3D-Animationen erstellen. VPython ist ein externes Modul, das vorab installiert werden muss. Unter openSUSE Tumbleweed gibt es dzt. kein entsprechendes rpm-Paket. Die übliche Methode der Installation mittels YaST oder zypper ist somit nicht möglich. Auch eine direkte Verwendung von pip führt nur zu einer Fehlermeldung (<code>error: externally-managed-environment</code>). Es empfiehlt sich dort folgende Vorgehensweise:
# Erstelle zuerst eine virtuelle Umgebung, z.B.: <code>python3.11 -m venv ~/tmp/venv1</code>
# Wechsle das Verzeichnis: <code>cd ~/tmp/venv1/bin</code>
# Installiere das entsprechende Paket: <code>./pip install vpython</code>
# Führe das entsprechende Skript aus: <code>./python ~/tmp/test1.py</code>
Aktuell (März 2026) ist dieses Programmpaket lt. der [https://vpython.org/presentation2018/install.html VPython-Homepage] nur für die Python-Versionen 3.8 bis 3.12 verfügbar.
Ein Beispiel zu einer einfachen Animation wird nachfolgend geliefert.
from vpython import *
scene.width = 1200
scene.height = 600
scene.center = vector(20,0,0)
scene.background = color.white
cylinder(pos=vector(0,0,0), axis=vector(20,0,0), radius=5,
color=color.blue)
cone(pos=vector(0,0,0), axis=vector(-10,0,0), radius=5,
color=color.blue)
helix(pos=vector(20,0,0), axis=vector(40,0,0), radius=2,
coils=10, thickness=0.5, color=color.blue)
ball = sphere(pos=vector(20,0,0), color = color.green, radius = 1)
ball.p = vector(0.15, 0, 0)
toc = True
while True:
rate(200)
if(ball.pos.x <= 60 and toc == True):
ball.pos += ball.p
else:
toc = False
ball.pos -= ball.p
if(ball.pos.x <= 20 and toc == False):
toc = True
[[Datei:PythonIng_vpython_anim.JPG]]
Idealerweise öffnet sich beim Ausführen des Scripts ein Browserfenster. Darin wird die programmierte Animation gezeigt (siehe auch den obigen Screenshot). Eine Größenänderung können Sie mit der mittleren Maustaste initiieren. Die Szenerie drehen können Sie mit der rechten Maustaste.
=== Mit build123d ===
Hiermit lassen sich einfach 3D-Modelle für CAD-Systeme erstellen. [https://build123d.readthedocs.io/en/latest/ build123d] ist ein externes Modul und muss vorab, wie schon für mehrere andere Module gezeigt, installiert werden (pip, venv etc.).
Beispielcode:
from build123d import *
# Bauteil
with BuildPart() as bauteil:
# Zylinder erstellen
Cylinder(100, 60)
# Bohrung
with BuildSketch(bauteil.faces().sort_by(Axis.Z)[-1]) as loch:
Circle(radius=10)
# negativ extrudieren
extrude(amount=-60, mode=Mode.SUBTRACT)
# Dem Bauteil z.B. die Farbe rot zuweisen
# bauteil.part.color = Color("red", alpha=1.0)
# Fertiges Modell exportieren
export_step(bauteil.part, "bauteil.step")
Ausgabe ({{W|Standard for the exchange of product model data | STEP}}-Datei, z.B. in {{W|FreeCAD}} importiert, Screenshot):
[[Datei:PythonIng_build123d.jpg | 300px]]
FreeCAD ist ein freies 3D-CAD-System. Die [[Ing_Mathematik:_Python#FreeCAD | Makroprogrammierung]] in diesem System wird später noch gezeigt. STEP steht für "'''St'''andard for the '''e'''xchange of '''p'''roduct model data" und ist ein Datenaustauschformat.
=== Mit VTK ===
Komplexer, aber auch mächtiger als VPython ist die Verwendung von VTK ('''V'''isualization '''T'''ool'''k'''it). Genauer gesagt des Python-Wrappers von VTK. Dieses externe Python-Modul muss vorab installiert werden (z.B. mittels YaST, pip oder in eine virtuelle Umgebung). VTK ist eine Softwarebibliothek zur 3D-Visualisierung und wurde ursprünglich in C++ geschrieben. Verbreitet eingesetzt wird diese Bibliothek in der Wissenschaft und Forschung, z.B.
* in der medizinischen Bildgebung
* für Strömungssimulationen
* für Klimadaten
VTK funktioniert nach dem {{W|Grafikpipeline|Pipeline-Prinzip}}:
Source (Quellen) -> Filter -> Mapper (Senken) -> Actor/Renderer
Daten fließen von den Quellen zu den Senken.
Als einfaches Beispiel wird die Darstellung eines Zylinders gezeigt, der mit den Maustasten gedreht oder in der Größe geändert werden kann:
import vtk
# Zylinder erzeugen
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
# Geometrie in darstellbare Daten umwandeln
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
# Objekt in der Szene
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Szene verwalten
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# Render-Fenster
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
# Maus/Tastatur-Steuerung
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Starten
render_window.Render()
interactor.Start()
Ausgabe:
[[Datei:PythonIng_VTK_1.png]]
Gleiches Beispiel wie oben, aber mit einer Animationssequenz:
import vtk
import time
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
render_window.Render()
time.sleep(0.01)
Das Grafikfenster schließt sich nach Ablauf der Schleife. Das Fenster bleibt geöffnet, wenn Sie am Programmende folgenden Befehl hinschreiben
interactor.Start()
Um den animierten Zylinder grün einzufärben, müssen Sie Folgendes im obigen Programm ergänzen (Farbnamen):
colors = vtk.vtkNamedColors()
actor.GetProperty().SetColor(colors.GetColor3d("Green"))
Als Namen können Sie u.a. die CSS3 Web-Farben verwenden (siehe z.B. [https://wiki.selfhtml.org/wiki/Farbe/Farbangaben] und {{W|Webfarbe#CSS_3}}).
Alternativ funktioniert auch das ({{W|RGB-Farbraum|RGB}}):
actor.GetProperty().SetColor(0.0, 0.6, 0.0)
Wie der Zylinder mit einer Textur versehen wird, zeigt folgendes Programm:
import vtk
import time
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(30)
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.CappingOn()
texture_coords = vtk.vtkTextureMapToCylinder()
texture_coords.SetInputConnection(cylinder.GetOutputPort())
texture_coords.PreventSeamOn()
reader = vtk.vtkJPEGReader()
reader.SetFileName("PythonIng_textur.jpg")
texture = vtk.vtkTexture()
texture.SetInputConnection(reader.GetOutputPort())
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(texture_coords.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.SetTexture(texture)
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
renderWindow.Render()
time.sleep(0.01)
interactor.Start()
<gallery>
PythonIng_textur.jpg | Textur-Datei
PythonIng_VTK_2.png | Ausgabe (Screenshot)
</gallery>
== Sonstige Grafikbibliotheken ==
=== Py5 ===
Im Buch ''Iacono et al.: Programmieren trainieren, mit über 150 Workouts in Java und Python; 3. Aufl., Hanser, 2023'' werden zahlreiche Aufgaben gestellt, die u.a. mit Processing zu lösen sind. Processing ist eine einfache Programmiersprache und Entwicklungsumgebung. Warum ich das erwähne? Weil in älteren Processing-Versionen auch die Programmiersprache Python 2 abgedeckt war. Bei neueren Versionen gibt es keine Python-Anbindung mehr. Somit funktioniert der Python-Teil im genannten Buch nicht mehr. Ist das tragisch, oder kann das Buch weggeschmissen werden? Nein! Es gibt Alternativen zu Processing. Zum einen die im Buch selbst genannten Bibliotheken tkinter oder pygame. Pygame wird dort auch kurz anhand eines Beispiels thematisiert. Aber noch besser ist es, die py5-Bibliothek zu verwenden (lt. Google KI vom 30. Sept. 2026: ''Der echte, moderne „spirituelle Nachfolger“''). Damit ist die Funktionalität von Processing gewährleistet. Man kann aber beliebige Editoren oder IDEs zur Programmerstellung verwenden, ohne an Processing als IDE gebunden zu sein. Nachfolgend werden ein paar Beispiele zu dieser externen Bibliothek gegeben. Der erste Schritt ist wieder, die py5-Bibliothek zu installieren (z.B. mittels pip in eine virtuelle Umgebung). Dann kann es schon mit dem Programmieren losgehen.
Beispiel (angelehnt an die ''Aufgabe W.2.3 Haus'' des genannten Buchs, jedoch etwas erweitert):
import py5
def setup():
py5.size(600, 600) # Fenstergröße 600px x 600px
py5.background(255, 255, 255) # Hintergrundfarbe ... weiss
def draw():
# Haus zeichnen
py5.fill(255, 255, 255) # Hintergrundfarbe ... weiss
py5.stroke(255, 0, 0) # Linienfarbe ... rot
py5.stroke_weight(3) # Linienbreite ... 3px
py5.rect(150, 200, 300, 300) # Rechteck zeichnen (x, y, b, h)
py5.triangle(150, 200, 300, 100, 450, 200) # Dreieck zeichnen
py5.circle(250, 300, 70) # Kreis zeichnen (x, y, d)
# Bemassung zeichnen
py5.stroke(0, 255, 0)
py5.stroke_weight(1)
py5.line(300, 100, 550, 100) # Linie zeichnen
py5.line(450, 200, 550, 200)
py5.line(450, 500, 550, 500)
py5.line(150, 500, 150, 550)
py5.line(450, 500, 450, 550)
py5.text_size(20) # Textgroesse
py5.fill(0, 255, 0) # Textfarbe
py5.text("300", 280, 550) # Text zeichnen
py5.text("100", 500, 150)
py5.text("300", 500, 350)
# Gedrehtes Rechteck zeichnen
py5.stroke(255, 255, 0)
py5.stroke_weight(3)
py5.fill(200, 200, 200)
py5.translate(320, 260)
py5.rotate(0.3) # Drehung (in Radiant)
py5.rect(0, 0, 100, 50)
# Startet den Sketch
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_1.png|300px]]
Das skizzierte Haus ist mit einer rudimentären Bemaßung versehen und hat zwei Fenster, ein rundes und ein gedrehtes, trübes rechteckiges.
Beispiel (Mausoperationen):
import py5
def setup():
py5.size(600, 600)
py5.background(255, 255, 255)
def draw():
pass
def mouse_pressed():
py5.text_size(15)
py5.fill(0, 0, 255)
x = py5.mouse_x
y = py5.mouse_y
py5.text("(%d, %d)" %(x, y), x, y) # Positionsdaten bei Maus-Klick schreiben
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_2.png|300px]]
Obiges Bild zeigt das Resultat nach einigen Mausklicks. Man erkennt, dass links-oben der Koordinatennullpunkt ist. Die x-Achse zeigt nach rechts, die y-Achse nach unten.
Beispiel (Fünfeck):
import py5
import random
def setup():
py5.size(400, 400)
py5.no_loop() # statisches Bild (schont die Ressourcen)
def draw():
py5.translate(py5.width / 2, py5.height / 2) # KS setzen
radius = 150
eck_anzahl = 5
py5.fill(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255)) # Füllfarbe auf Zufallswert setzen
py5.stroke(155, 0, 0)
py5.stroke_weight(5)
# Fünfeck als Polygon zeichnen
py5.begin_shape()
for i in range(eck_anzahl):
winkel = i * py5.TWO_PI / eck_anzahl - py5.HALF_PI
x = py5.cos(winkel) * radius
y = py5.sin(winkel) * radius
py5.vertex(x, y)
py5.end_shape(py5.CLOSE)
py5.run_sketch()
Ausgabe, bspw.:
[[Datei:PythonIng_py5_5.png|200px]]
<u>Kleine Aufgaben:</u>
* Um die Funktionsweise von <code>py5.no_loop()</code> zu verstehen, kommentieren Sie die Anweisung im Beispiel einfach aus, und starten Sie das Programm erneut.
* Zeichnen Sie ein Siebeneck.
* Was passiert, wenn man <code>py5.CLOSE</code> im <code>py5.end_shape()</code>-Befehl weglässt?
Beispiel (Grafik laden und zeichnen):
import py5
image1 = None
def setup():
global image1
py5.size(600, 600)
py5.no_loop()
image1 = py5.load_image("PythonIng_py5_1.png")
def draw():
py5.image(image1, 0, 0)
py5.run_sketch()
Hier wird einfach das Bild vom Haus-Beispiel (Screenshot von weiter oben) geladen und gezeichnet.
Hiermit belassen wir es mit der py5-Bibliothek und wenden uns wieder "mathematischeren" Themen zu.
= Vektoren und Matrizen =
== Zahlenfolgen ==
Für das Erstellen von Zahlenfolgen bieten sich die Funktionen <code>arange</code> und <code>linspace</code> aus dem <code>numpy</code>-Modul an.
from numpy import *
start = 0
stop = 10
step = 2
num = 10
r = arange(start, stop, step) # step ... Schrittweite
l = linspace(start, stop, num) # num ... Anzahl der Werte
print("r = ", r)
print("l = ", l)
Ausgabe:
r = [0 2 4 6 8]
l = [ 0. 1.11111111 2.22222222 3.33333333 4.44444444 5.55555556
6.66666667 7.77777778 8.88888889 10. ]
Bei <code>arange</code> ist der <code>stop</code>-Wert nicht im Ergebnis enthalten, bei <code>linspace</code> standardmäßig aber sehr wohl. Jedoch kann man das bei <code>linspace</code> auch ändern. Dann ist der Stoppwert nicht mehr enthalten:
linspace(start, stop, num, endpoint=False)
== Vektoren ==
Vektoren sollten jedem aus der Linearen Algebra bekannt sein.
=== Arrays ===
In Python mit NumPy kann man Vektoren durch die Funktion array erzeugen.
import numpy as np
l1 = (-5, 3, 2)
l2 = (1, 1, 4)
a1 = np.array(l1)
a2 = np.array(l2)
a3 = a1 + a2
a4 = 2 * a2
print(a1)
print(a2)
print(a3)
print(a3[2])
print(a4)
Ausgabe:
[-5 3 2]
[1 1 4]
[-4 4 6]
6
[2 2 8]
=== Zeilen- und Spaltenvektoren ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
print(z)
print(s)
Ausgabe:
[ [-5 3 2] ]
[[1]
[1]
[4]]
=== Skalarprodukt ===
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
skalarprodukt = np.dot(a1, a2)
print(skalarprodukt)
Ausgabe:
6
=== Vektorprodukt ===
<math>a\ast b=\left(\begin{array}{c}
a_{1}\\
a_{2}\\
a_{3}
\end{array}\right)\ast\left(\begin{array}{c}
b_{1}\\
b_{2}\\
b_{3}
\end{array}\right)=\left(\begin{array}{c}
a_{2}b_{3}-a_{3}b_{2}\\
a_{3}b_{1}-a_{1}b_{3}\\
a_{1}b_{2}-a_{2}b_{1}
\end{array}\right)
</math>
Python-Code:
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
vektorprodukt = np.cross(a1, a2)
print(vektorprodukt)
Ausgabe:
[10 22 -8]
=== Transponierter Vektor ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
# transponierter Vektor
z_tp = np.transpose(z)
# transponierter Vektor
s_tp = np.transpose(s)
print(z_tp)
print(s_tp)
Ausgabe:
[[-5]
[ 3]
[ 2]]
[ [1 1 4] ]
=== Vektorfelder visualisieren ===
import matplotlib.pyplot as plt
import numpy as np
# Daten generieren
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
X, Y = np.meshgrid(x, y)
U = X * Y
V = Y + X
# Plotten
fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='xy')
plt.show()
Ausgabe:
[[Datei:PythonIng_quiver1.png]]
== Matrizen==
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
print(m1)
Ausgabe:
[[1 2 3]
[4 5 6]]
=== Zugriff auf Matrizenelemente ===
Beispiel:
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
# Element aus Zeile 2 und Spalte 3 (Achtung! Index startet bei Null)
print(m1[1,2])
Ausgabe:
6
Visualisierung:
0 1 2
+-----------+
0 | 1 | 2 | 3 |
+-----------+
1 | 4 | 5 | '''6''' |
+-----------+
Beispiel:
import numpy as np
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
B = np.matrix(A)
print(B[2::, ::2])
Ausgabe:
[['20' '22']
['30' '32']
['40' '42']]
Mit der NumPy-Bibliothek funktioniert das zweidimensionale Slicing. Mit normalen Listen/Tupels geht das nicht, was wir schon früher thematisiert haben.
=== Addition und Subtraktion von Matrizen ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
m2 = np.matrix([[0, 0, 2], [1, 3, 2]])
print(m1 + m2)
print(m1 - m2)
Ausgabe:
[[1 2 5]
[5 8 8]]
[[1 2 1]
[3 2 4]]
=== Transponierte Matrix ===
import numpy as np
m = np.matrix([[1, 2, 3], [4, 5, 6]])
mt = np.transpose(m)
print(m)
print(mt)
Ausgabe:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]
=== Rang einer Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
rg = np.linalg.matrix_rank(m)
print(rg)
Ausgabe:
2
=== Inverse Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
mi = np.linalg.inv(m)
print(mi)
Ausgabe:
[[ 1. 0.6]
[-0. -0.2]]
=== Multiplikation von Matrizen (falksches Schema) ===
import numpy as np
m1 = np.matrix([[1, 3, 4], [0, -5, 1]])
m2 = np.matrix([[1, 2], [2, 3], [0, 2]])
print(m1 @ m2)
Ausgabe:
[[ 7 19]
[-10 -13]]
=== Eigenwerte und Eigenvektoren ===
import numpy as np
m = np.matrix([[5, 8], [1, 3]])
D,V = np.linalg.eig(m)
# Eigenwerte
print(D)
# Eigenvektoren
print(V)
Ausgabe:
[7. 1.]
[[ 0.9701425 -0.89442719]
[ 0.24253563 0.4472136 ]]
=== Teilmatrizen ===
import numpy as np
m = np.matrix([[1, 3, 4], [0, -5, 1]])
print("m = ", m)
# Erste Zeile extrahieren
m1 = m[0,:]
print("m1 = ", m1)
# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
m2 = m[0,1]
print("m2 = ", m2)
# Zweite Spalte extrahieren
m3 = m[:, 1]
print("m3 = ", m3)
Ausgabe:
m = [[ 1 3 4]
[ 0 -5 1]]
m1 = [ [1 3 4] ]
m2 = 3
m3 = [[ 3]
[-5]]
=== Spezielle Matrizen ===
==== Nullmatrix ====
import numpy as np
z = np.zeros((3, 2))
print(z)
Ausgabe:
[[0. 0.]
[0. 0.]
[0. 0.]]
==== Einheitsmatrix ====
import numpy as np
z = np.eye(3)
print(z)
Ausgabe:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
==== Matrix mit lauter Einsen ====
import numpy as np
z = np.ones((3, 2))
print(z)
Ausgabe:
[[1. 1.]
[1. 1.]
[1. 1.]]
=== Spärlich besetzte Matrizen ===
Das Thema spärlich besetzter Matrizen wird hier nur kurz angerissen. Nähere Details siehe unter dem Weblink [https://docs.scipy.org/doc/scipy/reference/sparse.html#module-scipy.sparse].
Beispiel:
import numpy as np
import scipy
A = scipy.sparse.csr_array(np.eye(5))
print(A)
Ausgabe:
<Compressed Sparse Row sparse array of dtype 'float64'
with 5 stored elements and shape (5, 5)>
Coords Values
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
(4, 4) 1.0
csr steht für '''c'''ompressed '''s'''parse '''r'''ow.
Andere Möglichkeiten:
* coo-Format ('''coo'''rdinate Format): <code>scipy.sparse.coo_array()</code>
* lil-Format ('''li'''st of '''l'''ists): <code>scipy.sparse.lil_array()</code>
* csc-Format ('''c'''ompressed '''s'''parse '''c'''olumn): <code>scipy.sparse.csc_array()</code>
Es gibt auch <code>scipy.sparse.csr_matrix()</code> etc. Diese Befehle sind aber veraltet und es wird empfohlen, statt dessen die <code>..._array()</code>-Funktionen zu verwenden.
<u>Aufgaben:</u>
Recherchieren Sie im Internet
* generell zum Thema "spärlich besetzte Matrizen mit Python".
* Was sind die Vor-/Nachteile von csr-arrays gegenüber coo- und lil-arrays?
* Wann verwendet man sinnvollerweise csr- und wann csc-arrays?
* Wie wandelt man coo-arrays in csr-arrays um?
= Lineare Gleichungssysteme =
Sei <math>Ax = b</math> ein lineares Gleichungssystem. <math>A</math> sei die Koeffizientenmatrix, <math>x</math> der Lösungsvektor und <math>b</math> ein bekannter Vektor.
Beispiel:
import numpy as np
A = np.array([[5, 1], [0, 2]])
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)
Ausgabe:
[0. 1.]
Siehe dazu auch das Kapitel [[Ing Mathematik: Numerisches Lösen von linearen Gleichungssystemen]]. Dort wird dieses Themengebiet u.a. mit weitergehenden Python-Skripten vertieft.
== Aufgabe ==
* Lösen Sie folgendes Gleichungssystem mittels Python (und zur Kontrolle auch händisch):
5x + 6y - 2z = 12
3x - y - 3z = 6
2x + 2y + 4z = 5
= Polynome =
== Ein erstes einfaches Beispiel ==
Gegeben sei das Polynom <math>7x^3+5x^2+1</math>. In Python:
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p)
Ausgabe:
3 2
7 x + 5 x + 1
== Einzelne Polynomwerte berechnen ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p(1.5))
Ausgabe:
35.875
== Polynome integrieren und differenzieren ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
# 1. Ableitung
p1 = p.deriv()
p2 = p.deriv(1)
# 2. Ableitung
p3 = p.deriv(2)
# Integral
p4 = p.integ()
print(p1)
print(p2)
print(p3)
print(p4)
Ausgabe:
2
21 x + 10 x
2
21 x + 10 x
42 x + 10
4 3
1.75 x + 1.667 x + 1 x
== Nullstellen bestimmen ==
import numpy as np
p = np.poly1d([2, 5, 0, 4])
r = np.roots(p)
print(r)
Ausgabe:
[-2.7621427 +0.j 0.13107135+0.84077099j 0.13107135-0.84077099j]
== Aufgaben ==
* Berechnen Sie den Wert für x = 3 des Polynoms <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Differenzieren und integrieren Sie das Polynom <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Berechnen Sie die Nullstellen von <math>y = 7x^5 - 3x^2 + 12</math>.
= Nichtlineare Gleichungen und Gleichungssysteme =
== Nullstellenbestimmung ==
Löse eine beliebige Gleichung f(x) = 0, z.B. <math> f(x) = x^2 - 5\cos(x) - 10 = 0 </math>:
import scipy
import numpy as np
def f(x):
return x**2 - 5*np.cos(x) - 10
xstart = [-1, 1] # Startwerte
xn = scipy.optimize.root(f, xstart)
print(xn.x)
Ausgabe:
[-2.46813009 2.46813009]
Funktionsgraph:
[[Datei:octave_nichtlin2.jpg]]
== Gleichungssysteme ==
SymPy ist ein externes Modul, das symbolisches Rechnen ('''Sym'''bolic '''Py'''thon) ermöglicht.
Folgende Aufgabe ist dem Buch "Knorrenschild: Numerische Mathematik, Hanser, 2017, Seite 72" entnommen. Zu lösen ist das nichtlineare Gleichungssystem
<math>f_1 = 2x_1 + 4x_2 = 0 </math>
<math>f_2 = 4x_1 + 8x_2^3 = 0</math>
Mit Python ist das so möglich:
import sympy
x1, x2 = sympy.symbols("x1 x2")
f1 = 2*x1 + 4*x2
f2 = 4*x1 + 8*x2**3
s = sympy.solve((f1, f2), x1, x2)
print(s)
Ausgabe:
[(-2, 1), (0, 0), (2, -1)]
Plot:
[[Datei:IngPython_nl_gleichung1.svg|500px]]
= Komplexe Zahlen =
Die imaginäre Einheit wird in Python durch den Buchstaben <code>j</code> symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:
* Kartesische Darstellung <math>z = \Re(z) + j \cdot \Im(z)</math>
* Polardarstellungen <math>z = r \cdot (\cos(\phi) + j \cdot \sin(\phi)) = r \cdot e^{j\cdot \phi}</math>
Die konjugiert komplexe Zahl ist <math>z^* = \Re(z) - j \cdot \Im(z)</math>
Nachfolgend einige mathematische Operationen mit Python und NumPy.
import numpy as np
z1 = 2 + 5j # kartesische Darstellung
z2 = 3 * np.exp(3j) # Polardarstellung
# Addition
res = z1 + z2
print("z1 + z2 = ", res)
# Multiplikation
res = z1 * z2
print("z1 * z2 = ", res)
# Realteil
res = np.real(z2)
print("Realteil von z2 = ", res)
# Imaginärteil
res = np.imag(z2)
print("Imaginaerteil von z2 = ", res)
# Betrag
res = np.abs(z1)
print("Betrag von z1 = ", res)
# Argument
res = np.angle(z1)
print("Argument von z1 = ", res)
# Konjugiert komplexe Zahl
res = np.conj(z1)
print("Konjugiert komplexe Zahl von z1 = ", res)
Ausgabe:
z1 + z2 = (-0.9699774898013365+5.423360024179601j)
z1 * z2 = (-8.05675510050068-14.003167400647481j)
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = (2-5j)
= Interpolation =
import numpy as np
import scipy
import matplotlib.pyplot as plt
# Stützpunkte
xp = np.arange(1, 6)
yp = (0, -5, 2, 7, 6)
ti = np.arange(1, 5, 0.01)
i1 = scipy.interpolate.interp1d(xp, yp, kind = "linear")
i2 = scipy.interpolate.interp1d(xp, yp, kind = "cubic")
plt.plot(xp, yp, "rx")
plt.plot(xp, i1(xp))
plt.plot(ti, i2(ti))
plt.show()
Ausgabe:
[[Datei:PythonIng_interpol1.png]]
= Differenzialrechnung =
== Numerisches Differenzieren ==
Als Beispiel differenzieren wir <math>y = 5x\sin{x}</math> und stellen das Ganze grafisch dar.
from findiff import Diff
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
f = 5 * x * np.sin(x)
dx = x[1] - x[0]
# Ableitung
d_dx = Diff(0, dx)
df_dx = d_dx(f)
# Grafik
plt.plot(x, f, label = "y")
plt.plot(x, df_dx, label = "y'")
plt.grid()
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:octave_diff1.jpg]]
<small>findiff ist ein externes Modul. Dieses muss installiert werden (z.B. so: ...\Python\Scripts\pip.exe install --upgrade findiff). Für die Vorgehensweise unter openSUSE Tumbleweed siehe das Kapitel [[Ing_Mathematik:_Python#Mit_VPython | VPython]], nur dass das Ganze mit einer aktuelleren Python-Version exekutiert wird, z.B. mit Python 3.13. Das im Buch "Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler, Rheinwerk" verwendete Modul "scipy.misc" ist veraltet (deprecated ... missbilligt). Lt. [https://docs.scipy.org/doc/scipy-1.17.0/dev/roadmap-detailed.html#misc SciPy-Dokumentation für die Version 1.17.0] wurden alle entsprechenden Features schon entfernt.</small>
== Symbolisches Differenzieren ==
Differenzieren Sie die Funktionen <math>f_1(x) = x^2</math> und <math>f_2(x) = \sin(x)\cos\left(\frac{x}{2}\right)</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2;
f2 = sympy.sin(x) * sympy.cos(x/2.)
d1 = sympy.diff(f1, x)
d2 = sympy.diff(f2, x)
print(d1)
print(d2)
Ausgabe:
2*x
-0.5*sin(0.5*x)*sin(x) + cos(0.5*x)*cos(x)
== Aufgaben ==
* Differenzieren Sie die Funktion <math>y = \log(x) + 10x</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
* Differenzieren Sie die Funktion <math>y = \frac{\sinh(x)}{(1+x)}</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
= Integralrechnung =
== Numerisches Integrieren ==
Berechnen Sie das Integral <math>\int_{0}^{3}x^2 dx</math>.
import scipy
def f(x):
return x**2
i = scipy.integrate.quad(f, 0, 3)
print(i)
Ausgabe:
(9.000000000000002, 9.992007221626411e-14)
Das trifft den exakten Wert 9.0 ziemlich genau.
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} dx</math>.
import scipy
import numpy as np
def f(x):
return 2**(-x)
i = scipy.integrate.quad(f, 0, np.inf)
print(i)
Ausgabe:
(1.4426950408889556, 4.486558477977586e-09)
== Symbolisches Integrieren ==
Berechnen Sie <math>\int x^2 \text{d}x</math> und <math>\int \sin{x}\cos{\frac{x}{2}} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2
f2 = sympy.sin(x) * sympy.cos(x/2.)
i1 = sympy.integrate(f1, x)
i2 = sympy.integrate(f2, x)
print(i1)
print(i2)
Ausgabe:
x**3/3
-0.666666666666667*sin(0.5*x)*sin(x) - 1.33333333333333*cos(0.5*x)*cos(x)
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f = 2**(-x)
i = sympy.integrate(f, (x, 0, sympy.oo))
print(i)
Ausgabe:
1/log(2)
<code>sympy.oo</code> steht für das {{W|Unendlichzeichen}} <math>\infty</math> (die liegende Acht oder das Möbiusband). Mit <code>sympy.pprint(i)</code> ließe sich letzere Ausgabe etwas schöner schreiben:
1
──────
log(2)
Man beachtete, <code>log</code> steht hier für den natürlichen Logarithmus <code>ln</code>.
== Aufgaben ==
* Integrieren Sie die Funktion <math>y = \log(x) + 10x</math> von 1 bis 5.
* Integrieren Sie die Funktion <math>y = x^3</math> von 0 bis 4.
* Integrieren Sie <math>\int x^x(\log (x) + 1)\mathrm dx</math> symbolisch.
= Gewöhnliche Differenzialgleichungen =
== DGL numerisch lösen ==
Für die Lösung von Differenzialgleichungen steht u.a. die Funktion scipy.integrate.solve_ivp() zur Verfügung. Diese Funktion implementiert auch das Runge-Kutta-Verfahren (RK45).
{{Wikipedia | Runge-Kutta-Verfahren}}
Beispiel <math>y' = x^2 + y^3</math>:
import scipy
import numpy as np
import matplotlib.pyplot as plt
def dy_dx(x, y):
return x**2 + y**3
y0 = [1]
xi = [0, 1]
x = np.arange(0, 1, 0.01)
z = scipy.integrate.solve_ivp(dy_dx, xi, y0, method="RK45", dense_output=True)
y = z.sol(x)
plt.plot(x, y.T)
plt.grid()
plt.show()
[[Datei:PythonIng_dgl1.png]]
== DGL symbolisch lösen ==
Beispiel <math>y' = x^2 + y^3</math>:
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
print(lsg)
Ausgabe:
[Eq(f(x), (-x**2)**(1/3)), Eq(f(x), (-x**2)**(1/3)*(-1 - sqrt(3)*I)/2), Eq(f(x), (-x**2)**(1/3)*(-1 + sqrt(3)*I)/2)]
Mit <code>sympy.pprint</code> (pretty print) lässt sich die Ausgabe etwas übersichtlicher darstellen.
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
sympy.pprint(lsg)
Ausgabe:
⎡ _____ _____ ⎤
⎢ _____ 3 ╱ 2 3 ╱ 2 ⎥
⎢ 3 ╱ 2 ╲╱ -x ⋅(-1 - √3⋅ⅈ) ╲╱ -x ⋅(-1 + √3⋅ⅈ)⎥
⎢f(x) = ╲╱ -x , f(x) = ────────────────────, f(x) = ────────────────────⎥
⎣ 2 2 ⎦
== Aufgaben ==
* Lösen Sie die Differenzialgleichung <math>y' = \frac{1}{x\cdot y}</math> mit Python. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>m' = -k\cdot m</math>. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>y' = \sqrt{|y|}</math>.
=Laplace-Transformation=
Laplace-Transformation:
<math>F(s) =\mathcal{L} \left\{f\right\}(s) = \int_{0}^{\infty} f(t) \mathrm e^{-st} \,\mathrm{d}t, \qquad s\in\mathbb{C}
</math>
Inverse Laplace-Transformation:
<math>\mathcal{L}^{-1} \left\{F\right\}(t)
= \frac{1}{2 \pi \mathrm j} \int_{ \gamma - \mathrm j \infty}^{ \gamma + \mathrm j \infty} \mathrm e^{st} F(s)\,\mathrm ds
= \begin{cases}
f(t) & \text{für } t \geq 0 \\
0 & \text{für } t < 0
\end{cases}
</math>
Siehe auch [[Ing_Mathematik:_Laplace-Transformation]]
Code:
import sympy
from sympy.abc import t, s
# Laplace-Transformation der Funktion f(t) = 1 (Heaviside-Fkt.)
f = 1
# alternativ: f = sympy.Heaviside(t)
F = sympy.laplace_transform(f, t, s, noconds=True)
print("Laplace-Transformierte F(s):", F)
# Inverse Laplace-Transformation zurück in den Zeitbereich
f_inv = sympy.inverse_laplace_transform(F, s, t)
print("Inverse Transformation f(t):", f_inv)
Ausgabe:
Laplace-Transformierte F(s): 1/s
Inverse Transformation f(t): Heaviside(t)
Die Zeile
from sympy.abc import t, s
steht alternativ für
t = sympy.symbols("t")
s = sympy.symbols("s")
<u>Aufgaben</u>: Ermitteln Sie mittels SymPy die <math>\mathcal{L}</math>-Transformierten und dann wieder die <math>\mathcal{L}^{-1}</math>-Transformationen (ähnlich wie beim obigen Beispiel):
* <math>\sin(t) \circ\! -\! \bullet \ ?</math>
* <math>t^3 \circ\! -\! \bullet \ ?</math>
* <math>\text{e}^{\omega t} \circ\! -\! \bullet \ ?</math>
=Fourier-Reihen=
<math>
f(x)\approx \frac{a_{0}}{2}+\sum_{k=1}^{\infty}\left(a_{k}\cos\left(kx\right)+b_{k}\sin\left(kx\right)\right)
</math>
<math>
a_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\cos\left(kx\right)\mathrm dx\quad\text{für }k\geq0
</math>
<math>
b_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\sin\left(kx\right)\mathrm dx\quad\text{für }k\geq1
</math>
Für die Sägezahnfunktion <math>y=x;\, 0 < x < 2\pi</math> sei die Fourierreihe mit einem Python-Programm (unter Mithilfe von sympy) hergeleitet.
Code:
from sympy import fourier_series, pi, symbols, pprint
x = symbols('x')
f = x
s = fourier_series(f, (x, 0, 2*pi))
pprint(s.truncate(n=4))
Ausgabe:
2⋅sin(3⋅x)
-2⋅sin(x) - sin(2⋅x) - ────────── + π
3
Siehe auch [[Ing Mathematik: Fourierreihen]].
Ein komplizierteres Beispiel:
[[Datei:IngMath fourier bsp13.svg | 300px]]
<math>0\le t < T/2\text{:}\quad f(t) = H</math>
<math>T/2 \le t \le T\text{:}\quad f(t) = \frac{2H}{T}\left( t-\frac{T}{2}\right)</math>
Code:
import sympy as sp
H = sp.Symbol('H', positive=True)
T = sp.Symbol('T', positive=True)
t = sp.Symbol('t')
f = sp.Piecewise(
(H, (t > 0) & (t < T/2)),
(2*H/T*(t-T/2), (t > T/2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Ausgabe:
⎛2⋅π⋅t⎞ ⎛4⋅π⋅t⎞ ⎛6⋅π⋅t⎞ ⎛2⋅π⋅t⎞ ⎛6⋅π⋅t⎞
H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ 2⋅H⋅cos⎜─────⎟ 2⋅H⋅cos⎜─────⎟
⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ 3⋅H
──────────── - ──────────── + ──────────── + ────────────── + ────────────── + ───
π 2⋅π 3⋅π 2 2 4
π 9⋅π
=Rechnen mit wirklich großen Zahlen=
Bekannt ist, dass Python kaum Einschränkungen beim Wertebereich von Ganzzahlen hat, z.B.
print(10**300)
Ausgabe (gekürzt):
100000000000000000000...00000000000000000000000000000000000000000000000000000000000000000000000
Ähnliches geht auch mit Gleitpunktzahlen, z.B. durch die Verwendung des Moduls [https://mpmath.org/ mpmath]:
import mpmath
print(mpmath.mpf(1500.4)**mpmath.mpf(300))
Ausgabe:
7.27975299218612e+952
Anderes Beispiel:
from mpmath import mp, pi
mp.dps = 100
print(pi)
Ausgabe:
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
mpmath kann noch einiges mehr, dazu sei aber auf die entsprechende Dokumentation auf der mpmath-Homepage verwiesen. mpmath ist Bestandteil von SymPy, kann aber auch separat installiert werden.
Aber auch Python selbst besitzt eine Möglichkeit, um mit großen bzw. exakten Gleitpunktzahlen zu rechnen, nämlich das interne Modul decimal. Dieses hat einige Vorteile gegenüber mpmath, aber auch gravierende Nachteile. Diese seien hier nicht detailliert aufgezählt. Grob gesagt hat decimal im Finanzwesen seine Berechtigung. Für wissenschaftliche Anwendungen wird aber mpmath vorzuziehen sein, da es u.a. vielfältige mathematische Funktionen bereit stellt. Nachfolgend ein einfaches Beispiel mit decimal:
import decimal
print("Potenzierung:", decimal.Decimal(1500.4) ** decimal.Decimal(300.0))
print("Einfache Addition:", 0.1 + 0.2)
decimal.getcontext().prec = 50
print("Addition mit decimal:", decimal.Decimal("0.1") + decimal.Decimal("0.2"))
Ausgabe:
Potenzierung: 7.279752992186121551039839134E+952
Einfache Addition: 0.30000000000000004
Addition mit decimal: 0.3
<u>Aufgabe:</u> Recherchieren Sie im Internet die genauen Vor- und Nachteile von decimal und mpmath. Verwenden Sie dazu auch KI (z.B. von Google, chatgpt).
= pint - mit physikalischen Größen rechnen =
[[File:Pint-Glas_UK.jpg|right|100px]]
pint ist ein externes Python-Paket zur Manipulation von physikalischen Einheiten. Es muss vor der ersten Benutzung installiert werden (Vorgehensweise wie immer: pip, YaST, via venv etc.).
Beispiel:
import pint
import numpy as np
ureg = pint.UnitRegistry()
# Einfache Berechnung
print(3 * ureg.meter + 4 * ureg.cm)
# Mit NumPy
npeinzel = [3, 4] * ureg.meter + [2, 5] * ureg.cm
print(npeinzel)
npsum = np.sum(npeinzel)
print(npsum)
# Konvertierung von Einheiten
npsum_inch = npsum.to(ureg.inch)
print(npsum_inch)
print(npeinzel.magnitude)
print(npeinzel.units)
print(npeinzel.dimensionality)
Ausgabe:
3.04 meter
[3.02 4.05] meter
7.07 meter
278.3464566929134 inch
[3.02 4.05]
meter
[length]
Die Dokumentation zu pint findet sich auf [https://pint.readthedocs.io/en/stable/].
=Regelungstechnische Aufgabenstellungen=
Für regelungstechnische Aufgaben gibt es u.a. das externe Paket <code>control</code>. Hier soll nicht detailliert darauf eingegangen werden. Anhand eines Beispiels soll anschließend nur die Visualisierung in Form eines Bode-Diagramms und der Sprungantwort gezeigt werden. Gegeben sei ein P-Regler mit <math>R = \frac{5}{2}</math> und eine Strecke <math>S= \frac{1}{30s^3+20s^2+10s+1,5}</math>. Gesucht sei vorerst ein Bode-Diagramm für den offenen Regelkreis und das Führungsverhalten.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke # oder: G0 = ct.series(regler, strecke)
Gw = ct.feedback(G0)
ct.bode_plot(G0, label='G0')
ct.bode_plot(Gw, label='Gw')
plt.show()
[[Datei:PythonIng_bode1.svg]]
Nun noch für obiges Beispiel die Sprungantwort. Diese zeigt einige große Überschwinger, d.h. der Regler kann sicher noch optimiert werden.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke
Gw = ct.feedback(G0)
t, y = ct.step_response(Gw)
plt.plot(t,y)
plt.title('Sprungantwort')
plt.xlabel('t')
plt.ylabel('h(t)')
plt.grid()
plt.show()
[[Datei:PythonIng_bode3.svg]]
Einige weitere wichtige Daten (Phasenreserve, Amplitudenreserve, Durchtrittsfrequenz) lassen sich mittels der <code>control</code>-Funktion <code>margin()</code> ermitteln. Die Ortskurve lässt sich mit der Funktion <code>nyquist_plot()</code> zeichnen. Dies sei hier aber nicht weiter ausgeführt.
==Aufgaben==
* Zeichen Sie mit Python die Ortskurve für obiges Beispiel.
* Was passiert, wenn man die Reglerverstärkung weiter aufdreht (z.B. auf <math>R = \frac{25}{2}</math>)?
* Wie sehen das Bode-Diagramm und die Sprungantwort aus, wenn ein PI-Regler verwendet wird?
= Stereostatik etc. =
Das Modul SymPy bietet einige Möglichkeiten einfache Bauwerke zu berechnen, z.B. Balken oder Fachwerke. Nachfolgend wird ein einfaches Fachwerk berechnet und gezeichnet.
Python-Code:
from sympy.physics.continuum_mechanics.truss import Truss
t = Truss()
# Knoten
t.add_node(("A", -3, 0), ("B", 0, 0), ("C", 4, 0), ("D", 7, 0),
("E", 6, 1.5), ("F", 2, 3), ("G", -2, 1.5))
# Stäbe
t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D"))
t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F"))
t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E"))
t.add_member(("FE","F","E"), ("DE","D","E"))
# Auflager; roller ... Loslager, pinned ... Festlager
t.apply_support(("A","roller"), ("D","pinned"))
# Einwirkende Kräfte
t.apply_load(("G", 5, 270), ("E", 3, 90))
# Berechnung
t.solve()
print("Reaction Forces: ", t.reaction_loads)
print("Internal Forces: ", t.internal_forces)
# Fachwerk zeichnen
p = t.draw()
p.show()
Ausgabe auf der Konsole:
Reaction Forces: {'R_A_y': 4.20000000000000, 'R_D_x': 0, 'R_D_y': -2.20000000000000}
Internal Forces: {'AB': 2.80000000000000, 'BC': 0.333333333333333, 'CD': -1.46666666666667,
'AG': -5.04777178564958, 'GB': -2.05555555555556, 'GF': -1.23413387432364,
'BF': 0.411111111111111*sqrt(13), 'FC': -0.3*sqrt(13), 'CE': 1.50000000000000,
'FE': 0.284800124843917, 'DE': 2.64407093534026}
Zeichnung:
[[File:PythonIng_fachwerk1.svg|300px]]
Details zu diesem Thema siehe z.B. [https://docs.sympy.org/latest/modules/physics/continuum_mechanics/index.html Continuum Mechanics] oder [https://docs.sympy.org/latest/tutorials/physics/continuum_mechanics/index.html Continuum Mechanics Tutorials]. Auch andere mechanische Probleme werden von SymPy abgehandelt ([https://docs.sympy.org/latest/tutorials/physics/index.html Physics Tutorials]).
== Aufgabe ==
Gegeben sei ein einseitig eingespannter Kragträger. Belastet wird er durch eine Einzellast am Trägerende. Für die Daten siehe folgende ASCII-Skizze:
| 20 kN
//|---> x |
//| V
//|----------------------
//| 10 m |
Elastizitätsmodul E = 2,1*10⁵ N/mm²
Flächenträgheitsmoment I = 0.001 m⁴
Berechnen Sie die Auflagerreaktionen, den Querkraft- und Biegemomentenverlauf, sowie die Verformungen.
Stellen Sie dies mit Hilfe von SymPy graphisch und auch mittels Formeln dar. Verwenden Sie dazu auch pprint (pretty print) aus dem SymPy-Modul. Zwecks Lösungsansatz siehe die oben aufgeführte Seite "Continuum Mechanics Tutorials". Achten Sie auch auf die Einheiten! Kontrollieren Sie das Ganze mittels händischer Rechnung. In dem genannten Tutorial ist von "Singularity Functions" die Rede. Gemeint ist damit in diesem Kontext die {{W|Föppl-Klammer}}.
Einige Python-Programme, vorrangig zu Maschinenelementen, finden sich auf [https://baymp.de/download_python.html BayMP für Python] (Balken, Zahnräder, Stabknickung usw.).
=Thermodynamik=
== PYroMat ==
Für thermodynamische Aufgabenstellungen gibt es verschiedene externe Module. Eines davon ist PYroMat (siehe auch [http://pyromat.org]). Damit lassen sich thermodynamische Stoffdaten für viele Substanzen berechnen.
Beispiel (einige Stoffdaten für Wasser bei 400°C und 20 bar berechnen):
import pyromat as pm
# Wasserdaten laden:
H2O = pm.get('mp.H2O')
# Stoffdaten berechnen:
T = 673.15 # Temperatur in Kelvin
p = 20 # Druck in bar
v = H2O.v(T, p)
h = H2O.h(T, p)
s = H2O.s(T, p)
print(f"Spezifisches Volumen: {v} m³/kg")
print(f"Spezifische Enthalpie: {h} kJ/kg")
print(f"Spezifische Entropie: {s} kJ/(kg K)")
Ausgabe:
Spezifisches Volumen: [0.1512163] m³/kg
Spezifische Enthalpie: [3248.3789473] kJ/kg
Spezifische Entropie: [7.12924142] kJ/(kg K)
<small>
PYroMat muss vorab installiert werden (z.B. mittels pip, in eine virtuelle Umgebung)
</small>
<code>mp</code> steht für "multi phase". Für ein ideales Gas wäre <code>ig</code> zuständig, z.B. <code>'ig.O2'</code>.
Beispiel (T-s-Diagramm für Wasser zeichnen):
import numpy as np
import matplotlib.pyplot as plt
import pyromat as pm
# Konfigurieren
pm.config["unit_pressure"] = "bar"
pm.config["unit_temperature"] = "K"
fluid = pm.get("mp.H2O")
# Temperaturbereich für das Nassdampfgebiet
T_tripel = 273.16
T_crit = 647.096
T = np.linspace(T_tripel, T_crit - 0.1, 200)
# Sättigungslinien berechnen und zeichnen
for x in np.linspace(0.0, 1.0, 5):
s = fluid.s(T=T, x=x)
if(x<=0.0):
plt.plot(s, T, label="Siedelinie x=%3.1f" % x, linewidth=2.0)
elif(x>=1.0):
plt.plot(s, T, label="Taulinie x=%3.1f" % x, linewidth=2.0)
else:
plt.plot(s, T, label="x=%3.1f" % x, linewidth=1.0)
# Isobaren zeichnen
p_values = [0.1, 1, 10, 50, 100]
T_isobar = np.linspace(T_tripel, 1000, 200)
t = 0.7
for p in p_values:
s_iso = fluid.s(T=T_isobar, p=p)
plt.plot(s_iso, T_isobar, 'k-', alpha=0.8, linewidth=0.8)
t += .05
idx = int(len(s_iso) * t)
plt.text(s_iso[idx], T_isobar[idx], f"{p} bar", fontsize=9, alpha=0.8)
# Diagramm zeichnen
plt.title("T-s-Diagramm für Wasser")
plt.xlabel("Spezifische Entropie s in kJ/kg K", fontsize=10)
plt.ylabel("Temperatur T in K", fontsize=10)
plt.legend(loc="best")
plt.grid(True)
plt.show()
Ausgabe (in etwa so):
[[Datei:T-s-Diagramm fuer Wasser.svg|400px]]
== CoolProp ==
Auch mit CoolProp können Stoffdaten berechnet werden. Siehe auch [https://coolprop.org/coolprop/wrappers/Python/index.html]
Beispiel (Wasser bei 20bar und 400°C):
import CoolProp.CoolProp as CP
fluid = 'Water'
T = 673.15 # Temperatur in Kelvin
P = 20e5 # Druck in Pascal
dichte = CP.PropsSI('D', 'T', T, 'P', P, fluid)
enthalpie = CP.PropsSI('H', 'T', T, 'P', P, fluid)
entropie = CP.PropsSI('S', 'T', T, 'P', P, fluid)
print(f"Spez. Volumen: {1/dichte:.6f} m³/kg")
print(f"Spez. Enthalpie: {enthalpie:.2f} J/kg")
print(f"Spez. Entropie: {entropie:.2f} J/kgK")
Ausgabe:
Spez. Volumen: 0.151215 m³/kg
Spez. Enthalpie: 3248344.02 J/kg
Spez. Entropie: 7129.16 J/kgK
== iapws ==
Um Werte für Wasser(dampf) zu erhalten (IAPWS; '''I'''nternational '''A'''ssociation for the '''P'''roperties of '''W'''ater and '''S'''team) gibt es die Bibliothek iapws. Siehe auch [https://iapws.org/] und [https://pypi.org/project/iapws/]
Beispiel (Wasser für 20bar und 400°C):
from iapws import IAPWS97
dampf = IAPWS97(P=2.0, T=673.15)
print(f"Spezifisches Volumen: {dampf.v:.6f} m³/kg")
print(f"Spezifische Enthalpie: {dampf.h:.2f} kJ/kg")
print(f"Spezifische Entropie: {dampf.s:.4f} kJ/(kgK)")
print(f"Phase: {dampf.phase}")
Ausgabe:
Spezifisches Volumen: 0.151208 m³/kg
Spezifische Enthalpie: 3248.23 kJ/kg
Spezifische Entropie: 7.1290 kJ/(kgK)
Phase: Gas
== TESPy ==
Ein anderes Modul für einen anderen Aufgabenzweck ist TESPy ('''T'''hermal '''E'''ngineering '''S'''ystems in '''Py'''thon). Dieses Modul ist für die Anlagensimulation zuständig. Für nähere Informationen siehe [https://tespy.readthedocs.io/en/main/getting_started/introduction.html]. Als Beipiel sei hier vorerst Code, der von der Google KI generiert wurde, angeführt. Der Code wurde überarbeitet, damit keine Warnungen auftreten. Bitte aber den Code trotzdem mit Vorsicht genießen, auch KI-generierter Code kann Fehler aufweisen. Eine Pumpe wird berechnet:
from tespy.components import Sink, Source, Pump
from tespy.connections import Connection
from tespy.networks import Network
# 1. Netzwerk definieren (Zentrales Steuerungselement)
# Wir wählen Wasser als Fluid und bar/Celsius als Einheiten
nw = Network(fluids=["water"])
nw.units.set_defaults(pressure="bar", pressure_difference="bar",
temperature="°C", enthalpy="kJ / kg")
# 2. Komponenten erstellen
eingang = Source("Wasserquelle")
ausgang = Sink("Wasserspeicher")
pumpe = Pump("Speisewasserpumpe")
# 3. Verbindungen definieren (Komponenten miteinander verknüpfen)
c1 = Connection(eingang, "out1", pumpe, "in1")
c2 = Connection(pumpe, "out1", ausgang, "in1")
# Verbindungen dem Netzwerk hinzufügen
nw.add_conns(c1, c2)
# 4. Randbedingungen und Parameter festlegen
# Zustand am Eingang (Druck, Temperatur, Massenstrom, Fluid-Zusammensetzung)
c1.set_attr(
v=1, # Massenstrom: 1 kg/s
T=20, # Temperatur: 20 °C
p=1, # Druck: 1 bar
fluid={"water": 1}, # 100% Wasser
)
# Zustand am Ausgang / Zielwerte der Pumpe
c2.set_attr(p=10) # Ziel-Druck nach der Pumpe: 10 bar
# Pumpeneigenschaften festlegen
pumpe.set_attr(eta_s=0.8) # Isentroper Wirkungsgrad von 80%
# 5. Simulation ausführen
nw.solve(mode="design")
# 6. Ergebnisse ausgeben
nw.print_results()
# Spezifische Werte direkt auslesen
print("\n--- Auswertung ---")
print(f"Erforderliche Pumpenleistung: {pumpe.P.val / 1000:.2f} kW")
print(f"Temperatur nach der Pumpe: {c2.T.val:.2f} °C")
Ausgabe (gekürzt):
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 7.04e+04 | 12 % | 9.96e+02 | 0.00e+00 | 8.81e+04 | 0.00e+00 | 0.00e+00
2 | 5.91e-12 | 100 % | 1.11e-13 | 0.00e+00 | 7.39e-12 | 0.00e+00 | 0.00e+00
3 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
4 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.01 s, Iterations per second: 480.85
##### RESULTS (Pump) #####
+-------------------+----------+----------+-----------+----------+----------+----------+
| | P | pr | dp | eta | eta_s | head |
|-------------------+----------+----------+-----------+----------+----------+----------|
| Speisewasserpumpe | 1.12e+06 | 1.00e+01 | -9.00e+00 | 8.00e-01 | 8.00e-01 | 9.19e+01 |
+-------------------+----------+----------+-----------+----------+----------+----------+
...
...
--- Auswertung ---
Erforderliche Pumpenleistung: 1124.77 kW
Temperatur nach der Pumpe: 20.07 °C
= Stochastik =
Die {{W|Stochastik}} ist ein sehr weites Feld. Hier werden etliche wichtige Themen kurz angerissen. Python stellt mit den Moduln math und statistics Software zu diesem Zwecke bereit. math und statistics sind bereits im Lieferumfang von Python enthalten. Aber auch mit den externen Modulen NumPy, SciPy, stochastic und pandas kann man Stochastik in Python betreiben. Die Theorie der Wahrscheinlichkeitsrechnung und Statistik soll etwas später in Band 5 dieser Buchreihe behandelt werden.
== Lageparameter ==
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
m1 = statistics.mean(werte)
m2 = statistics.mode(werte)
m3 = statistics.median(werte)
print("Arithmetischer Mittelwert = ", m1)
print("Modalwert = ", m2)
print("Median = ", m3)
Ausgabe:
Arithmetischer Mittelwert = 3.5
Modalwert = 1
Median = 3.0
== Streuungsparameter ==
Beispiel (Berechnung der Standardabweichung):
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
s = statistics.stdev(werte)
print("Standardabweichung = ", s)
Ausgabe:
Standardabweichung = 2.6770630673681683
Beispiel (Berechnung des Variationskoeffizienten V = Standardabweichung/Mittelwert)
import numpy as np
from scipy import stats
import statistics
k = 50
dat1 = [14, 21, 18, 25, 30, 17, 20]
dat = np.array(dat1)
# Mit SciPy
v = stats.variation(dat)
vddof = stats.variation(dat, ddof=1)
print("V SciPy: ", v)
print("V DDOF SciPy: ", vddof)
print(k*"-")
# mit NumPy
mittelwert1 = np.mean(dat)
std_abw1 = np.std(dat)
std_abw1ddof = np.std(dat, ddof=1)
v1= std_abw1 / mittelwert1
v1ddof = std_abw1ddof / mittelwert1
print("Mittelwert NumPy: ", mittelwert1)
print("Std.abw. NumPy: ", std_abw1)
print("Std.abw. DDOF NumPy: ", std_abw1ddof)
print("V NumPy: ", v1)
print("V DDOF NumPy: ", v1ddof)
print(k*"-")
# nur mit reinem Python
mittelwert2 = statistics.mean(dat1)
std_abw2 = statistics.stdev(dat1)
v2 = std_abw2 / mittelwert2
print("Mittelwert Python: ", mittelwert2)
print("Std.abw. Python: ", std_abw2)
print("V Python:", v2)
print(k*"-")
Ausgabe:
V SciPy: 0.23890355966467272
V DDOF SciPy: 0.25804533701889254
--------------------------------------------------
Mittelwert NumPy: 20.714285714285715
Std.abw. NumPy: 4.948716593053935
Std.abw. DDOF NumPy: 5.3452248382484875
V NumPy: 0.23890355966467272
V DDOF NumPy: 0.2580453370188925
--------------------------------------------------
Mittelwert Python: 20.714285714285715
Std.abw. Python: 5.3452248382484875
V Python: 0.2580453370188925
--------------------------------------------------
Der Unterschied bei der Standardabweichung zwischen reinem Python und den externen Bibliotheken SciPy und NumPy entsteht dadurch, dass einmal durch (n-1) und das andere Mal nur durch n dividiert wird. Dies kann bei NumPy und SciPy dadurch entschärft werden, indem <code>ddof=1</code> gesetzt wird. ddof steht für '''D'''elta '''D'''egrees '''o'''f '''F'''reedom. <small>Je größer die Anzahl der Datensätze n wird, umso weniger spielt das eine Rolle.</small>
== Kombinatorik ==
Beispiel:
import math
n = 7
k = 5
print("n! = ", math.factorial(n))
print("Kombinationen (n über k) = ", math.comb(n, k))
Ausgabe:
n! = 5040
Kombinationen (n über k) = 21
Siehe zu diesem Thema auch [[Ing Mathematik: Permutationen, Kombinationen, binomischer Lehrsatz]]. Die Anzahlen lassen sich einfach aus den dortigen Formeln ermitteln, z.B. bei Permutationen mit <math>n!</math> oder Variationen mit Wiederholungen als <math>n^k</math>. Will man die Kombinationen oder Variationen aber auch als Liste ausgeben, so kann das Modul <code>itertools</code> nützlich sein.
Beispiel (Variationen ohne Wiederholung):
from itertools import permutations
menge = ["A", "B", "C", "D"] # n = 4
k = 3
variationen = list(permutations(menge, k))
for v in variationen:
print("".join(v))
print(50*"-")
print(len(variationen))
Ausgabe (gekürzt):
ABC
ABD
ACB
...
DCA
DCB
--------------------------------------------------
24
Siehe zum Modul <code>itertools</code> auch die Website [https://docs.python.org/3/library/itertools.html].
* Variationen mit Wiederholung: <code>itertools.product()</code>
* Kombinationen ohne Wiederholung: <code>itertools.combinations()</code>
* Kombinationen mit Wiederholung: <code>itertools.combinations_with_replacement()</code>
== Zufallszahlen ==
Beispiel:
import random
# Ganzzahlige Zufallszahl von 1 bis 10
zufallszahl1 = random.randint(1, 10)
# Gleitpunktzahlen
# zwischen 0.0 und 1.0
zufallszahl2 = random.random()
# Zahl zwischen 1.5 und 9.5
zufallszahl3 = random.uniform(1.5, 9.5)
# aus Liste auswählen
farbe = ["Rot", "Grün", "Blau"]
zufallswert = random.choice(farbe)
print(zufallszahl1)
print(zufallszahl2)
print(zufallszahl3)
print(zufallswert)
Ausgabe, z.B.:
5
0.14147945849015753
6.894003397570905
Rot
Benötigt man mehrere Zufallszahlen, so ist das Modul <code>numpy</code> zu bevorzugen, z.B.:
* Normalverteilung: <code>np.random.normal(...)</code>
* Gleichverteilung: <code>np.random.uniform(...)</code>
== Histogramm ==
Zum Thema Histogramm siehe {{W|Histogramm}}.
Beispiel (mit Matplotlib):
import matplotlib.pyplot as plt
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
plt.hist(daten, bins=25, edgecolor='darkgray')
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm.svg|300px]]
Beispiel (mit Seaborn):
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
sns.set_theme(style="darkgrid")
sns.histplot(data=daten)
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm2.svg|300px]]
Das Kürzel <code>sns</code> ist Konvention und steht für die fiktive Figur '''S'''amuel '''N'''orman '''S'''eaborn aus der US-Fernsehserie {{W|The West Wing – Im Zentrum der Macht | The West Wing}}.
== Box-Plot ==
[[File:Elements of a boxplot.svg|400px]]
Siehe auch {{W|Box-Plot}}.
Beispiel (mit Seaborn erstellt):
import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("tips")
sns.boxplot(data=df, x="day", y="tip", hue="day", legend=False)
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot.svg|400px]]
Beispiel (mit Matplotlib erstellt):
import matplotlib.pyplot as plt
daten = [12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25]
plt.boxplot(daten, patch_artist=True)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot2.svg|300px]]
Um mehrere Box-Plots unterschiedlicher Farbe mit Matplotlib in einem Diagramm zu zeichnen, können Sie folgendermaßen vorgehen:
import matplotlib.pyplot as plt
daten = [[12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25],
[10, 19, 20, 21, 20, 30, 19, 40, 11, 17, 19, 21]]
farben = ["green", "blue"]
boxplot = plt.boxplot(daten, patch_artist=True)
for patch, farbe in zip(boxplot['boxes'], farben):
patch.set_facecolor(farbe)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
== Regressionsrechnung ==
Beispiel:
import numpy as np
import matplotlib.pyplot as plt
# Messpunkte
x = np.array([1, 3, 5, 6, 8, 10, 20])
y = np.array([3, 4, 5, 5, 7, 9, 11])
# Regressionskurve (Grad 1 = lineare Regression, 2 = Polynom-Regression 2. Gr.)
# y = kx + d
k, d = np.polyfit(x, y, deg=1)
# y = ax**2 + bx + c
a, b, c = np.polyfit(x, y, deg=2)
x_l = np.linspace(1, 20, 100)
y_p = a * x_l**2 + b * x_l + c
# Zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.plot(x, k*x + d, color='blue', label='Regressionsgerade')
plt.plot(x_l, y_p, color='red', label='Regressionspolynom 2. Gr.')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:IngMath_regression.svg|400px]]
== Korrelationsrechnung ==
Beispiel:
import pandas as pd
import matplotlib.pyplot as plt
# Messdaten
x = [1, 3, 4, 5, 6]
y = [2, 4, 6, 8, 5]
daten = {'X': x, 'Y': y}
df = pd.DataFrame(daten)
# Korrelation
korr = df['X'].corr(df['Y'])
print(f"Korrelationskoeff.: {korr}")
# Messpunkte zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
Korrelationskoeff.: 0.7556096518348252
[[Datei:IngMath_korrelation.svg|300px]]
== Mengen und Venn-Diagramme ==
Beispiel:
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
menge_a = {1, 2, 3, 4, 5, 6}
menge_b = {4, 5, 6, 7, 8}
vereinigung = menge_a | menge_b
schnitt = menge_a & menge_b
print("Vereinigungsmenge = ", vereinigung)
print("Schnittmenge = ", schnitt)
venn2([menge_a, menge_b], set_labels=('Menge A', 'Menge B'))
plt.show()
Ausgabe:
Vereinigungsmenge = {1, 2, 3, 4, 5, 6, 7, 8}
Schnittmenge = {4, 5, 6}
[[Datei:IngMath_venn.svg|300px]]
Siehe auch {{W|Mengendiagramm#Venn-Diagramme}}.
== Verteilungs- und Dichtefunktion ==
* CDF ... '''C'''umulative '''D'''istribution '''F'''unction, Verteilungsfunktion
* PDF ... '''P'''robability '''D'''ensity '''F'''unction, Dichtefunktion
Beispiel (Normalverteilung):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
my, sigma = 0, 1
x = np.linspace(-4, 4, 50)
pdf = norm.pdf(x, my, sigma)
cdf = norm.cdf(x, my, sigma)
plt.plot(x, pdf, lw=2, label="Dichtefunktion")
plt.plot(x, cdf, lw=2, label="Verteilungsfunktion")
plt.legend()
plt.grid()
plt.show()
Ausgabe:
[[Datei:IngMath_cdf_pdf.svg|300px]]
Beispiel (<math>\chi^2</math>-Verteilung):
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
x = np.linspace(0, 20, 500)
# df ... degree of freedom, Freiheitsgrad
pdf = (stats.chi2.pdf(x, df=2), stats.chi2.pdf(x, df=5), stats.chi2.pdf(x, df=10))
for i in range(0,3):
if(i==0):
lab = "Freiheitsgrad 2"
elif(i==1):
lab = "Freiheitsgrad 5"
else:
lab = "Freiheitsgrad 10"
plt.plot(x, pdf[i], label=lab, lw=2)
plt.grid()
plt.legend()
plt.show()
Ausgabe:
[[Datei:IngMath_chi2.svg | 300px]]
== Schätzen und Testen ==
=== Intervallschätzung ===
Als Beispiel seien Daten gegeben, die von ''Dürr, Mayer: Wahrscheinlichkeitsrechnung und Schließende Statistik; 7. Aufl., Hanser, 2014, Seite 137'' stammen. Und zwar soll das 95%-Vertrauensintervall für den Mittelwert des Kaloriengehalts (kcal/100g) von Hähnchen ermittelt werden. Wir wollen das mit Python inkl. NumPy und SciPy durchführen. Die Stichprobe ist groß (50 Hähnchen):
Python-Code:
import numpy as np
import scipy.stats as stats
# Stichprobe
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203]
# Parameter definieren
konfidenzniveau = 0.95
mean = np.mean(daten)
std = np.std(daten, ddof=1)
stdfehler = stats.sem(daten)
intervall = stats.norm.interval(confidence=konfidenzniveau, loc=mean, scale=stdfehler)
print(f"Mittelwert: {mean}")
print(f"Standardabweichung: {std}")
print(f"Konfidenzintervall: {intervall}")
Ausgabe:
Mittelwert: 215.48
Standardabweichung: 33.14238915925757
Konfidenzintervall: (np.float64(206.29356722321992), np.float64(224.66643277678006))
Diese Werte stimmen gerundet mit denen im genannten Buch überein. Zum Code selbst:
* sem steht für '''s'''tandard '''e'''rror of the '''m'''ean.
* <code>scipy.stats.norm</code> ... Modul für die Normalverteilung.
=== Punktschätzung ===
Gleiche Daten wie oben bei der Intervallschätzung.
Python-Code:
import numpy as np
from scipy import stats
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203
]
mu_hat, sigma_hat = stats.norm.fit(daten)
print(f"Schätzer für den Erwartungswert (μ): {mu_hat:.4f}")
print(f"Schätzer für die Standardabweichung (σ): {sigma_hat:.4f}")
Ausgabe:
Schätzer für den Erwartungswert (μ): 215.4800
Schätzer für die Standardabweichung (σ): 32.8093
=== Hypothesentests ===
Beispiel:
import numpy as np
import scipy.stats as stats
x_quer = 12.075 # Stichproben-Mittelwert
var = 0.069 # Stichproben-Varianz
n = 90 # Stichprobengröße
my_0 = 12.0 # Nullhypothese
alpha = 0.05 # Signifikanzniveau
z_stat = (x_quer - my_0) / np.sqrt(var / n)
p_val = 2 * (1 - stats.norm.cdf(np.abs(z_stat)))
print(f"Z-Statistik: {z_stat:.4f}")
if p_val < alpha:
print(f"p-Wert: {p_val:.6f} < alpha:", alpha)
print("Die Nullhypothese wird verworfen.")
else:
print(f"p-Wert: {p_val:.6f} > alpha:", alpha)
print("Die Nullhypothese wird nicht verworfen.")
Ausgabe:
Z-Statistik: 2.7087
p-Wert: 0.006755 < alpha: 0.05
Die Nullhypothese wird verworfen.
== Statistische Qualitätskontrolle ==
Beispiel (Mittelwertkarte):
import numpy as np
import matplotlib.pyplot as plt
# Gegeben
sollwert = 50.0
varianz = 4.0
stichproben_umfang = 1
daten = [49.5, 50.2, 53.0, 48.1, 52.6, 53.4, 49.8]
# Berechnung
standardabweichung = np.sqrt(varianz)
streuung = standardabweichung / np.sqrt(stichproben_umfang)
cl = sollwert
ucl = cl + 3 * streuung
lcl = cl - 3 * streuung
# Darstellung
plt.plot(daten, marker='o', linestyle='-', color='b', label='Messdaten')
plt.axhline(cl, color='green', linestyle='-', label=f'CL: {cl}')
plt.axhline(ucl, color='red', linestyle='--', label=f'UCL: {ucl:.2f}')
plt.axhline(lcl, color='red', linestyle='--', label=f'LCL: {lcl:.2f}')
plt.title('Mittelwertkarte')
plt.xlabel('Stichprobe')
plt.ylabel('Wert')
plt.legend(loc='lower left')
plt.grid(True)
plt.show()
Ausgabe:
[[Datei:IngMath_mittelwertkarte.svg|300px]]
Siehe auch {{W|Shewhart-Regelkarte}} und {{W|Qualitätsregelkarte}}.
* UCL ... '''U'''pper '''C'''ontrol '''Limit''', Obere Eingriffsgrenze
* LCL ... '''L'''ower '''C'''ontrol '''Limit''', Untere Eingriffsgrenze
* CL ... '''C'''enter '''L'''ine, Mittellinie
= Ein- und Ausgabe =
== print ==
Die Anweisung print haben wir schon oft verwendet. Hier soll anhand von Beispielen kurz beschrieben werden, was der Befehl print leisten kann.
print("Hallo", "Welt", 1, sep="-")
print("Hallo", end=" ")
print("Welt")
Ausgabe:
Hallo-Welt-1
Hallo Welt
== input ==
a = int(input("Zahl 1: "))
b = int(input("Zahl 2: "))
print("a + b = ", a+b)
Ausgabe (nach Eingabe der beiden Ganzzahlen):
Zahl 1: 4
Zahl 2: 5
a + b = 9
== Aus Dateien lesen ==
Es seinen die datei.txt
Hallo Welt.
Wie geht es dir?
...
und test1.py
dat = open("datei.txt", mode = "r")
print(dat.read())
dat.close()
Ausgabe
Hallo Welt.
Wie geht es dir?
...
Mit dem open()-Befehl wird die Datei datei.txt im Lesemodus geöffnet (r ... read). Mit dem read()-Befehl wird die Datei eingelesen und mittels print ausgegeben.
== In Dateien schreiben ==
dat = open("datei.txt", mode = "a", encoding = "utf-8")
dat.write("Hänge Zeile an\n")
dat.close()
Die Datei datei.txt sieht nach Abarbeitung des obigen Skripts nun so aus
Hallo Welt.
Wie geht es dir?
...
Hänge Zeile an
Es wird die Datei im Schreibmodus geöffnet (a ... append (anhängend), w ... write (überschreibend)).
write() fügt hier also eine Zeile Text am Dateiende ein. close() schließt die Datei wieder.
Das close() kann man sich mit der with-Anweisung auch sparen.
with open("datei.txt", mode="a", encoding="utf-8") as dat:
dat.write("Hänge Zeile an\n")
= Benutzeroberflächen erstellen =
== tkinter ==
{{Wikipedia | Tkinter}}
Python bietet standardmäßig das Modul tkinter zur Programmierung von Benutzeroberflächen. Es müssen also bei der Verwendung von tkinter keine externen Module installiert werden. Hier wird eine (sehr) kurze Einführung in das Erstellen von grafischen Oberflächen mittels tkinter gegeben.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
win.minsize(300, 50)
but = tk.Button(win, text = "Push the button")
but.pack()
win.mainloop()
Ausgabe:
[[Datei:PythonIng_gui1.jpg]]
Ein etwas komplizierteres Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
def on_button_clicked():
str = ent1.get() + ent2.get()
lab2["text"] = str
ent1 = tk.Entry(win)
ent2 = tk.Entry(win)
lab1 = tk.Label(win, text="verknuepfen mit")
lab2 = tk.Label(win, text="")
but = tk.Button(win, text = "=", command=on_button_clicked)
ent1.pack(side="left")
lab1.pack(side="left")
ent2.pack(side="left")
but.pack(side="left")
ent2.pack(side="left")
lab2.pack(side="left")
win.mainloop()
Ausgabe (vor der Eingabe der Teilstrings):
[[Datei:PythonIng_gui2.jpg]]
Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):
[[Datei:PythonIng_gui3.jpg]]
== curses ==
{{Wikipedia | curses}}
Mit dem curses-Modul lassen sich u.a. TUIs ('''T'''ext '''U'''ser '''I'''nterfaces) erstellen. Ein sehr einfaches Beispiel zur allgemeinen Funktionsweise wird nachstehend geliefert.
import curses
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
stdscr.clear()
stdscr.addstr("Hallo Welt", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.endwin()
Als Ausgabe sollte <span style="color:#FF0000;">Hallo Welt</span> (rote Schrift auf weißem Hintergrund) auf dem Terminal/der Konsole erscheinen. Getestet wurde dies mit openSUSE Tumbleweed, Python-Version 3.13.12. Das entsprechende Python-curses-Package muss installiert sein.
Allgemeine Informationen zur Terminal-/Konsolengröße und Cursorposition liefert folgendes Programm:
import curses
stdscr = curses.initscr()
stdscr.addstr(3, 5, "LINES: %d" % curses.LINES)
stdscr.addstr(4, 5, "COLS: %d" % curses.COLS)
(y,x) = stdscr.getyx()
stdscr.addstr(5, 5, "Momentane Cursorposition: [%d, %d]" % (y, x))
(y,x) = stdscr.getbegyx()
stdscr.addstr(6, 5, "Koordinatenursprung: [%d, %d]" % (y, x))
(y,x) = stdscr.getmaxyx()
stdscr.addstr(7, 5, "Fenstergröße: [%d, %d]" % (y, x))
stdscr.addstr(11, 2, "Taste drücken -> Ende")
stdscr.refresh()
stdscr.getch()
curses.endwin()
Es sollte sich in etwa folgende Ausgabe ergeben:
LINES: 44
COLS: 110
Momentane Cursorposition: [4, 15]
Koordinatenursprung: [0, 0]
Fenstergröße: [44, 110]
Taste drücken -> Ende
Zur Funktionsweise von curses siehe auch das Wikibook [[ncurses]]. Zum Verständnis sind dort allerdings elementare Kenntnisse in der Programmiersprache C erforderlich.
== Qt ==
{{Wikipedia | Qt (Bibliothek)}}
Auch für das Qt-Framework gibt es eine Anbindung an Python. Nachfolgend ein einfaches Beispiel.
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hallo Welt!")
label.show()
sys.exit(app.exec())
Ausgabe:
[[Datei:PythonIng_gui10.png]]
== Gtk ==
{{Wikipedia | GTK (Programmbibliothek)}}
Eine idente Ausgabe, wie oben für Qt gezeigt, erzeugt z.B. folgendes Gtk-Programm:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
lab = Gtk.Label(label="Hallo Welt!")
win.set_child(lab)
win.present()
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
Auch für die Benutzung von Qt und Gtk müssen die jeweiligen Packages installiert sein. Getestet wurden die entsprechenden Python-Programme nur unter openSUSE Tumbleweed. Wie das GTK-Paket unter MS Windows 11 installiert wird, siehe z.B. [https://www.gtk.org/docs/installations/windows Setting up GTK for Windows].
Damit sei aber das Thema "Benutzeroberflächen erstellen" hier abgeschlossen, da dies schon ein sehr spezielles Aufgabengebiet ist, das eher Informatiker und nicht so sehr Ingenieure anspricht. Bei Bedarf siehe aber ggf. die entsprechenden Links unten in diesem Tutorial. Dort sind weiterführende Informationen zu finden.
= Pandas kurz erklärt =
Hier wird kurz auf das externe Modul Pandas eingegangen. Pandas steht für '''Pan'''el '''Da'''ta und ist ein Modul für die Datenanalyse und -manipulation.
== Series ==
Vorstellbar ist eine "Series" wie eine einzelne Spalte in einem Tabellenkalkulationsprogramm.
Beispiel (Index implizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5]) # Temperaturwerte
print(temp)
Ausgabe:
0 8.5
1 11.0
2 12.5
3 10.0
4 13.0
5 11.0
6 14.5
dtype: float64
Das Kürzel <code>pd</code> ist Konvention. Es seien Temperaturwerte gegeben. Die erste Spalte bei der Ausgabe ist der Index. Die zweite Spalte enthält die Werte.
Beispiel (separater Zugriff auf den Index und auf die Werte):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5])
print(temp.index)
print(temp.values)
Ausgabe:
RangeIndex(start=0, stop=7, step=1)
[ 8.5 11. 12.5 10. 13. 11. 14.5]
Beispiel (Index explizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
print("*** Die gesamte Series ***")
print(temp)
print("*** Temperatur am Donnerstag ***")
print(temp["Do"])
print("*** Tage wärmer als 12 Grad ***")
temp_gr_12 = temp[temp > 12]
print(temp_gr_12)
Ausgabe:
*** Die gesamte Series ***
Mo 8.5
Di 11.0
Mi 12.5
Do 10.0
Fr 13.0
Sa 11.0
So 14.5
dtype: float64
*** Temperatur am Donnerstag ***
10.0
*** Tage wärmer als 12 Grad ***
Mi 12.5
Fr 13.0
So 14.5
dtype: float64
== DataFrame ==
Ein DataFrame entspricht einer Tabelle.
Beispiel (Erzeugen eines DataFrames):
import pandas as pd
tag = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
v1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=tag)
v2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=tag)
v3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=tag)
tab = pd.concat([v1, v2, v3], axis=1)
tab.columns = stadt
print(tab)
print(type(tab))
Ausgabe:
Linz Salzburg Innsbruck
Mo 1 8 Hallo
Di 2 9 16
Mi 3 10 17
Do 4 11 18
Fr 5 12 19
Sa 6 13 20
So 7 14 21
<class 'pandas.core.frame.DataFrame'>
Wir haben hier drei Datenspalten (v1, v2, v3) mit den Spaltennamen "Linz", "Salzburg" und "Innsbruck", sowie sieben Zeilen "Mo" bis "So".
Beispiel (Zugriff auf eine Spalte):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab["Salzburg"])
Ausgabe:
Mo 8
Di 9
Mi 10
Do 11
Fr 12
Sa 13
So 14
Name: Salzburg, dtype: int64
Beispiel (Zugriff auf eine Zeile):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab.loc["Di"])
Ausgabe:
Linz 2
Salzburg 9
Innsbruck 16
Name: Di, dtype: object
== Grafiken erstellen ==
Hier sei nur ein Torten- oder Kreisdiagramm gezeichnet:
import pandas as pd
import matplotlib.pyplot as plt
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
expl = [0, 0.2, 0, 0, 0, 0, 0]
temp.plot.pie(figsize=(5,5), explode=expl)
plt.show()
Ausgabe:
[[Datei:IngPython_pandas1.svg|350px]]
Die <code>figsize</code> hat nichts mit der Spaltenanzahl zu tun, sondern setzt die Fenster- oder Diagrammgröße in Inches (Breite * Höhe).
Mit Pandas kann man auch noch andere Diagrammarten erstellen, z.B. Linien- oder Balkendiagramme. Dies wird hier aber nicht vorgeführt.
== Arbeiten mit CSV- und LibreOffice-Dateien ==
Gegeben sei eine CSV-Datei test1.csv:
Mai;Juni;Juli
12;17;45
15;65;65
16;32;23
4;14;7
23;17;Keine Daten verfügbar
67;Keine Daten verfügbar;45
15;24;12
Lesen von dieser CSV-Datei:
import pandas as pd
tab = pd.read_csv("test1.csv", sep=";")
print(tab)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Schreiben in eine CSV-Datei test2.csv:
import pandas as pd
val = pd.read_csv("test1.csv", sep=";")
val.to_csv("test2.csv", index=False)
Ausgabedatei:
Mai,Juni,Juli
12,17,45
15,65,65
16,32,23
4,14,7
23,17,Keine Daten verfügbar
67,Keine Daten verfügbar,45
15,24,12
Die Ausgabedatei ist beinahe gleich wie die Eingabedatei. Es werden aber Kommas statt Strichpunkten verwendet. Daher kommt auch der Name CSV ('''C'''omma '''S'''eparated '''V'''alue). Will man wieder Strichpunkte, so kann man dies über den Parameter <code>sep=";"</code> in der <code>to_csv</code>-Funktion machen.
Um direkt von einer ODS-Datei (LibreOffice Calc, '''O'''pen '''D'''ocument '''S'''preadsheet) zu lesen muss das Modul odfpy extra installiert sein (per YaST, pip etc.). Gelesen wird dann folgendermaßen:
import pandas as pd
df = pd.read_excel('test1.ods', engine='odf')
print(df)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Die Datei "test1.ods" sei die Datei, aus der das obige "test1.csv" generiert wurde. Schreiben kann man ebenfalls in eine ODS-Datei:
import pandas as pd
daten = {
"Name": ["Hugo", "Richie", "Wilhelmine"],
"Alter": [38, 30, 29],
"Ort": ["Linz", "Innsbruck", "Salzburg"]
}
tab = pd.DataFrame(daten)
with pd.ExcelWriter("test2.ods", engine="odf") as writer:
tab.to_excel(writer, sheet_name="Daten", index=False)
Es ergibt sich eine "test2.ods"-Datei (Screenshot):
[[Datei:IngPython_pandas2.png|250px]]
== Sonstiges ==
Hier seien stichpunktartig einige weitere Features von Pandas angeführt:
* {{W|Pivot-Tabelle|Pivot-Tabellen}} (pivot ... Dreh-, Angelpunkt): Zweck - große Datenmengen schnell zusammenfassen, filtern und analysieren.
* NaN ('''n'''ot '''a''' '''n'''umber): In einem Datensatz fehlt ein Wert oder ist nicht definiert.
* groupby-Funktion: Daten strukturieren, aggregieren oder Zwischensummen bilden.
* {{W|Binning#Datenverarbeitung_und_-analyse|Binning}}: Klassenbildung.
* Mehrstufige Indizierung (Hierarchical Indexing oder MultiIndex)
* Zeitreihen (Time Series)
Für tiefergehende und weiterführende Informationen wird auf das Buch von ''Klein: Numerisches Python; Hanser, 2023'' und [https://pandas.pydata.org/ pandas] verwiesen.
= Style Guide, flake8, pylint, Black etc. =
== Style Guide ==
Wie man schönen und richtigen Python-Code schreibt, erfahren Sie in
* [https://peps.python.org/pep-0008/ PEP 8 – Style Guide for Python Code]
== Formatter und Linter ==
Ein Modul, das prüft, ob die Richtlinien im Style Guide eingehalten wurden, ist ''flake8'':
* [https://flake8.pycqa.org/en/latest/ Flake8: Your Tool For Style Guide Enforcement]
Code formatieren kann man auch mit [https://pypi.org/project/black/ Black]. Z.B. übersetzt <code>black test1.py</code> die Datei <code>test1.py</code>
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)),
(2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
in
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)), (2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Die Programmausgabe ist
reformatted test1.py
All done! ✨ 🍰 ✨
1 file reformatted.
Der Unterschied zwischen Black und Flake8:
* Black ist ein Code-Formatter. Er formatiert Ihren Code um, sodass er im Einklang mit PEP 8 steht.
* Flake8 ist ein {{W|Lint (Programmierwerkzeug) | Code-Linter}}. Flake8 verändert Ihren Code nicht, sondern durchsucht ihn nach potenziellen Fehlern etc.
Am obigen Beispiel sieht man auch, dass flake8 und Black nicht immer einer Meinung sind. Flake8 (<code>flake8 test1.py</code>) würde standardmäßig den mit Black formatierten Code bemängeln:
test1.py:8:80: E501 line too long (80 > 79 characters)
Diese Diskrepanz kann beseitigt werden. Da 79 Zeichen auf modernen Bildschirmen meist als zu kurz empfunden werden, ist ein Limit von 88 Zeichen (Black-Standard) oder mehr empfehlenswert. Um dies zu implementieren, erstellen Sie in Ihrem Projektverzeichnis eine <code>.flake8</code>-Datei mit dem Inhalt
[flake8]
max-line-length = 88
Und schon ignoriert Flake8 dieses Problem.
Ein anderer Linter ist pylint. Der würde beim Abarbeiten des obigen Beispiels, z.B. mit <code>pylint test1.py</code> noch eine Kleinigkeit bemängeln:
************* Module test1
/home/hr/tmp/test1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)
Auch pylint muss vor der ersten Verwendung installiert werden (z.B. mittels pip, virtuelle Umgebung, YaST). Die Dokumentation zu pylint findet sich auf [https://pylint.readthedocs.io/en/latest/].
<u>Aufgabe:</u> Fügen Sie einen "module docstring" in die <code>test1.py</code>-Datei ein und testen Sie erneut mit flake8, Black und pylint. <small>Sehen Sie zum Thema docstrings auch [https://peps.python.org/pep-0257/#what-is-a-docstring PEP 257 – Docstring Conventions].</small>
Es gibt noch weitere Formatierungswerkzeuge für Python-Code. Z.B. [https://docs.astral.sh/ruff/ Ruff], ein moderner Code-Formatter und -Linter. Mittels <code>ruff check test1.py</code> würde obiger Code geprüft (Linter). <code>ruff format test1.py</code> formatiert den Code (Formatter).
== Type Checker ==
"Type Checker" sind z.B.
* mypy
* pyright
* ty
Diese prüfen die Datentypen, z.B. in folgendem Code
def greetings(name: str) -> str:
return "Hello, %s" % name
print(greetings(42))
Python selbst, flake8, ruff oder black würden diesen Code ohne zu murren akzeptieren. "Type Checker" würden aber sehr wohl Alarm schlagen, z.B. liefert <code>mypy</code> folgende Ausgabe
test1.py:5: error: Argument 1 to "greetings" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Das funktioniert übrigens nicht nur bei Funktionsannotationen, sondern auch mit Variablen etc.
from typing import Final
# "Konstante", ab Python 3.8
NUMBER: Final = 123
print(NUMBER)
NUMBER = 125
print(NUMBER)
# Variable
a: int = 345
print(a)
a = "Irgendwas"
print(a)
# Variable (Pipe-Symbol), ab Python 3.10
b : int|str = 567
print(b)
b = "sonstiges"
print(b)
Ausgabe mit python:
123
125
345
Irgendwas
567
sonstiges
Ausgabe mit mypy:
test3.py:6: error: Cannot assign to final name "NUMBER" [misc]
test3.py:12: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
Found 2 errors in 1 file (checked 1 source file)
Python kennt übrigens keine Konstanten. Man kann diese mittels Großbuchstaben andeuten. Das ist aber nur Konvention, hat aber keine sonstigen Auswirkungen. Oder man verwendet wie oben gezeigt <code>Final</code>. Dann werfen Typchecker Errors aus.
==pydoc==
pydoc ist ein Werkzeug, um Python-Module, -Funktionen und -Klassen zu dokumentieren.
Beispiel <code>test1.py</code>:
"""Rechen-Modul.
Funktionen die von pydoc gelesen werden.
"""
def multiply(a, b):
"""Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a * b
def add(a, b):
"""Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a + b
if __name__ == '__main__':
print(multiply(3, 5))
print(add(4, 6))
Ausgabe mit <code>python3.13 -m pydoc test1</code> auf der Konsole:
Help on module test1:
NAME
test1 - Rechen-Modul.
DESCRIPTION
Funktionen die von pydoc gelesen werden.
FUNCTIONS
add(a, b)
Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
multiply(a, b)
Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
FILE
/home/xyz/tmp/test1.py
Siehe zu diesem Thema z.B. auch [https://docs.python.org/3/library/pydoc.html]. Mittels <code>python3.13 -m pydoc -w test1</code> kann man auch eine HTML-Dokumentation erstellen.
Wofür <code>if __name__ == '__main__':</code> steht, siehe z.B. etwas später im Abschnitt [[Ing_Mathematik:_Python#Doctests]].
== Sonstige Tools ==
Andere Tools für die {{W|Statische Code-Analyse|statische Codeanalyse}}, die aber für Ingenieure weniger interessant sein dürften, sind z.B.
* Radon: Liefert verschiedene {{W|Softwaremetrik|Codemetriken}} (Komplexität, Wartbarkeitsindex ...)
* Bandit: Findet Sicherheitslücken
Tools für die {{W|Dynamisches Software-Testverfahren|dynamische Codeanalyse}}, z.B.:
* DynaPyt (Framework zur dynamischen Programmanalyse)
* cProfile (Profiler)
* Memory Profiler (Speicheranalyse)
* Memray (Speicheranalyse)
* tracemalloc (Speicheranalyse)
Paket- und Projektmanagement (pip-Ersatz etc.):
* uv
* Poetry
* Conda
* pipx
Packaging-Tools (Freezer) und {{W|Compiler#Sonderformen|Transpiler}} :
* pyinstaller
** erstellt eigenständige, ausführbare Binärdatei
** kein Cross-Compiler
** kein Schutz vor Reverse-Engineering
** langsam
** packt alles in eine Datei
** sehr große Datei
** Befehl, z.B.: <code>pyinstaller --onefile test1.py</code>
** GUI: <code>auto-py-to-exe</code>
* cx_Freeze
* nuitka
** Übersetzt Python-Code in C/C++-Code und weiter in eine ausführbare Datei
** kein Cross-Compiler
** Schutz vor Reverse-Engineering
** Befehl, z.B.: <code>nuitka --standalone --onefile test1.py</code>
* cython
= Einige Integrierte Entwicklungsumgebungen (IDEs)=
Werden Programmtexte größer und umfangreicher, so ist das Arbeiten mit der interaktiven Programmierumgebung bzw. das direkte Ausführen von Python-Skripten mühsam. Man wünscht sich z.B. Hilfen zum Debuggen oder die automatische Code-Vervollständigung. Zu diesem Zweck wurden IDEs (Integrated Development Environments) geschaffen. Von diesen seinen nachfolgend auszugsweise einige kurz beschrieben. Testen Sie einfach aus, welche davon für Sie bzw. für Ihr Python-Projekt geeignet sind.
== IDLE ==
IDLE ist die mit dem Python-Programmpaket mitgelieferte IDE. Der Name leitet sich einerseits ab vom Monty-Python-Mitglied Eric Idle, andererseits steht es als Abkürzung für "'''I'''ntegrated '''D'''evelopment and '''L'''earning '''E'''nvironment. IDLE ist einfach zu bedienen, bietet aber schon einen beachtlichen Leistungsumfang. Nachfolgend wird ein Screenshot zu IDLE geliefert. Rechts ist das Editor-Fenster zu sehen, links die interaktive Programmierumgebung. Um das Beispiel selbst nachvollziehen zu können, starten Sie IDLE. Das geht ähnlich, wie Sie die interaktive Programmierumgebung von Python starten (nur, dass Sie eben das IDLE-Icon doppelklicken und nicht das Python-Icon. Unter Linux geben Sie einfach in einem Terminal <code>idle3.13</code> o. Ä. ein). Weiter geht es mit "File - Open - ...". Die auszuführende Datei auswählen (im konkreten Fall ein "Hallo-Welt"-Programm). Es erscheint das rechte Fenster. Dort "Run - Run Module" auswählen. Und schon wird im linken Fenster "Hallo Welt!" ausgegeben.
[[Datei:PythonIng_idle1.jpg | 600px]]
Siehe auch {{W|IDLE}}.
== PyCharm ==
PyCharm ist ein kommerzielles Produkt. Es gab aber auch eine kostenlose Community Edition. Seit 2025 sind beide Varianten vereint. Für die ersten 30 Tage sind die Pro-Funktionen frei verfügbar, danach nur noch die Kernfunktionalitäten (oder man bezieht kostenpflichtig die Pro-Version). Zu beziehen ist PyCharm unter dem Weblink [https://www.jetbrains.com/pycharm/]. Nachfolgend ein etwas abgewandeltes "Hallo Welt"-Programm, editiert und ausgeführt mit PyCharm.
[[Datei:PyCharm_IDE_2023_screenshot.png | 600px]]
Siehe auch {{W|PyCharm}}.
== Eric ==
Auch eric ist Open Source und steht unter der GNU General Public License Version 3 oder später. Zu beziehen ist diese Software unter [https://eric-ide.python-projects.org/].
[[Datei:Screenshot_Eric_4.png | 600px]]
Siehe auch {{W|eric (Software)}}.
<small>
Unter openSUSE Tumbleweed sollte sich eric auch mit YaST installieren lassen. Bei mir gibt es aber dann beim Ausführen des eric-Programms eine Fehlermeldung (Stand März 2026):
...
ModuleNotFoundError: No module named 'PyQt6.QtPdfWidgets'
Umgehen kann man dieses Problem aber wieder mit dem Erstellen einer virtuellen Umgebung, in etwa so
python3.13 -m venv ~/tmp/venv1
cd ~/tmp/venv1/bin
./python3.13 -m pip install --upgrade --prefer-binary eric-ide
./eric7_ide
</small>
== PyScripter ==
Vom Funktionsumfang vergleichbar mit den vorherigen IDEs ist PyScripter. Auch PyScripter ist Open Source. Die Projekt-Homepage findet sich auf [https://sourceforge.net/projects/pyscripter/]. PyScripter ist nur für MS Windows verfügbar.
[[Datei:PythonIng_pyscripter1.jpg | 600px]]
== Spyder IDE ==
Spyder enthält bereits eine stabile Python-Version und etliche Module (z.B. matplotlib, numpy, control). Ansonsten kann dieses Softwarepaket vom Funktionsumfang her mit den anderen genannten IDEs locker mithalten. Spyder wurde unter der MIT-Lizenz veröffentlicht. Diese Software findet sich auf [https://www.spyder-ide.org].
[[Datei:Spyder-windows-screenshot.png | 600px]]
Siehe auch {{W|Spyder (Software)}}
== Eclipse IDE==
Die {{W|Eclipse_(IDE)|Eclipse-IDE}} kann für Python aufgerüstet werden. Dazu gibt es das PyDev-Plugin. Installiert wird es über
* Help > Eclipse Marketplace...
* Find - PyDev - Install
Danach muss noch der Pfad zum Python-Interpreter festgelegt werden
* Window > Preferences > PyDev > Interpreters > Python Interpreter > New ...
Das Ergebnis ist ähnlich wie im folgenden Bild, nur dass statt C/C++ Python Verwendung findet.
[[Datei:Setting Up Eclipse CDT helloout.png | 600px]]
== Sonstige ==
Die genannten IDEs sind nicht die Einzigen. Es gibt, um dem Image Pythons als beliebteste Programmiersprache gerecht zu werden, noch einige andere. Sowohl Open Source-Programme als auch kommerzielle Programme sind im Web zu finden, z.B. Thonny oder {{W|Visual Studio Code}}. Unter Linux kann man auch {{W|KDevelop}}, ausgestattet mit dem Python3-Plugin, einsetzen. Braucht man den Umfang von ausgewachsenen IDEs nicht, so kann man auch normale Texteditoren verwenden (z.B. {{W|Geany}} oder {{W|Kate_(Texteditor)|Kate}}).
= Debuggen und Testen =
Das Debuggen und Testen von Programmen sind wichtige Bestandteile der Programmierung. Syntaxfehler lassen sich i.A. leicht beheben. Schwieriger ist das Eingrenzen von logischen Fehlern, die ev. nur in bestimmten Situationen auftreten und keine explizite Fehlermeldung hervorrufen. Das Programm liefert falsche Ergebnisse oder es stürzt aus heiterem Himmel ab. Um das zu verhindern gibt es verschiedene Werkzeuge, die bei der Fehlersuche behilflich sein können. Vorerst siehe aber zwecks Begriffsklärung noch folgende Links:
* {{W|Debuggen}}
* {{W|Debugger}}
* {{W|Softwaretest}}
<gallery>
First Computer Bug, 1947.jpg
Test ganzheitlich.png
V-Modell.svg
</gallery>
== Das Modul pdb ==
Python bringt schon ein Modul zum Debuggen mit. Siehe z.B. [https://docs.python.org/3/library/pdb.html pdb — The Python Debugger].
Komfortabler lässt sich das aber mittels Integrierter Entwicklungsumgebungen (IDEs) angehen.
== Debuggen mit IDEs ==
Für die IDEs IDLE und Spyder sei kurz auf die entsprechenden Webseiten verwiesen:
* [https://www.cs.uky.edu/~keen/help/debug-tutorial/debug.html Debugging under IDLE].
* [https://docs.spyder-ide.org/current/panes/debugging.html Spyder Debugger]
Dort wird die Vorgehensweise auch mittels Screenshots erläutert.
== assert ==
assert ... behaupten, zusichern ({{W|Assertion (Informatik)}})
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10., 0.)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10., 0.)
File "/home/hr/Develop/test1.py", line 4, in print1
assert y != 0.0
^^^^^^^^
AssertionError
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1("10.", "5.")
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Aber auch bei nachfolgendem Code gibt es eine Fehlermeldung:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10, 5)
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Damit letzteres funktioniert, kann man den Programmcode so umschreiben:
def print1(x, y):
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
2.0
Und jetzt fangen wir den <code>AssertionError</code> auf:
def print1(x, y):
try:
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
except(AssertionError):
print("Hallo")
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Hallo
Ich hoffe, es ist wenigstens im Ansatz klar geworden, wofür <code>assert</code> gut sein kann. Ausschalten kann man die <code>assert</code>-Überprüfung übrigens mit dem Python-Schalter <code>-O</code>.
== Doctests ==
Innerhalb eines Docstrings kann die Arbeit im interaktiven Modus simuliert werden. Nach den Promptzeichen (>>>) erfolgen dann bei unserem Beispiel innerhalb des Docstrings simulierte Aufrufe der Funktion <code>print1()</code>. Danach folgen jeweils die Sollresultate. Wird das Modul oder die Datei als Hauptprogramm aufgerufen, so wird die Funktion <code>doctest.testmode()</code> aufgerufen und ein Bericht auf der Konsole ausgegeben. Wird das Modul nicht als Hauptprogramm aufgerufen, sondern importiert, dann wird diese <code>testmod</code>-Funktion nicht aufgerufen. D.h. dieser Code kann sowohl für Testzwecke als auch für den produktiven Einsatz verwendet werden. Das ist auch sinnvoll, weil wenn man Teile der Datei immer löschen bzw. einfügen müsste, so würden sich Fehlerquellen auftun. Das würde den Sinn und Zweck von Doctests konterkarieren.
def print1(x=0., y=1.):
""" Dividiere zwei Zahlen
Autor: Intruder
Datum: 12.08.2025
>>> print1(2., 1.)
2.0
>>> print1(5., 2.)
2.5
>>> print1(5.)
5.0
"""
print(x/y)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Ausgabe:
Trying:
print1(2., 1.)
Expecting:
2.0
ok
Trying:
print1(5., 2)
Expecting:
2.5
ok
Trying:
print1(5.)
Expecting:
5.0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.print1
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Das gezeigte Beispiel ist so ziemlich das einfachste, das es gibt. Für weiterführende Details siehe z.B.:
* [https://peps.python.org/pep-0257/ PEP 257 – Docstring Conventions]
* [https://docs.python.org/3/library/doctest.html doctest — Test interactive Python examples]
''Einschub:'' Ganz ähnlich kann man auch Klassen testen, z.B. in folgendem Code-Fragment
class Fahrzeug:
# siehe Abschnitt "Objektorientierte Programmierung"
# ...
if __name__ == "__main__":
vauweh = Fahrzeug(170, 90)
beemweh = Fahrzeug(200, 120)
print(vauweh.convertGeschw())
print(beemweh.convertGeschw())
Wird das Script als Hauptprogramm ausgeführt (z.B. zu Testzwecken), so erfolgt die Ausgabe der zwei, via <code>convertGeschw()</code>, umgerechneten Geschwindigkeiten. Wird es aber als Modul eingebunden, so wird der letzte Programmabschnitt nicht ausgeführt (<code>__name__ == "__main__"</code> ergibt <code>False</code>).
== pytest ==
Siehe zu diesem Thema auch {{W|Modultest}}.
pytest ist ein externes Modul und muss vorab installiert werden, z.B. mittels
pip install -U pytest
pip install -U pytest-html
Python-Code, Datei test1.py:
def add(x, y):
return x + y
def test_answer():
assert add(1, 1) == 3
Starten von pytest in der Konsole:
pytest test1.py
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py F [100%]
========================================================= FAILURES ==========================================================
________________________________________________________ test_answer ________________________________________________________
def test_answer():
> assert add(1, 1) == 3
E assert 2 == 3
E + where 2 = add(1, 1)
test1.py:6: AssertionError
================================================== short test summary info ==================================================
FAILED test1.py::test_answer - assert 2 == 3
===================================================== 1 failed in 0.09s =====================================================
Hier erhalten wir einen Fehler, da 1+1 eindeutig ungleich 3 ist. Aber aus irgendeinem Grund wollte der Programmierer oder Tester in diesem Fall, dass dies so ist. Testfälle werden übrigens mit dem Präfix <code>test_</code> eingeleitet.
Python-Code:
def add(x, y):
return x + y + 1
def test_answer():
assert add(1, 1) == 3
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py . [100%]
===================================================== 1 passed in 0.01s =====================================================
Jetzt ist alles in Ordnung. Weiterführendes siehe z.B.
* [https://docs.pytest.org/en/stable/ pytest: helps you write better programs]
== unittest ==
Auch unittest dient zur Durchführung von Testreihen, ist aber Bestandteil von Python. Hier wird vorerst nicht näher darauf eingegangen. Siehe z.B.
* [https://docs.python.org/3/library/unittest.html unittest — Unit testing framework]
Lt. ''Inden: Python Challenge; dpunkt, 2021, Seite 481'' soll unittest weniger komfortabel als pytest sein.
Einen Vergleich von unittest mit pytest findet man in
* [https://knapsackpro.com/testing_frameworks/difference_between/pytest/vs/unittest pytest vs unittest]
= Python und Anwendungsprogramme =
Bisher stand immer alleine die Programmiersprache Python (ev. unter Einbeziehung von Modulen) im Mittelpunkt der Betrachtungen. Aber Python kann auch als Makrosprache für Anwendungsprogramme auftreten. Als Beispiele seien {{W|FreeCAD}} und {{W|LibreOffice}} genannt.
== FreeCAD ==
FreeCAD ist ein freies 3D-CAD-Programm. Hier soll nicht auf die Bedienung dieses CAD-Pakets eingegangen werden, sondern nur auf die Möglichkeit, mittels Python Makros zu schreiben. Als einfacher Einstieg soll ein Makro erstellt werden, welches eine Kugel (rot) und einen Quader (blau) zeichnet. Folgende Vorbereitungsschritte sind erforderlich (es sei vorausgesetzt, dass FreeCAD schon am Rechner installiert ist. Downloaden können Sie das Programm von der Website [https://www.freecad.org/downloads.php?lang=en]):
* FreeCAD starten
* Leere Datei erstellen
* Makro > Makros > Erstellen ...
Es öffnet sich ein leeres Editorfenster, in das Sie folgenden Code eingeben können:
import FreeCAD
import Part
doc = FreeCAD.newDocument()
# Kugel
kugel = Part.makeSphere(10)
form_element = doc.addObject("Part::Feature", "Kugel")
form_element.Shape = kugel
kug = FreeCAD.ActiveDocument.getObject("Kugel")
kug.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
neuePosition = App.Vector(5, 2.5, 2.5)
kug.Placement = App.Placement(neuePosition, kug.Placement.Rotation)
# Quader
quader = Part.makeBox(5, 5, 50)
form_element = doc.addObject("Part::Feature", "Quader")
form_element.Shape = quader
quad = FreeCAD.ActiveDocument.getObject("Quader")
quad.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
doc.recompute()
Diesen Code können Sie nun ausführen:
* Makro > Makro ausführen
Es ergibt sich folgende Ausgabe (gedreht und gezoomt):
[[Datei: PythonIng_freecad1.png|500px]]
Siehe auch [https://wiki.freecad.org/Python_scripting_tutorial/de# Anleitung Skripterstellung mit Python]. Getestet wurde obiges Beispiel mit FreeCAD 1.1.3 unter Linux und 1.1.1 unter MS Windows.
== LibreOffice ==
LibreOffice ist ein freies Officepaket ([https://de.libreoffice.org/]). Hier soll nur das Tabellenkalkulationsprogramm Calc kurz betrachtet werden. Es seinen in den ersten 3 Zellen (A1 bis A3) Zahlen gegeben. Diese sollen mit einem Python-Makro addiert und das Resultat in der Zelle A5 ausgegeben werden. Auch hier sind Vorbereitungsarbeiten nötig:
* zuerst muss unter Linux das Verzeichnis <code>~/.config/libreoffice/4/user/Scripts/python</code> erstellt werden
* für MS Windows ist es das Verzeichnis <code>%APPDATA%\LibreOffice\4\user\Scripts\python</code>
** drücken Sie zuerst Win + R (es öffnet sich das Ausführen-Fenster)
** geben Sie <code>%appdata%</code> ein, danach drücken Sie Enter (es öffnet sich der Explorer)
** navigieren Sie zu dem genannten Verzeichnis bzw. erstellen Sie das Verzeichnis
* in diesem Verzeichnis wird dann mit einem beliebigen Texteditor das Python-Makro erstellt, in unserem Fall die Datei <code>summiere_zellen.py</code>:
import uno
def summiere_zellen(*args):
# Zugriff auf das aktuelle Dokument und das aktive Tabellenblatt
ctx = uno.getComponentContext()
smgr = ctx.getServiceManager()
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.getCurrentController().getActiveSheet()
# Werte aus den Zellen A1 bis A3 auslesen
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
# Addition der drei Werte
summe = w1 + w2 + w3
# Ergebnis in die Zelle A5 schreiben
sheet.getCellRangeByName("A5").Value = summe
* siehe dazu ggf. auch [https://help.libreoffice.org/latest/de/text/sbasic/python/python_locations.html?DbPAR=BASIC].
Weiter geht es in LibreOffice Calc mit dem Menü ''Extras > Makros > Makros verwalten > Python''. Dort wird das Makro <code>summiere_zellen</code> ausgeführt. Es ergibt sich z.B. folgendes Resultat
[[Datei:PythonIng_libreoffice1.png]]
Das Kürzel <code>uno</code> steht für '''U'''niversal '''N'''etwork '''O'''bjects. Etwas einfacher geht's auch so:
def summiere_zellen():
desktop = XSCRIPTCONTEXT.getDesktop()
model = desktop.getCurrentComponent()
sheets = model.getSheets()
sheet = sheets.getByIndex(0)
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
cell = sheet.getCellRangeByName("A5")
cell.setValue(w1 + w2 + w3)
Empfohlen wird auch, das Erweiterungspaket APSO ('''A'''lternative '''P'''ython '''S'''cript '''O'''rganizer, apso.oxt) zu installieren. Die Vorgehensweise wird hier nicht gezeigt, sondern nur darauf hingewiesen, dass man das einfach "googeln" kann. Siehe zur Python-Programmierung für LibreOffice auch [https://wiki.documentfoundation.org/Macros/Python_Guide/de Makros/Python-Handbuch]. Getestet wurden obige Beispiele mit LibreOffice 26.2.5.1 unter Linux und 26.2.1.2 unter MS Windows.
= Ausblick =
Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Python. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks, Bücher und die Python-Hilfefunktion verwiesen. Python kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Module fast beliebig erweiterbar.
= Weblinks=
== Python allgemein ==
* [https://www.python.org/ Python Homepage]
== Externe mathematische Module ==
* [https://numpy.org/ NumPy]
* [https://numpy.org/doc/stable/user/numpy-for-matlab-users.html NumPy for MATLAB users]
* [https://scipy.org/ SciPy]
* [https://www.sympy.org/en/index.html SymPy]
* [https://pandas.pydata.org/ pandas]
* [https://github.com/maroba/findiff findiff]
* [https://mpmath.org/ mpmath]
== Externe Module für Grafiken ==
* [https://matplotlib.org/ Matplotlib]
* [https://vpython.org/ VPython]
* [https://build123d.readthedocs.io/en/latest/ build123d]
* [https://docs.vtk.org/en/latest/api/python.html VTK]
* [https://docs.bokeh.org/en/latest/docs/first_steps.html bokeh]
* [https://py5coding.org/ py5]
== Erstellung von User Interfaces ==
* [https://docs.python.org/3/library/tkinter.html tkinter - Python interface to Tcl/Tk]
* [https://docs.python.org/3/library/curses.html curses - Terminal handling for character-cell displays]
* [https://wiki.qt.io/Qt_for_Python Qt for Python]
* [https://www.gtk.org/docs/language-bindings/python GTK and Python]
== Erstellen virtueller Umgebungen ==
* [https://docs.python.org/3/library/venv.html venv - Creation of virtual environments]
== Sonstige ==
* [https://python-control.readthedocs.io/en/stable/ Python Control Systems Library]
* [https://pypi.org/project/regex/ regex - Regular Expressions]
* [http://pyromat.org/ PYroMat]
* [https://coolprop.org/coolprop/wrappers/Python/index.html CoolProp]
* [https://pypi.org/project/iapws/ iapws]
* [https://tespy.readthedocs.io/en/main/getting_started/introduction.html TESPy - Thermal Engineering Systems in Python]
* [https://pint.readthedocs.io/en/stable/ pint]
= Bücher =
== Gedruckte Bücher, OpenBooks, Magazine ==
* Diverse: c't Python Lernen, Verstehen, Anwenden; Heise, 2022
* Ernesti, Kaiser: Python3 - das umfassende Handbuch; 5. Aufl., Rheinwerk, [https://openbook.rheinwerk-verlag.de/python/ OpenBook]
* Iacono et al.: Programmieren trainieren; 3. Aufl., Hanser, 2023, ISBN 978-3-446-47766-7
* Inden: Python Challenge; dpunkt, 2021, ISBN 978-3-86490-809-5
* Klein: Numerisches Python; 2. Aufl., Hanser, 2023, ISBN 978-3-446-47170-2
* Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler; Rheinwerk, 2021, ISBN 978-3-8362-7316-9
* Weigend: Python 3 - Das umfassende Praxisbuch; 9. Aufl., mitp, 2022, ISBN 978-3-7475-0544-1
* Woyand: Python für Ingenieure und Naturwissenschaftler; 4. Aufl., Hanser, 2021, ISBN 978-3-446-46483-4
== Andere Wikibooks ==
* [[:en:Subject:Python_programming_language | Englische Wikibooks zum Thema Python]]
* [[Python|Deutschsprachiges Python-Wikibook]] [[Bild:2von10.png|20%]]
* [[Python unter Linux|Python 2.7 unter Linux]] [[Bild:10von10.png|100%]]
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
a5znnvbwv9j55fhfd9j2ssma3087e2y
1091892
1091891
2026-10-03T16:30:30Z
Intruder
1513
/* Py5 */
1091892
wikitext
text/x-wiki
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
= Hallo Welt und allgemeine Hinweise =
== Was ist Python ==
* Python ist eine universelle höhere Programmiersprache.
* Python ist objektorientiert.
* Python ist Open-Source (Python Software Foundation License).
* Python ist für viele Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
* Python ist ein Interpreter.
* Python ist durch Module fast beliebig erweiterbar.
* Python als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
* Python ist in etlichen Anwendungsprogrammen (z.B. {{W|FreeCAD}}, {{W|LibreOffice}}, {{W|GIMP}}, {{W|Blender (Software) | Blender}}) als Makrosprache verwendbar.
{{Wikipedia | Python (Programmiersprache)}}
== Python installieren ==
=== MS Windows ===
Laden Sie das aktuelle Python-Paket von der Webseite [https://www.python.org/] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.
=== Linux ===
Entweder ist Python bereits standardmäßig installiert, ansonsten ist die Installation mittels Paketmanagementsystem einfach möglich. Aber auch die Spyder-Entwicklungsumgebung ([https://www.spyder-ide.org]) bietet einen guten Einstieg mit Python (das gilt auch für MS Windows). Spyder bringt auch schon etliche wichtige Module standardmäßig mit.
== Python starten ==
=== MS Windows ===
Das Icon für das Python-Programm doppelklicken. Und schon startet das Programm.
[[Datei:PythonIng_start1.jpg]]
Python im interaktiven Modus präsentiert sich dann so:
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Alternativ kann das Programm auch über die Eingabeaufforderung oder die PowerShell gestartet werden:
c:\devel\Python>python.exe
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
=== Linux ===
Tippen Sie einfach das Wort „python“ (oder unter openSUSE Tumbleweed z.B. auch „python3.11“ oder „python3.13“) in einem Linux-Terminal ein, schließen den Befehl mit der RETURN-Taste ab, und schon startet Python im interaktiven Modus:
Python 3.13.12 (main, Feb 09 2026, 22:37:44) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Es gibt auch noch andere Möglichkeiten Python zwecks Programmausführung zu starten, z. B. den {{W|Shebang}} (<code>#!</code>) am Beginn eines Python-Scripts. Das Script sei als Script.py gespeichert. Dann kann das Script mit ./Script.py ausgeführt werden. Für openSUSE Tumbleweed sei nachfolgend ein lauffähiges "Hallo Welt!"-Script angegeben. Es wird in diesem Script der Python-Interpreter in der Version 3.13 verwendet :
#!/usr/bin/python3.13
print("Hallo Welt!")
Die Berechtigungen zum Ausführen der Datei müssen natürlich noch richtig gesetzt werden, z.B. mittels <code>chmod 777 Script.py</code>. <small><code>chmod</code> ist die Abkürzung für"'''ch'''ange file '''mod'''e bits".</small>
<small>Die "Maske" <code>777</code> ist nur für Testzwecke sinnvoll, weil sie leicht zu merken ist und für alle Benutzer alle Zugriffsberechtigungen ('''r'''ead/'''w'''rite/e'''x'''ecute für owner/group/others) setzt. Im richtigen Einsatz wird man das aus Sicherheitsgründen nicht so handhaben, sondern nur die Berechtigungen setzen, die unbedingt erforderlich sind. Welche Zugriffsberechtigungen gesetzt sind, kann man z.B. mit dem Befehl <code>ls -l</code> oder <code>ll</code> ('''l'''i'''s'''t directory contents) erfragen. Aber dazu im Moment genug. Erfahrene Linux-Nutzer kennen das ohnehin und Anfänger sollen jetzt nicht mit Linux-Interna überfordert werden. Bei Bedarf siehe die Linux-Man-Pages oder dezidierte Bücher zu Linux.</code></small>
<small>Oder das Script wird in einen Pfad verschoben, in dem sich ausführbare Programme generell befinden (welche Verzeichnisse im PATH liegen, kann bspw. mit <code>echo $PATH</code> abgefragt werden). Das Script kann dann wie ein normales Programm ohne weitere Angaben mit Script.py gestartet werden. Alternativ wird nicht das Script an sich verschoben, sondern nur ein symbolischer Link angelegt, z.B. mit <code>ln -s ~/tmp/Script.py ~/.local/bin/Script.py</code>. <code>~/.local/bin</code> sei ein im PATH gelegenes Verzeichnis. Dies sind aber schon Features für fortgeschrittene Linux-Benutzer und werden am Anfang eher selten benötigt.</small>
== Ein paar Worte zur Erklärung ==
=== Tests ===
Getestet wurden die Beispiele unter den Betriebssystemen
* MS Windows 10 mit der Python-Version 3.12.0 (teilweise auch mit 3.12.2 und 3.13.1; nur die Inhalte die bis spätestens Juli 2025 erstellt wurden)
* MS Windows 11 ab der Python-Version 3.13.4 (nur zum Teil; ab Juli 2025)
* openSUSE Leap 15.6 mit der Python-Version 3.11.12 (Spyder, nur vereinzelt) und zum Teil mit 3.12.11 (ab Juli 2025 bis November 2025).
* openSUSE Tumbleweed ab der Python-Version 3.13.9 (nur vereinzelt, ab November 2025)
=== Popularität ===
* An Beliebtheit rangiert Python mit Stand September 2026 mit einem Rating von 17,76% an 1. Stelle vor C und C++ (lt. [https://www.tiobe.com/tiobe-index/ TPCI - TIOBE Programming Community Index]).
* Lt. [https://innovationgraph.github.com/global-metrics/programming-languages GitHub Top 50 Programming Languages Globally] lag Python im Q1/2026 auf Rang 2, vor TypeScript und hinter JavaScript.
* [https://pypl.github.io/PYPL.html PYPL] (Popularity of Programming Language Index) ist ein anderer Popularitätsindex für Programmiersprachen. Auch hier liegt Python mit großem Vorsprung auf dem ersten Platz (52,08%), gefolgt von Java (13,34%) und C/C++ (7,99%) (Stand September 2026).
=== Namensgebung ===
Der Name "Python" rührt von der Komikertruppe {{W|Monty Python}} her. Die Icons für Python (z.B. Python selbst, Eric IDE, IDLE) sind aber durch die Python-Schlangenart symbolisiert.
<gallery>
Python-logo-notext.svg|Python-Logo
Guido van Rossum in PyConUS24.jpg|{{W|Guido van Rossum}} (geb. 1956), der Erfinder von Python
</gallery>
== Ein erstes Programm ==
Kommentare werden in Python mit der Raute (#) eingeleitet. Sie werden vom Python-Interpreter ignoriert. Text kann mit der print-Funktion ausgegeben werden. Starten Sie Python und geben sie folgende Anweisungen zeilenweise ein
>>> # Das ist ein Kommentar
>>> print("Hallo Welt!")
Als Ergebnis erhalten Sie
Hallo Welt!
Der Prompt (>>>) ist selbstverständlich nicht einzutippen, sondern wird vom Python-System geliefert.
Strings können in Python entweder in Anführungszeichen (") gesetzt werden oder in Hochkommatas('). In diesem Text wird die erste Variante bevorzugt eingesetzt.
Im Gegensatz zu Julia ist es hier egal, ob zwischen <code>print</code> und der öffnenden Klammer Leerzeichen stehen.
= Python als Taschenrechner =
== Allgemeines ==
Wir wollen 3 * 5 berechnen. Dazu starten wir Python im interaktiven Modus. Geben Sie dann die Formel
>>> 3 * 5
ein, drücken die Taste ENTER/RETURN ({{Taste|↵}}) und erhalten als Ergebnis
15
Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck <math>\sin\sqrt{15}</math> berechnen :
>>> import math
>>> math.sin(math.sqrt(15))
-0.6679052983383519
Als erstes wird das math-Modul importiert. Dann wird der mathematische Ausdruck berechnet.
Eine andere Variante, die dasselbe Ergebnis liefert, ist
>>> from math import *
>>> sin(sqrt(15))
-0.6679052983383519
Es wird also aus dem Modul <code>math</code> alles importiert (erkennbar am <code>*</code>). Will man nicht alles importieren, so kann man das auch einschränken:
>>> from math import sin, sqrt
Beenden lässt sich das Python-Programm durch Eingabe von <code>exit()</code> (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken).
== Die Hilfefunktion von Python ==
Bei Eingabe der Anweisung <code>help</code> oder <code>help()</code> springt Python in den Hilfemodus.
Eingabe:
>>> help()
Eingabe:
help> math.sin
Ausgabe:
Help on built-in function sin in math:
math.sin = sin(x, /)
Return the sine of x (measured in radians).
Für die komplette Python-Dokumentation siehe [https://docs.python.org/3/]. Verlassen kann man den Hilfemodus durch das Drücken von STRG-C, bzw. der Eingabe von q, quit oder exit mit anschließendem Drücken der RETURN-Taste.
== Aufgaben ==
* Erkunden Sie die Tangensfunktion "tan" mittels Python-Hilfe (vergessen Sie nicht das math-Modul zu importieren und das <code>math.</code> vor <code>tan</code>)
* Berechnen Sie mit Python den Ausdruck <math>\frac{1}{2}\cdot \text{e}^2 \cdot \tan(\pi/3)</math>. Siehe für die Exponentialfunktion im Python-Hilfesystem auch den Befehl <code>math.exp</code>. Alternativ kann auch die Konstante <code>math.e</code> eingesetzt werden. Potenzieren kann man bei Python mit dem **-Operator (z.B. 2**3 = 8). Für <math>\pi</math> gibt es <code>math.pi</code>.
= Python als Scriptsprache =
Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.py
# Das ist ein Kommentar
print("Hallo Welt!")
Python-Dateien werden mit der Dateiendung .py versehen. Achten Sie darauf, dass vor dem print keine Leerzeichen vorhanden sind. Das ist eine Python-Eigenheit. Wie wir später sehen werden, nutzt Python Einrückungen als syntaktisches Mittel, z.B. um bei Schleifen den Schleifenkörper zu kennzeichnen.
Danach bringen Sie die Skriptdatei test1.py (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:
1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ auch die Windows PowerShell). Das sieht dann etwa so aus:
Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\xyz>
: <small>Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol ([[Image:Windows_logo_-_2021_(Black).svg|10px]]) mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell unter Windows 10 den Eintrag "Windows PowerShell", unter Windows 11 den Eintrag "Terminal"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort <code>cmd</code> ein und mit "OK" wird das Ganze bestätigt.</small>
2) Wechseln Sie mittels <code>cd c:\tmp</code> in das Verzeichnis c:\tmp
3) Angenommen, Sie haben Python unter dem Pfad <code>c:\devel\Python\</code> installiert. Starten Sie das Programm so (der Prompt <code>c:\tmp></code>ist natürlich nicht mit einzutippen):
c:\tmp>c:\devel\Python\python.exe test1.py
4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm
Hallo Welt!
Die Vorgehensweise unter Linux ist prinzipiell gleich. Die kleinen Unterschiede, wie z.B. der Slash statt dem Backslash in Pfadangaben, sollten für Linux-Benutzer keine Hürde darstellen.
== Variablen ==
Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9) und Underscores (_) bestehen, dürfen aber nicht mit einer Zahl beginnen. Führende Underscores haben u.a. im Kontext mit der Objektorientierten Programmierung eine spezielle Bedeutung und sollten nicht für "normale" Variablenbezeichner verwendet werden.
Gültige Variablenbezeichner wären also:
xyz
x1
_wert
name_anzahl
Theoretisch kann man auch Umlaute, griechische Buchstaben u.ä. in Variablenbezeichnern nutzen, z.B.
ößÜ = 16
α = 134
print(ößÜ)
print(α)
Ausgabe:
16
134
Davon wird aber aus offensichtlichen Gründen ({{W|Englisch als Lingua franca}}) abgeraten. Das Eurozeichen (€) etc. darf man ohnehin nicht in Variablenbezeichnern verwenden, dies ergäbe einen Syntaxfehler. Siehe dazu auch [https://peps.python.org/pep-3131/].
Es gibt in Python etliche Schlüsselwörter (z.B. for, if oder return). Diese dürfen nicht als eigene Variablenbezeichner verwendet werden. Eine Liste aller Schlüsselwörter liefert das Script
import keyword
print(keyword.kwlist)
<small>Übung: Speichern Sie dieses Script in eine Datei, z.B. in c:\tmp\test1.py. Führen Sie diese Datei aus, um die Liste der Schlüsselwörter auszugeben.</small>
Da Python case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:
xyz
XYZ
xYz
Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.py gespeichert.
x = 5
y = 10
z = x*y
print(z)
Bringen Sie die Datei test1.py zur Ausführung, so erhalten Sie folgende Bildschirmausgabe
50
Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben. Dies führt aber zu unübersichtlichem Code.
x = 5; y = 10; z = x*y; print(z)
Ausgabe:
50
Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.
x = 5
# x = x - 2
x -= 2
print(x)
Bildschirmausgabe:
3
Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Den Inkrement-/Dekrementoperator (z.B. x++ oder x--) aus C/C++ oder Java kennt Python aber nicht.
Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Python problemlos möglich:
import math
wert = 10
print(wert)
wert = 35.5
print(wert)
wert = "Hallo"
print(wert)
wert = math.pi
print(wert)
Ausgabe:
10
35.5
Hallo
3.141592653589793
== Physische und logische Zeilen ==
In Python muss eine Anweisung in einer logischen Zeile Platz finden. Wird eine Anweisung aber zu lang für eine Zeile, dann kann sie in mehrere physische Zeilen unterteilt werden. Dies kann einerseits durch einen Backslash am Ende einer Zeile geschehen, z.B.
a = 2 + \
5
Dies stellt eine logische Zeile dar, die in zwei physische Zeilen unterbrochen ist.
Geklammerte Ausdrücke werden automatisch zu einer logischen Zeile verbunden, z.B.
a = (2 +
5)
Achtung: Im ersten Beispiel darf nach dem Backslash nichts mehr stehen, auch kein Kommentar. Dies trifft im zweiten Bespiel nicht zu, hier könnte noch ein Kommentar folgen, z.B.
a = (2 + # Kommentar
5)
Auch für Strings gibt es Möglichkeiten, diese auf mehrere Zeilen aufzuspalten.
# Kurzer String
str1 = "ABC"
# Langer String
str2 = """Hallo Welt,
Grüetzi Schwyzer,
Servus an alle"""
# Backslash
str3 = "UVW\
XYZ"
# Mit Klammern
str4 = ("Sehr langer Text, der automatisch .............. "
"in einer einzigen Variable zusammengefügt wird."
)
print(str1)
print(str2)
print(str3)
print(str4)
Ausgabe:
ABC
Hallo Welt,
Grüetzi Schwyzer,
Servus an alle
UVWXYZ
Sehr langer Text, der automatisch .............. in einer einzigen Variable zusammengefügt wird.
==Hexadezimale, oktale, binäre und andere Zahlen==
d = 1050 # Dezimalzahl
h = 0xAA2 # Hexadezimalzahl
o = 0o12 # Oktalzahl
b = 0b100001101 # Binärzahl
print(d)
print(h)
print(o)
print(b)
Ausgabe:
1050
2722
10
269
Groß- und Kleinbuchstaben sind in obigen Literalen übrigens egal. So kann man z.B. statt <code>0b1001</code> auch <code>0B1001</code> schreiben (siehe dazu [https://docs.python.org/3/reference/lexical_analysis.html#integer-literals]).
Sie können auch dezimale in hexadezimale Zahlen umwandeln, usw.:
h = hex(1050) # Dezimalzahl -> Hexadezimalzahl
b = bin(1050) # Dezimalzahl -> Binärzahl
o = oct(1050) # Dezimalzahl -> Oktalzahl
print(h)
print(b)
print(o)
Ausgabe:
0x41a
0b10000011010
0o2032
Gegeben sei die Zahl 121 zur Basis 3. Diese soll in eine Dezimalzahl umgewandelt werden. Das kann so geschehen:
z = int("121", 3)
print(z)
Ausgabe:
16
Dass dies richtig ist, davon kann man sich folgendermaßen überzeugen:
<math> 1 \cdot 3^2 + 2 \cdot 3^1 + 1 \cdot 3^0 = 9 + 6+ 1 = 16 </math>
Zahlen übersichtlicher schreiben kann man auch mittels Underscore, z.B.:
print("Eine Million (Variante 1) =", 1000000)
print("Eine Million (Variante 2) =", 1_000_000)
print("Eine Rechnung:", 2_000 * 400_000);
Es ergibt sich bei beiden Varianten die gleiche Ausgabe. Variante 2 ist aber im Sourcecode leichter lesbar, detto die Zahlen in der Rechnung:
Eine Million (Variante 1) = 1000000
Eine Million (Variante 2) = 1000000
Eine Rechnung: 800000000
== Strings und Platzhalter==
Ein paar einfache Beispiele:
print("Hallo {}" . format("Hugo"))
print("Hallo {:s}" . format("Hugo"))
print("Hallo %s" % "Hugo")
Ausgabe:
Hallo Hugo
Hallo Hugo
Hallo Hugo
Python-Code (formatted string literals, Beispiel 1):
str1 = "Hallo"
str2 = "Hugo"
print(f"{str1} {str2}")
Ausgabe:
Hallo Hugo
Python-Code (formatted string literals, Beispiel 2):
wert = 11.567
print(f"Ausgabe: {wert:.5f}")
Ausgabe:
Ausgabe: 11.56700
Komplexere Beispiele:
print("Hallo {} und {}" . format("Hugo", "Mike"))
print("Hallo {name1} und {name2}" . format(name2="Hugo", name1="Mike"))
# Füllzeichen: *
# Bündigkeit: > (=rechts), < (=links), ^ (=zentriert)
# Feldweite: 10
# Typ: s (=String), f (=Gleitkommazahl), d (=Dezimalzahl) etc.
print("Hallo {:*>10s}" . format("Hugo"))
print("Hallo {:*<10s}" . format("Hugo"))
Ausgabe:
Hallo Hugo und Mike
Hallo Mike und Hugo
Hallo ******Hugo
Hallo Hugo******
Python-Code:
str = "Hallo\t%s\t%7.2f\t%10.2e\t%i" % ("Hugo", 12.34567, 34.567, 264)
print(str)
Ausgabe:
Hallo Hugo 12.35 3.46e+01 264
== Unicode ==
Neben den bekannten ASCII-Zeichen lassen sich Zeichen auch mittels Unicode beschreiben. Griechische Buchstaben oder komplexere mathematische Operatoren - all das sollte kein Problem sein. Siehe auch {{W|Unicode}}, {{W|Liste der Unicodeblöcke}} und {{W|Unicodeblock Mathematische Operatoren}}. Im Folgenden werden ein paar Zeichen (Allquantor, Nabla-Operator, Existenzquantor), die man aus der Mathematik kennt, erzeugt.
ch1 = "\N{FOR ALL}"
ch2 = "\N{NABLA}"
ch3 = "\u2203"
print(ch1, ch2, ch3)
Ausgabe:
∀ ∇ ∃
<small>Diese Ausgabe ergibt sich z.B. mit der IDLE-Shell oder mit Cygwin. Beim Ausführen über die Windows-Eingabeaufforderung oder Windows PowerShell unter MS Windows 10 erfolgt keine korrekte Darstellung. IDLE ist die mit Python mitgelieferte IDE ('''I'''ntegrated '''D'''evelopment '''E'''nvironment, Integrierte Entwicklungsumgebung). Gegen Ende dieses Textes wird IDLE kurz beschrieben.
Das Problem mit der Windows Eingabeaufforderung lässt sich aber umgehen. Man muss nur eine Schriftart auswählen, die die Zeichen kennt, z.B. "DejaVu Sans Mono". Dazu klicken Sie einfach bei der Eingabeaufforderung mit der rechten Maustaste oben auf die weiße Leiste und wählen im aufpoppenden Fenster den Menüpunkt "Eigenschaften". Es öffnet sich ein Dialogfenster. Über den Reiter "Schriftart" lässt sich nun die Schriftart einstellen. Unter MS Windows 11 oder openSUSE Leap 15.6 (bash-Konsole) gibt es dieses Problem ohnehin nicht.</small>
== Reguläre Ausdrücke ==
Python kennt auch {{W|Regulärer Ausdruck|reguläre Ausdrücke}}. Dazu gibt es in Python das Modul <code>re</code>. Beipielsweise sollen alle Zahlen (<math>\text{zahl}\in\mathbb{N}_0</math>) in einem String gesucht und ausgegeben werden. Als String sei gegeben: <code>3x Grüße und 100 Kekse.</code> Das Muster (Pattern) ist <code>\d+</code>. <code>\d</code> steht für eine Dezimalziffer 0-9. Das Plus-Zeichen (+) steht symbolisch für ein oder mehrere Zeichen des vorherigen Ausdrucks. Hier also ein oder mehrere Dezimalziffern. Es wird die Funktion <code>findall</code> aus dem Modul <code>re</code>verwendet.
Python-Code:
from re import findall
str = "3x Grüße und 100 Kekse."
pat = "\\d+" # Doppel-Backslashes müssen verwendet werden, sonst gibt Python eine Warnung aus!
# alternativ: pat = r"\d+"
# oder: pat = "[0-9]+"
numb = findall(pat, str)
print(numb)
Ausgabe:
['3', '100']
Python kennt noch viele weitere Möglichkeiten mittels regulärer Ausdrücke zu hantieren. Dies soll hier aber nicht vertieft werden, da das Thema schon ziemlich speziell und komplex ist. Bei Bedarf siehe aber z.B. die Bücher ''Weigend, Seite 380ff'' und ''Ernesti, Kaiser'' [https://openbook.rheinwerk-verlag.de/python/28_001.html] oder die Python-Dokumentation [https://docs.python.org/3/library/re.html]. Auch [[Python unter Linux: Reguläre Ausdrücke]] liefert ein umfangreiches und brauchbares Python-2-Kapitel zu den regulären Ausdrücken. Die dort gelisteten Beispiele müssten ggf. vor Verwendung auf Python-3 umgeschrieben werden. <small>Wie macht man das? Dazu siehe z.B. [https://openbook.rheinwerk-verlag.de/python/43_001.html], [https://portingguide.readthedocs.io/en/latest/] oder [https://www.digitalocean.com/community/tutorials/how-to-port-python-2-code-to-python-3]</small>
<small>Es gibt auch ein externes Modul ''regex'', das bei Bedarf extra installiert werden muss ([https://pypi.org/project/regex/]). Es bietet zusätzliche Funktionalität und gründlicheren Unicode-Support. Dies sei hier aber nur der Vollständigkeit halber erwähnt.</small>
== Verzweigungen ==
=== if ===
Die IF-Verzweigung sei aus anderen Programmiersprachen bereits bekannt. In {{W|Pseudocode}} lässt sie sich folgendermaßen darstellen:
WENN bedingung TRUE
führe block1 aus
SONST
führe block2 aus
ENDE
Als {{W|Aktivitätsdiagramm|UML-Aktivitätsdiagramm}} sieht das in etwa so aus:
[[File:If-Then-Else-diagram.svg|200px]]
Und als {{W|Nassi-Shneiderman-Diagramm|Nassi-Shneiderman-Struktogramm}} so:
[[File:Zweiseitige Auswahl.png|250px]]
In Python gibt es keinen expliziten ENDE-Kennzeichner. Stattdessen wird der Code durch Einrückungen strukturiert. Alles mit der gleichen Einrückungstiefe gehört zum selben Block. Dies zeichnet Python vor anderen Programmiersprachen aus.
Die test1.py-Datei laute also wie folgt:
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4
Man achte auch auf die Doppelpunkte in der if- und else-Zeile. Darauf vergisst man gerne, wenn man von anderen Programmiersprachen kommt.
Folgendes wäre in Python ein Fehler (genauer gesagt ein IndentationError).
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Auch Nachstehendes würde nicht zum gewünschten Ergebnis führen (löst aber keine Fehlermeldung aus). Der letzte print-Befehl ist schon außerhalb der IF-ELSE-Verzweigung.
x = 3
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
x ist kleiner als 4
x ist groesser oder gleich 4
Python kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:
<, <= ... kleiner (gleich)
>, >= ... größer (gleich)
== ... gleich
!= ... ungleich
is ... identisch
is not ... nicht identisch
and ... AND
or ... OR
not ... NOT
Beispielsweise:
a = 5
b = 9
if a<=10 and b!=7:
print("OK")
else
print("Nicht OK")
Ausgabe:
OK
Der else-Block kann übrigens auch ersatzlos entfallen. Als Pseudocode sieht das so aus
WENN bedingung TRUE
führe block aus
ENDE
Mehrfache Verzweigungen werden durch das elif-Konstrukt erstellt. In Pseudocode:
WENN bedingung1 TRUE
führe block1 aus
SONST WENN bedingung2 TRUE
führe block2 aus
SONST WENN bedingung3 TRUE
führe block3 aus
SONST
führe block4 aus
ENDE
Ein Python-Beispiel:
a = 14
if a<=10:
print("<=5")
elif a>11 and a<15:
print("11 bis 15")
elif a>16 and a<20:
print("16 bis 20")
else:
print(">=20")
Ausgabe:
11 bis 15
In Python gibt es auch die Schlüsselwörter <code>True</code> (für wahr) und <code>False</code> (für falsch). Man beachte, dass sie mit Großbuchstaben beginnen. Andere Schreibweisen wären ein Fehler. Sie gehören zum Datentyp <code>bool</code>. Ihnen sind auch die Zahlen <code>1</code> und <code>0</code> zugewiesen.
Man beachte, dass {{W|Rundungsfehler}} auftreten können. D.h. man sollte bei der Verwendung von {{W|Gleitkommazahl|Gleitpunktzahlen}} niemals auf absolute Genauigkeit prüfen, sondern eine Toleranz (einen <math>\varepsilon</math>-Wert) vorgeben.
Ein klassisches Beispiel, das ein falsches Ergebnis liefert, ist:
i = 0.1 + 0.2
print(i)
if i == 0.3:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
NOK
Und das, obwohl man schon in der Volksschule lernt, dass 0.1 + 0.2 gleich 0.3 ist.
Korrekt muss das obige Beispiel z.B. so umgeschrieben werden:
ist = 0.1 + 0.2
soll = 0.3
epsilon = 0.000001
print(ist)
if abs(ist-soll) < epsilon:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
OK
Alternativ kann auch die <code>math.isclose()</code>-Funktion verwendet werden. Das sei aber hier nur erwähnt und nicht konkret ausgeführt.
<u>Aufgabe:</u> Recherchieren Sie im Internet zum Thema <code>math.isclose()</code>-Funktion.
=== match ===
Ab Python 3.10 gibt es auch die match-Anweisung. Dies ist das Python-Pendant für die switch-Anweisung in anderen Programmiersprachen, geht aber bei näherer Betrachtung weit darüber hinaus. Hier nur ein einfaches Beispiel:
x = "Hello"
match x:
case "Servus" | "Ciao": # or
print("Servus an alle")
case "Grüetzi":
print("Grüetzi Schwyzer")
case _: # other, default, sonstiges ...
print("Hallo Welt")
Ausgabe:
Hallo Welt
Als Struktogramm sieht das in etwa so aus:
[[File:Mehrseitige Auswahl.png|250px]]
Für nähere Details siehe z.B. [https://www.geeksforgeeks.org/python-match-case-statement/], [https://learnpython.com/blog/python-match-case-statement/], [https://docs.python.org/3/tutorial/controlflow.html#match-statements] und das Python Enhancement Proposal (PEP) 636 – Structural Pattern Matching: Tutorial [https://peps.python.org/pep-0636] und dort insbesondere den Anhang A - Quick Intro.
<small><code>match, case, _</code> etc. sind sogenannte ''soft keywords''. Im Gegensatz zu den normalen Schlüsselwörtern dürfen ihnen auch Werte zugewiesen werden. Eine Liste der weichen Schlüsselwörter lässt sich durch <code>keyword.softkwlist</code> erstellen (die Anweisung gibt es seit Python 3.9). Siehe dazu auch [https://stackoverflow.com/questions/65800344/what-are-soft-keywords] und [https://docs.python.org/3/library/keyword.html#keyword.softkwlist].</small>
== Schleifen ==
Kopfgesteuerte Schleife, Endlosschleife und fußgesteuerte Schleife:
[[File:Programmingloops.svg|450px]]
=== while ===
Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert wie aus anderen Programmiersprachen bekannt.
In Pseudocode:
SOLANGE bedingung TRUE
führe block aus
ENDE
In Python:
x = 0
while x <= 10:
print(x)
x += 1
Ausgabe:
0
1
2
3
4
5
6
7
8
9
10
Eine Endlosschleife ergibt sich z.B. so:
i = 5
while True:
print(i)
i-=1
Beendet werden kann sie mit der Tastenkombination STRG-C.
Eine fußgesteuerte Schleife kann so simuliert werden:
i = 5
while True:
print(i)
i-=1
if i<=0:
print("Fire")
break
Ausgabe:
5
4
3
2
1
Fire
Der <code>break</code>-Befehl wird etwas später noch einmal kurz thematisiert.
=== for ===
Struktogramm einer for-Schleife:
[[File:Zählschleife.png|200px]]
In Python bspw. so:
for x in range(6):
print(x*2)
Ausgabe:
0
2
4
6
8
10
Die Schleife läuft von 0 bis 5. Ausgegeben wird jeweils der Wert x*2. Aquivalent kann diese Schleife auch so geschrieben werden:
for x in range(0, 11, 2):
print(x)
Die Ausgabe ist wie oben. Der Startwert sei 0, der Endwert ist 11-1 und die Schrittweite ist 2.
Ein anderes Beispiel sei
for x in "text":
print(x)
Ausgabe:
t
e
x
t
== Schleifen abbrechen ==
=== break ===
<code>break</code> bricht die Schleife ab und setzt mit dem nächsten Befehl außerhalb der Schleife fort.
for var in range(100):
print(var)
if var == 5:
break
Ausgabe:
0
1
2
3
4
5
=== continue ===
<code>continue</code> bricht den aktuellen Schleifendurchlauf ab und setzt mit dem nächsten Schleifendurchlauf fort.
for var in range (11):
if var == 5:
continue
print(var)
Ausgabe:
0
1
2
3
4
6
7
8
9
10
== try - except ==
try:
z1 = 12 / 0
print(z1)
except ZeroDivisionError:
print("Das Ergebnis ist unendlich")
except:
print("Kann nicht berechnet werden!")
print("Bitte die Formel korrigieren!")
print("Setze Programm fort!")
Ausgabe:
Das Ergebnis ist unendlich
Setze Programm fort!
Es wird versucht, eine Zahl durch Null zu dividieren. Das ist nicht möglich, es wird eine Ausnahme ausgelöst. Das Programm springt daher in den except-ZeroDivisionError-Block und führt die dort gelisteten Anweisungen aus (in unserem Fall eine print-Anweisung). Danach wird das Programm fortgesetzt. Würden wir dieses Programm ohne try-except ausführen, so ergibt sich aus
z1 = 12 / 0
print(z1)
folgende Fehlermeldung und ein unmittelbarer Programmabbruch
Traceback (most recent call last):
File "C:\tmp\test1.py", line 1, in <module>
z1 = 12 / 0
ZeroDivisionError: division by zero
Mit dem try-except-Mechanismus können also Ausnahmen oder Fehler aufgefangen und behandelt werden. In unserem Beispiel ist das eher trivial, aber bei größeren Programmen kann das durchaus Sinn machen.
Neu in Python 3.14 ist, dass mehrere Ausnahmen auch ohne Klammern angegeben werden können, z.B.:
bis inkl. Python 3.13 nur:
except (ZeroDivisionError, ValueError):
ab Python 3.14 auch:
except ZeroDivisionError, ValueError:
== pass ==
Ein leerer Block muss in Python mittels dem Schlüsselwort <code>pass</code> dargestellt werden. Z.B.
x = 2
if x == 1:
print("Wert ist ", x)
else:
pass
Würde man das <code>pass</code> im else-Block weglassen, so würde man eine Fehlermeldung erhalten:
IndentationError: expected an indented block after 'else' statement on line 5
= Funktionen =
== Aufrufen von Funktionen ==
Funktionen sind uns im Rahmen dieses Kurses schon zuhauf begegnet. Sei es die print()-, die math.sin()- oder die hex()-Funktion. All diese Funktionen werden von Python zur Verfügung gestellt, ohne dass man sie explizit programmieren müsste. Aufgerufen werden diese Funktionen, indem man ihren Namen eintippt, gefolgt von runden Klammern. In diesen Klammern können noch Argumente übergeben werden. Auch Rückgabewerte sind möglich.
== Funktionen selber schreiben ==
Funktionen werden mit dem def-Schlüsselwort (man definiert die Funktion) eingeleitet, danach folgt der Funktionsname, danach wiederum runde Klammern, in denen formale Argumente stehen können. Abgeschlossen wird die def-Zeile mit einem Doppelpunkt. Danach folgt der Funktionskörper. Dieser Funktionskörper muss wiederum eingerückt werden (wie von den Verzweigungen und Schleifen bekannt). Aufgerufen wird diese Funktion, indem man ihren Funktionsnamen eingibt, gefolgt von runden Klammern (ggf. mit den aktuellen Parametern). Z.B.
# Funktion definieren
def halloWelt(i):
# i ... beliebige Ganzzahl
print("Hallo " * i, end="")
print("Welt!")
# Funktion aufrufen
halloWelt(3)
Ausgabe:
Hallo Hallo Hallo Welt!
Unterschied zwischen formalen und aktuellen Parametern:
[[Datei:PythonIng_func1.jpg]]
<small>Aktuelle Parameter werden auch Argumente genannt.</small>
Rückgabe von Funktionswerten:
# Funktion definieren
def mathFunc(a, b):
r1 = a + b
r2 = a * b
return r1, r2
# Funktion aufrufen
c, d = mathFunc(3, 5)
# Ausgabe der zurückgegebenen Werte
print(c)
print(d)
Ausgabe:
8
15
Es werden r1 und r2 zurückgegeben und den Variablen c und d zugewiesen. (r1, r2) und (c, d) sind Tupel. Was Tupel konkret sind, siehe etwas später in diesem Kapitel. 3 und 5 sind die aktuellen Parameter (die Argumente). a und b sind die formalen Parameter. Die Zuweisung der aktuellen zu den formalen Parametern erfolgt in der gegebenen Reihenfolge, also die Zahl 3 wird an a übergeben und die Zahl 5 an b.
Vorgabeparameter, z.B.:
def mathFunc(a=10, b=20):
r1 = a + b
r2 = a * b
return r1, r2
c, d = mathFunc(3, 5)
print(c)
print(d)
e, f = mathFunc(5)
print(e)
print(f)
g, h = mathFunc(b=6)
print(g)
print(h)
Ausgabe:
8
15
25
100
16
60
Erklärung:
* Erster <code>mathFunc</code>-Aufruf: Es werden, wie weiter oben, die Argumente 3 und 5 an die formalen Parameter a und b übergeben. Die Rückgabewerte r1 und r2 werden an c und d übergeben. Somit ist c=8 und d=15.
* Zweiter <code>mathFunc</code>-Aufruf: Es wird nur das Argment 5 an a übergeben. b behält den Vorgabewert 20. D.h. e= 25 und f=100.
* Dritter <code>mathFunc</code>-Aufruf: Es wird nur die Zahl 6 an b übergeben, a behält seinen Vorgabewert 10. Somit ergibt sich g=16 und h=60.
Beispiel (Schlüsselwortargumente vs. Positionsargumente):
def mathFunc(a, b):
r1 = a - b
r2 = a / b
return r1, r2
c, d = mathFunc(b=3, a=5) # Schlüsselwortargumente
e, f = mathFunc(3, 5) # Positionsargumente
print(c)
print(d)
print(e)
print(f)
Ausgabe:
2
1.6666666666666667
-2
0.6
Durch die Verwendung von Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge angegeben werden. Bei den Positionsargumenten ist die Reihenfolge vorgegeben. Daraus resultiert auch der Unterschied bei den obigen Ausgaben. Werden beide Arten in einem Aufruf gemischt, so müssen die Positionsargumente zuerst angegeben werden. Den Unterschied zwischen beiden Argumentarten zu kennen ist wichtig, nicht nur bei selbst erstellten Funktionen. Auch beim Aufruf von Python-Funktionen verfolgt einen die Mischung von Schlüsselwort- und Positionsargumenten auf Schritt und Tritt, z.B. beim etwas später folgenden Abschnitt über "Grafiken zeichnen":
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
Bei dieser <code>plot</code>-Funktion aus dem Modul <code>matplotlib.pyplot</code> sind <code>x</code> und <code>y1</code> Positionsargumente. <code>label, lw</code> und <code>ls</code> sind die Namen der Schlüsselwortargumente. Die Schlüsselwortargumente könnten auch in anderer Reihenfolge angeschrieben werden, nicht jedoch die Positionsargumente!
Siehe zu <code>matplotlib.pyplot.plot</code> auch die Seite [https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html].
== Lambda-Funktionen ==
print((lambda a, b: a*b) (3, 5))
Ausgabe:
15
Eingeleitet wird eine Lambda-Funktion (auch Lambda-Form, Lambda-Operator oder anonyme Funktion genannt) mit dem Schlüsselwort <code>lambda</code>. Es folgen die formalen Argumente, danach ein Doppelpunkt, die Berechnungsvorschrift und ggf. abschliessend in Klammern die aktuellen Parameter.
Man kann einer Lambda-Funktion auch einen Funktionsnamen geben und die Funktion über diesen Namen aufrufen, z.B.
prod = lambda a, b: a*b
print(prod(3, 5))
Als Ausgabe wird wieder die Zahl 15 geliefert.
== Rekursive Funktionen ==
Funktionen können wiederum andere Funktionen aufrufen. Von einem rekursiven Funktionsaufruf spricht man, wenn die aufgerufene Funktion gleich der aufrufenden ist.
def printFunc(i):
if (i >= 5):
return
else:
print("Hallo Welt")
printFunc(i+1)
printFunc(1)
Ausgabe:
Hallo Welt
Hallo Welt
Hallo Welt
Hallo Welt
== Funktionsannotationen ==
Python ist sehr flexibel, was Typen angeht. Im Vorhergehenden haben wir generell keine Typangaben gemacht. Will man Typen angeben, so bietet Python das Konzept der Funktionsannotation.
def calcFunc(a: int, b: int) -> int:
return a+b
r1 = calcFunc(8, 9)
r2 = calcFunc(8.0, 9.0)
r3 = calcFunc("Hallo", "Welt")
print(r1)
print(r2)
print(r3)
Ausgabe:
17
17.0
HalloWelt
Jetzt sieht man auf den ersten Blick, welche Typen der Programmierer im Sinn hatte, als er die Funktion erstellte. Das Problem dabei ist nur, dass es Python ziemlich egal ist, welche Typen man im Endeffekt eingibt. Im obigen Beispiel können statt Integer-Typen u.a. auch Float- oder String-Typen eingegeben werden.
<small>
Siehe zum Thema "Type Checking" aber auch den später folgenden Abschnitt [[Ing_Mathematik:_Python#Type_Checker]].
</small>
== Variadische Funktionen ==
Python-Code:
def test1(a, *b):
print(a);
for c in b:
print(c);
test1("Hallo", "Welt", "Schweizer", "und alle anderen")
Ausgabe:
Hallo
Welt
Schweizer
und alle anderen
Mit dem Stern (auch als Splat-Operator bezeichnet) in der formalen Parameterliste bei der Funktion <code>test1</code> wird angezeigt, dass eine beliebige Anzahl von Argumenten übergeben wird. <small> Dies entspricht in etwa dem, was in anderen Programmiersprachen (PHP etc.) mittels Ellipse (<code>...</code>) angezeigt wird.</small>
= Tupel, Listen und andere =
[[Datei:Python 3. The standard type hierarchy.png|mini|hochkant=1.7|Datentypen und Strukturen]]
== Tupel und Listen ==
Tupel, Listen und einige andere sind Datenstrukturen oder Sequenzen.
Listen (z.B. eine Einkaufsliste) sind veränderbar (mutable). Ein Tupel kann dagegen nicht verändert werden (immutable). Listen werden beim Anlegen in eckige Klammern eingeschlossen, Tupel in runde Klammern. Beim Tupel können die Klammern auch weggelassen werden. Ein Tupel mit nur einem Element muss mit einem Beistrich abgeschlossen werden. Der Grund ist, dass Python sonst nicht entscheiden kann, ob ein Tupel angelegt werden soll, oder nur ein geklammerter Wert.
Als Gedächtnisstütze kann man sich den Unterschied zwischen Tupel und Liste ev. so leichter merken:
: T'''u'''pel ... r'''u'''nde Klammern, '''u'''nveränderlich
: L'''i'''ste ... eck'''i'''ge Klammern, veränderl'''i'''ch.
Nachfolgend werden einige Operationen mit Listen und Tupel dargestellt.
# Liste und Tupel
liste = [1, 2, "Hallo"]
tupel = (1, 2, "Hallo")
# Ausgabe von liste und tupel
print(liste)
print(tupel)
# Ausgabe von Einzelelementen
print(liste[1])
print(tupel[2])
# Element an Liste anhängen und einfügen
liste.append(55)
liste.insert(4, "Welt")
print(liste)
# Element aus Liste entfernen
liste.remove(1)
print(liste)
# einige weitere Beispiele
liste2 = [1,]
tupel2 = 1, 2
tupel3 = (1,)
print(liste2)
print(tupel2)
print(tupel3)
Ausgabe:
[1, 2, 'Hallo']
(1, 2, 'Hallo')
2
Hallo
[1, 2, 'Hallo', 55, 'Welt']
[2, 'Hallo', 55, 'Welt']
[1]
(1, 2)
(1,)
Beispiel (eine Liste von Wörtern zu einem einzigen zusammenhängenden Text verbinden):
woerter = ["Hallo", "Welt"]
satz = " ".join(woerter)
print(satz)
Ausgabe:
Hallo Welt
== Dictionaries und Mengen ==
Zu den Datenstrukturen gehören weiters auch Mengen und Dictionaries. Mengen sind von der Mathematik bekannt, sie sind ungeordnet und es kommen keine mehrfachen Elemente vor. Dictionaries sind durch Schlüssel :Wert-Paare gekennzeichnet. Mengen werden beim Anlegen wie Dictionaries in geschweifte Klammern eingeschlossen.
dict = {"vorname":"Hugo", "nachname":"Meister" }
menge = {1, 1, 3, 4, 4, 4, "Hallo"}
print(dict)
print(menge)
print(dict["vorname"])
Ausgabe:
{'vorname': 'Hugo', 'nachname': 'Meister'}
{1, 3, 4, 'Hallo'}
Hugo
Geschweifte Klammern ohne Inhalt stellen Dictionaries dar und keine Mengen:
di = {}
print(type(di))
Ausgabe:
<class 'dict'>
Leere Mengen lassen sich mit <code>set()</code> erzeugen:
menge = set() # leere Menge
print(menge)
menge.add("Hallo") # Element hinzufügen
print(menge)
Ausgabe:
set()
{'Hallo'}
Beispiel (einige Mengenoperationen):
mengeA = {"Hallo", "Welt"}
mengeB = {1, 2, "Welt", 3}
# Vereinigung
print(mengeA | mengeB)
print(mengeA.union(mengeB))
# Durchschnitt
print(mengeA & mengeB)
print(mengeA.intersection(mengeB))
# Differenz
print(mengeA - mengeB)
print(mengeA.difference(mengeB))
# Symmetrische Differenz
print(mengeA ^ mengeB)
print(mengeA.symmetric_difference(mengeB))
# Teilmenge
print(mengeA.issubset(mengeB))
# Mehrere Elemente hinzu
mengeA.update(["Super", 67, 125])
print(mengeA)
# Element löschen
mengeA.discard("Hallo")
print(mengeA)
Ausgabe:
{1, 2, 3, 'Welt', 'Hallo'}
{1, 2, 3, 'Welt', 'Hallo'}
{'Welt'}
{'Welt'}
{'Hallo'}
{'Hallo'}
{1, 2, 3, 'Hallo'}
{1, 2, 3, 'Hallo'}
False
{67, 'Super', 'Welt', 'Hallo', 125}
{67, 'Super', 'Welt', 125}
Es gibt schon seit "ewigen" Zeiten unveränderbare Mengen, die mittels <code>frozenset</code> eingeleitet werden. Neu ab Python 3.15 ist dagegen das Pendant <code>frozendict</code>, das unveränderbare Dictionaries darstellt.
fdict = frozendict({"vorname":"Hugo", "nachname":"Meister"})
fset = frozenset({"A", 1, "A"})
print(fdict)
print(fdict["vorname"])
print (fset)
try:
fdict["vorname"] = "Max"
print(fdict["vorname"])
except TypeError as e:
print(f"Fehler: {e}")
try:
fset.add("B")
print(fset)
except AttributeError as e:
print(f"Fehler: {e}")
Ausgabe:
frozendict({'vorname': 'Hugo', 'nachname': 'Meister'})
Hugo
frozenset({1, 'A'})
Fehler: 'frozendict' object does not support item assignment
Fehler: 'frozenset' object has no attribute 'add'
== List Comprehensions ==
Aus einer Eingabeliste soll eine Ausgabeliste erzeugt werden. Das kann folgendermaßen geschehen.
Mathematische Schreibweise: <math>lc = \{2x|x\in\ \mathbb{N}, 1\le x < 11\}</math>
Python-Code:
lc = [x*2 for x in range(1,11)]
print(lc)
Ausgabe:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Mathematische Schreibweise: <math>lc = \{2x | x \in \mathbb{N}, 1\le x < 11, x \bmod 2 = 0 \}</math>
Python-Code:
lc = [x*2 for x in range(1,11) if x%2 == 0]
print(lc)
Ausgabe:
[4, 8, 12, 16, 20]
Siehe auch {{W|List Comprehension}}.
== Set Comprehensions ==
Dies ist sehr ähnlich wie im vorigen Abschnitt beschrieben. Es wird aber keine Liste, sondern eine Menge erzeugt.
sc = {x*2 for x in range(1,11)}
print(sc)
Ausgabe:
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
== Listen zusammenführen - zip() ==
li1 = ["A", "B", "C", "D"]
li2 = [1, 2, 3, 4]
li3 = [5.5, 6.6, 7.7, 8.8]
z = zip(li1, li2, li3)
print(z)
li4 = list(z)
print(li4)
Ausgabe:
<zip object at 0x00000283B6C6AC80>
[('A', 1, 5.5), ('B', 2, 6.6), ('C', 3, 7.7), ('D', 4, 8.8)]
== Generatorausdruck ==
g = (i*2 for i in range(1,11))
print(g)
t = tuple(g)
print(t)
print(t[1:3])
Ausgabe:
<generator object <genexpr> at 0x00000241D2A4A5A0>
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
(4, 6)
== Slicing ==
slice ... Scheibe, Teil, in Scheiben schneiden
Beispiel: Zugriff auf Elemente eines geordneten sequentiellen Objekttyps (Liste, Tupel oder String):
str1 = "Hallo"
# Das erste Element wird mit dem Index 0 angesprochen
# [start (inkl.) : stop (exkl.) : step (default=1)]
str2 = str1[0:2]
# Alternativ auch: str2 = str1[:2]
print(str2)
tup1 = (0,1,2,3)
# Das letzte Element hat auch den Index -1, das vorletzte den Index -2 usw.
tup2 = tup1[-3:-1]
print(tup2)
lst1 = [[1, 5, 10, 20],
[30, 40, 50, 60]]
lst2 = lst1[1][1]
print(lst2)
Ausgabe:
Ha
(1, 2)
40
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2])
print(x[-3])
print(x)
print(x[:])
print(x[2:])
print(x[:2])
print(x[::-1])
Ausgabe:
c
c
('a', 'b', 'c', 'd', 'e')
('a', 'b', 'c', 'd', 'e')
('c', 'd', 'e')
('a', 'b')
('e', 'd', 'c', 'b', 'a')
Visualisierung:
'''a''' '''b''' '''c''' '''d''' '''e'''
+-----------------------------+
| 0 | 1 |//'''2'''//| 3 | 4 |
+-----------------------------+
| -5 | -4 |/'''-3'''//| -2 | -1 |
+-----------------------------+
|/////////////////////////////|
+-----------------------------+
|/////////////''':'''///////////////|
+-----------------------------+
| | |///////'''2:'''////////|
+-----------------------------+
|////''':2'''/////| | | |
+-----------------------------+
|\\\\\<--\\\\\'''::-1'''\\\\<--\\\\\|
+-----------------------------+
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2::2])
print(x[2::-1])
print(x[2:0:-1])
Ausgabe:
('c', 'e')
('c', 'b', 'a')
('c', 'b')
Hier sieht man sehr schön, dass beim letzen <code>print</code>-Befehl die 0, die in diesem Fall den Buchstaben "a" repräsentiert, als letzer Wert nicht mehr dazugehört (wie weiter oben angedeutet ist der End- oder Stoppwert exklusiv). Will man den Buchstaben "a" dazunehmen, so ist die vorletzte Zeile die richtige.
Beispiel: Umdrehen von Strings
str1 = "Hallo"
str2 = str1[::-1]
print(str2)
Ausgabe:
ollaH
Mit zweidimensionalen Listen/Tupels wird das Ganze schon bedeutend komplexer.
Beispiel: Verkettetes Slicing
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
print(A[2::][::2])
Ausgabe:
[['20', '21', '22', '23'], ['40', '41', '42', '43']]
Das erste Slicing erstellt folgenden Slice:
[["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
Das zweite Slicing wird dann auf diesen Slice angewendet und ergibt das genannte Endergebnis. Will man Spalten statt Zeilen, so funktioniert dieser direkte Weg nicht. Man verwendet dann List Comprehensions oder die NumPy-Bibliothek. Diese Bibliothek erlaubt zweidimensionales Slicing. Sie wird erst später bei den Grafiken eingeführt. Deshalb wird hier dazu noch kein Beispiel gezeigt.
= Objektorientierte Programmierung =
{{Wikipedia|Objektorientierte Programmierung}}
* {{W|Klasse (Objektorientierung)|Klasse}} ... die Schablone oder der Bauplan, enthält Methoden und Attribute
* {{W|Objekt (Programmierung)|Objekt}} ... eine Klasseninstanz (die konkrete Ausprägung der Klasse)
* {{W|Attribut (Programmierung)|Attribute}} ... die Eigenschaften eines Objekts
* {{W|Methode (Programmierung)|Methoden}} ... die Aktionen (Operationen), die ein Objekt ausführen kann
* {{W|Vererbung (Programmierung)|Vererbung}} ... neue Klassen (Subklassen, Unterklassen, abgeleitete Klassen) aus vorhandenen Klassen (Superklassen, Oberklassen, Basisklassen, Elternklassen) ableiten. Ermöglicht den Aufbau von Klassenhierarchien. Die Subklasse "erbt" Attribute und Methoden von der Superklasse. Python unterstützt (so wie C++, aber im Gegensatz zu Java) Mehrfachvererbung.
== UML ==
* {{W|Unified Modeling Language|UML}} ... '''U'''nified '''M'''odeling '''L'''anguage, eine Modellierungssprache. Die UML enthält zahlreiche Diagrammarten, um Programme zu modellieren. Im Nachfolgenden wird nur das {{W|Klassendiagramm}} verwendet.
[[File:UmlCd Klasse-3.svg|300px]]
* {{W|Sichtbarkeit (Programmierung)|Sichtbarkeit}}:
** + ... public (öffentlich)
** - ... private
** # ... protected
* {{W|Attribut_(UML)#Attribute_für_Instanzen_und_für_Klassen|Klassenattribute}} (statische Attribute): Werden nur einmal pro Klasse angelegt. Im Klassendiagramm werden sie unterstrichen.
[[File:Attribute-3.png|200px]]
* Vererbung:
<gallery>
InheritancePgmUML.svg | Abgeleitete Klasse erbt von Basisklasse (Einfachvererbung)
Diamond inheritance.svg | D erbt von B und C (Mehrfachvererbung). B und C erben von A (Einfachvererbung)
</gallery>
Für weitergehende Betrachtungen zur UML wird auf Spezialliteratur verwiesen, z.B.:
* Seidl et al.: UML@Classroom. dpunkt, 2012, ISBN 978-3-89864-776-2
* Rupp et al.: UML 2 glasklar. Hanser, 4. Aufl., 2012, ISBN 978-3-446-43057-0
== Eine einfache Klasse ==
[[Datei:PythonIng_uml1.svg | 200px]]
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
fahr = Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die Klasse Fahrzeug wird durch das class-Schlüsselwort eingeleitet. raeder ist ein Klassenattribut und public. __init__ wird bei der Objekterzeugung automatisch aufgerufen (ist der sogenannte Konstruktor). Man achte darauf, dass diese Methode immer mit zwei Unterstrichen eingeleitet und abgeschlossen wird. Instanzattributen wird das Wort self vorangestellt. Wir sehen uns z.B. das Attribut self.__geschwind an. Auch hier werden zwei Unterstriche verwendet. Das bedeutet, dass dieses Attribut strikt/stark private ist. Wird nur ein Unterstrich verwendet, so deutet dies auf schwach/weakly private hin. Letzteres wird in Python deutlich häufiger verwendet. Bei den Methoden wird immer self als erster Parameter angegeben. Beim Aufruf der entsprechenden Funktion wird das self aber nicht berücksichtigt.
Besonderheiten bei stark und schwach private:
* '''stark private''':
** zwei führende Unterstriche
** Name Mangling: Name wird zu <code>_Klassenname__variablenname</code>
** Schutz vor Namenskollisionen bei Vererbung
** am Ende des Namens dürfen keine zwei Unterstriche verwendet werden. Das wären dann Magic Methods oder Dunder-Methods (z.B. __init__). Diese sind public.
* '''schwach private''':
** ein führender Unterstrich
** Name bleibt gleich
** ist nur ein Hinweis an die Programmierer, kein starker Schutz
** <code>from modul import *</code>: Objekte mit einem führenden Unterstrich werden standardmäßig nicht importiert
** Standard für die Kapselung bei Python. Schätzung: Weit mehr als 80% der nicht-öffentlichen Attribute/Methoden werden als schwach private deklariert. Weniger als 5-10% als stark private (Quelle: Google KI)
== Klassen importieren ==
Häufig ist es sinnvoll und übersichtlicher Klassen in eigenen Dateien zu speichern. Das sind dann eigene Module. Abgespeichert werden Sie mit der Endung py, wie bisher auch praktiziert. Aufgerufen werden Sie mit der import-Anweisung. Dann ist aber nur der Dateiname ohne Endung py zu verwenden. Klarer wird das mit einem Beispiel.
Datei c:\tmp\fahrzeug.py
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
Datei c:\tmp\test1.py
import fahrzeug
fahr = fahrzeug.Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die üblichen import-Anweisungen lauten wie folgt:
{| {{prettytable}}
! import-Befehl
! Instanz
|-
| import xyz || xyz.Klasse
|-
| import xyz as x || x.Klasse
|-
| from xyz import Klasse || Klasse
|-
| from xyz import * || Klasse
|}
Der Vorteil der ersten beiden import-Anweisungen ist, dass es kaum zu Namenskollisionen kommen kann. Dafür hat man bei den letzten beiden Varianten weniger Tipparbeit.
== Vererbung ==
=== Einfachvererbung ===
[[Datei:PythonIng_uml2.svg | 200px]]
Datei fahrzeug.py:
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
class Luftfahrzeug(Fahrzeug):
def __init__(self, geschwindigkeit, leistung, fluegel):
super().__init__(geschwindigkeit, leistung)
self.__flueg = fluegel
def getFlueg(self):
return self.__flueg
Datei test1.py:
import fahrzeug
fahr = fahrzeug.Luftfahrzeug(150, 90, 4)
print(fahr.getFlueg())
Ausgabe:
4
=== Mehrfachvererbung ===
Mit Python ist auch Mehrfachvererbung möglich, z.B.:
class A:
def _printA(self):
print("Klasse A")
class B:
def _printB(self):
print("Klasse B")
class C(A,B):
def __init__(self):
self._printA()
self._printB()
c = C()
Ausgabe:
Klasse A
Klasse B
Die Klasse C erbt von A und B. In UML sieht das in etwa so aus:
+-----------------------------+ +-------------------------+
| A | | B |
+-----------------------------+ +-------------------------+
| | | |
+-----------------------------+ +-------------------------+
| # printA() | | # printB() |
+-----------------------------+ +-------------------------+
. .
/ \ / \
--- ---
| |
| |
+---------------------+
| C |
+---------------------+
| |
+---------------------+
| |
+---------------------+
<code>printA()</code> und <code>printB()</code> sind schwach private (in UML als <code>protected</code> mit einem # dargestellt). Es ist aber zu beachten, dass schwach private nur Konvention ist. Praktisch könnte man auch von außerhalb auf diese Methoden zugreifen. Das soll man aber nicht tun, und das wird in Python durch einen Unterstrich angedeutet.
= Grafiken zeichnen =
Für das Zeichnen von Grafiken wird hier das Modul <code>matplotlib</code> verwendet. <code>matplotlib</code> ist ein externes Modul und muss vor der ersten Verwendung installiert werden. Das geht so:
# Starten Sie ein Terminal (bei Windows die Eingabeaufforderung).
# Führen Sie darin folgenden Befehl aus <code>c:\devel\Python\Scripts\pip.exe install matplotlib</code>
pip ist übrigens der Paketmanager von Python ({{W|Pip_(Python)}}).
Optimalerweise installieren wir auch gleich das Modul <code>numpy</code> (Numerical Python). Wir werden es im Folgenden oft benötigen (nicht nur bei den Grafiken). Das funktioniert vom Prinzip her genauso, wie für <code>matplotlib</code> gezeigt.
<small>Verwenden Sie Spyder, so sind diese Schritte nicht nötig. Spyder inkludiert diese Pakete standardmäßig. Unter openSUSE Tumbleweed lassen sich diese Pakete mittels YaST oder zypper installieren.</small>
== 2D ==
=== Graph einer Funktion ===
Es soll die cosh-Funktion im Intervall <math>x\in[-3,3]</math> gezeichnet werden. Der Programmcode lautet in der einfachsten Form:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x)
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh1.jpg]]
Der Code ist quasi selbsterklärend. Das Untermodul pyplot des matplotlib-Moduls und das numpy-Modul werden importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plt.plot()" ist der Zeichenbefehl. "plt.show" ist notwendig, um das Fenster mit der Grafik anzuzeigen.
Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen. "plt.grid()" zeichnet ein Gitter in die Grafik (kann auch weggelassen werden).
Die Bezeichnungen plt und np könnten auch anders gewählt werden. Es ist aber Konvention, diese so wie hier gezeigt zu wählen. Die "arange"-Funktion aus der NumPy-Bibliothek wird später ein bisschen genauer behandelt (siehe [[Ing_Mathematik:_Python#Zahlenfolgen|Zahlenfolgen]]).
<small>Mit der im obigen Bild gezeigten Menüleiste kann die dargestellte Grafik nachträglich noch geändert werden (Zoom, Pan, Achsenparameter, Kurvenparameter etc.). Natürlich kann man das alles auch direkt programmieren. Wie das funktioniert wird ansatzweise etwas später gezeigt.</small>
Ein etwas komplexeres Beispiel ist Folgendes:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x) + 2**x
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh4.png]]
Man beachte, dass im Gegensatz zu Octave und Julia der ominöse Punkt (.) bei 2**x mit Python nicht benötigt wird. Das macht das Programmiererleben etwas einfacher.
Die Farbe des Graphen kann man über den <code>color</code>-Schalter einstellen, z.B. auf rot setzen:
plt.plot(x, y, color="red")
Das ist nur eine Möglichkeit, es gibt auch andere, z.B. mittels
* hexadezimaler Zahl, z.B. <code>color="#ff0000"</code>
* Kurzform, z.B. <code>"r"</code>
Statt <code>color</code> kann auch die Kurzform <code>c</code> verwendet werden.
<u>Kleine Aufgabe:</u> Probieren Sie diese "Farbspielereien" am Computer aus.
=== Graphen mehrerer Funktionen und weiteres ===
==== Mehrere Funktionen in einen Plot zeichnen ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x")
plt.plot(x, y2, label = "sin(x) * cos(x)")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh2.png]]
Um die Linienstile etwas individueller zu gestalten, ist folgender Programmcode gedacht:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
plt.plot(x, y2, label = "sin(x) * cos(x)", lw=3, ls="--")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh3.png]]
Einige weitere Bespiele zu <code>ls</code></code>:
* - ... durchgezogene Linie
* -. ... Strichpunkt-Linie
* dashed ... gestrichelte Linie
==== Marker ====
Desweiteren kann man Marker verwenden.
Beispiel:
import matplotlib.pyplot as plt
plt.plot(10, 10, "ob", markersize=30)
plt.plot(20,20, ".r")
plt.plot(30,30, "Dg", ms=15)
plt.plot(40, 40, "ok", ms=20, mec="#FF5733", mew=3)
plt.plot(50, 50, "vk", ms=20, mec="yellow", mew=3)
plt.grid()
plt.show()
Das erste Zeichen im String nach den Koordinaten im plot-Befehl symbolisiert die Form (z.B. o für einen Kreis). Das zweite Zeichen steht für die Farbe (z.B. b für blue). <code>markersize</code> oder <code>ms</code> setzt die Größe des Markers.
Ausgabe:
[[Bild:PythonIng_formatpara1.svg|200px]]
Einige weitere Marker:
* * ... Stern
* + ... Plus
* h oder H ... Sechseck
Man kann mit den Parametern
* <code>markeredgecolor</code> oder kurz <code>mec</code> die Farbe des Markerrandes
* <code>markeredgewidth</code> oder kurz <code>mew</code> die Dicke des Randes
* <code>markerfacecolor</code> oder kurz <code>mfc</code> die Innenfarbe des Markers
bestimmen.
=== Funktion in Parameterdarstellung ===
Es soll die archimedische Spirale <math>x = t \cos(t), y = t \sin(t)</math> im Intervall <math>[0, 6\pi[</math> gezeichnet werden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.show()
[[Datei:PythonIng_spirale1.png]]
Diese Darstellung erscheint verzerrt. Will man gleiche Achsenskalierungen, so kann man den plt.axis()-Befehl verwenden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.axis("equal")
plt.show()
[[Datei:PythonIng_spirale2.png]]
=== Funktion in Polardarstellung ===
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
r = np.arange(0, 1, 0.01)
theta = r**3
line = ax.plot(theta, r)
plt.show()
[[Datei:PythonIng_polar1.png]]
=== Logarithmische Achsenskalierung ===
==== Semilog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.semilogy()
plt.show()
Ausgabe:
[[Datei:PythonIng_semilog1.png]]
==== LogLog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.loglog()
plt.show()
[[Datei:PythonIng_loglog1.png]]
=== Gefüllte Fläche ===
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 3, 0.1)
y1 = 3*x - 1
y2 = x**2
plt.plot(x, y1, x, y2, color='black')
plt.fill_between(x, y1, y2, where=y1>=y2)
plt.show()
[[Datei:PythonIng_gefuellt.png]]
=== Linien, Pfeile, Rechtecke, Kreise und Texte ===
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
r = mpl.patches.Rectangle((0, 0), 3, 3, angle=30, fill=False)
c = mpl.patches.Circle((4, 4), 2, fill=False)
ax.add_patch(r)
ax.add_patch(c)
ax.plot([-2, 7], [-2, 0], color="black")
ax.arrow(0, 7, 5, 0, length_includes_head=True, head_width=0.5, head_length=1.5,
color="black")
ax.set_aspect("equal")
plt.axis([-3, 8, -3, 8])
plt.show()
[[Datei:PythonIng_linien_pfeile_etc.png]]
Text kann mit <code>ax.text(x, y, "Text")</code> hinzugefügt werden, bspw.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
ax.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
Oder einfacher auch ohne <code>subplots</code>
import matplotlib.pyplot as plt
plt.text(0.1, 0.1, "Hallo")
plt.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text1.png]]
Auch Sonderzeichen (griechische Buchstaben etc.) können verwendet werden (siehe dazu auch [https://matplotlib.org/stable/users/explain/text/mathtext.html]).
import matplotlib.pyplot as plt
plt.text(.3, .5,
r'$\Omega\ \psi\ \oint\ \nabla\ \dot a\ \frac{a}{b}\ a_b$',
size="20")
plt.show()
[[Datei:PythonIng_text20.svg]]
Jetzt wird noch gezeigt, wofür <code>subplots</code> sinnvoll eingesetzt werden können.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(0.1, 0.1, "Hallo")
ax[1].text(0.1, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text2.png]]
=== Anmerkungen hinzufügen ===
Anmerkungen (engl. annotations) lassen sich mit matplotlib einfach hinzufügen. Unter Anmerkung wird hier ein Pfeil mit Text verstanden.
Beispiel:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1,10], [1,10])
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0))
plt.show()
Ausgabe:
[[Datei: PythonIng_ann1.svg|400px]]
<code>shrink</code> verkürzt den Pfeil. Sinnvoll sind beim obigen Beispiel Werte irgendwo zwischen 0.0 und 0.3.
<u>Kleine Aufgabe:</u> Probieren Sie verschiedene Pfeillängen aus.
Die Schriftgröße verändern können Sie übrigens mit <code>fontsize</code> oder <code>size</code>, z.B.
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0), fontsize=25)
Eine andere Schreibweise für Dictionaries, die wir weiter oben schon kennengelernt haben, die wir aber nochmals explizit aufschreiben wollen, ist
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops={"facecolor":"red", "shrink":0.0})
=== Figure, Axes etc.===
[[Bild:PythonIng_figure33.svg|350px]]
* fig (figure) ... das übergeordnete Fenster
* ax (axes) ... "Plot", das eigentliche Zeichenfenster
* axis ... die Koordinatenachsen
* spine ... Begrenzungslinien des Zeichenfensters
* tick ... Markierung an den Achsen des Zeichenfensters
Beispiel (eine figure mit 6 axes, ax-Titel, y-axis-Titel):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=3, ncols=2)
ax[0][0].text(0.1, 0.5, "11")
ax[0][1].text(0.1, 0.5, "12")
ax[1][0].text(0.1, 0.5, "21")
ax[1][1].text(0.1, 0.5, "22")
ax[2][0].text(0.1, 0.5, "31")
ax[2][1].text(0.1, 0.5, "32")
ax[0][0].set(ylabel="y-label", title="axes 1")
plt.show()
[[Bild:PythonIng_figure34.png|350px]]
Beispiel (Achsenbereiche setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-1, 10, 1, 12))
plt.show()
[[Bild:PythonIng_figure35.svg|350px]]
Beispiel (Gitter einschalten):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-5, 10, 1, 12))
ax[0].minorticks_on()
ax[0].grid(which='minor')
ax[1].grid(which='major')
plt.show()
[[Bild:PythonIng_figure36.svg|350px]]
Beispiel (ticks setzen)
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
pos = [0, .2, .5]
lab = ["a", "b", "c"]
ax.xaxis.set_major_locator(tick.FixedLocator(pos))
ax.xaxis.set_major_formatter(tick.FixedFormatter(lab))
plt.show()
[[Bild:PythonIng_figure37.svg|350px]]
Beispiel (Achsenkreuz beliebig setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position(('data', 0.3))
ax.spines['left'].set_position(('data', 0.5))
plt.show()
[[Bild:PythonIng_figure38.svg|350px]]
Beispiel (Inset):
import matplotlib.pyplot as plt
# Hauptplot erstellen
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
# Inset hinzu:
axin = ax.inset_axes([0.4, 0.4, 0.3, 0.3])
axin.text(0, 0, "Servus")
axin.plot()
plt.show()
[[Bild:PythonIng_figure40.svg|350px]]
Beispiel (Hintergrundfarben setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_facecolor("green")
fig.set_facecolor("yellow")
plt.plot([1, 3], [6, 8])
plt.show()
[[Bild:PythonIng_figure39.svg|300px]]
=== GridSpec ===
Mit figures und axes lassen sich schon jede Menge an Grafikdetails einstellen. GridSpec ist dann der Turbo oder Raketenantrieb den matplotlib eingebaut hat. Naja, vielleicht ist das etwas übertrieben, aber GridSpec ist sozusagen ein flexibler Layout-Manager. Bisher haben wir immer gleich große axes gezeichnet. Mit GridSpec können wir Subplots über mehrere Zeilen und Spalten ziehen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(3, 3)
ax1 = fig.add_subplot(gs[0, :])
ax1.set_title("Bereich 1: gs[0, :]")
ax2 = fig.add_subplot(gs[1:, 0])
ax2.set_title("Bereich 2: gs[1:, 0]")
ax3 = fig.add_subplot(gs[1, 1:])
ax3.set_title("Bereich 3: gs[1, 1:]")
ax4 = fig.add_subplot(gs[2, 1:])
ax4.set_title("Bereich 4: gs[2, 1:]")
plt.show()
[[Bild:PythonIng_gridspec1.svg|350px]]
Erklärung zu <code>(gs[zeile, spalte])</code>: Slicing; damit legen Sie fest, welche Zellen ein Subplot belegt. Achtung! Die Indizes beginnen bei 0 und nicht bei 1 (d.h., die erste Zeile/Spalte hat den Index 0)
* : ... alle
* 1: ... 1 bis Ende
* etc.
<code>constrained_layout=True</code> sorgt dafür, dass sich die Subplots nicht überlappen.
Aber auch die Spaltenbreiten und Zeilenhöhen lassen sich anpassen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
# Verhältnis erste zu zweite Zeile = 1.5:1
# Verhältnis erste zu zweite Spalte = 1:4
gs = fig.add_gridspec(2, 2, figure=fig, height_ratios=[1.5, 1], width_ratios=[1, 4])
ax1 = fig.add_subplot(gs[0, 0])
ax1.set_title("Bereich 1: gs[0, 0]")
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_title("Bereich 2: gs[0, 0]")
ax3 = fig.add_subplot(gs[1, 0])
ax3.set_title("Bereich 3: gs[1, 0]")
ax4 = fig.add_subplot(gs[1, 1:])
ax4.set_title("Bereich 4: gs[1, 1]")
plt.show()
[[Bild:PythonIng_gridspec2.svg|350px]]
Auch die Ränder lassen sich einstellen.
Beispiel 1:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.1, right=0.9, bottom=0.1,
top=0.9, wspace=0.2, hspace=0.2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec3.svg|300px]]
* hspace ... height space, vertikaler Abstand zwischen den Zeilen
* wspace ... width space, horizontaler Abstand zwischen den Spalten
Und im Vergleich dazu Beispiel 2:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.3, right=0.7, bottom=0.3,
top=0.7, wspace=0.3, hspace=0.3)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec4.svg|300px]]
Es gibt noch einige weitere Details, die sich mit GridSpec variieren lassen (z.B. SubGridSpec ... verschachtelte Grid-Layouts). Aber wir belassen es vorerst dabei. Das bisher Gezeigte sollte für die meisten Probleme ausreichend sein.
=== Aufgaben ===
* Zeichnen Sie die Strophoide <math>x = \frac{a(t^2-1)}{t^2+1}, y = \frac{at(t^2-1)}{t^2+1}, a = 2, -3 \leq t \leq 3</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_strophoide.jpg|300px|center]]
* Zeichnen Sie die verschlungene Hypozykloide <math>x = (R-r)\cos t + c\cos\frac{R-r}{r}t, y = (R-r)\sin t - c\sin\frac{R-r}{r}t, c = 3, r = 2, R = 6, -15 \leq t \leq 15</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_hypozykloide.jpg|300px|center]]
* Testen Sie bei den obigen Übungsaufgaben verschiedene Linienstile und Farben. Farben können mit dem plt.plot()-Parameter color gewählt werden.
* Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.
* Zeichnen Sie folgendes Bild (die Achsenbeschriftungen positionieren Sie z.B. mit den Befehlen <code>ax.set_xlabel("x", loc="right"); ax.set_ylabel("y", loc="top")</code>):
[[Bild:PythonIng_aufgabe24.svg|400px|center]]
* Zeichnen Sie mit Python, matplotlib und NumPy folgendes Bild:
[[Bild:PythonIng_figure41.svg|400px|center]]
* Zeichnen Sie mit GridSpec ein Layout, das in etwa wie folgendes aussieht (<code>height_ratios=[1, 2], width_ratios=[2, 1]</code>):
[[Bild:PythonIng_aufgabe23.svg|300px|center]]
== 3D ==
=== Räumliche Kurven ===
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0, 6*np.pi, 0.1)
x = t * np.cos(t)
y = t * np.sin(t)
z = t
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot(x, y, z)
plt.show()
[[Datei:PythonIng_raumkurve1.png]]
=== Flächen ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z)
plt.show()
[[Datei:PythonIng_fläche1.png]]
Das Ganze in Netzdarstellung läßt sich so programmieren:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = np.arange(0, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_wireframe(x, y, z)
plt.show()
[[Datei:PythonIng_fläche2.png]]
Ein etwas komplexeres Beispiel:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.1, 10, 0.1)
y = np.arange(0.1, 10, 0.1)
x, y = np.meshgrid(x, y)
z1 = np.sin(x) + 3 * np.cos(y)
z2 = np.sin(x) + np.log(y)
z3 = x + np.cos(y)
z4 = x**2 - y
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, nrows=2, ncols=2)
ax[0][0].plot_surface(x, y, z1)
ax[0][1].plot_surface(x, y, z2)
ax[1][0].plot_surface(x, y, z3)
ax[1][1].plot_surface(x, y, z4)
plt.show()
[[Datei:PythonIng_subplot1.png]]
Man beachte, dass man die Unterbilder im Bild nach dem Ausführen des Scripts z.B. mit der mittleren Maustaste einzeln drehen, oder über die Einträge in der Menüzeile einzeln bearbeiten kann. Mit ein paar Zeilen Programmtext lässt sich also eine Menge an Funktionalität generieren.
Die Farbgebung lässt sich über <code>colormaps</code> variieren.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm)
plt.show()
[[Datei:PythonIng_colormap1.png]]
Es gibt eine Menge an Colormaps, z.B. <code>plasma, Greys, Dark2, ocean</code>. Zwecks detaillierterer Infos siehe die matplotlib-Dokumentation. <small>Verwendet man die IDE namens IDLE, so gibt es dort auch die automatische Codevervollständigung. D.h. es werden alle Möglichkeiten (in unserem Fall nach dem Eintippen von <code>cm.</code> alle verfügbaren Colormaps) angezeigt.</small>
Die "edgecolor" und Linienbreite können auch frei gewählt werden:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm, edgecolor="black", linewidth=1.0)
plt.show()
[[Datei:PythonIng_colormap2.png]]
=== Höhenlinien ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
ax.contour(x, y, z)
plt.show()
[[Datei:PythonIng_höhenlinien1.png|400px]]
Etwas abgewandelt sieht das so aus:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contour(x, y, z)
ax.clabel(hl, inline = True)
plt.show()
[[Datei:PythonIng_höhenlinien2.png|400px]]
Und noch eine Variante (mit einem Farbbalken) sei gezeigt.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contourf(x, y, z)
fig.colorbar(hl)
plt.show()
[[Datei:PythonIng_höhenlinien5.svg|400px]]
=== Aufgaben ===
* Zeichnen Sie die räumliche Kurve <math>x = 2 \cdot \cosh(t)</math>, <math>y = 5 \cdot \sin(t)</math>, <math> z = t^{2} - t</math>, <math>0 \leq t \leq 3\pi</math>.
* Zeichnen Sie die Fläche <math>z = \log(x) + \cos(y)</math>.
== Animationen und fortgeschrittenes 3D ==
=== Mit matplotlib ===
Auch mit matplotlib sind Animationen möglich. Das ist ein bisschen komplizierter und wird deshalb hier nur mit einem sehr einfachen Beispiel dargestellt (bei Interesse siehe z.B. auch das [https://matplotlib.org/stable/users/explain/animations/animations.html#animations Animations using Matplotlib-Tutorial]).
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib
import numpy as np
def update(frame):
line.set_xdata(x[:frame])
line.set_ydata(y[:frame])
return (line)
fig, ax = plt.subplots()
x = np.arange(0, 10, .1)
y = np.sin(x)
line, = ax.plot(x[0], y[0])
ax.set(xlim=[0, 10], ylim=[-1, 1])
a = ani.FuncAnimation(fig=fig, func=update, frames=100, interval=20)
plt.show()
# Speichere die Animation in einem animierten GIF (optional)
a.save(filename="c:/tmp/PythonIng_anim5.gif", writer="pillow")
[[Datei:PythonIng_anim5.gif]]
Es wird eine Sinuskurve auf den Bildschirm gezeichnet. In der letzten Zeile wird diese Animation in ein animiertes GIF gespeichert. Das ist natürlich optional und kann auch weggelassen werden.
=== Mit VPython ===
Aber auch mit dem Modul VPython lassen sich einfache 3D-Animationen erstellen. VPython ist ein externes Modul, das vorab installiert werden muss. Unter openSUSE Tumbleweed gibt es dzt. kein entsprechendes rpm-Paket. Die übliche Methode der Installation mittels YaST oder zypper ist somit nicht möglich. Auch eine direkte Verwendung von pip führt nur zu einer Fehlermeldung (<code>error: externally-managed-environment</code>). Es empfiehlt sich dort folgende Vorgehensweise:
# Erstelle zuerst eine virtuelle Umgebung, z.B.: <code>python3.11 -m venv ~/tmp/venv1</code>
# Wechsle das Verzeichnis: <code>cd ~/tmp/venv1/bin</code>
# Installiere das entsprechende Paket: <code>./pip install vpython</code>
# Führe das entsprechende Skript aus: <code>./python ~/tmp/test1.py</code>
Aktuell (März 2026) ist dieses Programmpaket lt. der [https://vpython.org/presentation2018/install.html VPython-Homepage] nur für die Python-Versionen 3.8 bis 3.12 verfügbar.
Ein Beispiel zu einer einfachen Animation wird nachfolgend geliefert.
from vpython import *
scene.width = 1200
scene.height = 600
scene.center = vector(20,0,0)
scene.background = color.white
cylinder(pos=vector(0,0,0), axis=vector(20,0,0), radius=5,
color=color.blue)
cone(pos=vector(0,0,0), axis=vector(-10,0,0), radius=5,
color=color.blue)
helix(pos=vector(20,0,0), axis=vector(40,0,0), radius=2,
coils=10, thickness=0.5, color=color.blue)
ball = sphere(pos=vector(20,0,0), color = color.green, radius = 1)
ball.p = vector(0.15, 0, 0)
toc = True
while True:
rate(200)
if(ball.pos.x <= 60 and toc == True):
ball.pos += ball.p
else:
toc = False
ball.pos -= ball.p
if(ball.pos.x <= 20 and toc == False):
toc = True
[[Datei:PythonIng_vpython_anim.JPG]]
Idealerweise öffnet sich beim Ausführen des Scripts ein Browserfenster. Darin wird die programmierte Animation gezeigt (siehe auch den obigen Screenshot). Eine Größenänderung können Sie mit der mittleren Maustaste initiieren. Die Szenerie drehen können Sie mit der rechten Maustaste.
=== Mit build123d ===
Hiermit lassen sich einfach 3D-Modelle für CAD-Systeme erstellen. [https://build123d.readthedocs.io/en/latest/ build123d] ist ein externes Modul und muss vorab, wie schon für mehrere andere Module gezeigt, installiert werden (pip, venv etc.).
Beispielcode:
from build123d import *
# Bauteil
with BuildPart() as bauteil:
# Zylinder erstellen
Cylinder(100, 60)
# Bohrung
with BuildSketch(bauteil.faces().sort_by(Axis.Z)[-1]) as loch:
Circle(radius=10)
# negativ extrudieren
extrude(amount=-60, mode=Mode.SUBTRACT)
# Dem Bauteil z.B. die Farbe rot zuweisen
# bauteil.part.color = Color("red", alpha=1.0)
# Fertiges Modell exportieren
export_step(bauteil.part, "bauteil.step")
Ausgabe ({{W|Standard for the exchange of product model data | STEP}}-Datei, z.B. in {{W|FreeCAD}} importiert, Screenshot):
[[Datei:PythonIng_build123d.jpg | 300px]]
FreeCAD ist ein freies 3D-CAD-System. Die [[Ing_Mathematik:_Python#FreeCAD | Makroprogrammierung]] in diesem System wird später noch gezeigt. STEP steht für "'''St'''andard for the '''e'''xchange of '''p'''roduct model data" und ist ein Datenaustauschformat.
=== Mit VTK ===
Komplexer, aber auch mächtiger als VPython ist die Verwendung von VTK ('''V'''isualization '''T'''ool'''k'''it). Genauer gesagt des Python-Wrappers von VTK. Dieses externe Python-Modul muss vorab installiert werden (z.B. mittels YaST, pip oder in eine virtuelle Umgebung). VTK ist eine Softwarebibliothek zur 3D-Visualisierung und wurde ursprünglich in C++ geschrieben. Verbreitet eingesetzt wird diese Bibliothek in der Wissenschaft und Forschung, z.B.
* in der medizinischen Bildgebung
* für Strömungssimulationen
* für Klimadaten
VTK funktioniert nach dem {{W|Grafikpipeline|Pipeline-Prinzip}}:
Source (Quellen) -> Filter -> Mapper (Senken) -> Actor/Renderer
Daten fließen von den Quellen zu den Senken.
Als einfaches Beispiel wird die Darstellung eines Zylinders gezeigt, der mit den Maustasten gedreht oder in der Größe geändert werden kann:
import vtk
# Zylinder erzeugen
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
# Geometrie in darstellbare Daten umwandeln
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
# Objekt in der Szene
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Szene verwalten
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# Render-Fenster
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
# Maus/Tastatur-Steuerung
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Starten
render_window.Render()
interactor.Start()
Ausgabe:
[[Datei:PythonIng_VTK_1.png]]
Gleiches Beispiel wie oben, aber mit einer Animationssequenz:
import vtk
import time
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
render_window.Render()
time.sleep(0.01)
Das Grafikfenster schließt sich nach Ablauf der Schleife. Das Fenster bleibt geöffnet, wenn Sie am Programmende folgenden Befehl hinschreiben
interactor.Start()
Um den animierten Zylinder grün einzufärben, müssen Sie Folgendes im obigen Programm ergänzen (Farbnamen):
colors = vtk.vtkNamedColors()
actor.GetProperty().SetColor(colors.GetColor3d("Green"))
Als Namen können Sie u.a. die CSS3 Web-Farben verwenden (siehe z.B. [https://wiki.selfhtml.org/wiki/Farbe/Farbangaben] und {{W|Webfarbe#CSS_3}}).
Alternativ funktioniert auch das ({{W|RGB-Farbraum|RGB}}):
actor.GetProperty().SetColor(0.0, 0.6, 0.0)
Wie der Zylinder mit einer Textur versehen wird, zeigt folgendes Programm:
import vtk
import time
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(30)
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.CappingOn()
texture_coords = vtk.vtkTextureMapToCylinder()
texture_coords.SetInputConnection(cylinder.GetOutputPort())
texture_coords.PreventSeamOn()
reader = vtk.vtkJPEGReader()
reader.SetFileName("PythonIng_textur.jpg")
texture = vtk.vtkTexture()
texture.SetInputConnection(reader.GetOutputPort())
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(texture_coords.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.SetTexture(texture)
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
renderWindow.Render()
time.sleep(0.01)
interactor.Start()
<gallery>
PythonIng_textur.jpg | Textur-Datei
PythonIng_VTK_2.png | Ausgabe (Screenshot)
</gallery>
== Sonstige Grafikbibliotheken ==
=== Py5 ===
Im Buch ''Iacono et al.: Programmieren trainieren, mit über 150 Workouts in Java und Python; 3. Aufl., Hanser, 2023'' werden zahlreiche Aufgaben gestellt, die u.a. mit Processing zu lösen sind. Processing ist eine einfache Programmiersprache und Entwicklungsumgebung. Warum ich das erwähne? Weil in älteren Processing-Versionen auch die Programmiersprache Python 2 abgedeckt war. Bei neueren Versionen gibt es keine Python-Anbindung mehr (getestet nur mit openSUSE Tumbleweed und Python 3). Somit funktioniert der Python-Teil im genannten Buch zum Teil nicht mehr. Ist das tragisch, oder kann das Buch weggeschmissen werden? Nein! Es gibt Alternativen zu Processing. Zum einen die im Buch selbst genannten Bibliotheken tkinter oder pygame. Pygame wird dort auch kurz anhand eines Beispiels thematisiert. Aber noch besser ist es, die py5-Bibliothek zu verwenden (lt. Google KI vom 30. Sept. 2026: ''Der echte, moderne „spirituelle Nachfolger“''). Damit ist die Funktionalität von Processing gewährleistet. Man kann aber beliebige Editoren oder IDEs zur Programmerstellung verwenden, ohne an Processing als IDE gebunden zu sein. Nachfolgend werden ein paar Beispiele zu dieser externen Bibliothek gegeben. Der erste Schritt ist wieder, die py5-Bibliothek zu installieren (z.B. mittels pip in eine virtuelle Umgebung). Dann kann es schon mit dem Programmieren losgehen.
Beispiel (angelehnt an die ''Aufgabe W.2.3 Haus'' des genannten Buchs, jedoch etwas erweitert):
import py5
def setup():
py5.size(600, 600) # Fenstergröße 600px x 600px
py5.background(255, 255, 255) # Hintergrundfarbe ... weiss
def draw():
# Haus zeichnen
py5.fill(255, 255, 255) # Hintergrundfarbe ... weiss
py5.stroke(255, 0, 0) # Linienfarbe ... rot
py5.stroke_weight(3) # Linienbreite ... 3px
py5.rect(150, 200, 300, 300) # Rechteck zeichnen (x, y, b, h)
py5.triangle(150, 200, 300, 100, 450, 200) # Dreieck zeichnen
py5.circle(250, 300, 70) # Kreis zeichnen (x, y, d)
# Bemassung zeichnen
py5.stroke(0, 255, 0)
py5.stroke_weight(1)
py5.line(300, 100, 550, 100) # Linie zeichnen
py5.line(450, 200, 550, 200)
py5.line(450, 500, 550, 500)
py5.line(150, 500, 150, 550)
py5.line(450, 500, 450, 550)
py5.text_size(20) # Textgroesse
py5.fill(0, 255, 0) # Textfarbe
py5.text("300", 280, 550) # Text zeichnen
py5.text("100", 500, 150)
py5.text("300", 500, 350)
# Gedrehtes Rechteck zeichnen
py5.stroke(255, 255, 0)
py5.stroke_weight(3)
py5.fill(200, 200, 200)
py5.translate(320, 260)
py5.rotate(0.3) # Drehung (in Radiant)
py5.rect(0, 0, 100, 50)
# Startet den Sketch
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_1.png|300px]]
Das skizzierte Haus ist mit einer rudimentären Bemaßung versehen und hat zwei Fenster, ein rundes und ein gedrehtes, trübes rechteckiges.
Beispiel (Mausoperationen):
import py5
def setup():
py5.size(600, 600)
py5.background(255, 255, 255)
def draw():
pass
def mouse_pressed():
py5.text_size(15)
py5.fill(0, 0, 255)
x = py5.mouse_x
y = py5.mouse_y
py5.text("(%d, %d)" %(x, y), x, y) # Positionsdaten bei Maus-Klick schreiben
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_2.png|300px]]
Obiges Bild zeigt das Resultat nach einigen Mausklicks. Man erkennt, dass links-oben der Koordinatennullpunkt ist. Die x-Achse zeigt nach rechts, die y-Achse nach unten.
Beispiel (Fünfeck):
import py5
import random
def setup():
py5.size(400, 400)
py5.no_loop() # statisches Bild (schont die Ressourcen)
def draw():
py5.translate(py5.width / 2, py5.height / 2) # KS setzen
radius = 150
eck_anzahl = 5
py5.fill(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255)) # Füllfarbe auf Zufallswert setzen
py5.stroke(155, 0, 0)
py5.stroke_weight(5)
# Fünfeck als Polygon zeichnen
py5.begin_shape()
for i in range(eck_anzahl):
winkel = i * py5.TWO_PI / eck_anzahl - py5.HALF_PI
x = py5.cos(winkel) * radius
y = py5.sin(winkel) * radius
py5.vertex(x, y)
py5.end_shape(py5.CLOSE)
py5.run_sketch()
Ausgabe, bspw.:
[[Datei:PythonIng_py5_5.png|200px]]
<u>Kleine Aufgaben:</u>
* Um die Funktionsweise von <code>py5.no_loop()</code> zu verstehen, kommentieren Sie die Anweisung im Beispiel einfach aus, und starten Sie das Programm erneut.
* Zeichnen Sie ein Siebeneck.
* Was passiert, wenn man <code>py5.CLOSE</code> im <code>py5.end_shape()</code>-Befehl weglässt?
Beispiel (Grafik laden und zeichnen):
import py5
image1 = None
def setup():
global image1
py5.size(600, 600)
py5.no_loop()
image1 = py5.load_image("PythonIng_py5_1.png")
def draw():
py5.image(image1, 0, 0)
py5.run_sketch()
Hier wird einfach das Bild vom Haus-Beispiel (Screenshot von weiter oben) geladen und gezeichnet.
Hiermit belassen wir es mit der py5-Bibliothek und wenden uns wieder "mathematischeren" Themen zu.
= Vektoren und Matrizen =
== Zahlenfolgen ==
Für das Erstellen von Zahlenfolgen bieten sich die Funktionen <code>arange</code> und <code>linspace</code> aus dem <code>numpy</code>-Modul an.
from numpy import *
start = 0
stop = 10
step = 2
num = 10
r = arange(start, stop, step) # step ... Schrittweite
l = linspace(start, stop, num) # num ... Anzahl der Werte
print("r = ", r)
print("l = ", l)
Ausgabe:
r = [0 2 4 6 8]
l = [ 0. 1.11111111 2.22222222 3.33333333 4.44444444 5.55555556
6.66666667 7.77777778 8.88888889 10. ]
Bei <code>arange</code> ist der <code>stop</code>-Wert nicht im Ergebnis enthalten, bei <code>linspace</code> standardmäßig aber sehr wohl. Jedoch kann man das bei <code>linspace</code> auch ändern. Dann ist der Stoppwert nicht mehr enthalten:
linspace(start, stop, num, endpoint=False)
== Vektoren ==
Vektoren sollten jedem aus der Linearen Algebra bekannt sein.
=== Arrays ===
In Python mit NumPy kann man Vektoren durch die Funktion array erzeugen.
import numpy as np
l1 = (-5, 3, 2)
l2 = (1, 1, 4)
a1 = np.array(l1)
a2 = np.array(l2)
a3 = a1 + a2
a4 = 2 * a2
print(a1)
print(a2)
print(a3)
print(a3[2])
print(a4)
Ausgabe:
[-5 3 2]
[1 1 4]
[-4 4 6]
6
[2 2 8]
=== Zeilen- und Spaltenvektoren ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
print(z)
print(s)
Ausgabe:
[ [-5 3 2] ]
[[1]
[1]
[4]]
=== Skalarprodukt ===
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
skalarprodukt = np.dot(a1, a2)
print(skalarprodukt)
Ausgabe:
6
=== Vektorprodukt ===
<math>a\ast b=\left(\begin{array}{c}
a_{1}\\
a_{2}\\
a_{3}
\end{array}\right)\ast\left(\begin{array}{c}
b_{1}\\
b_{2}\\
b_{3}
\end{array}\right)=\left(\begin{array}{c}
a_{2}b_{3}-a_{3}b_{2}\\
a_{3}b_{1}-a_{1}b_{3}\\
a_{1}b_{2}-a_{2}b_{1}
\end{array}\right)
</math>
Python-Code:
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
vektorprodukt = np.cross(a1, a2)
print(vektorprodukt)
Ausgabe:
[10 22 -8]
=== Transponierter Vektor ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
# transponierter Vektor
z_tp = np.transpose(z)
# transponierter Vektor
s_tp = np.transpose(s)
print(z_tp)
print(s_tp)
Ausgabe:
[[-5]
[ 3]
[ 2]]
[ [1 1 4] ]
=== Vektorfelder visualisieren ===
import matplotlib.pyplot as plt
import numpy as np
# Daten generieren
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
X, Y = np.meshgrid(x, y)
U = X * Y
V = Y + X
# Plotten
fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='xy')
plt.show()
Ausgabe:
[[Datei:PythonIng_quiver1.png]]
== Matrizen==
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
print(m1)
Ausgabe:
[[1 2 3]
[4 5 6]]
=== Zugriff auf Matrizenelemente ===
Beispiel:
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
# Element aus Zeile 2 und Spalte 3 (Achtung! Index startet bei Null)
print(m1[1,2])
Ausgabe:
6
Visualisierung:
0 1 2
+-----------+
0 | 1 | 2 | 3 |
+-----------+
1 | 4 | 5 | '''6''' |
+-----------+
Beispiel:
import numpy as np
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
B = np.matrix(A)
print(B[2::, ::2])
Ausgabe:
[['20' '22']
['30' '32']
['40' '42']]
Mit der NumPy-Bibliothek funktioniert das zweidimensionale Slicing. Mit normalen Listen/Tupels geht das nicht, was wir schon früher thematisiert haben.
=== Addition und Subtraktion von Matrizen ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
m2 = np.matrix([[0, 0, 2], [1, 3, 2]])
print(m1 + m2)
print(m1 - m2)
Ausgabe:
[[1 2 5]
[5 8 8]]
[[1 2 1]
[3 2 4]]
=== Transponierte Matrix ===
import numpy as np
m = np.matrix([[1, 2, 3], [4, 5, 6]])
mt = np.transpose(m)
print(m)
print(mt)
Ausgabe:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]
=== Rang einer Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
rg = np.linalg.matrix_rank(m)
print(rg)
Ausgabe:
2
=== Inverse Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
mi = np.linalg.inv(m)
print(mi)
Ausgabe:
[[ 1. 0.6]
[-0. -0.2]]
=== Multiplikation von Matrizen (falksches Schema) ===
import numpy as np
m1 = np.matrix([[1, 3, 4], [0, -5, 1]])
m2 = np.matrix([[1, 2], [2, 3], [0, 2]])
print(m1 @ m2)
Ausgabe:
[[ 7 19]
[-10 -13]]
=== Eigenwerte und Eigenvektoren ===
import numpy as np
m = np.matrix([[5, 8], [1, 3]])
D,V = np.linalg.eig(m)
# Eigenwerte
print(D)
# Eigenvektoren
print(V)
Ausgabe:
[7. 1.]
[[ 0.9701425 -0.89442719]
[ 0.24253563 0.4472136 ]]
=== Teilmatrizen ===
import numpy as np
m = np.matrix([[1, 3, 4], [0, -5, 1]])
print("m = ", m)
# Erste Zeile extrahieren
m1 = m[0,:]
print("m1 = ", m1)
# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
m2 = m[0,1]
print("m2 = ", m2)
# Zweite Spalte extrahieren
m3 = m[:, 1]
print("m3 = ", m3)
Ausgabe:
m = [[ 1 3 4]
[ 0 -5 1]]
m1 = [ [1 3 4] ]
m2 = 3
m3 = [[ 3]
[-5]]
=== Spezielle Matrizen ===
==== Nullmatrix ====
import numpy as np
z = np.zeros((3, 2))
print(z)
Ausgabe:
[[0. 0.]
[0. 0.]
[0. 0.]]
==== Einheitsmatrix ====
import numpy as np
z = np.eye(3)
print(z)
Ausgabe:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
==== Matrix mit lauter Einsen ====
import numpy as np
z = np.ones((3, 2))
print(z)
Ausgabe:
[[1. 1.]
[1. 1.]
[1. 1.]]
=== Spärlich besetzte Matrizen ===
Das Thema spärlich besetzter Matrizen wird hier nur kurz angerissen. Nähere Details siehe unter dem Weblink [https://docs.scipy.org/doc/scipy/reference/sparse.html#module-scipy.sparse].
Beispiel:
import numpy as np
import scipy
A = scipy.sparse.csr_array(np.eye(5))
print(A)
Ausgabe:
<Compressed Sparse Row sparse array of dtype 'float64'
with 5 stored elements and shape (5, 5)>
Coords Values
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
(4, 4) 1.0
csr steht für '''c'''ompressed '''s'''parse '''r'''ow.
Andere Möglichkeiten:
* coo-Format ('''coo'''rdinate Format): <code>scipy.sparse.coo_array()</code>
* lil-Format ('''li'''st of '''l'''ists): <code>scipy.sparse.lil_array()</code>
* csc-Format ('''c'''ompressed '''s'''parse '''c'''olumn): <code>scipy.sparse.csc_array()</code>
Es gibt auch <code>scipy.sparse.csr_matrix()</code> etc. Diese Befehle sind aber veraltet und es wird empfohlen, statt dessen die <code>..._array()</code>-Funktionen zu verwenden.
<u>Aufgaben:</u>
Recherchieren Sie im Internet
* generell zum Thema "spärlich besetzte Matrizen mit Python".
* Was sind die Vor-/Nachteile von csr-arrays gegenüber coo- und lil-arrays?
* Wann verwendet man sinnvollerweise csr- und wann csc-arrays?
* Wie wandelt man coo-arrays in csr-arrays um?
= Lineare Gleichungssysteme =
Sei <math>Ax = b</math> ein lineares Gleichungssystem. <math>A</math> sei die Koeffizientenmatrix, <math>x</math> der Lösungsvektor und <math>b</math> ein bekannter Vektor.
Beispiel:
import numpy as np
A = np.array([[5, 1], [0, 2]])
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)
Ausgabe:
[0. 1.]
Siehe dazu auch das Kapitel [[Ing Mathematik: Numerisches Lösen von linearen Gleichungssystemen]]. Dort wird dieses Themengebiet u.a. mit weitergehenden Python-Skripten vertieft.
== Aufgabe ==
* Lösen Sie folgendes Gleichungssystem mittels Python (und zur Kontrolle auch händisch):
5x + 6y - 2z = 12
3x - y - 3z = 6
2x + 2y + 4z = 5
= Polynome =
== Ein erstes einfaches Beispiel ==
Gegeben sei das Polynom <math>7x^3+5x^2+1</math>. In Python:
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p)
Ausgabe:
3 2
7 x + 5 x + 1
== Einzelne Polynomwerte berechnen ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p(1.5))
Ausgabe:
35.875
== Polynome integrieren und differenzieren ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
# 1. Ableitung
p1 = p.deriv()
p2 = p.deriv(1)
# 2. Ableitung
p3 = p.deriv(2)
# Integral
p4 = p.integ()
print(p1)
print(p2)
print(p3)
print(p4)
Ausgabe:
2
21 x + 10 x
2
21 x + 10 x
42 x + 10
4 3
1.75 x + 1.667 x + 1 x
== Nullstellen bestimmen ==
import numpy as np
p = np.poly1d([2, 5, 0, 4])
r = np.roots(p)
print(r)
Ausgabe:
[-2.7621427 +0.j 0.13107135+0.84077099j 0.13107135-0.84077099j]
== Aufgaben ==
* Berechnen Sie den Wert für x = 3 des Polynoms <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Differenzieren und integrieren Sie das Polynom <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Berechnen Sie die Nullstellen von <math>y = 7x^5 - 3x^2 + 12</math>.
= Nichtlineare Gleichungen und Gleichungssysteme =
== Nullstellenbestimmung ==
Löse eine beliebige Gleichung f(x) = 0, z.B. <math> f(x) = x^2 - 5\cos(x) - 10 = 0 </math>:
import scipy
import numpy as np
def f(x):
return x**2 - 5*np.cos(x) - 10
xstart = [-1, 1] # Startwerte
xn = scipy.optimize.root(f, xstart)
print(xn.x)
Ausgabe:
[-2.46813009 2.46813009]
Funktionsgraph:
[[Datei:octave_nichtlin2.jpg]]
== Gleichungssysteme ==
SymPy ist ein externes Modul, das symbolisches Rechnen ('''Sym'''bolic '''Py'''thon) ermöglicht.
Folgende Aufgabe ist dem Buch "Knorrenschild: Numerische Mathematik, Hanser, 2017, Seite 72" entnommen. Zu lösen ist das nichtlineare Gleichungssystem
<math>f_1 = 2x_1 + 4x_2 = 0 </math>
<math>f_2 = 4x_1 + 8x_2^3 = 0</math>
Mit Python ist das so möglich:
import sympy
x1, x2 = sympy.symbols("x1 x2")
f1 = 2*x1 + 4*x2
f2 = 4*x1 + 8*x2**3
s = sympy.solve((f1, f2), x1, x2)
print(s)
Ausgabe:
[(-2, 1), (0, 0), (2, -1)]
Plot:
[[Datei:IngPython_nl_gleichung1.svg|500px]]
= Komplexe Zahlen =
Die imaginäre Einheit wird in Python durch den Buchstaben <code>j</code> symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:
* Kartesische Darstellung <math>z = \Re(z) + j \cdot \Im(z)</math>
* Polardarstellungen <math>z = r \cdot (\cos(\phi) + j \cdot \sin(\phi)) = r \cdot e^{j\cdot \phi}</math>
Die konjugiert komplexe Zahl ist <math>z^* = \Re(z) - j \cdot \Im(z)</math>
Nachfolgend einige mathematische Operationen mit Python und NumPy.
import numpy as np
z1 = 2 + 5j # kartesische Darstellung
z2 = 3 * np.exp(3j) # Polardarstellung
# Addition
res = z1 + z2
print("z1 + z2 = ", res)
# Multiplikation
res = z1 * z2
print("z1 * z2 = ", res)
# Realteil
res = np.real(z2)
print("Realteil von z2 = ", res)
# Imaginärteil
res = np.imag(z2)
print("Imaginaerteil von z2 = ", res)
# Betrag
res = np.abs(z1)
print("Betrag von z1 = ", res)
# Argument
res = np.angle(z1)
print("Argument von z1 = ", res)
# Konjugiert komplexe Zahl
res = np.conj(z1)
print("Konjugiert komplexe Zahl von z1 = ", res)
Ausgabe:
z1 + z2 = (-0.9699774898013365+5.423360024179601j)
z1 * z2 = (-8.05675510050068-14.003167400647481j)
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = (2-5j)
= Interpolation =
import numpy as np
import scipy
import matplotlib.pyplot as plt
# Stützpunkte
xp = np.arange(1, 6)
yp = (0, -5, 2, 7, 6)
ti = np.arange(1, 5, 0.01)
i1 = scipy.interpolate.interp1d(xp, yp, kind = "linear")
i2 = scipy.interpolate.interp1d(xp, yp, kind = "cubic")
plt.plot(xp, yp, "rx")
plt.plot(xp, i1(xp))
plt.plot(ti, i2(ti))
plt.show()
Ausgabe:
[[Datei:PythonIng_interpol1.png]]
= Differenzialrechnung =
== Numerisches Differenzieren ==
Als Beispiel differenzieren wir <math>y = 5x\sin{x}</math> und stellen das Ganze grafisch dar.
from findiff import Diff
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
f = 5 * x * np.sin(x)
dx = x[1] - x[0]
# Ableitung
d_dx = Diff(0, dx)
df_dx = d_dx(f)
# Grafik
plt.plot(x, f, label = "y")
plt.plot(x, df_dx, label = "y'")
plt.grid()
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:octave_diff1.jpg]]
<small>findiff ist ein externes Modul. Dieses muss installiert werden (z.B. so: ...\Python\Scripts\pip.exe install --upgrade findiff). Für die Vorgehensweise unter openSUSE Tumbleweed siehe das Kapitel [[Ing_Mathematik:_Python#Mit_VPython | VPython]], nur dass das Ganze mit einer aktuelleren Python-Version exekutiert wird, z.B. mit Python 3.13. Das im Buch "Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler, Rheinwerk" verwendete Modul "scipy.misc" ist veraltet (deprecated ... missbilligt). Lt. [https://docs.scipy.org/doc/scipy-1.17.0/dev/roadmap-detailed.html#misc SciPy-Dokumentation für die Version 1.17.0] wurden alle entsprechenden Features schon entfernt.</small>
== Symbolisches Differenzieren ==
Differenzieren Sie die Funktionen <math>f_1(x) = x^2</math> und <math>f_2(x) = \sin(x)\cos\left(\frac{x}{2}\right)</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2;
f2 = sympy.sin(x) * sympy.cos(x/2.)
d1 = sympy.diff(f1, x)
d2 = sympy.diff(f2, x)
print(d1)
print(d2)
Ausgabe:
2*x
-0.5*sin(0.5*x)*sin(x) + cos(0.5*x)*cos(x)
== Aufgaben ==
* Differenzieren Sie die Funktion <math>y = \log(x) + 10x</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
* Differenzieren Sie die Funktion <math>y = \frac{\sinh(x)}{(1+x)}</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
= Integralrechnung =
== Numerisches Integrieren ==
Berechnen Sie das Integral <math>\int_{0}^{3}x^2 dx</math>.
import scipy
def f(x):
return x**2
i = scipy.integrate.quad(f, 0, 3)
print(i)
Ausgabe:
(9.000000000000002, 9.992007221626411e-14)
Das trifft den exakten Wert 9.0 ziemlich genau.
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} dx</math>.
import scipy
import numpy as np
def f(x):
return 2**(-x)
i = scipy.integrate.quad(f, 0, np.inf)
print(i)
Ausgabe:
(1.4426950408889556, 4.486558477977586e-09)
== Symbolisches Integrieren ==
Berechnen Sie <math>\int x^2 \text{d}x</math> und <math>\int \sin{x}\cos{\frac{x}{2}} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2
f2 = sympy.sin(x) * sympy.cos(x/2.)
i1 = sympy.integrate(f1, x)
i2 = sympy.integrate(f2, x)
print(i1)
print(i2)
Ausgabe:
x**3/3
-0.666666666666667*sin(0.5*x)*sin(x) - 1.33333333333333*cos(0.5*x)*cos(x)
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f = 2**(-x)
i = sympy.integrate(f, (x, 0, sympy.oo))
print(i)
Ausgabe:
1/log(2)
<code>sympy.oo</code> steht für das {{W|Unendlichzeichen}} <math>\infty</math> (die liegende Acht oder das Möbiusband). Mit <code>sympy.pprint(i)</code> ließe sich letzere Ausgabe etwas schöner schreiben:
1
──────
log(2)
Man beachtete, <code>log</code> steht hier für den natürlichen Logarithmus <code>ln</code>.
== Aufgaben ==
* Integrieren Sie die Funktion <math>y = \log(x) + 10x</math> von 1 bis 5.
* Integrieren Sie die Funktion <math>y = x^3</math> von 0 bis 4.
* Integrieren Sie <math>\int x^x(\log (x) + 1)\mathrm dx</math> symbolisch.
= Gewöhnliche Differenzialgleichungen =
== DGL numerisch lösen ==
Für die Lösung von Differenzialgleichungen steht u.a. die Funktion scipy.integrate.solve_ivp() zur Verfügung. Diese Funktion implementiert auch das Runge-Kutta-Verfahren (RK45).
{{Wikipedia | Runge-Kutta-Verfahren}}
Beispiel <math>y' = x^2 + y^3</math>:
import scipy
import numpy as np
import matplotlib.pyplot as plt
def dy_dx(x, y):
return x**2 + y**3
y0 = [1]
xi = [0, 1]
x = np.arange(0, 1, 0.01)
z = scipy.integrate.solve_ivp(dy_dx, xi, y0, method="RK45", dense_output=True)
y = z.sol(x)
plt.plot(x, y.T)
plt.grid()
plt.show()
[[Datei:PythonIng_dgl1.png]]
== DGL symbolisch lösen ==
Beispiel <math>y' = x^2 + y^3</math>:
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
print(lsg)
Ausgabe:
[Eq(f(x), (-x**2)**(1/3)), Eq(f(x), (-x**2)**(1/3)*(-1 - sqrt(3)*I)/2), Eq(f(x), (-x**2)**(1/3)*(-1 + sqrt(3)*I)/2)]
Mit <code>sympy.pprint</code> (pretty print) lässt sich die Ausgabe etwas übersichtlicher darstellen.
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
sympy.pprint(lsg)
Ausgabe:
⎡ _____ _____ ⎤
⎢ _____ 3 ╱ 2 3 ╱ 2 ⎥
⎢ 3 ╱ 2 ╲╱ -x ⋅(-1 - √3⋅ⅈ) ╲╱ -x ⋅(-1 + √3⋅ⅈ)⎥
⎢f(x) = ╲╱ -x , f(x) = ────────────────────, f(x) = ────────────────────⎥
⎣ 2 2 ⎦
== Aufgaben ==
* Lösen Sie die Differenzialgleichung <math>y' = \frac{1}{x\cdot y}</math> mit Python. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>m' = -k\cdot m</math>. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>y' = \sqrt{|y|}</math>.
=Laplace-Transformation=
Laplace-Transformation:
<math>F(s) =\mathcal{L} \left\{f\right\}(s) = \int_{0}^{\infty} f(t) \mathrm e^{-st} \,\mathrm{d}t, \qquad s\in\mathbb{C}
</math>
Inverse Laplace-Transformation:
<math>\mathcal{L}^{-1} \left\{F\right\}(t)
= \frac{1}{2 \pi \mathrm j} \int_{ \gamma - \mathrm j \infty}^{ \gamma + \mathrm j \infty} \mathrm e^{st} F(s)\,\mathrm ds
= \begin{cases}
f(t) & \text{für } t \geq 0 \\
0 & \text{für } t < 0
\end{cases}
</math>
Siehe auch [[Ing_Mathematik:_Laplace-Transformation]]
Code:
import sympy
from sympy.abc import t, s
# Laplace-Transformation der Funktion f(t) = 1 (Heaviside-Fkt.)
f = 1
# alternativ: f = sympy.Heaviside(t)
F = sympy.laplace_transform(f, t, s, noconds=True)
print("Laplace-Transformierte F(s):", F)
# Inverse Laplace-Transformation zurück in den Zeitbereich
f_inv = sympy.inverse_laplace_transform(F, s, t)
print("Inverse Transformation f(t):", f_inv)
Ausgabe:
Laplace-Transformierte F(s): 1/s
Inverse Transformation f(t): Heaviside(t)
Die Zeile
from sympy.abc import t, s
steht alternativ für
t = sympy.symbols("t")
s = sympy.symbols("s")
<u>Aufgaben</u>: Ermitteln Sie mittels SymPy die <math>\mathcal{L}</math>-Transformierten und dann wieder die <math>\mathcal{L}^{-1}</math>-Transformationen (ähnlich wie beim obigen Beispiel):
* <math>\sin(t) \circ\! -\! \bullet \ ?</math>
* <math>t^3 \circ\! -\! \bullet \ ?</math>
* <math>\text{e}^{\omega t} \circ\! -\! \bullet \ ?</math>
=Fourier-Reihen=
<math>
f(x)\approx \frac{a_{0}}{2}+\sum_{k=1}^{\infty}\left(a_{k}\cos\left(kx\right)+b_{k}\sin\left(kx\right)\right)
</math>
<math>
a_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\cos\left(kx\right)\mathrm dx\quad\text{für }k\geq0
</math>
<math>
b_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\sin\left(kx\right)\mathrm dx\quad\text{für }k\geq1
</math>
Für die Sägezahnfunktion <math>y=x;\, 0 < x < 2\pi</math> sei die Fourierreihe mit einem Python-Programm (unter Mithilfe von sympy) hergeleitet.
Code:
from sympy import fourier_series, pi, symbols, pprint
x = symbols('x')
f = x
s = fourier_series(f, (x, 0, 2*pi))
pprint(s.truncate(n=4))
Ausgabe:
2⋅sin(3⋅x)
-2⋅sin(x) - sin(2⋅x) - ────────── + π
3
Siehe auch [[Ing Mathematik: Fourierreihen]].
Ein komplizierteres Beispiel:
[[Datei:IngMath fourier bsp13.svg | 300px]]
<math>0\le t < T/2\text{:}\quad f(t) = H</math>
<math>T/2 \le t \le T\text{:}\quad f(t) = \frac{2H}{T}\left( t-\frac{T}{2}\right)</math>
Code:
import sympy as sp
H = sp.Symbol('H', positive=True)
T = sp.Symbol('T', positive=True)
t = sp.Symbol('t')
f = sp.Piecewise(
(H, (t > 0) & (t < T/2)),
(2*H/T*(t-T/2), (t > T/2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Ausgabe:
⎛2⋅π⋅t⎞ ⎛4⋅π⋅t⎞ ⎛6⋅π⋅t⎞ ⎛2⋅π⋅t⎞ ⎛6⋅π⋅t⎞
H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ 2⋅H⋅cos⎜─────⎟ 2⋅H⋅cos⎜─────⎟
⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ 3⋅H
──────────── - ──────────── + ──────────── + ────────────── + ────────────── + ───
π 2⋅π 3⋅π 2 2 4
π 9⋅π
=Rechnen mit wirklich großen Zahlen=
Bekannt ist, dass Python kaum Einschränkungen beim Wertebereich von Ganzzahlen hat, z.B.
print(10**300)
Ausgabe (gekürzt):
100000000000000000000...00000000000000000000000000000000000000000000000000000000000000000000000
Ähnliches geht auch mit Gleitpunktzahlen, z.B. durch die Verwendung des Moduls [https://mpmath.org/ mpmath]:
import mpmath
print(mpmath.mpf(1500.4)**mpmath.mpf(300))
Ausgabe:
7.27975299218612e+952
Anderes Beispiel:
from mpmath import mp, pi
mp.dps = 100
print(pi)
Ausgabe:
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
mpmath kann noch einiges mehr, dazu sei aber auf die entsprechende Dokumentation auf der mpmath-Homepage verwiesen. mpmath ist Bestandteil von SymPy, kann aber auch separat installiert werden.
Aber auch Python selbst besitzt eine Möglichkeit, um mit großen bzw. exakten Gleitpunktzahlen zu rechnen, nämlich das interne Modul decimal. Dieses hat einige Vorteile gegenüber mpmath, aber auch gravierende Nachteile. Diese seien hier nicht detailliert aufgezählt. Grob gesagt hat decimal im Finanzwesen seine Berechtigung. Für wissenschaftliche Anwendungen wird aber mpmath vorzuziehen sein, da es u.a. vielfältige mathematische Funktionen bereit stellt. Nachfolgend ein einfaches Beispiel mit decimal:
import decimal
print("Potenzierung:", decimal.Decimal(1500.4) ** decimal.Decimal(300.0))
print("Einfache Addition:", 0.1 + 0.2)
decimal.getcontext().prec = 50
print("Addition mit decimal:", decimal.Decimal("0.1") + decimal.Decimal("0.2"))
Ausgabe:
Potenzierung: 7.279752992186121551039839134E+952
Einfache Addition: 0.30000000000000004
Addition mit decimal: 0.3
<u>Aufgabe:</u> Recherchieren Sie im Internet die genauen Vor- und Nachteile von decimal und mpmath. Verwenden Sie dazu auch KI (z.B. von Google, chatgpt).
= pint - mit physikalischen Größen rechnen =
[[File:Pint-Glas_UK.jpg|right|100px]]
pint ist ein externes Python-Paket zur Manipulation von physikalischen Einheiten. Es muss vor der ersten Benutzung installiert werden (Vorgehensweise wie immer: pip, YaST, via venv etc.).
Beispiel:
import pint
import numpy as np
ureg = pint.UnitRegistry()
# Einfache Berechnung
print(3 * ureg.meter + 4 * ureg.cm)
# Mit NumPy
npeinzel = [3, 4] * ureg.meter + [2, 5] * ureg.cm
print(npeinzel)
npsum = np.sum(npeinzel)
print(npsum)
# Konvertierung von Einheiten
npsum_inch = npsum.to(ureg.inch)
print(npsum_inch)
print(npeinzel.magnitude)
print(npeinzel.units)
print(npeinzel.dimensionality)
Ausgabe:
3.04 meter
[3.02 4.05] meter
7.07 meter
278.3464566929134 inch
[3.02 4.05]
meter
[length]
Die Dokumentation zu pint findet sich auf [https://pint.readthedocs.io/en/stable/].
=Regelungstechnische Aufgabenstellungen=
Für regelungstechnische Aufgaben gibt es u.a. das externe Paket <code>control</code>. Hier soll nicht detailliert darauf eingegangen werden. Anhand eines Beispiels soll anschließend nur die Visualisierung in Form eines Bode-Diagramms und der Sprungantwort gezeigt werden. Gegeben sei ein P-Regler mit <math>R = \frac{5}{2}</math> und eine Strecke <math>S= \frac{1}{30s^3+20s^2+10s+1,5}</math>. Gesucht sei vorerst ein Bode-Diagramm für den offenen Regelkreis und das Führungsverhalten.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke # oder: G0 = ct.series(regler, strecke)
Gw = ct.feedback(G0)
ct.bode_plot(G0, label='G0')
ct.bode_plot(Gw, label='Gw')
plt.show()
[[Datei:PythonIng_bode1.svg]]
Nun noch für obiges Beispiel die Sprungantwort. Diese zeigt einige große Überschwinger, d.h. der Regler kann sicher noch optimiert werden.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke
Gw = ct.feedback(G0)
t, y = ct.step_response(Gw)
plt.plot(t,y)
plt.title('Sprungantwort')
plt.xlabel('t')
plt.ylabel('h(t)')
plt.grid()
plt.show()
[[Datei:PythonIng_bode3.svg]]
Einige weitere wichtige Daten (Phasenreserve, Amplitudenreserve, Durchtrittsfrequenz) lassen sich mittels der <code>control</code>-Funktion <code>margin()</code> ermitteln. Die Ortskurve lässt sich mit der Funktion <code>nyquist_plot()</code> zeichnen. Dies sei hier aber nicht weiter ausgeführt.
==Aufgaben==
* Zeichen Sie mit Python die Ortskurve für obiges Beispiel.
* Was passiert, wenn man die Reglerverstärkung weiter aufdreht (z.B. auf <math>R = \frac{25}{2}</math>)?
* Wie sehen das Bode-Diagramm und die Sprungantwort aus, wenn ein PI-Regler verwendet wird?
= Stereostatik etc. =
Das Modul SymPy bietet einige Möglichkeiten einfache Bauwerke zu berechnen, z.B. Balken oder Fachwerke. Nachfolgend wird ein einfaches Fachwerk berechnet und gezeichnet.
Python-Code:
from sympy.physics.continuum_mechanics.truss import Truss
t = Truss()
# Knoten
t.add_node(("A", -3, 0), ("B", 0, 0), ("C", 4, 0), ("D", 7, 0),
("E", 6, 1.5), ("F", 2, 3), ("G", -2, 1.5))
# Stäbe
t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D"))
t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F"))
t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E"))
t.add_member(("FE","F","E"), ("DE","D","E"))
# Auflager; roller ... Loslager, pinned ... Festlager
t.apply_support(("A","roller"), ("D","pinned"))
# Einwirkende Kräfte
t.apply_load(("G", 5, 270), ("E", 3, 90))
# Berechnung
t.solve()
print("Reaction Forces: ", t.reaction_loads)
print("Internal Forces: ", t.internal_forces)
# Fachwerk zeichnen
p = t.draw()
p.show()
Ausgabe auf der Konsole:
Reaction Forces: {'R_A_y': 4.20000000000000, 'R_D_x': 0, 'R_D_y': -2.20000000000000}
Internal Forces: {'AB': 2.80000000000000, 'BC': 0.333333333333333, 'CD': -1.46666666666667,
'AG': -5.04777178564958, 'GB': -2.05555555555556, 'GF': -1.23413387432364,
'BF': 0.411111111111111*sqrt(13), 'FC': -0.3*sqrt(13), 'CE': 1.50000000000000,
'FE': 0.284800124843917, 'DE': 2.64407093534026}
Zeichnung:
[[File:PythonIng_fachwerk1.svg|300px]]
Details zu diesem Thema siehe z.B. [https://docs.sympy.org/latest/modules/physics/continuum_mechanics/index.html Continuum Mechanics] oder [https://docs.sympy.org/latest/tutorials/physics/continuum_mechanics/index.html Continuum Mechanics Tutorials]. Auch andere mechanische Probleme werden von SymPy abgehandelt ([https://docs.sympy.org/latest/tutorials/physics/index.html Physics Tutorials]).
== Aufgabe ==
Gegeben sei ein einseitig eingespannter Kragträger. Belastet wird er durch eine Einzellast am Trägerende. Für die Daten siehe folgende ASCII-Skizze:
| 20 kN
//|---> x |
//| V
//|----------------------
//| 10 m |
Elastizitätsmodul E = 2,1*10⁵ N/mm²
Flächenträgheitsmoment I = 0.001 m⁴
Berechnen Sie die Auflagerreaktionen, den Querkraft- und Biegemomentenverlauf, sowie die Verformungen.
Stellen Sie dies mit Hilfe von SymPy graphisch und auch mittels Formeln dar. Verwenden Sie dazu auch pprint (pretty print) aus dem SymPy-Modul. Zwecks Lösungsansatz siehe die oben aufgeführte Seite "Continuum Mechanics Tutorials". Achten Sie auch auf die Einheiten! Kontrollieren Sie das Ganze mittels händischer Rechnung. In dem genannten Tutorial ist von "Singularity Functions" die Rede. Gemeint ist damit in diesem Kontext die {{W|Föppl-Klammer}}.
Einige Python-Programme, vorrangig zu Maschinenelementen, finden sich auf [https://baymp.de/download_python.html BayMP für Python] (Balken, Zahnräder, Stabknickung usw.).
=Thermodynamik=
== PYroMat ==
Für thermodynamische Aufgabenstellungen gibt es verschiedene externe Module. Eines davon ist PYroMat (siehe auch [http://pyromat.org]). Damit lassen sich thermodynamische Stoffdaten für viele Substanzen berechnen.
Beispiel (einige Stoffdaten für Wasser bei 400°C und 20 bar berechnen):
import pyromat as pm
# Wasserdaten laden:
H2O = pm.get('mp.H2O')
# Stoffdaten berechnen:
T = 673.15 # Temperatur in Kelvin
p = 20 # Druck in bar
v = H2O.v(T, p)
h = H2O.h(T, p)
s = H2O.s(T, p)
print(f"Spezifisches Volumen: {v} m³/kg")
print(f"Spezifische Enthalpie: {h} kJ/kg")
print(f"Spezifische Entropie: {s} kJ/(kg K)")
Ausgabe:
Spezifisches Volumen: [0.1512163] m³/kg
Spezifische Enthalpie: [3248.3789473] kJ/kg
Spezifische Entropie: [7.12924142] kJ/(kg K)
<small>
PYroMat muss vorab installiert werden (z.B. mittels pip, in eine virtuelle Umgebung)
</small>
<code>mp</code> steht für "multi phase". Für ein ideales Gas wäre <code>ig</code> zuständig, z.B. <code>'ig.O2'</code>.
Beispiel (T-s-Diagramm für Wasser zeichnen):
import numpy as np
import matplotlib.pyplot as plt
import pyromat as pm
# Konfigurieren
pm.config["unit_pressure"] = "bar"
pm.config["unit_temperature"] = "K"
fluid = pm.get("mp.H2O")
# Temperaturbereich für das Nassdampfgebiet
T_tripel = 273.16
T_crit = 647.096
T = np.linspace(T_tripel, T_crit - 0.1, 200)
# Sättigungslinien berechnen und zeichnen
for x in np.linspace(0.0, 1.0, 5):
s = fluid.s(T=T, x=x)
if(x<=0.0):
plt.plot(s, T, label="Siedelinie x=%3.1f" % x, linewidth=2.0)
elif(x>=1.0):
plt.plot(s, T, label="Taulinie x=%3.1f" % x, linewidth=2.0)
else:
plt.plot(s, T, label="x=%3.1f" % x, linewidth=1.0)
# Isobaren zeichnen
p_values = [0.1, 1, 10, 50, 100]
T_isobar = np.linspace(T_tripel, 1000, 200)
t = 0.7
for p in p_values:
s_iso = fluid.s(T=T_isobar, p=p)
plt.plot(s_iso, T_isobar, 'k-', alpha=0.8, linewidth=0.8)
t += .05
idx = int(len(s_iso) * t)
plt.text(s_iso[idx], T_isobar[idx], f"{p} bar", fontsize=9, alpha=0.8)
# Diagramm zeichnen
plt.title("T-s-Diagramm für Wasser")
plt.xlabel("Spezifische Entropie s in kJ/kg K", fontsize=10)
plt.ylabel("Temperatur T in K", fontsize=10)
plt.legend(loc="best")
plt.grid(True)
plt.show()
Ausgabe (in etwa so):
[[Datei:T-s-Diagramm fuer Wasser.svg|400px]]
== CoolProp ==
Auch mit CoolProp können Stoffdaten berechnet werden. Siehe auch [https://coolprop.org/coolprop/wrappers/Python/index.html]
Beispiel (Wasser bei 20bar und 400°C):
import CoolProp.CoolProp as CP
fluid = 'Water'
T = 673.15 # Temperatur in Kelvin
P = 20e5 # Druck in Pascal
dichte = CP.PropsSI('D', 'T', T, 'P', P, fluid)
enthalpie = CP.PropsSI('H', 'T', T, 'P', P, fluid)
entropie = CP.PropsSI('S', 'T', T, 'P', P, fluid)
print(f"Spez. Volumen: {1/dichte:.6f} m³/kg")
print(f"Spez. Enthalpie: {enthalpie:.2f} J/kg")
print(f"Spez. Entropie: {entropie:.2f} J/kgK")
Ausgabe:
Spez. Volumen: 0.151215 m³/kg
Spez. Enthalpie: 3248344.02 J/kg
Spez. Entropie: 7129.16 J/kgK
== iapws ==
Um Werte für Wasser(dampf) zu erhalten (IAPWS; '''I'''nternational '''A'''ssociation for the '''P'''roperties of '''W'''ater and '''S'''team) gibt es die Bibliothek iapws. Siehe auch [https://iapws.org/] und [https://pypi.org/project/iapws/]
Beispiel (Wasser für 20bar und 400°C):
from iapws import IAPWS97
dampf = IAPWS97(P=2.0, T=673.15)
print(f"Spezifisches Volumen: {dampf.v:.6f} m³/kg")
print(f"Spezifische Enthalpie: {dampf.h:.2f} kJ/kg")
print(f"Spezifische Entropie: {dampf.s:.4f} kJ/(kgK)")
print(f"Phase: {dampf.phase}")
Ausgabe:
Spezifisches Volumen: 0.151208 m³/kg
Spezifische Enthalpie: 3248.23 kJ/kg
Spezifische Entropie: 7.1290 kJ/(kgK)
Phase: Gas
== TESPy ==
Ein anderes Modul für einen anderen Aufgabenzweck ist TESPy ('''T'''hermal '''E'''ngineering '''S'''ystems in '''Py'''thon). Dieses Modul ist für die Anlagensimulation zuständig. Für nähere Informationen siehe [https://tespy.readthedocs.io/en/main/getting_started/introduction.html]. Als Beipiel sei hier vorerst Code, der von der Google KI generiert wurde, angeführt. Der Code wurde überarbeitet, damit keine Warnungen auftreten. Bitte aber den Code trotzdem mit Vorsicht genießen, auch KI-generierter Code kann Fehler aufweisen. Eine Pumpe wird berechnet:
from tespy.components import Sink, Source, Pump
from tespy.connections import Connection
from tespy.networks import Network
# 1. Netzwerk definieren (Zentrales Steuerungselement)
# Wir wählen Wasser als Fluid und bar/Celsius als Einheiten
nw = Network(fluids=["water"])
nw.units.set_defaults(pressure="bar", pressure_difference="bar",
temperature="°C", enthalpy="kJ / kg")
# 2. Komponenten erstellen
eingang = Source("Wasserquelle")
ausgang = Sink("Wasserspeicher")
pumpe = Pump("Speisewasserpumpe")
# 3. Verbindungen definieren (Komponenten miteinander verknüpfen)
c1 = Connection(eingang, "out1", pumpe, "in1")
c2 = Connection(pumpe, "out1", ausgang, "in1")
# Verbindungen dem Netzwerk hinzufügen
nw.add_conns(c1, c2)
# 4. Randbedingungen und Parameter festlegen
# Zustand am Eingang (Druck, Temperatur, Massenstrom, Fluid-Zusammensetzung)
c1.set_attr(
v=1, # Massenstrom: 1 kg/s
T=20, # Temperatur: 20 °C
p=1, # Druck: 1 bar
fluid={"water": 1}, # 100% Wasser
)
# Zustand am Ausgang / Zielwerte der Pumpe
c2.set_attr(p=10) # Ziel-Druck nach der Pumpe: 10 bar
# Pumpeneigenschaften festlegen
pumpe.set_attr(eta_s=0.8) # Isentroper Wirkungsgrad von 80%
# 5. Simulation ausführen
nw.solve(mode="design")
# 6. Ergebnisse ausgeben
nw.print_results()
# Spezifische Werte direkt auslesen
print("\n--- Auswertung ---")
print(f"Erforderliche Pumpenleistung: {pumpe.P.val / 1000:.2f} kW")
print(f"Temperatur nach der Pumpe: {c2.T.val:.2f} °C")
Ausgabe (gekürzt):
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 7.04e+04 | 12 % | 9.96e+02 | 0.00e+00 | 8.81e+04 | 0.00e+00 | 0.00e+00
2 | 5.91e-12 | 100 % | 1.11e-13 | 0.00e+00 | 7.39e-12 | 0.00e+00 | 0.00e+00
3 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
4 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.01 s, Iterations per second: 480.85
##### RESULTS (Pump) #####
+-------------------+----------+----------+-----------+----------+----------+----------+
| | P | pr | dp | eta | eta_s | head |
|-------------------+----------+----------+-----------+----------+----------+----------|
| Speisewasserpumpe | 1.12e+06 | 1.00e+01 | -9.00e+00 | 8.00e-01 | 8.00e-01 | 9.19e+01 |
+-------------------+----------+----------+-----------+----------+----------+----------+
...
...
--- Auswertung ---
Erforderliche Pumpenleistung: 1124.77 kW
Temperatur nach der Pumpe: 20.07 °C
= Stochastik =
Die {{W|Stochastik}} ist ein sehr weites Feld. Hier werden etliche wichtige Themen kurz angerissen. Python stellt mit den Moduln math und statistics Software zu diesem Zwecke bereit. math und statistics sind bereits im Lieferumfang von Python enthalten. Aber auch mit den externen Modulen NumPy, SciPy, stochastic und pandas kann man Stochastik in Python betreiben. Die Theorie der Wahrscheinlichkeitsrechnung und Statistik soll etwas später in Band 5 dieser Buchreihe behandelt werden.
== Lageparameter ==
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
m1 = statistics.mean(werte)
m2 = statistics.mode(werte)
m3 = statistics.median(werte)
print("Arithmetischer Mittelwert = ", m1)
print("Modalwert = ", m2)
print("Median = ", m3)
Ausgabe:
Arithmetischer Mittelwert = 3.5
Modalwert = 1
Median = 3.0
== Streuungsparameter ==
Beispiel (Berechnung der Standardabweichung):
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
s = statistics.stdev(werte)
print("Standardabweichung = ", s)
Ausgabe:
Standardabweichung = 2.6770630673681683
Beispiel (Berechnung des Variationskoeffizienten V = Standardabweichung/Mittelwert)
import numpy as np
from scipy import stats
import statistics
k = 50
dat1 = [14, 21, 18, 25, 30, 17, 20]
dat = np.array(dat1)
# Mit SciPy
v = stats.variation(dat)
vddof = stats.variation(dat, ddof=1)
print("V SciPy: ", v)
print("V DDOF SciPy: ", vddof)
print(k*"-")
# mit NumPy
mittelwert1 = np.mean(dat)
std_abw1 = np.std(dat)
std_abw1ddof = np.std(dat, ddof=1)
v1= std_abw1 / mittelwert1
v1ddof = std_abw1ddof / mittelwert1
print("Mittelwert NumPy: ", mittelwert1)
print("Std.abw. NumPy: ", std_abw1)
print("Std.abw. DDOF NumPy: ", std_abw1ddof)
print("V NumPy: ", v1)
print("V DDOF NumPy: ", v1ddof)
print(k*"-")
# nur mit reinem Python
mittelwert2 = statistics.mean(dat1)
std_abw2 = statistics.stdev(dat1)
v2 = std_abw2 / mittelwert2
print("Mittelwert Python: ", mittelwert2)
print("Std.abw. Python: ", std_abw2)
print("V Python:", v2)
print(k*"-")
Ausgabe:
V SciPy: 0.23890355966467272
V DDOF SciPy: 0.25804533701889254
--------------------------------------------------
Mittelwert NumPy: 20.714285714285715
Std.abw. NumPy: 4.948716593053935
Std.abw. DDOF NumPy: 5.3452248382484875
V NumPy: 0.23890355966467272
V DDOF NumPy: 0.2580453370188925
--------------------------------------------------
Mittelwert Python: 20.714285714285715
Std.abw. Python: 5.3452248382484875
V Python: 0.2580453370188925
--------------------------------------------------
Der Unterschied bei der Standardabweichung zwischen reinem Python und den externen Bibliotheken SciPy und NumPy entsteht dadurch, dass einmal durch (n-1) und das andere Mal nur durch n dividiert wird. Dies kann bei NumPy und SciPy dadurch entschärft werden, indem <code>ddof=1</code> gesetzt wird. ddof steht für '''D'''elta '''D'''egrees '''o'''f '''F'''reedom. <small>Je größer die Anzahl der Datensätze n wird, umso weniger spielt das eine Rolle.</small>
== Kombinatorik ==
Beispiel:
import math
n = 7
k = 5
print("n! = ", math.factorial(n))
print("Kombinationen (n über k) = ", math.comb(n, k))
Ausgabe:
n! = 5040
Kombinationen (n über k) = 21
Siehe zu diesem Thema auch [[Ing Mathematik: Permutationen, Kombinationen, binomischer Lehrsatz]]. Die Anzahlen lassen sich einfach aus den dortigen Formeln ermitteln, z.B. bei Permutationen mit <math>n!</math> oder Variationen mit Wiederholungen als <math>n^k</math>. Will man die Kombinationen oder Variationen aber auch als Liste ausgeben, so kann das Modul <code>itertools</code> nützlich sein.
Beispiel (Variationen ohne Wiederholung):
from itertools import permutations
menge = ["A", "B", "C", "D"] # n = 4
k = 3
variationen = list(permutations(menge, k))
for v in variationen:
print("".join(v))
print(50*"-")
print(len(variationen))
Ausgabe (gekürzt):
ABC
ABD
ACB
...
DCA
DCB
--------------------------------------------------
24
Siehe zum Modul <code>itertools</code> auch die Website [https://docs.python.org/3/library/itertools.html].
* Variationen mit Wiederholung: <code>itertools.product()</code>
* Kombinationen ohne Wiederholung: <code>itertools.combinations()</code>
* Kombinationen mit Wiederholung: <code>itertools.combinations_with_replacement()</code>
== Zufallszahlen ==
Beispiel:
import random
# Ganzzahlige Zufallszahl von 1 bis 10
zufallszahl1 = random.randint(1, 10)
# Gleitpunktzahlen
# zwischen 0.0 und 1.0
zufallszahl2 = random.random()
# Zahl zwischen 1.5 und 9.5
zufallszahl3 = random.uniform(1.5, 9.5)
# aus Liste auswählen
farbe = ["Rot", "Grün", "Blau"]
zufallswert = random.choice(farbe)
print(zufallszahl1)
print(zufallszahl2)
print(zufallszahl3)
print(zufallswert)
Ausgabe, z.B.:
5
0.14147945849015753
6.894003397570905
Rot
Benötigt man mehrere Zufallszahlen, so ist das Modul <code>numpy</code> zu bevorzugen, z.B.:
* Normalverteilung: <code>np.random.normal(...)</code>
* Gleichverteilung: <code>np.random.uniform(...)</code>
== Histogramm ==
Zum Thema Histogramm siehe {{W|Histogramm}}.
Beispiel (mit Matplotlib):
import matplotlib.pyplot as plt
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
plt.hist(daten, bins=25, edgecolor='darkgray')
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm.svg|300px]]
Beispiel (mit Seaborn):
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
sns.set_theme(style="darkgrid")
sns.histplot(data=daten)
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm2.svg|300px]]
Das Kürzel <code>sns</code> ist Konvention und steht für die fiktive Figur '''S'''amuel '''N'''orman '''S'''eaborn aus der US-Fernsehserie {{W|The West Wing – Im Zentrum der Macht | The West Wing}}.
== Box-Plot ==
[[File:Elements of a boxplot.svg|400px]]
Siehe auch {{W|Box-Plot}}.
Beispiel (mit Seaborn erstellt):
import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("tips")
sns.boxplot(data=df, x="day", y="tip", hue="day", legend=False)
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot.svg|400px]]
Beispiel (mit Matplotlib erstellt):
import matplotlib.pyplot as plt
daten = [12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25]
plt.boxplot(daten, patch_artist=True)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot2.svg|300px]]
Um mehrere Box-Plots unterschiedlicher Farbe mit Matplotlib in einem Diagramm zu zeichnen, können Sie folgendermaßen vorgehen:
import matplotlib.pyplot as plt
daten = [[12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25],
[10, 19, 20, 21, 20, 30, 19, 40, 11, 17, 19, 21]]
farben = ["green", "blue"]
boxplot = plt.boxplot(daten, patch_artist=True)
for patch, farbe in zip(boxplot['boxes'], farben):
patch.set_facecolor(farbe)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
== Regressionsrechnung ==
Beispiel:
import numpy as np
import matplotlib.pyplot as plt
# Messpunkte
x = np.array([1, 3, 5, 6, 8, 10, 20])
y = np.array([3, 4, 5, 5, 7, 9, 11])
# Regressionskurve (Grad 1 = lineare Regression, 2 = Polynom-Regression 2. Gr.)
# y = kx + d
k, d = np.polyfit(x, y, deg=1)
# y = ax**2 + bx + c
a, b, c = np.polyfit(x, y, deg=2)
x_l = np.linspace(1, 20, 100)
y_p = a * x_l**2 + b * x_l + c
# Zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.plot(x, k*x + d, color='blue', label='Regressionsgerade')
plt.plot(x_l, y_p, color='red', label='Regressionspolynom 2. Gr.')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:IngMath_regression.svg|400px]]
== Korrelationsrechnung ==
Beispiel:
import pandas as pd
import matplotlib.pyplot as plt
# Messdaten
x = [1, 3, 4, 5, 6]
y = [2, 4, 6, 8, 5]
daten = {'X': x, 'Y': y}
df = pd.DataFrame(daten)
# Korrelation
korr = df['X'].corr(df['Y'])
print(f"Korrelationskoeff.: {korr}")
# Messpunkte zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
Korrelationskoeff.: 0.7556096518348252
[[Datei:IngMath_korrelation.svg|300px]]
== Mengen und Venn-Diagramme ==
Beispiel:
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
menge_a = {1, 2, 3, 4, 5, 6}
menge_b = {4, 5, 6, 7, 8}
vereinigung = menge_a | menge_b
schnitt = menge_a & menge_b
print("Vereinigungsmenge = ", vereinigung)
print("Schnittmenge = ", schnitt)
venn2([menge_a, menge_b], set_labels=('Menge A', 'Menge B'))
plt.show()
Ausgabe:
Vereinigungsmenge = {1, 2, 3, 4, 5, 6, 7, 8}
Schnittmenge = {4, 5, 6}
[[Datei:IngMath_venn.svg|300px]]
Siehe auch {{W|Mengendiagramm#Venn-Diagramme}}.
== Verteilungs- und Dichtefunktion ==
* CDF ... '''C'''umulative '''D'''istribution '''F'''unction, Verteilungsfunktion
* PDF ... '''P'''robability '''D'''ensity '''F'''unction, Dichtefunktion
Beispiel (Normalverteilung):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
my, sigma = 0, 1
x = np.linspace(-4, 4, 50)
pdf = norm.pdf(x, my, sigma)
cdf = norm.cdf(x, my, sigma)
plt.plot(x, pdf, lw=2, label="Dichtefunktion")
plt.plot(x, cdf, lw=2, label="Verteilungsfunktion")
plt.legend()
plt.grid()
plt.show()
Ausgabe:
[[Datei:IngMath_cdf_pdf.svg|300px]]
Beispiel (<math>\chi^2</math>-Verteilung):
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
x = np.linspace(0, 20, 500)
# df ... degree of freedom, Freiheitsgrad
pdf = (stats.chi2.pdf(x, df=2), stats.chi2.pdf(x, df=5), stats.chi2.pdf(x, df=10))
for i in range(0,3):
if(i==0):
lab = "Freiheitsgrad 2"
elif(i==1):
lab = "Freiheitsgrad 5"
else:
lab = "Freiheitsgrad 10"
plt.plot(x, pdf[i], label=lab, lw=2)
plt.grid()
plt.legend()
plt.show()
Ausgabe:
[[Datei:IngMath_chi2.svg | 300px]]
== Schätzen und Testen ==
=== Intervallschätzung ===
Als Beispiel seien Daten gegeben, die von ''Dürr, Mayer: Wahrscheinlichkeitsrechnung und Schließende Statistik; 7. Aufl., Hanser, 2014, Seite 137'' stammen. Und zwar soll das 95%-Vertrauensintervall für den Mittelwert des Kaloriengehalts (kcal/100g) von Hähnchen ermittelt werden. Wir wollen das mit Python inkl. NumPy und SciPy durchführen. Die Stichprobe ist groß (50 Hähnchen):
Python-Code:
import numpy as np
import scipy.stats as stats
# Stichprobe
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203]
# Parameter definieren
konfidenzniveau = 0.95
mean = np.mean(daten)
std = np.std(daten, ddof=1)
stdfehler = stats.sem(daten)
intervall = stats.norm.interval(confidence=konfidenzniveau, loc=mean, scale=stdfehler)
print(f"Mittelwert: {mean}")
print(f"Standardabweichung: {std}")
print(f"Konfidenzintervall: {intervall}")
Ausgabe:
Mittelwert: 215.48
Standardabweichung: 33.14238915925757
Konfidenzintervall: (np.float64(206.29356722321992), np.float64(224.66643277678006))
Diese Werte stimmen gerundet mit denen im genannten Buch überein. Zum Code selbst:
* sem steht für '''s'''tandard '''e'''rror of the '''m'''ean.
* <code>scipy.stats.norm</code> ... Modul für die Normalverteilung.
=== Punktschätzung ===
Gleiche Daten wie oben bei der Intervallschätzung.
Python-Code:
import numpy as np
from scipy import stats
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203
]
mu_hat, sigma_hat = stats.norm.fit(daten)
print(f"Schätzer für den Erwartungswert (μ): {mu_hat:.4f}")
print(f"Schätzer für die Standardabweichung (σ): {sigma_hat:.4f}")
Ausgabe:
Schätzer für den Erwartungswert (μ): 215.4800
Schätzer für die Standardabweichung (σ): 32.8093
=== Hypothesentests ===
Beispiel:
import numpy as np
import scipy.stats as stats
x_quer = 12.075 # Stichproben-Mittelwert
var = 0.069 # Stichproben-Varianz
n = 90 # Stichprobengröße
my_0 = 12.0 # Nullhypothese
alpha = 0.05 # Signifikanzniveau
z_stat = (x_quer - my_0) / np.sqrt(var / n)
p_val = 2 * (1 - stats.norm.cdf(np.abs(z_stat)))
print(f"Z-Statistik: {z_stat:.4f}")
if p_val < alpha:
print(f"p-Wert: {p_val:.6f} < alpha:", alpha)
print("Die Nullhypothese wird verworfen.")
else:
print(f"p-Wert: {p_val:.6f} > alpha:", alpha)
print("Die Nullhypothese wird nicht verworfen.")
Ausgabe:
Z-Statistik: 2.7087
p-Wert: 0.006755 < alpha: 0.05
Die Nullhypothese wird verworfen.
== Statistische Qualitätskontrolle ==
Beispiel (Mittelwertkarte):
import numpy as np
import matplotlib.pyplot as plt
# Gegeben
sollwert = 50.0
varianz = 4.0
stichproben_umfang = 1
daten = [49.5, 50.2, 53.0, 48.1, 52.6, 53.4, 49.8]
# Berechnung
standardabweichung = np.sqrt(varianz)
streuung = standardabweichung / np.sqrt(stichproben_umfang)
cl = sollwert
ucl = cl + 3 * streuung
lcl = cl - 3 * streuung
# Darstellung
plt.plot(daten, marker='o', linestyle='-', color='b', label='Messdaten')
plt.axhline(cl, color='green', linestyle='-', label=f'CL: {cl}')
plt.axhline(ucl, color='red', linestyle='--', label=f'UCL: {ucl:.2f}')
plt.axhline(lcl, color='red', linestyle='--', label=f'LCL: {lcl:.2f}')
plt.title('Mittelwertkarte')
plt.xlabel('Stichprobe')
plt.ylabel('Wert')
plt.legend(loc='lower left')
plt.grid(True)
plt.show()
Ausgabe:
[[Datei:IngMath_mittelwertkarte.svg|300px]]
Siehe auch {{W|Shewhart-Regelkarte}} und {{W|Qualitätsregelkarte}}.
* UCL ... '''U'''pper '''C'''ontrol '''Limit''', Obere Eingriffsgrenze
* LCL ... '''L'''ower '''C'''ontrol '''Limit''', Untere Eingriffsgrenze
* CL ... '''C'''enter '''L'''ine, Mittellinie
= Ein- und Ausgabe =
== print ==
Die Anweisung print haben wir schon oft verwendet. Hier soll anhand von Beispielen kurz beschrieben werden, was der Befehl print leisten kann.
print("Hallo", "Welt", 1, sep="-")
print("Hallo", end=" ")
print("Welt")
Ausgabe:
Hallo-Welt-1
Hallo Welt
== input ==
a = int(input("Zahl 1: "))
b = int(input("Zahl 2: "))
print("a + b = ", a+b)
Ausgabe (nach Eingabe der beiden Ganzzahlen):
Zahl 1: 4
Zahl 2: 5
a + b = 9
== Aus Dateien lesen ==
Es seinen die datei.txt
Hallo Welt.
Wie geht es dir?
...
und test1.py
dat = open("datei.txt", mode = "r")
print(dat.read())
dat.close()
Ausgabe
Hallo Welt.
Wie geht es dir?
...
Mit dem open()-Befehl wird die Datei datei.txt im Lesemodus geöffnet (r ... read). Mit dem read()-Befehl wird die Datei eingelesen und mittels print ausgegeben.
== In Dateien schreiben ==
dat = open("datei.txt", mode = "a", encoding = "utf-8")
dat.write("Hänge Zeile an\n")
dat.close()
Die Datei datei.txt sieht nach Abarbeitung des obigen Skripts nun so aus
Hallo Welt.
Wie geht es dir?
...
Hänge Zeile an
Es wird die Datei im Schreibmodus geöffnet (a ... append (anhängend), w ... write (überschreibend)).
write() fügt hier also eine Zeile Text am Dateiende ein. close() schließt die Datei wieder.
Das close() kann man sich mit der with-Anweisung auch sparen.
with open("datei.txt", mode="a", encoding="utf-8") as dat:
dat.write("Hänge Zeile an\n")
= Benutzeroberflächen erstellen =
== tkinter ==
{{Wikipedia | Tkinter}}
Python bietet standardmäßig das Modul tkinter zur Programmierung von Benutzeroberflächen. Es müssen also bei der Verwendung von tkinter keine externen Module installiert werden. Hier wird eine (sehr) kurze Einführung in das Erstellen von grafischen Oberflächen mittels tkinter gegeben.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
win.minsize(300, 50)
but = tk.Button(win, text = "Push the button")
but.pack()
win.mainloop()
Ausgabe:
[[Datei:PythonIng_gui1.jpg]]
Ein etwas komplizierteres Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
def on_button_clicked():
str = ent1.get() + ent2.get()
lab2["text"] = str
ent1 = tk.Entry(win)
ent2 = tk.Entry(win)
lab1 = tk.Label(win, text="verknuepfen mit")
lab2 = tk.Label(win, text="")
but = tk.Button(win, text = "=", command=on_button_clicked)
ent1.pack(side="left")
lab1.pack(side="left")
ent2.pack(side="left")
but.pack(side="left")
ent2.pack(side="left")
lab2.pack(side="left")
win.mainloop()
Ausgabe (vor der Eingabe der Teilstrings):
[[Datei:PythonIng_gui2.jpg]]
Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):
[[Datei:PythonIng_gui3.jpg]]
== curses ==
{{Wikipedia | curses}}
Mit dem curses-Modul lassen sich u.a. TUIs ('''T'''ext '''U'''ser '''I'''nterfaces) erstellen. Ein sehr einfaches Beispiel zur allgemeinen Funktionsweise wird nachstehend geliefert.
import curses
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
stdscr.clear()
stdscr.addstr("Hallo Welt", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.endwin()
Als Ausgabe sollte <span style="color:#FF0000;">Hallo Welt</span> (rote Schrift auf weißem Hintergrund) auf dem Terminal/der Konsole erscheinen. Getestet wurde dies mit openSUSE Tumbleweed, Python-Version 3.13.12. Das entsprechende Python-curses-Package muss installiert sein.
Allgemeine Informationen zur Terminal-/Konsolengröße und Cursorposition liefert folgendes Programm:
import curses
stdscr = curses.initscr()
stdscr.addstr(3, 5, "LINES: %d" % curses.LINES)
stdscr.addstr(4, 5, "COLS: %d" % curses.COLS)
(y,x) = stdscr.getyx()
stdscr.addstr(5, 5, "Momentane Cursorposition: [%d, %d]" % (y, x))
(y,x) = stdscr.getbegyx()
stdscr.addstr(6, 5, "Koordinatenursprung: [%d, %d]" % (y, x))
(y,x) = stdscr.getmaxyx()
stdscr.addstr(7, 5, "Fenstergröße: [%d, %d]" % (y, x))
stdscr.addstr(11, 2, "Taste drücken -> Ende")
stdscr.refresh()
stdscr.getch()
curses.endwin()
Es sollte sich in etwa folgende Ausgabe ergeben:
LINES: 44
COLS: 110
Momentane Cursorposition: [4, 15]
Koordinatenursprung: [0, 0]
Fenstergröße: [44, 110]
Taste drücken -> Ende
Zur Funktionsweise von curses siehe auch das Wikibook [[ncurses]]. Zum Verständnis sind dort allerdings elementare Kenntnisse in der Programmiersprache C erforderlich.
== Qt ==
{{Wikipedia | Qt (Bibliothek)}}
Auch für das Qt-Framework gibt es eine Anbindung an Python. Nachfolgend ein einfaches Beispiel.
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hallo Welt!")
label.show()
sys.exit(app.exec())
Ausgabe:
[[Datei:PythonIng_gui10.png]]
== Gtk ==
{{Wikipedia | GTK (Programmbibliothek)}}
Eine idente Ausgabe, wie oben für Qt gezeigt, erzeugt z.B. folgendes Gtk-Programm:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
lab = Gtk.Label(label="Hallo Welt!")
win.set_child(lab)
win.present()
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
Auch für die Benutzung von Qt und Gtk müssen die jeweiligen Packages installiert sein. Getestet wurden die entsprechenden Python-Programme nur unter openSUSE Tumbleweed. Wie das GTK-Paket unter MS Windows 11 installiert wird, siehe z.B. [https://www.gtk.org/docs/installations/windows Setting up GTK for Windows].
Damit sei aber das Thema "Benutzeroberflächen erstellen" hier abgeschlossen, da dies schon ein sehr spezielles Aufgabengebiet ist, das eher Informatiker und nicht so sehr Ingenieure anspricht. Bei Bedarf siehe aber ggf. die entsprechenden Links unten in diesem Tutorial. Dort sind weiterführende Informationen zu finden.
= Pandas kurz erklärt =
Hier wird kurz auf das externe Modul Pandas eingegangen. Pandas steht für '''Pan'''el '''Da'''ta und ist ein Modul für die Datenanalyse und -manipulation.
== Series ==
Vorstellbar ist eine "Series" wie eine einzelne Spalte in einem Tabellenkalkulationsprogramm.
Beispiel (Index implizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5]) # Temperaturwerte
print(temp)
Ausgabe:
0 8.5
1 11.0
2 12.5
3 10.0
4 13.0
5 11.0
6 14.5
dtype: float64
Das Kürzel <code>pd</code> ist Konvention. Es seien Temperaturwerte gegeben. Die erste Spalte bei der Ausgabe ist der Index. Die zweite Spalte enthält die Werte.
Beispiel (separater Zugriff auf den Index und auf die Werte):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5])
print(temp.index)
print(temp.values)
Ausgabe:
RangeIndex(start=0, stop=7, step=1)
[ 8.5 11. 12.5 10. 13. 11. 14.5]
Beispiel (Index explizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
print("*** Die gesamte Series ***")
print(temp)
print("*** Temperatur am Donnerstag ***")
print(temp["Do"])
print("*** Tage wärmer als 12 Grad ***")
temp_gr_12 = temp[temp > 12]
print(temp_gr_12)
Ausgabe:
*** Die gesamte Series ***
Mo 8.5
Di 11.0
Mi 12.5
Do 10.0
Fr 13.0
Sa 11.0
So 14.5
dtype: float64
*** Temperatur am Donnerstag ***
10.0
*** Tage wärmer als 12 Grad ***
Mi 12.5
Fr 13.0
So 14.5
dtype: float64
== DataFrame ==
Ein DataFrame entspricht einer Tabelle.
Beispiel (Erzeugen eines DataFrames):
import pandas as pd
tag = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
v1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=tag)
v2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=tag)
v3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=tag)
tab = pd.concat([v1, v2, v3], axis=1)
tab.columns = stadt
print(tab)
print(type(tab))
Ausgabe:
Linz Salzburg Innsbruck
Mo 1 8 Hallo
Di 2 9 16
Mi 3 10 17
Do 4 11 18
Fr 5 12 19
Sa 6 13 20
So 7 14 21
<class 'pandas.core.frame.DataFrame'>
Wir haben hier drei Datenspalten (v1, v2, v3) mit den Spaltennamen "Linz", "Salzburg" und "Innsbruck", sowie sieben Zeilen "Mo" bis "So".
Beispiel (Zugriff auf eine Spalte):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab["Salzburg"])
Ausgabe:
Mo 8
Di 9
Mi 10
Do 11
Fr 12
Sa 13
So 14
Name: Salzburg, dtype: int64
Beispiel (Zugriff auf eine Zeile):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab.loc["Di"])
Ausgabe:
Linz 2
Salzburg 9
Innsbruck 16
Name: Di, dtype: object
== Grafiken erstellen ==
Hier sei nur ein Torten- oder Kreisdiagramm gezeichnet:
import pandas as pd
import matplotlib.pyplot as plt
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
expl = [0, 0.2, 0, 0, 0, 0, 0]
temp.plot.pie(figsize=(5,5), explode=expl)
plt.show()
Ausgabe:
[[Datei:IngPython_pandas1.svg|350px]]
Die <code>figsize</code> hat nichts mit der Spaltenanzahl zu tun, sondern setzt die Fenster- oder Diagrammgröße in Inches (Breite * Höhe).
Mit Pandas kann man auch noch andere Diagrammarten erstellen, z.B. Linien- oder Balkendiagramme. Dies wird hier aber nicht vorgeführt.
== Arbeiten mit CSV- und LibreOffice-Dateien ==
Gegeben sei eine CSV-Datei test1.csv:
Mai;Juni;Juli
12;17;45
15;65;65
16;32;23
4;14;7
23;17;Keine Daten verfügbar
67;Keine Daten verfügbar;45
15;24;12
Lesen von dieser CSV-Datei:
import pandas as pd
tab = pd.read_csv("test1.csv", sep=";")
print(tab)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Schreiben in eine CSV-Datei test2.csv:
import pandas as pd
val = pd.read_csv("test1.csv", sep=";")
val.to_csv("test2.csv", index=False)
Ausgabedatei:
Mai,Juni,Juli
12,17,45
15,65,65
16,32,23
4,14,7
23,17,Keine Daten verfügbar
67,Keine Daten verfügbar,45
15,24,12
Die Ausgabedatei ist beinahe gleich wie die Eingabedatei. Es werden aber Kommas statt Strichpunkten verwendet. Daher kommt auch der Name CSV ('''C'''omma '''S'''eparated '''V'''alue). Will man wieder Strichpunkte, so kann man dies über den Parameter <code>sep=";"</code> in der <code>to_csv</code>-Funktion machen.
Um direkt von einer ODS-Datei (LibreOffice Calc, '''O'''pen '''D'''ocument '''S'''preadsheet) zu lesen muss das Modul odfpy extra installiert sein (per YaST, pip etc.). Gelesen wird dann folgendermaßen:
import pandas as pd
df = pd.read_excel('test1.ods', engine='odf')
print(df)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Die Datei "test1.ods" sei die Datei, aus der das obige "test1.csv" generiert wurde. Schreiben kann man ebenfalls in eine ODS-Datei:
import pandas as pd
daten = {
"Name": ["Hugo", "Richie", "Wilhelmine"],
"Alter": [38, 30, 29],
"Ort": ["Linz", "Innsbruck", "Salzburg"]
}
tab = pd.DataFrame(daten)
with pd.ExcelWriter("test2.ods", engine="odf") as writer:
tab.to_excel(writer, sheet_name="Daten", index=False)
Es ergibt sich eine "test2.ods"-Datei (Screenshot):
[[Datei:IngPython_pandas2.png|250px]]
== Sonstiges ==
Hier seien stichpunktartig einige weitere Features von Pandas angeführt:
* {{W|Pivot-Tabelle|Pivot-Tabellen}} (pivot ... Dreh-, Angelpunkt): Zweck - große Datenmengen schnell zusammenfassen, filtern und analysieren.
* NaN ('''n'''ot '''a''' '''n'''umber): In einem Datensatz fehlt ein Wert oder ist nicht definiert.
* groupby-Funktion: Daten strukturieren, aggregieren oder Zwischensummen bilden.
* {{W|Binning#Datenverarbeitung_und_-analyse|Binning}}: Klassenbildung.
* Mehrstufige Indizierung (Hierarchical Indexing oder MultiIndex)
* Zeitreihen (Time Series)
Für tiefergehende und weiterführende Informationen wird auf das Buch von ''Klein: Numerisches Python; Hanser, 2023'' und [https://pandas.pydata.org/ pandas] verwiesen.
= Style Guide, flake8, pylint, Black etc. =
== Style Guide ==
Wie man schönen und richtigen Python-Code schreibt, erfahren Sie in
* [https://peps.python.org/pep-0008/ PEP 8 – Style Guide for Python Code]
== Formatter und Linter ==
Ein Modul, das prüft, ob die Richtlinien im Style Guide eingehalten wurden, ist ''flake8'':
* [https://flake8.pycqa.org/en/latest/ Flake8: Your Tool For Style Guide Enforcement]
Code formatieren kann man auch mit [https://pypi.org/project/black/ Black]. Z.B. übersetzt <code>black test1.py</code> die Datei <code>test1.py</code>
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)),
(2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
in
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)), (2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Die Programmausgabe ist
reformatted test1.py
All done! ✨ 🍰 ✨
1 file reformatted.
Der Unterschied zwischen Black und Flake8:
* Black ist ein Code-Formatter. Er formatiert Ihren Code um, sodass er im Einklang mit PEP 8 steht.
* Flake8 ist ein {{W|Lint (Programmierwerkzeug) | Code-Linter}}. Flake8 verändert Ihren Code nicht, sondern durchsucht ihn nach potenziellen Fehlern etc.
Am obigen Beispiel sieht man auch, dass flake8 und Black nicht immer einer Meinung sind. Flake8 (<code>flake8 test1.py</code>) würde standardmäßig den mit Black formatierten Code bemängeln:
test1.py:8:80: E501 line too long (80 > 79 characters)
Diese Diskrepanz kann beseitigt werden. Da 79 Zeichen auf modernen Bildschirmen meist als zu kurz empfunden werden, ist ein Limit von 88 Zeichen (Black-Standard) oder mehr empfehlenswert. Um dies zu implementieren, erstellen Sie in Ihrem Projektverzeichnis eine <code>.flake8</code>-Datei mit dem Inhalt
[flake8]
max-line-length = 88
Und schon ignoriert Flake8 dieses Problem.
Ein anderer Linter ist pylint. Der würde beim Abarbeiten des obigen Beispiels, z.B. mit <code>pylint test1.py</code> noch eine Kleinigkeit bemängeln:
************* Module test1
/home/hr/tmp/test1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)
Auch pylint muss vor der ersten Verwendung installiert werden (z.B. mittels pip, virtuelle Umgebung, YaST). Die Dokumentation zu pylint findet sich auf [https://pylint.readthedocs.io/en/latest/].
<u>Aufgabe:</u> Fügen Sie einen "module docstring" in die <code>test1.py</code>-Datei ein und testen Sie erneut mit flake8, Black und pylint. <small>Sehen Sie zum Thema docstrings auch [https://peps.python.org/pep-0257/#what-is-a-docstring PEP 257 – Docstring Conventions].</small>
Es gibt noch weitere Formatierungswerkzeuge für Python-Code. Z.B. [https://docs.astral.sh/ruff/ Ruff], ein moderner Code-Formatter und -Linter. Mittels <code>ruff check test1.py</code> würde obiger Code geprüft (Linter). <code>ruff format test1.py</code> formatiert den Code (Formatter).
== Type Checker ==
"Type Checker" sind z.B.
* mypy
* pyright
* ty
Diese prüfen die Datentypen, z.B. in folgendem Code
def greetings(name: str) -> str:
return "Hello, %s" % name
print(greetings(42))
Python selbst, flake8, ruff oder black würden diesen Code ohne zu murren akzeptieren. "Type Checker" würden aber sehr wohl Alarm schlagen, z.B. liefert <code>mypy</code> folgende Ausgabe
test1.py:5: error: Argument 1 to "greetings" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Das funktioniert übrigens nicht nur bei Funktionsannotationen, sondern auch mit Variablen etc.
from typing import Final
# "Konstante", ab Python 3.8
NUMBER: Final = 123
print(NUMBER)
NUMBER = 125
print(NUMBER)
# Variable
a: int = 345
print(a)
a = "Irgendwas"
print(a)
# Variable (Pipe-Symbol), ab Python 3.10
b : int|str = 567
print(b)
b = "sonstiges"
print(b)
Ausgabe mit python:
123
125
345
Irgendwas
567
sonstiges
Ausgabe mit mypy:
test3.py:6: error: Cannot assign to final name "NUMBER" [misc]
test3.py:12: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
Found 2 errors in 1 file (checked 1 source file)
Python kennt übrigens keine Konstanten. Man kann diese mittels Großbuchstaben andeuten. Das ist aber nur Konvention, hat aber keine sonstigen Auswirkungen. Oder man verwendet wie oben gezeigt <code>Final</code>. Dann werfen Typchecker Errors aus.
==pydoc==
pydoc ist ein Werkzeug, um Python-Module, -Funktionen und -Klassen zu dokumentieren.
Beispiel <code>test1.py</code>:
"""Rechen-Modul.
Funktionen die von pydoc gelesen werden.
"""
def multiply(a, b):
"""Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a * b
def add(a, b):
"""Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a + b
if __name__ == '__main__':
print(multiply(3, 5))
print(add(4, 6))
Ausgabe mit <code>python3.13 -m pydoc test1</code> auf der Konsole:
Help on module test1:
NAME
test1 - Rechen-Modul.
DESCRIPTION
Funktionen die von pydoc gelesen werden.
FUNCTIONS
add(a, b)
Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
multiply(a, b)
Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
FILE
/home/xyz/tmp/test1.py
Siehe zu diesem Thema z.B. auch [https://docs.python.org/3/library/pydoc.html]. Mittels <code>python3.13 -m pydoc -w test1</code> kann man auch eine HTML-Dokumentation erstellen.
Wofür <code>if __name__ == '__main__':</code> steht, siehe z.B. etwas später im Abschnitt [[Ing_Mathematik:_Python#Doctests]].
== Sonstige Tools ==
Andere Tools für die {{W|Statische Code-Analyse|statische Codeanalyse}}, die aber für Ingenieure weniger interessant sein dürften, sind z.B.
* Radon: Liefert verschiedene {{W|Softwaremetrik|Codemetriken}} (Komplexität, Wartbarkeitsindex ...)
* Bandit: Findet Sicherheitslücken
Tools für die {{W|Dynamisches Software-Testverfahren|dynamische Codeanalyse}}, z.B.:
* DynaPyt (Framework zur dynamischen Programmanalyse)
* cProfile (Profiler)
* Memory Profiler (Speicheranalyse)
* Memray (Speicheranalyse)
* tracemalloc (Speicheranalyse)
Paket- und Projektmanagement (pip-Ersatz etc.):
* uv
* Poetry
* Conda
* pipx
Packaging-Tools (Freezer) und {{W|Compiler#Sonderformen|Transpiler}} :
* pyinstaller
** erstellt eigenständige, ausführbare Binärdatei
** kein Cross-Compiler
** kein Schutz vor Reverse-Engineering
** langsam
** packt alles in eine Datei
** sehr große Datei
** Befehl, z.B.: <code>pyinstaller --onefile test1.py</code>
** GUI: <code>auto-py-to-exe</code>
* cx_Freeze
* nuitka
** Übersetzt Python-Code in C/C++-Code und weiter in eine ausführbare Datei
** kein Cross-Compiler
** Schutz vor Reverse-Engineering
** Befehl, z.B.: <code>nuitka --standalone --onefile test1.py</code>
* cython
= Einige Integrierte Entwicklungsumgebungen (IDEs)=
Werden Programmtexte größer und umfangreicher, so ist das Arbeiten mit der interaktiven Programmierumgebung bzw. das direkte Ausführen von Python-Skripten mühsam. Man wünscht sich z.B. Hilfen zum Debuggen oder die automatische Code-Vervollständigung. Zu diesem Zweck wurden IDEs (Integrated Development Environments) geschaffen. Von diesen seinen nachfolgend auszugsweise einige kurz beschrieben. Testen Sie einfach aus, welche davon für Sie bzw. für Ihr Python-Projekt geeignet sind.
== IDLE ==
IDLE ist die mit dem Python-Programmpaket mitgelieferte IDE. Der Name leitet sich einerseits ab vom Monty-Python-Mitglied Eric Idle, andererseits steht es als Abkürzung für "'''I'''ntegrated '''D'''evelopment and '''L'''earning '''E'''nvironment. IDLE ist einfach zu bedienen, bietet aber schon einen beachtlichen Leistungsumfang. Nachfolgend wird ein Screenshot zu IDLE geliefert. Rechts ist das Editor-Fenster zu sehen, links die interaktive Programmierumgebung. Um das Beispiel selbst nachvollziehen zu können, starten Sie IDLE. Das geht ähnlich, wie Sie die interaktive Programmierumgebung von Python starten (nur, dass Sie eben das IDLE-Icon doppelklicken und nicht das Python-Icon. Unter Linux geben Sie einfach in einem Terminal <code>idle3.13</code> o. Ä. ein). Weiter geht es mit "File - Open - ...". Die auszuführende Datei auswählen (im konkreten Fall ein "Hallo-Welt"-Programm). Es erscheint das rechte Fenster. Dort "Run - Run Module" auswählen. Und schon wird im linken Fenster "Hallo Welt!" ausgegeben.
[[Datei:PythonIng_idle1.jpg | 600px]]
Siehe auch {{W|IDLE}}.
== PyCharm ==
PyCharm ist ein kommerzielles Produkt. Es gab aber auch eine kostenlose Community Edition. Seit 2025 sind beide Varianten vereint. Für die ersten 30 Tage sind die Pro-Funktionen frei verfügbar, danach nur noch die Kernfunktionalitäten (oder man bezieht kostenpflichtig die Pro-Version). Zu beziehen ist PyCharm unter dem Weblink [https://www.jetbrains.com/pycharm/]. Nachfolgend ein etwas abgewandeltes "Hallo Welt"-Programm, editiert und ausgeführt mit PyCharm.
[[Datei:PyCharm_IDE_2023_screenshot.png | 600px]]
Siehe auch {{W|PyCharm}}.
== Eric ==
Auch eric ist Open Source und steht unter der GNU General Public License Version 3 oder später. Zu beziehen ist diese Software unter [https://eric-ide.python-projects.org/].
[[Datei:Screenshot_Eric_4.png | 600px]]
Siehe auch {{W|eric (Software)}}.
<small>
Unter openSUSE Tumbleweed sollte sich eric auch mit YaST installieren lassen. Bei mir gibt es aber dann beim Ausführen des eric-Programms eine Fehlermeldung (Stand März 2026):
...
ModuleNotFoundError: No module named 'PyQt6.QtPdfWidgets'
Umgehen kann man dieses Problem aber wieder mit dem Erstellen einer virtuellen Umgebung, in etwa so
python3.13 -m venv ~/tmp/venv1
cd ~/tmp/venv1/bin
./python3.13 -m pip install --upgrade --prefer-binary eric-ide
./eric7_ide
</small>
== PyScripter ==
Vom Funktionsumfang vergleichbar mit den vorherigen IDEs ist PyScripter. Auch PyScripter ist Open Source. Die Projekt-Homepage findet sich auf [https://sourceforge.net/projects/pyscripter/]. PyScripter ist nur für MS Windows verfügbar.
[[Datei:PythonIng_pyscripter1.jpg | 600px]]
== Spyder IDE ==
Spyder enthält bereits eine stabile Python-Version und etliche Module (z.B. matplotlib, numpy, control). Ansonsten kann dieses Softwarepaket vom Funktionsumfang her mit den anderen genannten IDEs locker mithalten. Spyder wurde unter der MIT-Lizenz veröffentlicht. Diese Software findet sich auf [https://www.spyder-ide.org].
[[Datei:Spyder-windows-screenshot.png | 600px]]
Siehe auch {{W|Spyder (Software)}}
== Eclipse IDE==
Die {{W|Eclipse_(IDE)|Eclipse-IDE}} kann für Python aufgerüstet werden. Dazu gibt es das PyDev-Plugin. Installiert wird es über
* Help > Eclipse Marketplace...
* Find - PyDev - Install
Danach muss noch der Pfad zum Python-Interpreter festgelegt werden
* Window > Preferences > PyDev > Interpreters > Python Interpreter > New ...
Das Ergebnis ist ähnlich wie im folgenden Bild, nur dass statt C/C++ Python Verwendung findet.
[[Datei:Setting Up Eclipse CDT helloout.png | 600px]]
== Sonstige ==
Die genannten IDEs sind nicht die Einzigen. Es gibt, um dem Image Pythons als beliebteste Programmiersprache gerecht zu werden, noch einige andere. Sowohl Open Source-Programme als auch kommerzielle Programme sind im Web zu finden, z.B. Thonny oder {{W|Visual Studio Code}}. Unter Linux kann man auch {{W|KDevelop}}, ausgestattet mit dem Python3-Plugin, einsetzen. Braucht man den Umfang von ausgewachsenen IDEs nicht, so kann man auch normale Texteditoren verwenden (z.B. {{W|Geany}} oder {{W|Kate_(Texteditor)|Kate}}).
= Debuggen und Testen =
Das Debuggen und Testen von Programmen sind wichtige Bestandteile der Programmierung. Syntaxfehler lassen sich i.A. leicht beheben. Schwieriger ist das Eingrenzen von logischen Fehlern, die ev. nur in bestimmten Situationen auftreten und keine explizite Fehlermeldung hervorrufen. Das Programm liefert falsche Ergebnisse oder es stürzt aus heiterem Himmel ab. Um das zu verhindern gibt es verschiedene Werkzeuge, die bei der Fehlersuche behilflich sein können. Vorerst siehe aber zwecks Begriffsklärung noch folgende Links:
* {{W|Debuggen}}
* {{W|Debugger}}
* {{W|Softwaretest}}
<gallery>
First Computer Bug, 1947.jpg
Test ganzheitlich.png
V-Modell.svg
</gallery>
== Das Modul pdb ==
Python bringt schon ein Modul zum Debuggen mit. Siehe z.B. [https://docs.python.org/3/library/pdb.html pdb — The Python Debugger].
Komfortabler lässt sich das aber mittels Integrierter Entwicklungsumgebungen (IDEs) angehen.
== Debuggen mit IDEs ==
Für die IDEs IDLE und Spyder sei kurz auf die entsprechenden Webseiten verwiesen:
* [https://www.cs.uky.edu/~keen/help/debug-tutorial/debug.html Debugging under IDLE].
* [https://docs.spyder-ide.org/current/panes/debugging.html Spyder Debugger]
Dort wird die Vorgehensweise auch mittels Screenshots erläutert.
== assert ==
assert ... behaupten, zusichern ({{W|Assertion (Informatik)}})
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10., 0.)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10., 0.)
File "/home/hr/Develop/test1.py", line 4, in print1
assert y != 0.0
^^^^^^^^
AssertionError
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1("10.", "5.")
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Aber auch bei nachfolgendem Code gibt es eine Fehlermeldung:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10, 5)
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Damit letzteres funktioniert, kann man den Programmcode so umschreiben:
def print1(x, y):
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
2.0
Und jetzt fangen wir den <code>AssertionError</code> auf:
def print1(x, y):
try:
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
except(AssertionError):
print("Hallo")
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Hallo
Ich hoffe, es ist wenigstens im Ansatz klar geworden, wofür <code>assert</code> gut sein kann. Ausschalten kann man die <code>assert</code>-Überprüfung übrigens mit dem Python-Schalter <code>-O</code>.
== Doctests ==
Innerhalb eines Docstrings kann die Arbeit im interaktiven Modus simuliert werden. Nach den Promptzeichen (>>>) erfolgen dann bei unserem Beispiel innerhalb des Docstrings simulierte Aufrufe der Funktion <code>print1()</code>. Danach folgen jeweils die Sollresultate. Wird das Modul oder die Datei als Hauptprogramm aufgerufen, so wird die Funktion <code>doctest.testmode()</code> aufgerufen und ein Bericht auf der Konsole ausgegeben. Wird das Modul nicht als Hauptprogramm aufgerufen, sondern importiert, dann wird diese <code>testmod</code>-Funktion nicht aufgerufen. D.h. dieser Code kann sowohl für Testzwecke als auch für den produktiven Einsatz verwendet werden. Das ist auch sinnvoll, weil wenn man Teile der Datei immer löschen bzw. einfügen müsste, so würden sich Fehlerquellen auftun. Das würde den Sinn und Zweck von Doctests konterkarieren.
def print1(x=0., y=1.):
""" Dividiere zwei Zahlen
Autor: Intruder
Datum: 12.08.2025
>>> print1(2., 1.)
2.0
>>> print1(5., 2.)
2.5
>>> print1(5.)
5.0
"""
print(x/y)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Ausgabe:
Trying:
print1(2., 1.)
Expecting:
2.0
ok
Trying:
print1(5., 2)
Expecting:
2.5
ok
Trying:
print1(5.)
Expecting:
5.0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.print1
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Das gezeigte Beispiel ist so ziemlich das einfachste, das es gibt. Für weiterführende Details siehe z.B.:
* [https://peps.python.org/pep-0257/ PEP 257 – Docstring Conventions]
* [https://docs.python.org/3/library/doctest.html doctest — Test interactive Python examples]
''Einschub:'' Ganz ähnlich kann man auch Klassen testen, z.B. in folgendem Code-Fragment
class Fahrzeug:
# siehe Abschnitt "Objektorientierte Programmierung"
# ...
if __name__ == "__main__":
vauweh = Fahrzeug(170, 90)
beemweh = Fahrzeug(200, 120)
print(vauweh.convertGeschw())
print(beemweh.convertGeschw())
Wird das Script als Hauptprogramm ausgeführt (z.B. zu Testzwecken), so erfolgt die Ausgabe der zwei, via <code>convertGeschw()</code>, umgerechneten Geschwindigkeiten. Wird es aber als Modul eingebunden, so wird der letzte Programmabschnitt nicht ausgeführt (<code>__name__ == "__main__"</code> ergibt <code>False</code>).
== pytest ==
Siehe zu diesem Thema auch {{W|Modultest}}.
pytest ist ein externes Modul und muss vorab installiert werden, z.B. mittels
pip install -U pytest
pip install -U pytest-html
Python-Code, Datei test1.py:
def add(x, y):
return x + y
def test_answer():
assert add(1, 1) == 3
Starten von pytest in der Konsole:
pytest test1.py
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py F [100%]
========================================================= FAILURES ==========================================================
________________________________________________________ test_answer ________________________________________________________
def test_answer():
> assert add(1, 1) == 3
E assert 2 == 3
E + where 2 = add(1, 1)
test1.py:6: AssertionError
================================================== short test summary info ==================================================
FAILED test1.py::test_answer - assert 2 == 3
===================================================== 1 failed in 0.09s =====================================================
Hier erhalten wir einen Fehler, da 1+1 eindeutig ungleich 3 ist. Aber aus irgendeinem Grund wollte der Programmierer oder Tester in diesem Fall, dass dies so ist. Testfälle werden übrigens mit dem Präfix <code>test_</code> eingeleitet.
Python-Code:
def add(x, y):
return x + y + 1
def test_answer():
assert add(1, 1) == 3
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py . [100%]
===================================================== 1 passed in 0.01s =====================================================
Jetzt ist alles in Ordnung. Weiterführendes siehe z.B.
* [https://docs.pytest.org/en/stable/ pytest: helps you write better programs]
== unittest ==
Auch unittest dient zur Durchführung von Testreihen, ist aber Bestandteil von Python. Hier wird vorerst nicht näher darauf eingegangen. Siehe z.B.
* [https://docs.python.org/3/library/unittest.html unittest — Unit testing framework]
Lt. ''Inden: Python Challenge; dpunkt, 2021, Seite 481'' soll unittest weniger komfortabel als pytest sein.
Einen Vergleich von unittest mit pytest findet man in
* [https://knapsackpro.com/testing_frameworks/difference_between/pytest/vs/unittest pytest vs unittest]
= Python und Anwendungsprogramme =
Bisher stand immer alleine die Programmiersprache Python (ev. unter Einbeziehung von Modulen) im Mittelpunkt der Betrachtungen. Aber Python kann auch als Makrosprache für Anwendungsprogramme auftreten. Als Beispiele seien {{W|FreeCAD}} und {{W|LibreOffice}} genannt.
== FreeCAD ==
FreeCAD ist ein freies 3D-CAD-Programm. Hier soll nicht auf die Bedienung dieses CAD-Pakets eingegangen werden, sondern nur auf die Möglichkeit, mittels Python Makros zu schreiben. Als einfacher Einstieg soll ein Makro erstellt werden, welches eine Kugel (rot) und einen Quader (blau) zeichnet. Folgende Vorbereitungsschritte sind erforderlich (es sei vorausgesetzt, dass FreeCAD schon am Rechner installiert ist. Downloaden können Sie das Programm von der Website [https://www.freecad.org/downloads.php?lang=en]):
* FreeCAD starten
* Leere Datei erstellen
* Makro > Makros > Erstellen ...
Es öffnet sich ein leeres Editorfenster, in das Sie folgenden Code eingeben können:
import FreeCAD
import Part
doc = FreeCAD.newDocument()
# Kugel
kugel = Part.makeSphere(10)
form_element = doc.addObject("Part::Feature", "Kugel")
form_element.Shape = kugel
kug = FreeCAD.ActiveDocument.getObject("Kugel")
kug.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
neuePosition = App.Vector(5, 2.5, 2.5)
kug.Placement = App.Placement(neuePosition, kug.Placement.Rotation)
# Quader
quader = Part.makeBox(5, 5, 50)
form_element = doc.addObject("Part::Feature", "Quader")
form_element.Shape = quader
quad = FreeCAD.ActiveDocument.getObject("Quader")
quad.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
doc.recompute()
Diesen Code können Sie nun ausführen:
* Makro > Makro ausführen
Es ergibt sich folgende Ausgabe (gedreht und gezoomt):
[[Datei: PythonIng_freecad1.png|500px]]
Siehe auch [https://wiki.freecad.org/Python_scripting_tutorial/de# Anleitung Skripterstellung mit Python]. Getestet wurde obiges Beispiel mit FreeCAD 1.1.3 unter Linux und 1.1.1 unter MS Windows.
== LibreOffice ==
LibreOffice ist ein freies Officepaket ([https://de.libreoffice.org/]). Hier soll nur das Tabellenkalkulationsprogramm Calc kurz betrachtet werden. Es seinen in den ersten 3 Zellen (A1 bis A3) Zahlen gegeben. Diese sollen mit einem Python-Makro addiert und das Resultat in der Zelle A5 ausgegeben werden. Auch hier sind Vorbereitungsarbeiten nötig:
* zuerst muss unter Linux das Verzeichnis <code>~/.config/libreoffice/4/user/Scripts/python</code> erstellt werden
* für MS Windows ist es das Verzeichnis <code>%APPDATA%\LibreOffice\4\user\Scripts\python</code>
** drücken Sie zuerst Win + R (es öffnet sich das Ausführen-Fenster)
** geben Sie <code>%appdata%</code> ein, danach drücken Sie Enter (es öffnet sich der Explorer)
** navigieren Sie zu dem genannten Verzeichnis bzw. erstellen Sie das Verzeichnis
* in diesem Verzeichnis wird dann mit einem beliebigen Texteditor das Python-Makro erstellt, in unserem Fall die Datei <code>summiere_zellen.py</code>:
import uno
def summiere_zellen(*args):
# Zugriff auf das aktuelle Dokument und das aktive Tabellenblatt
ctx = uno.getComponentContext()
smgr = ctx.getServiceManager()
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.getCurrentController().getActiveSheet()
# Werte aus den Zellen A1 bis A3 auslesen
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
# Addition der drei Werte
summe = w1 + w2 + w3
# Ergebnis in die Zelle A5 schreiben
sheet.getCellRangeByName("A5").Value = summe
* siehe dazu ggf. auch [https://help.libreoffice.org/latest/de/text/sbasic/python/python_locations.html?DbPAR=BASIC].
Weiter geht es in LibreOffice Calc mit dem Menü ''Extras > Makros > Makros verwalten > Python''. Dort wird das Makro <code>summiere_zellen</code> ausgeführt. Es ergibt sich z.B. folgendes Resultat
[[Datei:PythonIng_libreoffice1.png]]
Das Kürzel <code>uno</code> steht für '''U'''niversal '''N'''etwork '''O'''bjects. Etwas einfacher geht's auch so:
def summiere_zellen():
desktop = XSCRIPTCONTEXT.getDesktop()
model = desktop.getCurrentComponent()
sheets = model.getSheets()
sheet = sheets.getByIndex(0)
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
cell = sheet.getCellRangeByName("A5")
cell.setValue(w1 + w2 + w3)
Empfohlen wird auch, das Erweiterungspaket APSO ('''A'''lternative '''P'''ython '''S'''cript '''O'''rganizer, apso.oxt) zu installieren. Die Vorgehensweise wird hier nicht gezeigt, sondern nur darauf hingewiesen, dass man das einfach "googeln" kann. Siehe zur Python-Programmierung für LibreOffice auch [https://wiki.documentfoundation.org/Macros/Python_Guide/de Makros/Python-Handbuch]. Getestet wurden obige Beispiele mit LibreOffice 26.2.5.1 unter Linux und 26.2.1.2 unter MS Windows.
= Ausblick =
Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Python. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks, Bücher und die Python-Hilfefunktion verwiesen. Python kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Module fast beliebig erweiterbar.
= Weblinks=
== Python allgemein ==
* [https://www.python.org/ Python Homepage]
== Externe mathematische Module ==
* [https://numpy.org/ NumPy]
* [https://numpy.org/doc/stable/user/numpy-for-matlab-users.html NumPy for MATLAB users]
* [https://scipy.org/ SciPy]
* [https://www.sympy.org/en/index.html SymPy]
* [https://pandas.pydata.org/ pandas]
* [https://github.com/maroba/findiff findiff]
* [https://mpmath.org/ mpmath]
== Externe Module für Grafiken ==
* [https://matplotlib.org/ Matplotlib]
* [https://vpython.org/ VPython]
* [https://build123d.readthedocs.io/en/latest/ build123d]
* [https://docs.vtk.org/en/latest/api/python.html VTK]
* [https://docs.bokeh.org/en/latest/docs/first_steps.html bokeh]
* [https://py5coding.org/ py5]
== Erstellung von User Interfaces ==
* [https://docs.python.org/3/library/tkinter.html tkinter - Python interface to Tcl/Tk]
* [https://docs.python.org/3/library/curses.html curses - Terminal handling for character-cell displays]
* [https://wiki.qt.io/Qt_for_Python Qt for Python]
* [https://www.gtk.org/docs/language-bindings/python GTK and Python]
== Erstellen virtueller Umgebungen ==
* [https://docs.python.org/3/library/venv.html venv - Creation of virtual environments]
== Sonstige ==
* [https://python-control.readthedocs.io/en/stable/ Python Control Systems Library]
* [https://pypi.org/project/regex/ regex - Regular Expressions]
* [http://pyromat.org/ PYroMat]
* [https://coolprop.org/coolprop/wrappers/Python/index.html CoolProp]
* [https://pypi.org/project/iapws/ iapws]
* [https://tespy.readthedocs.io/en/main/getting_started/introduction.html TESPy - Thermal Engineering Systems in Python]
* [https://pint.readthedocs.io/en/stable/ pint]
= Bücher =
== Gedruckte Bücher, OpenBooks, Magazine ==
* Diverse: c't Python Lernen, Verstehen, Anwenden; Heise, 2022
* Ernesti, Kaiser: Python3 - das umfassende Handbuch; 5. Aufl., Rheinwerk, [https://openbook.rheinwerk-verlag.de/python/ OpenBook]
* Iacono et al.: Programmieren trainieren; 3. Aufl., Hanser, 2023, ISBN 978-3-446-47766-7
* Inden: Python Challenge; dpunkt, 2021, ISBN 978-3-86490-809-5
* Klein: Numerisches Python; 2. Aufl., Hanser, 2023, ISBN 978-3-446-47170-2
* Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler; Rheinwerk, 2021, ISBN 978-3-8362-7316-9
* Weigend: Python 3 - Das umfassende Praxisbuch; 9. Aufl., mitp, 2022, ISBN 978-3-7475-0544-1
* Woyand: Python für Ingenieure und Naturwissenschaftler; 4. Aufl., Hanser, 2021, ISBN 978-3-446-46483-4
== Andere Wikibooks ==
* [[:en:Subject:Python_programming_language | Englische Wikibooks zum Thema Python]]
* [[Python|Deutschsprachiges Python-Wikibook]] [[Bild:2von10.png|20%]]
* [[Python unter Linux|Python 2.7 unter Linux]] [[Bild:10von10.png|100%]]
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
khcyl60pvmj0kmyiajgaivja1oq4bqs
1091893
1091892
2026-10-03T17:28:17Z
Intruder
1513
/* Py5 */
1091893
wikitext
text/x-wiki
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
= Hallo Welt und allgemeine Hinweise =
== Was ist Python ==
* Python ist eine universelle höhere Programmiersprache.
* Python ist objektorientiert.
* Python ist Open-Source (Python Software Foundation License).
* Python ist für viele Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
* Python ist ein Interpreter.
* Python ist durch Module fast beliebig erweiterbar.
* Python als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
* Python ist in etlichen Anwendungsprogrammen (z.B. {{W|FreeCAD}}, {{W|LibreOffice}}, {{W|GIMP}}, {{W|Blender (Software) | Blender}}) als Makrosprache verwendbar.
{{Wikipedia | Python (Programmiersprache)}}
== Python installieren ==
=== MS Windows ===
Laden Sie das aktuelle Python-Paket von der Webseite [https://www.python.org/] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.
=== Linux ===
Entweder ist Python bereits standardmäßig installiert, ansonsten ist die Installation mittels Paketmanagementsystem einfach möglich. Aber auch die Spyder-Entwicklungsumgebung ([https://www.spyder-ide.org]) bietet einen guten Einstieg mit Python (das gilt auch für MS Windows). Spyder bringt auch schon etliche wichtige Module standardmäßig mit.
== Python starten ==
=== MS Windows ===
Das Icon für das Python-Programm doppelklicken. Und schon startet das Programm.
[[Datei:PythonIng_start1.jpg]]
Python im interaktiven Modus präsentiert sich dann so:
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Alternativ kann das Programm auch über die Eingabeaufforderung oder die PowerShell gestartet werden:
c:\devel\Python>python.exe
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
=== Linux ===
Tippen Sie einfach das Wort „python“ (oder unter openSUSE Tumbleweed z.B. auch „python3.11“ oder „python3.13“) in einem Linux-Terminal ein, schließen den Befehl mit der RETURN-Taste ab, und schon startet Python im interaktiven Modus:
Python 3.13.12 (main, Feb 09 2026, 22:37:44) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Es gibt auch noch andere Möglichkeiten Python zwecks Programmausführung zu starten, z. B. den {{W|Shebang}} (<code>#!</code>) am Beginn eines Python-Scripts. Das Script sei als Script.py gespeichert. Dann kann das Script mit ./Script.py ausgeführt werden. Für openSUSE Tumbleweed sei nachfolgend ein lauffähiges "Hallo Welt!"-Script angegeben. Es wird in diesem Script der Python-Interpreter in der Version 3.13 verwendet :
#!/usr/bin/python3.13
print("Hallo Welt!")
Die Berechtigungen zum Ausführen der Datei müssen natürlich noch richtig gesetzt werden, z.B. mittels <code>chmod 777 Script.py</code>. <small><code>chmod</code> ist die Abkürzung für"'''ch'''ange file '''mod'''e bits".</small>
<small>Die "Maske" <code>777</code> ist nur für Testzwecke sinnvoll, weil sie leicht zu merken ist und für alle Benutzer alle Zugriffsberechtigungen ('''r'''ead/'''w'''rite/e'''x'''ecute für owner/group/others) setzt. Im richtigen Einsatz wird man das aus Sicherheitsgründen nicht so handhaben, sondern nur die Berechtigungen setzen, die unbedingt erforderlich sind. Welche Zugriffsberechtigungen gesetzt sind, kann man z.B. mit dem Befehl <code>ls -l</code> oder <code>ll</code> ('''l'''i'''s'''t directory contents) erfragen. Aber dazu im Moment genug. Erfahrene Linux-Nutzer kennen das ohnehin und Anfänger sollen jetzt nicht mit Linux-Interna überfordert werden. Bei Bedarf siehe die Linux-Man-Pages oder dezidierte Bücher zu Linux.</code></small>
<small>Oder das Script wird in einen Pfad verschoben, in dem sich ausführbare Programme generell befinden (welche Verzeichnisse im PATH liegen, kann bspw. mit <code>echo $PATH</code> abgefragt werden). Das Script kann dann wie ein normales Programm ohne weitere Angaben mit Script.py gestartet werden. Alternativ wird nicht das Script an sich verschoben, sondern nur ein symbolischer Link angelegt, z.B. mit <code>ln -s ~/tmp/Script.py ~/.local/bin/Script.py</code>. <code>~/.local/bin</code> sei ein im PATH gelegenes Verzeichnis. Dies sind aber schon Features für fortgeschrittene Linux-Benutzer und werden am Anfang eher selten benötigt.</small>
== Ein paar Worte zur Erklärung ==
=== Tests ===
Getestet wurden die Beispiele unter den Betriebssystemen
* MS Windows 10 mit der Python-Version 3.12.0 (teilweise auch mit 3.12.2 und 3.13.1; nur die Inhalte die bis spätestens Juli 2025 erstellt wurden)
* MS Windows 11 ab der Python-Version 3.13.4 (nur zum Teil; ab Juli 2025)
* openSUSE Leap 15.6 mit der Python-Version 3.11.12 (Spyder, nur vereinzelt) und zum Teil mit 3.12.11 (ab Juli 2025 bis November 2025).
* openSUSE Tumbleweed ab der Python-Version 3.13.9 (nur vereinzelt, ab November 2025)
=== Popularität ===
* An Beliebtheit rangiert Python mit Stand September 2026 mit einem Rating von 17,76% an 1. Stelle vor C und C++ (lt. [https://www.tiobe.com/tiobe-index/ TPCI - TIOBE Programming Community Index]).
* Lt. [https://innovationgraph.github.com/global-metrics/programming-languages GitHub Top 50 Programming Languages Globally] lag Python im Q1/2026 auf Rang 2, vor TypeScript und hinter JavaScript.
* [https://pypl.github.io/PYPL.html PYPL] (Popularity of Programming Language Index) ist ein anderer Popularitätsindex für Programmiersprachen. Auch hier liegt Python mit großem Vorsprung auf dem ersten Platz (52,08%), gefolgt von Java (13,34%) und C/C++ (7,99%) (Stand September 2026).
=== Namensgebung ===
Der Name "Python" rührt von der Komikertruppe {{W|Monty Python}} her. Die Icons für Python (z.B. Python selbst, Eric IDE, IDLE) sind aber durch die Python-Schlangenart symbolisiert.
<gallery>
Python-logo-notext.svg|Python-Logo
Guido van Rossum in PyConUS24.jpg|{{W|Guido van Rossum}} (geb. 1956), der Erfinder von Python
</gallery>
== Ein erstes Programm ==
Kommentare werden in Python mit der Raute (#) eingeleitet. Sie werden vom Python-Interpreter ignoriert. Text kann mit der print-Funktion ausgegeben werden. Starten Sie Python und geben sie folgende Anweisungen zeilenweise ein
>>> # Das ist ein Kommentar
>>> print("Hallo Welt!")
Als Ergebnis erhalten Sie
Hallo Welt!
Der Prompt (>>>) ist selbstverständlich nicht einzutippen, sondern wird vom Python-System geliefert.
Strings können in Python entweder in Anführungszeichen (") gesetzt werden oder in Hochkommatas('). In diesem Text wird die erste Variante bevorzugt eingesetzt.
Im Gegensatz zu Julia ist es hier egal, ob zwischen <code>print</code> und der öffnenden Klammer Leerzeichen stehen.
= Python als Taschenrechner =
== Allgemeines ==
Wir wollen 3 * 5 berechnen. Dazu starten wir Python im interaktiven Modus. Geben Sie dann die Formel
>>> 3 * 5
ein, drücken die Taste ENTER/RETURN ({{Taste|↵}}) und erhalten als Ergebnis
15
Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck <math>\sin\sqrt{15}</math> berechnen :
>>> import math
>>> math.sin(math.sqrt(15))
-0.6679052983383519
Als erstes wird das math-Modul importiert. Dann wird der mathematische Ausdruck berechnet.
Eine andere Variante, die dasselbe Ergebnis liefert, ist
>>> from math import *
>>> sin(sqrt(15))
-0.6679052983383519
Es wird also aus dem Modul <code>math</code> alles importiert (erkennbar am <code>*</code>). Will man nicht alles importieren, so kann man das auch einschränken:
>>> from math import sin, sqrt
Beenden lässt sich das Python-Programm durch Eingabe von <code>exit()</code> (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken).
== Die Hilfefunktion von Python ==
Bei Eingabe der Anweisung <code>help</code> oder <code>help()</code> springt Python in den Hilfemodus.
Eingabe:
>>> help()
Eingabe:
help> math.sin
Ausgabe:
Help on built-in function sin in math:
math.sin = sin(x, /)
Return the sine of x (measured in radians).
Für die komplette Python-Dokumentation siehe [https://docs.python.org/3/]. Verlassen kann man den Hilfemodus durch das Drücken von STRG-C, bzw. der Eingabe von q, quit oder exit mit anschließendem Drücken der RETURN-Taste.
== Aufgaben ==
* Erkunden Sie die Tangensfunktion "tan" mittels Python-Hilfe (vergessen Sie nicht das math-Modul zu importieren und das <code>math.</code> vor <code>tan</code>)
* Berechnen Sie mit Python den Ausdruck <math>\frac{1}{2}\cdot \text{e}^2 \cdot \tan(\pi/3)</math>. Siehe für die Exponentialfunktion im Python-Hilfesystem auch den Befehl <code>math.exp</code>. Alternativ kann auch die Konstante <code>math.e</code> eingesetzt werden. Potenzieren kann man bei Python mit dem **-Operator (z.B. 2**3 = 8). Für <math>\pi</math> gibt es <code>math.pi</code>.
= Python als Scriptsprache =
Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.py
# Das ist ein Kommentar
print("Hallo Welt!")
Python-Dateien werden mit der Dateiendung .py versehen. Achten Sie darauf, dass vor dem print keine Leerzeichen vorhanden sind. Das ist eine Python-Eigenheit. Wie wir später sehen werden, nutzt Python Einrückungen als syntaktisches Mittel, z.B. um bei Schleifen den Schleifenkörper zu kennzeichnen.
Danach bringen Sie die Skriptdatei test1.py (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:
1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ auch die Windows PowerShell). Das sieht dann etwa so aus:
Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\xyz>
: <small>Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol ([[Image:Windows_logo_-_2021_(Black).svg|10px]]) mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell unter Windows 10 den Eintrag "Windows PowerShell", unter Windows 11 den Eintrag "Terminal"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort <code>cmd</code> ein und mit "OK" wird das Ganze bestätigt.</small>
2) Wechseln Sie mittels <code>cd c:\tmp</code> in das Verzeichnis c:\tmp
3) Angenommen, Sie haben Python unter dem Pfad <code>c:\devel\Python\</code> installiert. Starten Sie das Programm so (der Prompt <code>c:\tmp></code>ist natürlich nicht mit einzutippen):
c:\tmp>c:\devel\Python\python.exe test1.py
4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm
Hallo Welt!
Die Vorgehensweise unter Linux ist prinzipiell gleich. Die kleinen Unterschiede, wie z.B. der Slash statt dem Backslash in Pfadangaben, sollten für Linux-Benutzer keine Hürde darstellen.
== Variablen ==
Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9) und Underscores (_) bestehen, dürfen aber nicht mit einer Zahl beginnen. Führende Underscores haben u.a. im Kontext mit der Objektorientierten Programmierung eine spezielle Bedeutung und sollten nicht für "normale" Variablenbezeichner verwendet werden.
Gültige Variablenbezeichner wären also:
xyz
x1
_wert
name_anzahl
Theoretisch kann man auch Umlaute, griechische Buchstaben u.ä. in Variablenbezeichnern nutzen, z.B.
ößÜ = 16
α = 134
print(ößÜ)
print(α)
Ausgabe:
16
134
Davon wird aber aus offensichtlichen Gründen ({{W|Englisch als Lingua franca}}) abgeraten. Das Eurozeichen (€) etc. darf man ohnehin nicht in Variablenbezeichnern verwenden, dies ergäbe einen Syntaxfehler. Siehe dazu auch [https://peps.python.org/pep-3131/].
Es gibt in Python etliche Schlüsselwörter (z.B. for, if oder return). Diese dürfen nicht als eigene Variablenbezeichner verwendet werden. Eine Liste aller Schlüsselwörter liefert das Script
import keyword
print(keyword.kwlist)
<small>Übung: Speichern Sie dieses Script in eine Datei, z.B. in c:\tmp\test1.py. Führen Sie diese Datei aus, um die Liste der Schlüsselwörter auszugeben.</small>
Da Python case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:
xyz
XYZ
xYz
Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.py gespeichert.
x = 5
y = 10
z = x*y
print(z)
Bringen Sie die Datei test1.py zur Ausführung, so erhalten Sie folgende Bildschirmausgabe
50
Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben. Dies führt aber zu unübersichtlichem Code.
x = 5; y = 10; z = x*y; print(z)
Ausgabe:
50
Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.
x = 5
# x = x - 2
x -= 2
print(x)
Bildschirmausgabe:
3
Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Den Inkrement-/Dekrementoperator (z.B. x++ oder x--) aus C/C++ oder Java kennt Python aber nicht.
Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Python problemlos möglich:
import math
wert = 10
print(wert)
wert = 35.5
print(wert)
wert = "Hallo"
print(wert)
wert = math.pi
print(wert)
Ausgabe:
10
35.5
Hallo
3.141592653589793
== Physische und logische Zeilen ==
In Python muss eine Anweisung in einer logischen Zeile Platz finden. Wird eine Anweisung aber zu lang für eine Zeile, dann kann sie in mehrere physische Zeilen unterteilt werden. Dies kann einerseits durch einen Backslash am Ende einer Zeile geschehen, z.B.
a = 2 + \
5
Dies stellt eine logische Zeile dar, die in zwei physische Zeilen unterbrochen ist.
Geklammerte Ausdrücke werden automatisch zu einer logischen Zeile verbunden, z.B.
a = (2 +
5)
Achtung: Im ersten Beispiel darf nach dem Backslash nichts mehr stehen, auch kein Kommentar. Dies trifft im zweiten Bespiel nicht zu, hier könnte noch ein Kommentar folgen, z.B.
a = (2 + # Kommentar
5)
Auch für Strings gibt es Möglichkeiten, diese auf mehrere Zeilen aufzuspalten.
# Kurzer String
str1 = "ABC"
# Langer String
str2 = """Hallo Welt,
Grüetzi Schwyzer,
Servus an alle"""
# Backslash
str3 = "UVW\
XYZ"
# Mit Klammern
str4 = ("Sehr langer Text, der automatisch .............. "
"in einer einzigen Variable zusammengefügt wird."
)
print(str1)
print(str2)
print(str3)
print(str4)
Ausgabe:
ABC
Hallo Welt,
Grüetzi Schwyzer,
Servus an alle
UVWXYZ
Sehr langer Text, der automatisch .............. in einer einzigen Variable zusammengefügt wird.
==Hexadezimale, oktale, binäre und andere Zahlen==
d = 1050 # Dezimalzahl
h = 0xAA2 # Hexadezimalzahl
o = 0o12 # Oktalzahl
b = 0b100001101 # Binärzahl
print(d)
print(h)
print(o)
print(b)
Ausgabe:
1050
2722
10
269
Groß- und Kleinbuchstaben sind in obigen Literalen übrigens egal. So kann man z.B. statt <code>0b1001</code> auch <code>0B1001</code> schreiben (siehe dazu [https://docs.python.org/3/reference/lexical_analysis.html#integer-literals]).
Sie können auch dezimale in hexadezimale Zahlen umwandeln, usw.:
h = hex(1050) # Dezimalzahl -> Hexadezimalzahl
b = bin(1050) # Dezimalzahl -> Binärzahl
o = oct(1050) # Dezimalzahl -> Oktalzahl
print(h)
print(b)
print(o)
Ausgabe:
0x41a
0b10000011010
0o2032
Gegeben sei die Zahl 121 zur Basis 3. Diese soll in eine Dezimalzahl umgewandelt werden. Das kann so geschehen:
z = int("121", 3)
print(z)
Ausgabe:
16
Dass dies richtig ist, davon kann man sich folgendermaßen überzeugen:
<math> 1 \cdot 3^2 + 2 \cdot 3^1 + 1 \cdot 3^0 = 9 + 6+ 1 = 16 </math>
Zahlen übersichtlicher schreiben kann man auch mittels Underscore, z.B.:
print("Eine Million (Variante 1) =", 1000000)
print("Eine Million (Variante 2) =", 1_000_000)
print("Eine Rechnung:", 2_000 * 400_000);
Es ergibt sich bei beiden Varianten die gleiche Ausgabe. Variante 2 ist aber im Sourcecode leichter lesbar, detto die Zahlen in der Rechnung:
Eine Million (Variante 1) = 1000000
Eine Million (Variante 2) = 1000000
Eine Rechnung: 800000000
== Strings und Platzhalter==
Ein paar einfache Beispiele:
print("Hallo {}" . format("Hugo"))
print("Hallo {:s}" . format("Hugo"))
print("Hallo %s" % "Hugo")
Ausgabe:
Hallo Hugo
Hallo Hugo
Hallo Hugo
Python-Code (formatted string literals, Beispiel 1):
str1 = "Hallo"
str2 = "Hugo"
print(f"{str1} {str2}")
Ausgabe:
Hallo Hugo
Python-Code (formatted string literals, Beispiel 2):
wert = 11.567
print(f"Ausgabe: {wert:.5f}")
Ausgabe:
Ausgabe: 11.56700
Komplexere Beispiele:
print("Hallo {} und {}" . format("Hugo", "Mike"))
print("Hallo {name1} und {name2}" . format(name2="Hugo", name1="Mike"))
# Füllzeichen: *
# Bündigkeit: > (=rechts), < (=links), ^ (=zentriert)
# Feldweite: 10
# Typ: s (=String), f (=Gleitkommazahl), d (=Dezimalzahl) etc.
print("Hallo {:*>10s}" . format("Hugo"))
print("Hallo {:*<10s}" . format("Hugo"))
Ausgabe:
Hallo Hugo und Mike
Hallo Mike und Hugo
Hallo ******Hugo
Hallo Hugo******
Python-Code:
str = "Hallo\t%s\t%7.2f\t%10.2e\t%i" % ("Hugo", 12.34567, 34.567, 264)
print(str)
Ausgabe:
Hallo Hugo 12.35 3.46e+01 264
== Unicode ==
Neben den bekannten ASCII-Zeichen lassen sich Zeichen auch mittels Unicode beschreiben. Griechische Buchstaben oder komplexere mathematische Operatoren - all das sollte kein Problem sein. Siehe auch {{W|Unicode}}, {{W|Liste der Unicodeblöcke}} und {{W|Unicodeblock Mathematische Operatoren}}. Im Folgenden werden ein paar Zeichen (Allquantor, Nabla-Operator, Existenzquantor), die man aus der Mathematik kennt, erzeugt.
ch1 = "\N{FOR ALL}"
ch2 = "\N{NABLA}"
ch3 = "\u2203"
print(ch1, ch2, ch3)
Ausgabe:
∀ ∇ ∃
<small>Diese Ausgabe ergibt sich z.B. mit der IDLE-Shell oder mit Cygwin. Beim Ausführen über die Windows-Eingabeaufforderung oder Windows PowerShell unter MS Windows 10 erfolgt keine korrekte Darstellung. IDLE ist die mit Python mitgelieferte IDE ('''I'''ntegrated '''D'''evelopment '''E'''nvironment, Integrierte Entwicklungsumgebung). Gegen Ende dieses Textes wird IDLE kurz beschrieben.
Das Problem mit der Windows Eingabeaufforderung lässt sich aber umgehen. Man muss nur eine Schriftart auswählen, die die Zeichen kennt, z.B. "DejaVu Sans Mono". Dazu klicken Sie einfach bei der Eingabeaufforderung mit der rechten Maustaste oben auf die weiße Leiste und wählen im aufpoppenden Fenster den Menüpunkt "Eigenschaften". Es öffnet sich ein Dialogfenster. Über den Reiter "Schriftart" lässt sich nun die Schriftart einstellen. Unter MS Windows 11 oder openSUSE Leap 15.6 (bash-Konsole) gibt es dieses Problem ohnehin nicht.</small>
== Reguläre Ausdrücke ==
Python kennt auch {{W|Regulärer Ausdruck|reguläre Ausdrücke}}. Dazu gibt es in Python das Modul <code>re</code>. Beipielsweise sollen alle Zahlen (<math>\text{zahl}\in\mathbb{N}_0</math>) in einem String gesucht und ausgegeben werden. Als String sei gegeben: <code>3x Grüße und 100 Kekse.</code> Das Muster (Pattern) ist <code>\d+</code>. <code>\d</code> steht für eine Dezimalziffer 0-9. Das Plus-Zeichen (+) steht symbolisch für ein oder mehrere Zeichen des vorherigen Ausdrucks. Hier also ein oder mehrere Dezimalziffern. Es wird die Funktion <code>findall</code> aus dem Modul <code>re</code>verwendet.
Python-Code:
from re import findall
str = "3x Grüße und 100 Kekse."
pat = "\\d+" # Doppel-Backslashes müssen verwendet werden, sonst gibt Python eine Warnung aus!
# alternativ: pat = r"\d+"
# oder: pat = "[0-9]+"
numb = findall(pat, str)
print(numb)
Ausgabe:
['3', '100']
Python kennt noch viele weitere Möglichkeiten mittels regulärer Ausdrücke zu hantieren. Dies soll hier aber nicht vertieft werden, da das Thema schon ziemlich speziell und komplex ist. Bei Bedarf siehe aber z.B. die Bücher ''Weigend, Seite 380ff'' und ''Ernesti, Kaiser'' [https://openbook.rheinwerk-verlag.de/python/28_001.html] oder die Python-Dokumentation [https://docs.python.org/3/library/re.html]. Auch [[Python unter Linux: Reguläre Ausdrücke]] liefert ein umfangreiches und brauchbares Python-2-Kapitel zu den regulären Ausdrücken. Die dort gelisteten Beispiele müssten ggf. vor Verwendung auf Python-3 umgeschrieben werden. <small>Wie macht man das? Dazu siehe z.B. [https://openbook.rheinwerk-verlag.de/python/43_001.html], [https://portingguide.readthedocs.io/en/latest/] oder [https://www.digitalocean.com/community/tutorials/how-to-port-python-2-code-to-python-3]</small>
<small>Es gibt auch ein externes Modul ''regex'', das bei Bedarf extra installiert werden muss ([https://pypi.org/project/regex/]). Es bietet zusätzliche Funktionalität und gründlicheren Unicode-Support. Dies sei hier aber nur der Vollständigkeit halber erwähnt.</small>
== Verzweigungen ==
=== if ===
Die IF-Verzweigung sei aus anderen Programmiersprachen bereits bekannt. In {{W|Pseudocode}} lässt sie sich folgendermaßen darstellen:
WENN bedingung TRUE
führe block1 aus
SONST
führe block2 aus
ENDE
Als {{W|Aktivitätsdiagramm|UML-Aktivitätsdiagramm}} sieht das in etwa so aus:
[[File:If-Then-Else-diagram.svg|200px]]
Und als {{W|Nassi-Shneiderman-Diagramm|Nassi-Shneiderman-Struktogramm}} so:
[[File:Zweiseitige Auswahl.png|250px]]
In Python gibt es keinen expliziten ENDE-Kennzeichner. Stattdessen wird der Code durch Einrückungen strukturiert. Alles mit der gleichen Einrückungstiefe gehört zum selben Block. Dies zeichnet Python vor anderen Programmiersprachen aus.
Die test1.py-Datei laute also wie folgt:
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4
Man achte auch auf die Doppelpunkte in der if- und else-Zeile. Darauf vergisst man gerne, wenn man von anderen Programmiersprachen kommt.
Folgendes wäre in Python ein Fehler (genauer gesagt ein IndentationError).
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Auch Nachstehendes würde nicht zum gewünschten Ergebnis führen (löst aber keine Fehlermeldung aus). Der letzte print-Befehl ist schon außerhalb der IF-ELSE-Verzweigung.
x = 3
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
x ist kleiner als 4
x ist groesser oder gleich 4
Python kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:
<, <= ... kleiner (gleich)
>, >= ... größer (gleich)
== ... gleich
!= ... ungleich
is ... identisch
is not ... nicht identisch
and ... AND
or ... OR
not ... NOT
Beispielsweise:
a = 5
b = 9
if a<=10 and b!=7:
print("OK")
else
print("Nicht OK")
Ausgabe:
OK
Der else-Block kann übrigens auch ersatzlos entfallen. Als Pseudocode sieht das so aus
WENN bedingung TRUE
führe block aus
ENDE
Mehrfache Verzweigungen werden durch das elif-Konstrukt erstellt. In Pseudocode:
WENN bedingung1 TRUE
führe block1 aus
SONST WENN bedingung2 TRUE
führe block2 aus
SONST WENN bedingung3 TRUE
führe block3 aus
SONST
führe block4 aus
ENDE
Ein Python-Beispiel:
a = 14
if a<=10:
print("<=5")
elif a>11 and a<15:
print("11 bis 15")
elif a>16 and a<20:
print("16 bis 20")
else:
print(">=20")
Ausgabe:
11 bis 15
In Python gibt es auch die Schlüsselwörter <code>True</code> (für wahr) und <code>False</code> (für falsch). Man beachte, dass sie mit Großbuchstaben beginnen. Andere Schreibweisen wären ein Fehler. Sie gehören zum Datentyp <code>bool</code>. Ihnen sind auch die Zahlen <code>1</code> und <code>0</code> zugewiesen.
Man beachte, dass {{W|Rundungsfehler}} auftreten können. D.h. man sollte bei der Verwendung von {{W|Gleitkommazahl|Gleitpunktzahlen}} niemals auf absolute Genauigkeit prüfen, sondern eine Toleranz (einen <math>\varepsilon</math>-Wert) vorgeben.
Ein klassisches Beispiel, das ein falsches Ergebnis liefert, ist:
i = 0.1 + 0.2
print(i)
if i == 0.3:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
NOK
Und das, obwohl man schon in der Volksschule lernt, dass 0.1 + 0.2 gleich 0.3 ist.
Korrekt muss das obige Beispiel z.B. so umgeschrieben werden:
ist = 0.1 + 0.2
soll = 0.3
epsilon = 0.000001
print(ist)
if abs(ist-soll) < epsilon:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
OK
Alternativ kann auch die <code>math.isclose()</code>-Funktion verwendet werden. Das sei aber hier nur erwähnt und nicht konkret ausgeführt.
<u>Aufgabe:</u> Recherchieren Sie im Internet zum Thema <code>math.isclose()</code>-Funktion.
=== match ===
Ab Python 3.10 gibt es auch die match-Anweisung. Dies ist das Python-Pendant für die switch-Anweisung in anderen Programmiersprachen, geht aber bei näherer Betrachtung weit darüber hinaus. Hier nur ein einfaches Beispiel:
x = "Hello"
match x:
case "Servus" | "Ciao": # or
print("Servus an alle")
case "Grüetzi":
print("Grüetzi Schwyzer")
case _: # other, default, sonstiges ...
print("Hallo Welt")
Ausgabe:
Hallo Welt
Als Struktogramm sieht das in etwa so aus:
[[File:Mehrseitige Auswahl.png|250px]]
Für nähere Details siehe z.B. [https://www.geeksforgeeks.org/python-match-case-statement/], [https://learnpython.com/blog/python-match-case-statement/], [https://docs.python.org/3/tutorial/controlflow.html#match-statements] und das Python Enhancement Proposal (PEP) 636 – Structural Pattern Matching: Tutorial [https://peps.python.org/pep-0636] und dort insbesondere den Anhang A - Quick Intro.
<small><code>match, case, _</code> etc. sind sogenannte ''soft keywords''. Im Gegensatz zu den normalen Schlüsselwörtern dürfen ihnen auch Werte zugewiesen werden. Eine Liste der weichen Schlüsselwörter lässt sich durch <code>keyword.softkwlist</code> erstellen (die Anweisung gibt es seit Python 3.9). Siehe dazu auch [https://stackoverflow.com/questions/65800344/what-are-soft-keywords] und [https://docs.python.org/3/library/keyword.html#keyword.softkwlist].</small>
== Schleifen ==
Kopfgesteuerte Schleife, Endlosschleife und fußgesteuerte Schleife:
[[File:Programmingloops.svg|450px]]
=== while ===
Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert wie aus anderen Programmiersprachen bekannt.
In Pseudocode:
SOLANGE bedingung TRUE
führe block aus
ENDE
In Python:
x = 0
while x <= 10:
print(x)
x += 1
Ausgabe:
0
1
2
3
4
5
6
7
8
9
10
Eine Endlosschleife ergibt sich z.B. so:
i = 5
while True:
print(i)
i-=1
Beendet werden kann sie mit der Tastenkombination STRG-C.
Eine fußgesteuerte Schleife kann so simuliert werden:
i = 5
while True:
print(i)
i-=1
if i<=0:
print("Fire")
break
Ausgabe:
5
4
3
2
1
Fire
Der <code>break</code>-Befehl wird etwas später noch einmal kurz thematisiert.
=== for ===
Struktogramm einer for-Schleife:
[[File:Zählschleife.png|200px]]
In Python bspw. so:
for x in range(6):
print(x*2)
Ausgabe:
0
2
4
6
8
10
Die Schleife läuft von 0 bis 5. Ausgegeben wird jeweils der Wert x*2. Aquivalent kann diese Schleife auch so geschrieben werden:
for x in range(0, 11, 2):
print(x)
Die Ausgabe ist wie oben. Der Startwert sei 0, der Endwert ist 11-1 und die Schrittweite ist 2.
Ein anderes Beispiel sei
for x in "text":
print(x)
Ausgabe:
t
e
x
t
== Schleifen abbrechen ==
=== break ===
<code>break</code> bricht die Schleife ab und setzt mit dem nächsten Befehl außerhalb der Schleife fort.
for var in range(100):
print(var)
if var == 5:
break
Ausgabe:
0
1
2
3
4
5
=== continue ===
<code>continue</code> bricht den aktuellen Schleifendurchlauf ab und setzt mit dem nächsten Schleifendurchlauf fort.
for var in range (11):
if var == 5:
continue
print(var)
Ausgabe:
0
1
2
3
4
6
7
8
9
10
== try - except ==
try:
z1 = 12 / 0
print(z1)
except ZeroDivisionError:
print("Das Ergebnis ist unendlich")
except:
print("Kann nicht berechnet werden!")
print("Bitte die Formel korrigieren!")
print("Setze Programm fort!")
Ausgabe:
Das Ergebnis ist unendlich
Setze Programm fort!
Es wird versucht, eine Zahl durch Null zu dividieren. Das ist nicht möglich, es wird eine Ausnahme ausgelöst. Das Programm springt daher in den except-ZeroDivisionError-Block und führt die dort gelisteten Anweisungen aus (in unserem Fall eine print-Anweisung). Danach wird das Programm fortgesetzt. Würden wir dieses Programm ohne try-except ausführen, so ergibt sich aus
z1 = 12 / 0
print(z1)
folgende Fehlermeldung und ein unmittelbarer Programmabbruch
Traceback (most recent call last):
File "C:\tmp\test1.py", line 1, in <module>
z1 = 12 / 0
ZeroDivisionError: division by zero
Mit dem try-except-Mechanismus können also Ausnahmen oder Fehler aufgefangen und behandelt werden. In unserem Beispiel ist das eher trivial, aber bei größeren Programmen kann das durchaus Sinn machen.
Neu in Python 3.14 ist, dass mehrere Ausnahmen auch ohne Klammern angegeben werden können, z.B.:
bis inkl. Python 3.13 nur:
except (ZeroDivisionError, ValueError):
ab Python 3.14 auch:
except ZeroDivisionError, ValueError:
== pass ==
Ein leerer Block muss in Python mittels dem Schlüsselwort <code>pass</code> dargestellt werden. Z.B.
x = 2
if x == 1:
print("Wert ist ", x)
else:
pass
Würde man das <code>pass</code> im else-Block weglassen, so würde man eine Fehlermeldung erhalten:
IndentationError: expected an indented block after 'else' statement on line 5
= Funktionen =
== Aufrufen von Funktionen ==
Funktionen sind uns im Rahmen dieses Kurses schon zuhauf begegnet. Sei es die print()-, die math.sin()- oder die hex()-Funktion. All diese Funktionen werden von Python zur Verfügung gestellt, ohne dass man sie explizit programmieren müsste. Aufgerufen werden diese Funktionen, indem man ihren Namen eintippt, gefolgt von runden Klammern. In diesen Klammern können noch Argumente übergeben werden. Auch Rückgabewerte sind möglich.
== Funktionen selber schreiben ==
Funktionen werden mit dem def-Schlüsselwort (man definiert die Funktion) eingeleitet, danach folgt der Funktionsname, danach wiederum runde Klammern, in denen formale Argumente stehen können. Abgeschlossen wird die def-Zeile mit einem Doppelpunkt. Danach folgt der Funktionskörper. Dieser Funktionskörper muss wiederum eingerückt werden (wie von den Verzweigungen und Schleifen bekannt). Aufgerufen wird diese Funktion, indem man ihren Funktionsnamen eingibt, gefolgt von runden Klammern (ggf. mit den aktuellen Parametern). Z.B.
# Funktion definieren
def halloWelt(i):
# i ... beliebige Ganzzahl
print("Hallo " * i, end="")
print("Welt!")
# Funktion aufrufen
halloWelt(3)
Ausgabe:
Hallo Hallo Hallo Welt!
Unterschied zwischen formalen und aktuellen Parametern:
[[Datei:PythonIng_func1.jpg]]
<small>Aktuelle Parameter werden auch Argumente genannt.</small>
Rückgabe von Funktionswerten:
# Funktion definieren
def mathFunc(a, b):
r1 = a + b
r2 = a * b
return r1, r2
# Funktion aufrufen
c, d = mathFunc(3, 5)
# Ausgabe der zurückgegebenen Werte
print(c)
print(d)
Ausgabe:
8
15
Es werden r1 und r2 zurückgegeben und den Variablen c und d zugewiesen. (r1, r2) und (c, d) sind Tupel. Was Tupel konkret sind, siehe etwas später in diesem Kapitel. 3 und 5 sind die aktuellen Parameter (die Argumente). a und b sind die formalen Parameter. Die Zuweisung der aktuellen zu den formalen Parametern erfolgt in der gegebenen Reihenfolge, also die Zahl 3 wird an a übergeben und die Zahl 5 an b.
Vorgabeparameter, z.B.:
def mathFunc(a=10, b=20):
r1 = a + b
r2 = a * b
return r1, r2
c, d = mathFunc(3, 5)
print(c)
print(d)
e, f = mathFunc(5)
print(e)
print(f)
g, h = mathFunc(b=6)
print(g)
print(h)
Ausgabe:
8
15
25
100
16
60
Erklärung:
* Erster <code>mathFunc</code>-Aufruf: Es werden, wie weiter oben, die Argumente 3 und 5 an die formalen Parameter a und b übergeben. Die Rückgabewerte r1 und r2 werden an c und d übergeben. Somit ist c=8 und d=15.
* Zweiter <code>mathFunc</code>-Aufruf: Es wird nur das Argment 5 an a übergeben. b behält den Vorgabewert 20. D.h. e= 25 und f=100.
* Dritter <code>mathFunc</code>-Aufruf: Es wird nur die Zahl 6 an b übergeben, a behält seinen Vorgabewert 10. Somit ergibt sich g=16 und h=60.
Beispiel (Schlüsselwortargumente vs. Positionsargumente):
def mathFunc(a, b):
r1 = a - b
r2 = a / b
return r1, r2
c, d = mathFunc(b=3, a=5) # Schlüsselwortargumente
e, f = mathFunc(3, 5) # Positionsargumente
print(c)
print(d)
print(e)
print(f)
Ausgabe:
2
1.6666666666666667
-2
0.6
Durch die Verwendung von Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge angegeben werden. Bei den Positionsargumenten ist die Reihenfolge vorgegeben. Daraus resultiert auch der Unterschied bei den obigen Ausgaben. Werden beide Arten in einem Aufruf gemischt, so müssen die Positionsargumente zuerst angegeben werden. Den Unterschied zwischen beiden Argumentarten zu kennen ist wichtig, nicht nur bei selbst erstellten Funktionen. Auch beim Aufruf von Python-Funktionen verfolgt einen die Mischung von Schlüsselwort- und Positionsargumenten auf Schritt und Tritt, z.B. beim etwas später folgenden Abschnitt über "Grafiken zeichnen":
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
Bei dieser <code>plot</code>-Funktion aus dem Modul <code>matplotlib.pyplot</code> sind <code>x</code> und <code>y1</code> Positionsargumente. <code>label, lw</code> und <code>ls</code> sind die Namen der Schlüsselwortargumente. Die Schlüsselwortargumente könnten auch in anderer Reihenfolge angeschrieben werden, nicht jedoch die Positionsargumente!
Siehe zu <code>matplotlib.pyplot.plot</code> auch die Seite [https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html].
== Lambda-Funktionen ==
print((lambda a, b: a*b) (3, 5))
Ausgabe:
15
Eingeleitet wird eine Lambda-Funktion (auch Lambda-Form, Lambda-Operator oder anonyme Funktion genannt) mit dem Schlüsselwort <code>lambda</code>. Es folgen die formalen Argumente, danach ein Doppelpunkt, die Berechnungsvorschrift und ggf. abschliessend in Klammern die aktuellen Parameter.
Man kann einer Lambda-Funktion auch einen Funktionsnamen geben und die Funktion über diesen Namen aufrufen, z.B.
prod = lambda a, b: a*b
print(prod(3, 5))
Als Ausgabe wird wieder die Zahl 15 geliefert.
== Rekursive Funktionen ==
Funktionen können wiederum andere Funktionen aufrufen. Von einem rekursiven Funktionsaufruf spricht man, wenn die aufgerufene Funktion gleich der aufrufenden ist.
def printFunc(i):
if (i >= 5):
return
else:
print("Hallo Welt")
printFunc(i+1)
printFunc(1)
Ausgabe:
Hallo Welt
Hallo Welt
Hallo Welt
Hallo Welt
== Funktionsannotationen ==
Python ist sehr flexibel, was Typen angeht. Im Vorhergehenden haben wir generell keine Typangaben gemacht. Will man Typen angeben, so bietet Python das Konzept der Funktionsannotation.
def calcFunc(a: int, b: int) -> int:
return a+b
r1 = calcFunc(8, 9)
r2 = calcFunc(8.0, 9.0)
r3 = calcFunc("Hallo", "Welt")
print(r1)
print(r2)
print(r3)
Ausgabe:
17
17.0
HalloWelt
Jetzt sieht man auf den ersten Blick, welche Typen der Programmierer im Sinn hatte, als er die Funktion erstellte. Das Problem dabei ist nur, dass es Python ziemlich egal ist, welche Typen man im Endeffekt eingibt. Im obigen Beispiel können statt Integer-Typen u.a. auch Float- oder String-Typen eingegeben werden.
<small>
Siehe zum Thema "Type Checking" aber auch den später folgenden Abschnitt [[Ing_Mathematik:_Python#Type_Checker]].
</small>
== Variadische Funktionen ==
Python-Code:
def test1(a, *b):
print(a);
for c in b:
print(c);
test1("Hallo", "Welt", "Schweizer", "und alle anderen")
Ausgabe:
Hallo
Welt
Schweizer
und alle anderen
Mit dem Stern (auch als Splat-Operator bezeichnet) in der formalen Parameterliste bei der Funktion <code>test1</code> wird angezeigt, dass eine beliebige Anzahl von Argumenten übergeben wird. <small> Dies entspricht in etwa dem, was in anderen Programmiersprachen (PHP etc.) mittels Ellipse (<code>...</code>) angezeigt wird.</small>
= Tupel, Listen und andere =
[[Datei:Python 3. The standard type hierarchy.png|mini|hochkant=1.7|Datentypen und Strukturen]]
== Tupel und Listen ==
Tupel, Listen und einige andere sind Datenstrukturen oder Sequenzen.
Listen (z.B. eine Einkaufsliste) sind veränderbar (mutable). Ein Tupel kann dagegen nicht verändert werden (immutable). Listen werden beim Anlegen in eckige Klammern eingeschlossen, Tupel in runde Klammern. Beim Tupel können die Klammern auch weggelassen werden. Ein Tupel mit nur einem Element muss mit einem Beistrich abgeschlossen werden. Der Grund ist, dass Python sonst nicht entscheiden kann, ob ein Tupel angelegt werden soll, oder nur ein geklammerter Wert.
Als Gedächtnisstütze kann man sich den Unterschied zwischen Tupel und Liste ev. so leichter merken:
: T'''u'''pel ... r'''u'''nde Klammern, '''u'''nveränderlich
: L'''i'''ste ... eck'''i'''ge Klammern, veränderl'''i'''ch.
Nachfolgend werden einige Operationen mit Listen und Tupel dargestellt.
# Liste und Tupel
liste = [1, 2, "Hallo"]
tupel = (1, 2, "Hallo")
# Ausgabe von liste und tupel
print(liste)
print(tupel)
# Ausgabe von Einzelelementen
print(liste[1])
print(tupel[2])
# Element an Liste anhängen und einfügen
liste.append(55)
liste.insert(4, "Welt")
print(liste)
# Element aus Liste entfernen
liste.remove(1)
print(liste)
# einige weitere Beispiele
liste2 = [1,]
tupel2 = 1, 2
tupel3 = (1,)
print(liste2)
print(tupel2)
print(tupel3)
Ausgabe:
[1, 2, 'Hallo']
(1, 2, 'Hallo')
2
Hallo
[1, 2, 'Hallo', 55, 'Welt']
[2, 'Hallo', 55, 'Welt']
[1]
(1, 2)
(1,)
Beispiel (eine Liste von Wörtern zu einem einzigen zusammenhängenden Text verbinden):
woerter = ["Hallo", "Welt"]
satz = " ".join(woerter)
print(satz)
Ausgabe:
Hallo Welt
== Dictionaries und Mengen ==
Zu den Datenstrukturen gehören weiters auch Mengen und Dictionaries. Mengen sind von der Mathematik bekannt, sie sind ungeordnet und es kommen keine mehrfachen Elemente vor. Dictionaries sind durch Schlüssel :Wert-Paare gekennzeichnet. Mengen werden beim Anlegen wie Dictionaries in geschweifte Klammern eingeschlossen.
dict = {"vorname":"Hugo", "nachname":"Meister" }
menge = {1, 1, 3, 4, 4, 4, "Hallo"}
print(dict)
print(menge)
print(dict["vorname"])
Ausgabe:
{'vorname': 'Hugo', 'nachname': 'Meister'}
{1, 3, 4, 'Hallo'}
Hugo
Geschweifte Klammern ohne Inhalt stellen Dictionaries dar und keine Mengen:
di = {}
print(type(di))
Ausgabe:
<class 'dict'>
Leere Mengen lassen sich mit <code>set()</code> erzeugen:
menge = set() # leere Menge
print(menge)
menge.add("Hallo") # Element hinzufügen
print(menge)
Ausgabe:
set()
{'Hallo'}
Beispiel (einige Mengenoperationen):
mengeA = {"Hallo", "Welt"}
mengeB = {1, 2, "Welt", 3}
# Vereinigung
print(mengeA | mengeB)
print(mengeA.union(mengeB))
# Durchschnitt
print(mengeA & mengeB)
print(mengeA.intersection(mengeB))
# Differenz
print(mengeA - mengeB)
print(mengeA.difference(mengeB))
# Symmetrische Differenz
print(mengeA ^ mengeB)
print(mengeA.symmetric_difference(mengeB))
# Teilmenge
print(mengeA.issubset(mengeB))
# Mehrere Elemente hinzu
mengeA.update(["Super", 67, 125])
print(mengeA)
# Element löschen
mengeA.discard("Hallo")
print(mengeA)
Ausgabe:
{1, 2, 3, 'Welt', 'Hallo'}
{1, 2, 3, 'Welt', 'Hallo'}
{'Welt'}
{'Welt'}
{'Hallo'}
{'Hallo'}
{1, 2, 3, 'Hallo'}
{1, 2, 3, 'Hallo'}
False
{67, 'Super', 'Welt', 'Hallo', 125}
{67, 'Super', 'Welt', 125}
Es gibt schon seit "ewigen" Zeiten unveränderbare Mengen, die mittels <code>frozenset</code> eingeleitet werden. Neu ab Python 3.15 ist dagegen das Pendant <code>frozendict</code>, das unveränderbare Dictionaries darstellt.
fdict = frozendict({"vorname":"Hugo", "nachname":"Meister"})
fset = frozenset({"A", 1, "A"})
print(fdict)
print(fdict["vorname"])
print (fset)
try:
fdict["vorname"] = "Max"
print(fdict["vorname"])
except TypeError as e:
print(f"Fehler: {e}")
try:
fset.add("B")
print(fset)
except AttributeError as e:
print(f"Fehler: {e}")
Ausgabe:
frozendict({'vorname': 'Hugo', 'nachname': 'Meister'})
Hugo
frozenset({1, 'A'})
Fehler: 'frozendict' object does not support item assignment
Fehler: 'frozenset' object has no attribute 'add'
== List Comprehensions ==
Aus einer Eingabeliste soll eine Ausgabeliste erzeugt werden. Das kann folgendermaßen geschehen.
Mathematische Schreibweise: <math>lc = \{2x|x\in\ \mathbb{N}, 1\le x < 11\}</math>
Python-Code:
lc = [x*2 for x in range(1,11)]
print(lc)
Ausgabe:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Mathematische Schreibweise: <math>lc = \{2x | x \in \mathbb{N}, 1\le x < 11, x \bmod 2 = 0 \}</math>
Python-Code:
lc = [x*2 for x in range(1,11) if x%2 == 0]
print(lc)
Ausgabe:
[4, 8, 12, 16, 20]
Siehe auch {{W|List Comprehension}}.
== Set Comprehensions ==
Dies ist sehr ähnlich wie im vorigen Abschnitt beschrieben. Es wird aber keine Liste, sondern eine Menge erzeugt.
sc = {x*2 for x in range(1,11)}
print(sc)
Ausgabe:
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
== Listen zusammenführen - zip() ==
li1 = ["A", "B", "C", "D"]
li2 = [1, 2, 3, 4]
li3 = [5.5, 6.6, 7.7, 8.8]
z = zip(li1, li2, li3)
print(z)
li4 = list(z)
print(li4)
Ausgabe:
<zip object at 0x00000283B6C6AC80>
[('A', 1, 5.5), ('B', 2, 6.6), ('C', 3, 7.7), ('D', 4, 8.8)]
== Generatorausdruck ==
g = (i*2 for i in range(1,11))
print(g)
t = tuple(g)
print(t)
print(t[1:3])
Ausgabe:
<generator object <genexpr> at 0x00000241D2A4A5A0>
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
(4, 6)
== Slicing ==
slice ... Scheibe, Teil, in Scheiben schneiden
Beispiel: Zugriff auf Elemente eines geordneten sequentiellen Objekttyps (Liste, Tupel oder String):
str1 = "Hallo"
# Das erste Element wird mit dem Index 0 angesprochen
# [start (inkl.) : stop (exkl.) : step (default=1)]
str2 = str1[0:2]
# Alternativ auch: str2 = str1[:2]
print(str2)
tup1 = (0,1,2,3)
# Das letzte Element hat auch den Index -1, das vorletzte den Index -2 usw.
tup2 = tup1[-3:-1]
print(tup2)
lst1 = [[1, 5, 10, 20],
[30, 40, 50, 60]]
lst2 = lst1[1][1]
print(lst2)
Ausgabe:
Ha
(1, 2)
40
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2])
print(x[-3])
print(x)
print(x[:])
print(x[2:])
print(x[:2])
print(x[::-1])
Ausgabe:
c
c
('a', 'b', 'c', 'd', 'e')
('a', 'b', 'c', 'd', 'e')
('c', 'd', 'e')
('a', 'b')
('e', 'd', 'c', 'b', 'a')
Visualisierung:
'''a''' '''b''' '''c''' '''d''' '''e'''
+-----------------------------+
| 0 | 1 |//'''2'''//| 3 | 4 |
+-----------------------------+
| -5 | -4 |/'''-3'''//| -2 | -1 |
+-----------------------------+
|/////////////////////////////|
+-----------------------------+
|/////////////''':'''///////////////|
+-----------------------------+
| | |///////'''2:'''////////|
+-----------------------------+
|////''':2'''/////| | | |
+-----------------------------+
|\\\\\<--\\\\\'''::-1'''\\\\<--\\\\\|
+-----------------------------+
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2::2])
print(x[2::-1])
print(x[2:0:-1])
Ausgabe:
('c', 'e')
('c', 'b', 'a')
('c', 'b')
Hier sieht man sehr schön, dass beim letzen <code>print</code>-Befehl die 0, die in diesem Fall den Buchstaben "a" repräsentiert, als letzer Wert nicht mehr dazugehört (wie weiter oben angedeutet ist der End- oder Stoppwert exklusiv). Will man den Buchstaben "a" dazunehmen, so ist die vorletzte Zeile die richtige.
Beispiel: Umdrehen von Strings
str1 = "Hallo"
str2 = str1[::-1]
print(str2)
Ausgabe:
ollaH
Mit zweidimensionalen Listen/Tupels wird das Ganze schon bedeutend komplexer.
Beispiel: Verkettetes Slicing
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
print(A[2::][::2])
Ausgabe:
[['20', '21', '22', '23'], ['40', '41', '42', '43']]
Das erste Slicing erstellt folgenden Slice:
[["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
Das zweite Slicing wird dann auf diesen Slice angewendet und ergibt das genannte Endergebnis. Will man Spalten statt Zeilen, so funktioniert dieser direkte Weg nicht. Man verwendet dann List Comprehensions oder die NumPy-Bibliothek. Diese Bibliothek erlaubt zweidimensionales Slicing. Sie wird erst später bei den Grafiken eingeführt. Deshalb wird hier dazu noch kein Beispiel gezeigt.
= Objektorientierte Programmierung =
{{Wikipedia|Objektorientierte Programmierung}}
* {{W|Klasse (Objektorientierung)|Klasse}} ... die Schablone oder der Bauplan, enthält Methoden und Attribute
* {{W|Objekt (Programmierung)|Objekt}} ... eine Klasseninstanz (die konkrete Ausprägung der Klasse)
* {{W|Attribut (Programmierung)|Attribute}} ... die Eigenschaften eines Objekts
* {{W|Methode (Programmierung)|Methoden}} ... die Aktionen (Operationen), die ein Objekt ausführen kann
* {{W|Vererbung (Programmierung)|Vererbung}} ... neue Klassen (Subklassen, Unterklassen, abgeleitete Klassen) aus vorhandenen Klassen (Superklassen, Oberklassen, Basisklassen, Elternklassen) ableiten. Ermöglicht den Aufbau von Klassenhierarchien. Die Subklasse "erbt" Attribute und Methoden von der Superklasse. Python unterstützt (so wie C++, aber im Gegensatz zu Java) Mehrfachvererbung.
== UML ==
* {{W|Unified Modeling Language|UML}} ... '''U'''nified '''M'''odeling '''L'''anguage, eine Modellierungssprache. Die UML enthält zahlreiche Diagrammarten, um Programme zu modellieren. Im Nachfolgenden wird nur das {{W|Klassendiagramm}} verwendet.
[[File:UmlCd Klasse-3.svg|300px]]
* {{W|Sichtbarkeit (Programmierung)|Sichtbarkeit}}:
** + ... public (öffentlich)
** - ... private
** # ... protected
* {{W|Attribut_(UML)#Attribute_für_Instanzen_und_für_Klassen|Klassenattribute}} (statische Attribute): Werden nur einmal pro Klasse angelegt. Im Klassendiagramm werden sie unterstrichen.
[[File:Attribute-3.png|200px]]
* Vererbung:
<gallery>
InheritancePgmUML.svg | Abgeleitete Klasse erbt von Basisklasse (Einfachvererbung)
Diamond inheritance.svg | D erbt von B und C (Mehrfachvererbung). B und C erben von A (Einfachvererbung)
</gallery>
Für weitergehende Betrachtungen zur UML wird auf Spezialliteratur verwiesen, z.B.:
* Seidl et al.: UML@Classroom. dpunkt, 2012, ISBN 978-3-89864-776-2
* Rupp et al.: UML 2 glasklar. Hanser, 4. Aufl., 2012, ISBN 978-3-446-43057-0
== Eine einfache Klasse ==
[[Datei:PythonIng_uml1.svg | 200px]]
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
fahr = Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die Klasse Fahrzeug wird durch das class-Schlüsselwort eingeleitet. raeder ist ein Klassenattribut und public. __init__ wird bei der Objekterzeugung automatisch aufgerufen (ist der sogenannte Konstruktor). Man achte darauf, dass diese Methode immer mit zwei Unterstrichen eingeleitet und abgeschlossen wird. Instanzattributen wird das Wort self vorangestellt. Wir sehen uns z.B. das Attribut self.__geschwind an. Auch hier werden zwei Unterstriche verwendet. Das bedeutet, dass dieses Attribut strikt/stark private ist. Wird nur ein Unterstrich verwendet, so deutet dies auf schwach/weakly private hin. Letzteres wird in Python deutlich häufiger verwendet. Bei den Methoden wird immer self als erster Parameter angegeben. Beim Aufruf der entsprechenden Funktion wird das self aber nicht berücksichtigt.
Besonderheiten bei stark und schwach private:
* '''stark private''':
** zwei führende Unterstriche
** Name Mangling: Name wird zu <code>_Klassenname__variablenname</code>
** Schutz vor Namenskollisionen bei Vererbung
** am Ende des Namens dürfen keine zwei Unterstriche verwendet werden. Das wären dann Magic Methods oder Dunder-Methods (z.B. __init__). Diese sind public.
* '''schwach private''':
** ein führender Unterstrich
** Name bleibt gleich
** ist nur ein Hinweis an die Programmierer, kein starker Schutz
** <code>from modul import *</code>: Objekte mit einem führenden Unterstrich werden standardmäßig nicht importiert
** Standard für die Kapselung bei Python. Schätzung: Weit mehr als 80% der nicht-öffentlichen Attribute/Methoden werden als schwach private deklariert. Weniger als 5-10% als stark private (Quelle: Google KI)
== Klassen importieren ==
Häufig ist es sinnvoll und übersichtlicher Klassen in eigenen Dateien zu speichern. Das sind dann eigene Module. Abgespeichert werden Sie mit der Endung py, wie bisher auch praktiziert. Aufgerufen werden Sie mit der import-Anweisung. Dann ist aber nur der Dateiname ohne Endung py zu verwenden. Klarer wird das mit einem Beispiel.
Datei c:\tmp\fahrzeug.py
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
Datei c:\tmp\test1.py
import fahrzeug
fahr = fahrzeug.Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die üblichen import-Anweisungen lauten wie folgt:
{| {{prettytable}}
! import-Befehl
! Instanz
|-
| import xyz || xyz.Klasse
|-
| import xyz as x || x.Klasse
|-
| from xyz import Klasse || Klasse
|-
| from xyz import * || Klasse
|}
Der Vorteil der ersten beiden import-Anweisungen ist, dass es kaum zu Namenskollisionen kommen kann. Dafür hat man bei den letzten beiden Varianten weniger Tipparbeit.
== Vererbung ==
=== Einfachvererbung ===
[[Datei:PythonIng_uml2.svg | 200px]]
Datei fahrzeug.py:
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
class Luftfahrzeug(Fahrzeug):
def __init__(self, geschwindigkeit, leistung, fluegel):
super().__init__(geschwindigkeit, leistung)
self.__flueg = fluegel
def getFlueg(self):
return self.__flueg
Datei test1.py:
import fahrzeug
fahr = fahrzeug.Luftfahrzeug(150, 90, 4)
print(fahr.getFlueg())
Ausgabe:
4
=== Mehrfachvererbung ===
Mit Python ist auch Mehrfachvererbung möglich, z.B.:
class A:
def _printA(self):
print("Klasse A")
class B:
def _printB(self):
print("Klasse B")
class C(A,B):
def __init__(self):
self._printA()
self._printB()
c = C()
Ausgabe:
Klasse A
Klasse B
Die Klasse C erbt von A und B. In UML sieht das in etwa so aus:
+-----------------------------+ +-------------------------+
| A | | B |
+-----------------------------+ +-------------------------+
| | | |
+-----------------------------+ +-------------------------+
| # printA() | | # printB() |
+-----------------------------+ +-------------------------+
. .
/ \ / \
--- ---
| |
| |
+---------------------+
| C |
+---------------------+
| |
+---------------------+
| |
+---------------------+
<code>printA()</code> und <code>printB()</code> sind schwach private (in UML als <code>protected</code> mit einem # dargestellt). Es ist aber zu beachten, dass schwach private nur Konvention ist. Praktisch könnte man auch von außerhalb auf diese Methoden zugreifen. Das soll man aber nicht tun, und das wird in Python durch einen Unterstrich angedeutet.
= Grafiken zeichnen =
Für das Zeichnen von Grafiken wird hier das Modul <code>matplotlib</code> verwendet. <code>matplotlib</code> ist ein externes Modul und muss vor der ersten Verwendung installiert werden. Das geht so:
# Starten Sie ein Terminal (bei Windows die Eingabeaufforderung).
# Führen Sie darin folgenden Befehl aus <code>c:\devel\Python\Scripts\pip.exe install matplotlib</code>
pip ist übrigens der Paketmanager von Python ({{W|Pip_(Python)}}).
Optimalerweise installieren wir auch gleich das Modul <code>numpy</code> (Numerical Python). Wir werden es im Folgenden oft benötigen (nicht nur bei den Grafiken). Das funktioniert vom Prinzip her genauso, wie für <code>matplotlib</code> gezeigt.
<small>Verwenden Sie Spyder, so sind diese Schritte nicht nötig. Spyder inkludiert diese Pakete standardmäßig. Unter openSUSE Tumbleweed lassen sich diese Pakete mittels YaST oder zypper installieren.</small>
== 2D ==
=== Graph einer Funktion ===
Es soll die cosh-Funktion im Intervall <math>x\in[-3,3]</math> gezeichnet werden. Der Programmcode lautet in der einfachsten Form:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x)
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh1.jpg]]
Der Code ist quasi selbsterklärend. Das Untermodul pyplot des matplotlib-Moduls und das numpy-Modul werden importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plt.plot()" ist der Zeichenbefehl. "plt.show" ist notwendig, um das Fenster mit der Grafik anzuzeigen.
Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen. "plt.grid()" zeichnet ein Gitter in die Grafik (kann auch weggelassen werden).
Die Bezeichnungen plt und np könnten auch anders gewählt werden. Es ist aber Konvention, diese so wie hier gezeigt zu wählen. Die "arange"-Funktion aus der NumPy-Bibliothek wird später ein bisschen genauer behandelt (siehe [[Ing_Mathematik:_Python#Zahlenfolgen|Zahlenfolgen]]).
<small>Mit der im obigen Bild gezeigten Menüleiste kann die dargestellte Grafik nachträglich noch geändert werden (Zoom, Pan, Achsenparameter, Kurvenparameter etc.). Natürlich kann man das alles auch direkt programmieren. Wie das funktioniert wird ansatzweise etwas später gezeigt.</small>
Ein etwas komplexeres Beispiel ist Folgendes:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x) + 2**x
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh4.png]]
Man beachte, dass im Gegensatz zu Octave und Julia der ominöse Punkt (.) bei 2**x mit Python nicht benötigt wird. Das macht das Programmiererleben etwas einfacher.
Die Farbe des Graphen kann man über den <code>color</code>-Schalter einstellen, z.B. auf rot setzen:
plt.plot(x, y, color="red")
Das ist nur eine Möglichkeit, es gibt auch andere, z.B. mittels
* hexadezimaler Zahl, z.B. <code>color="#ff0000"</code>
* Kurzform, z.B. <code>"r"</code>
Statt <code>color</code> kann auch die Kurzform <code>c</code> verwendet werden.
<u>Kleine Aufgabe:</u> Probieren Sie diese "Farbspielereien" am Computer aus.
=== Graphen mehrerer Funktionen und weiteres ===
==== Mehrere Funktionen in einen Plot zeichnen ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x")
plt.plot(x, y2, label = "sin(x) * cos(x)")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh2.png]]
Um die Linienstile etwas individueller zu gestalten, ist folgender Programmcode gedacht:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
plt.plot(x, y2, label = "sin(x) * cos(x)", lw=3, ls="--")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh3.png]]
Einige weitere Bespiele zu <code>ls</code></code>:
* - ... durchgezogene Linie
* -. ... Strichpunkt-Linie
* dashed ... gestrichelte Linie
==== Marker ====
Desweiteren kann man Marker verwenden.
Beispiel:
import matplotlib.pyplot as plt
plt.plot(10, 10, "ob", markersize=30)
plt.plot(20,20, ".r")
plt.plot(30,30, "Dg", ms=15)
plt.plot(40, 40, "ok", ms=20, mec="#FF5733", mew=3)
plt.plot(50, 50, "vk", ms=20, mec="yellow", mew=3)
plt.grid()
plt.show()
Das erste Zeichen im String nach den Koordinaten im plot-Befehl symbolisiert die Form (z.B. o für einen Kreis). Das zweite Zeichen steht für die Farbe (z.B. b für blue). <code>markersize</code> oder <code>ms</code> setzt die Größe des Markers.
Ausgabe:
[[Bild:PythonIng_formatpara1.svg|200px]]
Einige weitere Marker:
* * ... Stern
* + ... Plus
* h oder H ... Sechseck
Man kann mit den Parametern
* <code>markeredgecolor</code> oder kurz <code>mec</code> die Farbe des Markerrandes
* <code>markeredgewidth</code> oder kurz <code>mew</code> die Dicke des Randes
* <code>markerfacecolor</code> oder kurz <code>mfc</code> die Innenfarbe des Markers
bestimmen.
=== Funktion in Parameterdarstellung ===
Es soll die archimedische Spirale <math>x = t \cos(t), y = t \sin(t)</math> im Intervall <math>[0, 6\pi[</math> gezeichnet werden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.show()
[[Datei:PythonIng_spirale1.png]]
Diese Darstellung erscheint verzerrt. Will man gleiche Achsenskalierungen, so kann man den plt.axis()-Befehl verwenden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.axis("equal")
plt.show()
[[Datei:PythonIng_spirale2.png]]
=== Funktion in Polardarstellung ===
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
r = np.arange(0, 1, 0.01)
theta = r**3
line = ax.plot(theta, r)
plt.show()
[[Datei:PythonIng_polar1.png]]
=== Logarithmische Achsenskalierung ===
==== Semilog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.semilogy()
plt.show()
Ausgabe:
[[Datei:PythonIng_semilog1.png]]
==== LogLog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.loglog()
plt.show()
[[Datei:PythonIng_loglog1.png]]
=== Gefüllte Fläche ===
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 3, 0.1)
y1 = 3*x - 1
y2 = x**2
plt.plot(x, y1, x, y2, color='black')
plt.fill_between(x, y1, y2, where=y1>=y2)
plt.show()
[[Datei:PythonIng_gefuellt.png]]
=== Linien, Pfeile, Rechtecke, Kreise und Texte ===
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
r = mpl.patches.Rectangle((0, 0), 3, 3, angle=30, fill=False)
c = mpl.patches.Circle((4, 4), 2, fill=False)
ax.add_patch(r)
ax.add_patch(c)
ax.plot([-2, 7], [-2, 0], color="black")
ax.arrow(0, 7, 5, 0, length_includes_head=True, head_width=0.5, head_length=1.5,
color="black")
ax.set_aspect("equal")
plt.axis([-3, 8, -3, 8])
plt.show()
[[Datei:PythonIng_linien_pfeile_etc.png]]
Text kann mit <code>ax.text(x, y, "Text")</code> hinzugefügt werden, bspw.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
ax.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
Oder einfacher auch ohne <code>subplots</code>
import matplotlib.pyplot as plt
plt.text(0.1, 0.1, "Hallo")
plt.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text1.png]]
Auch Sonderzeichen (griechische Buchstaben etc.) können verwendet werden (siehe dazu auch [https://matplotlib.org/stable/users/explain/text/mathtext.html]).
import matplotlib.pyplot as plt
plt.text(.3, .5,
r'$\Omega\ \psi\ \oint\ \nabla\ \dot a\ \frac{a}{b}\ a_b$',
size="20")
plt.show()
[[Datei:PythonIng_text20.svg]]
Jetzt wird noch gezeigt, wofür <code>subplots</code> sinnvoll eingesetzt werden können.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(0.1, 0.1, "Hallo")
ax[1].text(0.1, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text2.png]]
=== Anmerkungen hinzufügen ===
Anmerkungen (engl. annotations) lassen sich mit matplotlib einfach hinzufügen. Unter Anmerkung wird hier ein Pfeil mit Text verstanden.
Beispiel:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1,10], [1,10])
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0))
plt.show()
Ausgabe:
[[Datei: PythonIng_ann1.svg|400px]]
<code>shrink</code> verkürzt den Pfeil. Sinnvoll sind beim obigen Beispiel Werte irgendwo zwischen 0.0 und 0.3.
<u>Kleine Aufgabe:</u> Probieren Sie verschiedene Pfeillängen aus.
Die Schriftgröße verändern können Sie übrigens mit <code>fontsize</code> oder <code>size</code>, z.B.
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0), fontsize=25)
Eine andere Schreibweise für Dictionaries, die wir weiter oben schon kennengelernt haben, die wir aber nochmals explizit aufschreiben wollen, ist
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops={"facecolor":"red", "shrink":0.0})
=== Figure, Axes etc.===
[[Bild:PythonIng_figure33.svg|350px]]
* fig (figure) ... das übergeordnete Fenster
* ax (axes) ... "Plot", das eigentliche Zeichenfenster
* axis ... die Koordinatenachsen
* spine ... Begrenzungslinien des Zeichenfensters
* tick ... Markierung an den Achsen des Zeichenfensters
Beispiel (eine figure mit 6 axes, ax-Titel, y-axis-Titel):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=3, ncols=2)
ax[0][0].text(0.1, 0.5, "11")
ax[0][1].text(0.1, 0.5, "12")
ax[1][0].text(0.1, 0.5, "21")
ax[1][1].text(0.1, 0.5, "22")
ax[2][0].text(0.1, 0.5, "31")
ax[2][1].text(0.1, 0.5, "32")
ax[0][0].set(ylabel="y-label", title="axes 1")
plt.show()
[[Bild:PythonIng_figure34.png|350px]]
Beispiel (Achsenbereiche setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-1, 10, 1, 12))
plt.show()
[[Bild:PythonIng_figure35.svg|350px]]
Beispiel (Gitter einschalten):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-5, 10, 1, 12))
ax[0].minorticks_on()
ax[0].grid(which='minor')
ax[1].grid(which='major')
plt.show()
[[Bild:PythonIng_figure36.svg|350px]]
Beispiel (ticks setzen)
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
pos = [0, .2, .5]
lab = ["a", "b", "c"]
ax.xaxis.set_major_locator(tick.FixedLocator(pos))
ax.xaxis.set_major_formatter(tick.FixedFormatter(lab))
plt.show()
[[Bild:PythonIng_figure37.svg|350px]]
Beispiel (Achsenkreuz beliebig setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position(('data', 0.3))
ax.spines['left'].set_position(('data', 0.5))
plt.show()
[[Bild:PythonIng_figure38.svg|350px]]
Beispiel (Inset):
import matplotlib.pyplot as plt
# Hauptplot erstellen
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
# Inset hinzu:
axin = ax.inset_axes([0.4, 0.4, 0.3, 0.3])
axin.text(0, 0, "Servus")
axin.plot()
plt.show()
[[Bild:PythonIng_figure40.svg|350px]]
Beispiel (Hintergrundfarben setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_facecolor("green")
fig.set_facecolor("yellow")
plt.plot([1, 3], [6, 8])
plt.show()
[[Bild:PythonIng_figure39.svg|300px]]
=== GridSpec ===
Mit figures und axes lassen sich schon jede Menge an Grafikdetails einstellen. GridSpec ist dann der Turbo oder Raketenantrieb den matplotlib eingebaut hat. Naja, vielleicht ist das etwas übertrieben, aber GridSpec ist sozusagen ein flexibler Layout-Manager. Bisher haben wir immer gleich große axes gezeichnet. Mit GridSpec können wir Subplots über mehrere Zeilen und Spalten ziehen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(3, 3)
ax1 = fig.add_subplot(gs[0, :])
ax1.set_title("Bereich 1: gs[0, :]")
ax2 = fig.add_subplot(gs[1:, 0])
ax2.set_title("Bereich 2: gs[1:, 0]")
ax3 = fig.add_subplot(gs[1, 1:])
ax3.set_title("Bereich 3: gs[1, 1:]")
ax4 = fig.add_subplot(gs[2, 1:])
ax4.set_title("Bereich 4: gs[2, 1:]")
plt.show()
[[Bild:PythonIng_gridspec1.svg|350px]]
Erklärung zu <code>(gs[zeile, spalte])</code>: Slicing; damit legen Sie fest, welche Zellen ein Subplot belegt. Achtung! Die Indizes beginnen bei 0 und nicht bei 1 (d.h., die erste Zeile/Spalte hat den Index 0)
* : ... alle
* 1: ... 1 bis Ende
* etc.
<code>constrained_layout=True</code> sorgt dafür, dass sich die Subplots nicht überlappen.
Aber auch die Spaltenbreiten und Zeilenhöhen lassen sich anpassen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
# Verhältnis erste zu zweite Zeile = 1.5:1
# Verhältnis erste zu zweite Spalte = 1:4
gs = fig.add_gridspec(2, 2, figure=fig, height_ratios=[1.5, 1], width_ratios=[1, 4])
ax1 = fig.add_subplot(gs[0, 0])
ax1.set_title("Bereich 1: gs[0, 0]")
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_title("Bereich 2: gs[0, 0]")
ax3 = fig.add_subplot(gs[1, 0])
ax3.set_title("Bereich 3: gs[1, 0]")
ax4 = fig.add_subplot(gs[1, 1:])
ax4.set_title("Bereich 4: gs[1, 1]")
plt.show()
[[Bild:PythonIng_gridspec2.svg|350px]]
Auch die Ränder lassen sich einstellen.
Beispiel 1:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.1, right=0.9, bottom=0.1,
top=0.9, wspace=0.2, hspace=0.2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec3.svg|300px]]
* hspace ... height space, vertikaler Abstand zwischen den Zeilen
* wspace ... width space, horizontaler Abstand zwischen den Spalten
Und im Vergleich dazu Beispiel 2:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.3, right=0.7, bottom=0.3,
top=0.7, wspace=0.3, hspace=0.3)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec4.svg|300px]]
Es gibt noch einige weitere Details, die sich mit GridSpec variieren lassen (z.B. SubGridSpec ... verschachtelte Grid-Layouts). Aber wir belassen es vorerst dabei. Das bisher Gezeigte sollte für die meisten Probleme ausreichend sein.
=== Aufgaben ===
* Zeichnen Sie die Strophoide <math>x = \frac{a(t^2-1)}{t^2+1}, y = \frac{at(t^2-1)}{t^2+1}, a = 2, -3 \leq t \leq 3</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_strophoide.jpg|300px|center]]
* Zeichnen Sie die verschlungene Hypozykloide <math>x = (R-r)\cos t + c\cos\frac{R-r}{r}t, y = (R-r)\sin t - c\sin\frac{R-r}{r}t, c = 3, r = 2, R = 6, -15 \leq t \leq 15</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_hypozykloide.jpg|300px|center]]
* Testen Sie bei den obigen Übungsaufgaben verschiedene Linienstile und Farben. Farben können mit dem plt.plot()-Parameter color gewählt werden.
* Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.
* Zeichnen Sie folgendes Bild (die Achsenbeschriftungen positionieren Sie z.B. mit den Befehlen <code>ax.set_xlabel("x", loc="right"); ax.set_ylabel("y", loc="top")</code>):
[[Bild:PythonIng_aufgabe24.svg|400px|center]]
* Zeichnen Sie mit Python, matplotlib und NumPy folgendes Bild:
[[Bild:PythonIng_figure41.svg|400px|center]]
* Zeichnen Sie mit GridSpec ein Layout, das in etwa wie folgendes aussieht (<code>height_ratios=[1, 2], width_ratios=[2, 1]</code>):
[[Bild:PythonIng_aufgabe23.svg|300px|center]]
== 3D ==
=== Räumliche Kurven ===
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0, 6*np.pi, 0.1)
x = t * np.cos(t)
y = t * np.sin(t)
z = t
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot(x, y, z)
plt.show()
[[Datei:PythonIng_raumkurve1.png]]
=== Flächen ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z)
plt.show()
[[Datei:PythonIng_fläche1.png]]
Das Ganze in Netzdarstellung läßt sich so programmieren:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = np.arange(0, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_wireframe(x, y, z)
plt.show()
[[Datei:PythonIng_fläche2.png]]
Ein etwas komplexeres Beispiel:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.1, 10, 0.1)
y = np.arange(0.1, 10, 0.1)
x, y = np.meshgrid(x, y)
z1 = np.sin(x) + 3 * np.cos(y)
z2 = np.sin(x) + np.log(y)
z3 = x + np.cos(y)
z4 = x**2 - y
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, nrows=2, ncols=2)
ax[0][0].plot_surface(x, y, z1)
ax[0][1].plot_surface(x, y, z2)
ax[1][0].plot_surface(x, y, z3)
ax[1][1].plot_surface(x, y, z4)
plt.show()
[[Datei:PythonIng_subplot1.png]]
Man beachte, dass man die Unterbilder im Bild nach dem Ausführen des Scripts z.B. mit der mittleren Maustaste einzeln drehen, oder über die Einträge in der Menüzeile einzeln bearbeiten kann. Mit ein paar Zeilen Programmtext lässt sich also eine Menge an Funktionalität generieren.
Die Farbgebung lässt sich über <code>colormaps</code> variieren.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm)
plt.show()
[[Datei:PythonIng_colormap1.png]]
Es gibt eine Menge an Colormaps, z.B. <code>plasma, Greys, Dark2, ocean</code>. Zwecks detaillierterer Infos siehe die matplotlib-Dokumentation. <small>Verwendet man die IDE namens IDLE, so gibt es dort auch die automatische Codevervollständigung. D.h. es werden alle Möglichkeiten (in unserem Fall nach dem Eintippen von <code>cm.</code> alle verfügbaren Colormaps) angezeigt.</small>
Die "edgecolor" und Linienbreite können auch frei gewählt werden:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm, edgecolor="black", linewidth=1.0)
plt.show()
[[Datei:PythonIng_colormap2.png]]
=== Höhenlinien ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
ax.contour(x, y, z)
plt.show()
[[Datei:PythonIng_höhenlinien1.png|400px]]
Etwas abgewandelt sieht das so aus:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contour(x, y, z)
ax.clabel(hl, inline = True)
plt.show()
[[Datei:PythonIng_höhenlinien2.png|400px]]
Und noch eine Variante (mit einem Farbbalken) sei gezeigt.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contourf(x, y, z)
fig.colorbar(hl)
plt.show()
[[Datei:PythonIng_höhenlinien5.svg|400px]]
=== Aufgaben ===
* Zeichnen Sie die räumliche Kurve <math>x = 2 \cdot \cosh(t)</math>, <math>y = 5 \cdot \sin(t)</math>, <math> z = t^{2} - t</math>, <math>0 \leq t \leq 3\pi</math>.
* Zeichnen Sie die Fläche <math>z = \log(x) + \cos(y)</math>.
== Animationen und fortgeschrittenes 3D ==
=== Mit matplotlib ===
Auch mit matplotlib sind Animationen möglich. Das ist ein bisschen komplizierter und wird deshalb hier nur mit einem sehr einfachen Beispiel dargestellt (bei Interesse siehe z.B. auch das [https://matplotlib.org/stable/users/explain/animations/animations.html#animations Animations using Matplotlib-Tutorial]).
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib
import numpy as np
def update(frame):
line.set_xdata(x[:frame])
line.set_ydata(y[:frame])
return (line)
fig, ax = plt.subplots()
x = np.arange(0, 10, .1)
y = np.sin(x)
line, = ax.plot(x[0], y[0])
ax.set(xlim=[0, 10], ylim=[-1, 1])
a = ani.FuncAnimation(fig=fig, func=update, frames=100, interval=20)
plt.show()
# Speichere die Animation in einem animierten GIF (optional)
a.save(filename="c:/tmp/PythonIng_anim5.gif", writer="pillow")
[[Datei:PythonIng_anim5.gif]]
Es wird eine Sinuskurve auf den Bildschirm gezeichnet. In der letzten Zeile wird diese Animation in ein animiertes GIF gespeichert. Das ist natürlich optional und kann auch weggelassen werden.
=== Mit VPython ===
Aber auch mit dem Modul VPython lassen sich einfache 3D-Animationen erstellen. VPython ist ein externes Modul, das vorab installiert werden muss. Unter openSUSE Tumbleweed gibt es dzt. kein entsprechendes rpm-Paket. Die übliche Methode der Installation mittels YaST oder zypper ist somit nicht möglich. Auch eine direkte Verwendung von pip führt nur zu einer Fehlermeldung (<code>error: externally-managed-environment</code>). Es empfiehlt sich dort folgende Vorgehensweise:
# Erstelle zuerst eine virtuelle Umgebung, z.B.: <code>python3.11 -m venv ~/tmp/venv1</code>
# Wechsle das Verzeichnis: <code>cd ~/tmp/venv1/bin</code>
# Installiere das entsprechende Paket: <code>./pip install vpython</code>
# Führe das entsprechende Skript aus: <code>./python ~/tmp/test1.py</code>
Aktuell (März 2026) ist dieses Programmpaket lt. der [https://vpython.org/presentation2018/install.html VPython-Homepage] nur für die Python-Versionen 3.8 bis 3.12 verfügbar.
Ein Beispiel zu einer einfachen Animation wird nachfolgend geliefert.
from vpython import *
scene.width = 1200
scene.height = 600
scene.center = vector(20,0,0)
scene.background = color.white
cylinder(pos=vector(0,0,0), axis=vector(20,0,0), radius=5,
color=color.blue)
cone(pos=vector(0,0,0), axis=vector(-10,0,0), radius=5,
color=color.blue)
helix(pos=vector(20,0,0), axis=vector(40,0,0), radius=2,
coils=10, thickness=0.5, color=color.blue)
ball = sphere(pos=vector(20,0,0), color = color.green, radius = 1)
ball.p = vector(0.15, 0, 0)
toc = True
while True:
rate(200)
if(ball.pos.x <= 60 and toc == True):
ball.pos += ball.p
else:
toc = False
ball.pos -= ball.p
if(ball.pos.x <= 20 and toc == False):
toc = True
[[Datei:PythonIng_vpython_anim.JPG]]
Idealerweise öffnet sich beim Ausführen des Scripts ein Browserfenster. Darin wird die programmierte Animation gezeigt (siehe auch den obigen Screenshot). Eine Größenänderung können Sie mit der mittleren Maustaste initiieren. Die Szenerie drehen können Sie mit der rechten Maustaste.
=== Mit build123d ===
Hiermit lassen sich einfach 3D-Modelle für CAD-Systeme erstellen. [https://build123d.readthedocs.io/en/latest/ build123d] ist ein externes Modul und muss vorab, wie schon für mehrere andere Module gezeigt, installiert werden (pip, venv etc.).
Beispielcode:
from build123d import *
# Bauteil
with BuildPart() as bauteil:
# Zylinder erstellen
Cylinder(100, 60)
# Bohrung
with BuildSketch(bauteil.faces().sort_by(Axis.Z)[-1]) as loch:
Circle(radius=10)
# negativ extrudieren
extrude(amount=-60, mode=Mode.SUBTRACT)
# Dem Bauteil z.B. die Farbe rot zuweisen
# bauteil.part.color = Color("red", alpha=1.0)
# Fertiges Modell exportieren
export_step(bauteil.part, "bauteil.step")
Ausgabe ({{W|Standard for the exchange of product model data | STEP}}-Datei, z.B. in {{W|FreeCAD}} importiert, Screenshot):
[[Datei:PythonIng_build123d.jpg | 300px]]
FreeCAD ist ein freies 3D-CAD-System. Die [[Ing_Mathematik:_Python#FreeCAD | Makroprogrammierung]] in diesem System wird später noch gezeigt. STEP steht für "'''St'''andard for the '''e'''xchange of '''p'''roduct model data" und ist ein Datenaustauschformat.
=== Mit VTK ===
Komplexer, aber auch mächtiger als VPython ist die Verwendung von VTK ('''V'''isualization '''T'''ool'''k'''it). Genauer gesagt des Python-Wrappers von VTK. Dieses externe Python-Modul muss vorab installiert werden (z.B. mittels YaST, pip oder in eine virtuelle Umgebung). VTK ist eine Softwarebibliothek zur 3D-Visualisierung und wurde ursprünglich in C++ geschrieben. Verbreitet eingesetzt wird diese Bibliothek in der Wissenschaft und Forschung, z.B.
* in der medizinischen Bildgebung
* für Strömungssimulationen
* für Klimadaten
VTK funktioniert nach dem {{W|Grafikpipeline|Pipeline-Prinzip}}:
Source (Quellen) -> Filter -> Mapper (Senken) -> Actor/Renderer
Daten fließen von den Quellen zu den Senken.
Als einfaches Beispiel wird die Darstellung eines Zylinders gezeigt, der mit den Maustasten gedreht oder in der Größe geändert werden kann:
import vtk
# Zylinder erzeugen
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
# Geometrie in darstellbare Daten umwandeln
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
# Objekt in der Szene
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Szene verwalten
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# Render-Fenster
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
# Maus/Tastatur-Steuerung
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Starten
render_window.Render()
interactor.Start()
Ausgabe:
[[Datei:PythonIng_VTK_1.png]]
Gleiches Beispiel wie oben, aber mit einer Animationssequenz:
import vtk
import time
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
render_window.Render()
time.sleep(0.01)
Das Grafikfenster schließt sich nach Ablauf der Schleife. Das Fenster bleibt geöffnet, wenn Sie am Programmende folgenden Befehl hinschreiben
interactor.Start()
Um den animierten Zylinder grün einzufärben, müssen Sie Folgendes im obigen Programm ergänzen (Farbnamen):
colors = vtk.vtkNamedColors()
actor.GetProperty().SetColor(colors.GetColor3d("Green"))
Als Namen können Sie u.a. die CSS3 Web-Farben verwenden (siehe z.B. [https://wiki.selfhtml.org/wiki/Farbe/Farbangaben] und {{W|Webfarbe#CSS_3}}).
Alternativ funktioniert auch das ({{W|RGB-Farbraum|RGB}}):
actor.GetProperty().SetColor(0.0, 0.6, 0.0)
Wie der Zylinder mit einer Textur versehen wird, zeigt folgendes Programm:
import vtk
import time
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(30)
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.CappingOn()
texture_coords = vtk.vtkTextureMapToCylinder()
texture_coords.SetInputConnection(cylinder.GetOutputPort())
texture_coords.PreventSeamOn()
reader = vtk.vtkJPEGReader()
reader.SetFileName("PythonIng_textur.jpg")
texture = vtk.vtkTexture()
texture.SetInputConnection(reader.GetOutputPort())
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(texture_coords.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.SetTexture(texture)
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
renderWindow.Render()
time.sleep(0.01)
interactor.Start()
<gallery>
PythonIng_textur.jpg | Textur-Datei
PythonIng_VTK_2.png | Ausgabe (Screenshot)
</gallery>
== Sonstige Grafikbibliotheken ==
=== Py5 ===
Im Buch ''Iacono et al.: Programmieren trainieren, mit über 150 Workouts in Java und Python; 3. Aufl., Hanser, 2023'' werden zahlreiche Aufgaben gestellt, die u.a. mit Processing zu lösen sind. Processing ist eine einfache Programmiersprache und Entwicklungsumgebung. Warum ich das erwähne? Weil in älteren Processing-Versionen auch die Programmiersprache Python 2 abgedeckt war. Bei neueren Versionen gibt es keine Python-Anbindung mehr (getestet nur mit openSUSE Tumbleweed und Python 3). Somit funktioniert der Python-Teil im genannten Buch zum Teil nicht mehr. Ist das tragisch, oder kann das Buch weggeschmissen werden? Nein! Es gibt Alternativen zu Processing. Zum einen die im Buch selbst genannten Bibliotheken tkinter oder pygame. Pygame wird dort auch kurz anhand eines Beispiels thematisiert. Aber noch besser ist es, die py5-Bibliothek zu verwenden (lt. Google KI vom 30. Sept. 2026: ''Der echte, moderne „spirituelle Nachfolger“''). Damit ist die Funktionalität von Processing gewährleistet. Man kann aber beliebige Editoren oder IDEs zur Programmerstellung verwenden, ohne an Processing als IDE gebunden zu sein. Nachfolgend werden ein paar Beispiele zu dieser externen Bibliothek gegeben. Der erste Schritt ist wieder, die py5-Bibliothek zu installieren (z.B. mittels pip in eine virtuelle Umgebung; Python>=3.10 und ein JDK>=17 müssen auch installiert sein (Stand Okt. 2026)). Dann kann es schon mit dem Programmieren losgehen.
Beispiel (angelehnt an die ''Aufgabe W.2.3 Haus'' des genannten Buchs, jedoch etwas erweitert):
import py5
def setup():
py5.size(600, 600) # Fenstergröße 600px x 600px
py5.background(255, 255, 255) # Hintergrundfarbe ... weiss
def draw():
# Haus zeichnen
py5.fill(255, 255, 255) # Hintergrundfarbe ... weiss
py5.stroke(255, 0, 0) # Linienfarbe ... rot
py5.stroke_weight(3) # Linienbreite ... 3px
py5.rect(150, 200, 300, 300) # Rechteck zeichnen (x, y, b, h)
py5.triangle(150, 200, 300, 100, 450, 200) # Dreieck zeichnen
py5.circle(250, 300, 70) # Kreis zeichnen (x, y, d)
# Bemassung zeichnen
py5.stroke(0, 255, 0)
py5.stroke_weight(1)
py5.line(300, 100, 550, 100) # Linie zeichnen
py5.line(450, 200, 550, 200)
py5.line(450, 500, 550, 500)
py5.line(150, 500, 150, 550)
py5.line(450, 500, 450, 550)
py5.text_size(20) # Textgroesse
py5.fill(0, 255, 0) # Textfarbe
py5.text("300", 280, 550) # Text zeichnen
py5.text("100", 500, 150)
py5.text("300", 500, 350)
# Gedrehtes Rechteck zeichnen
py5.stroke(255, 255, 0)
py5.stroke_weight(3)
py5.fill(200, 200, 200)
py5.translate(320, 260)
py5.rotate(0.3) # Drehung (in Radiant)
py5.rect(0, 0, 100, 50)
# Startet den Sketch
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_1.png|300px]]
Das skizzierte Haus ist mit einer rudimentären Bemaßung versehen und hat zwei Fenster, ein rundes und ein gedrehtes, trübes rechteckiges.
Beispiel (Mausoperationen):
import py5
def setup():
py5.size(600, 600)
py5.background(255, 255, 255)
def draw():
pass
def mouse_pressed():
py5.text_size(15)
py5.fill(0, 0, 255)
x = py5.mouse_x
y = py5.mouse_y
py5.text("(%d, %d)" %(x, y), x, y) # Positionsdaten bei Maus-Klick schreiben
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_2.png|300px]]
Obiges Bild zeigt das Resultat nach einigen Mausklicks. Man erkennt, dass links-oben der Koordinatennullpunkt ist. Die x-Achse zeigt nach rechts, die y-Achse nach unten.
Beispiel (Fünfeck):
import py5
import random
def setup():
py5.size(400, 400)
py5.no_loop() # statisches Bild (schont die Ressourcen)
def draw():
py5.translate(py5.width / 2, py5.height / 2) # KS setzen
radius = 150
eck_anzahl = 5
py5.fill(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255)) # Füllfarbe auf Zufallswert setzen
py5.stroke(155, 0, 0)
py5.stroke_weight(5)
# Fünfeck als Polygon zeichnen
py5.begin_shape()
for i in range(eck_anzahl):
winkel = i * py5.TWO_PI / eck_anzahl - py5.HALF_PI
x = py5.cos(winkel) * radius
y = py5.sin(winkel) * radius
py5.vertex(x, y)
py5.end_shape(py5.CLOSE)
py5.run_sketch()
Ausgabe, bspw.:
[[Datei:PythonIng_py5_5.png|200px]]
<u>Kleine Aufgaben:</u>
* Um die Funktionsweise von <code>py5.no_loop()</code> zu verstehen, kommentieren Sie die Anweisung im Beispiel einfach aus, und starten Sie das Programm erneut.
* Zeichnen Sie ein Siebeneck.
* Was passiert, wenn man <code>py5.CLOSE</code> im <code>py5.end_shape()</code>-Befehl weglässt?
Beispiel (Grafik laden und zeichnen):
import py5
image1 = None
def setup():
global image1
py5.size(600, 600)
py5.no_loop()
image1 = py5.load_image("PythonIng_py5_1.png")
def draw():
py5.image(image1, 0, 0)
py5.run_sketch()
Hier wird einfach das Bild vom Haus-Beispiel (Screenshot von weiter oben) geladen und gezeichnet.
Hiermit belassen wir es mit der py5-Bibliothek und wenden uns wieder "mathematischeren" Themen zu.
= Vektoren und Matrizen =
== Zahlenfolgen ==
Für das Erstellen von Zahlenfolgen bieten sich die Funktionen <code>arange</code> und <code>linspace</code> aus dem <code>numpy</code>-Modul an.
from numpy import *
start = 0
stop = 10
step = 2
num = 10
r = arange(start, stop, step) # step ... Schrittweite
l = linspace(start, stop, num) # num ... Anzahl der Werte
print("r = ", r)
print("l = ", l)
Ausgabe:
r = [0 2 4 6 8]
l = [ 0. 1.11111111 2.22222222 3.33333333 4.44444444 5.55555556
6.66666667 7.77777778 8.88888889 10. ]
Bei <code>arange</code> ist der <code>stop</code>-Wert nicht im Ergebnis enthalten, bei <code>linspace</code> standardmäßig aber sehr wohl. Jedoch kann man das bei <code>linspace</code> auch ändern. Dann ist der Stoppwert nicht mehr enthalten:
linspace(start, stop, num, endpoint=False)
== Vektoren ==
Vektoren sollten jedem aus der Linearen Algebra bekannt sein.
=== Arrays ===
In Python mit NumPy kann man Vektoren durch die Funktion array erzeugen.
import numpy as np
l1 = (-5, 3, 2)
l2 = (1, 1, 4)
a1 = np.array(l1)
a2 = np.array(l2)
a3 = a1 + a2
a4 = 2 * a2
print(a1)
print(a2)
print(a3)
print(a3[2])
print(a4)
Ausgabe:
[-5 3 2]
[1 1 4]
[-4 4 6]
6
[2 2 8]
=== Zeilen- und Spaltenvektoren ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
print(z)
print(s)
Ausgabe:
[ [-5 3 2] ]
[[1]
[1]
[4]]
=== Skalarprodukt ===
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
skalarprodukt = np.dot(a1, a2)
print(skalarprodukt)
Ausgabe:
6
=== Vektorprodukt ===
<math>a\ast b=\left(\begin{array}{c}
a_{1}\\
a_{2}\\
a_{3}
\end{array}\right)\ast\left(\begin{array}{c}
b_{1}\\
b_{2}\\
b_{3}
\end{array}\right)=\left(\begin{array}{c}
a_{2}b_{3}-a_{3}b_{2}\\
a_{3}b_{1}-a_{1}b_{3}\\
a_{1}b_{2}-a_{2}b_{1}
\end{array}\right)
</math>
Python-Code:
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
vektorprodukt = np.cross(a1, a2)
print(vektorprodukt)
Ausgabe:
[10 22 -8]
=== Transponierter Vektor ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
# transponierter Vektor
z_tp = np.transpose(z)
# transponierter Vektor
s_tp = np.transpose(s)
print(z_tp)
print(s_tp)
Ausgabe:
[[-5]
[ 3]
[ 2]]
[ [1 1 4] ]
=== Vektorfelder visualisieren ===
import matplotlib.pyplot as plt
import numpy as np
# Daten generieren
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
X, Y = np.meshgrid(x, y)
U = X * Y
V = Y + X
# Plotten
fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='xy')
plt.show()
Ausgabe:
[[Datei:PythonIng_quiver1.png]]
== Matrizen==
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
print(m1)
Ausgabe:
[[1 2 3]
[4 5 6]]
=== Zugriff auf Matrizenelemente ===
Beispiel:
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
# Element aus Zeile 2 und Spalte 3 (Achtung! Index startet bei Null)
print(m1[1,2])
Ausgabe:
6
Visualisierung:
0 1 2
+-----------+
0 | 1 | 2 | 3 |
+-----------+
1 | 4 | 5 | '''6''' |
+-----------+
Beispiel:
import numpy as np
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
B = np.matrix(A)
print(B[2::, ::2])
Ausgabe:
[['20' '22']
['30' '32']
['40' '42']]
Mit der NumPy-Bibliothek funktioniert das zweidimensionale Slicing. Mit normalen Listen/Tupels geht das nicht, was wir schon früher thematisiert haben.
=== Addition und Subtraktion von Matrizen ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
m2 = np.matrix([[0, 0, 2], [1, 3, 2]])
print(m1 + m2)
print(m1 - m2)
Ausgabe:
[[1 2 5]
[5 8 8]]
[[1 2 1]
[3 2 4]]
=== Transponierte Matrix ===
import numpy as np
m = np.matrix([[1, 2, 3], [4, 5, 6]])
mt = np.transpose(m)
print(m)
print(mt)
Ausgabe:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]
=== Rang einer Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
rg = np.linalg.matrix_rank(m)
print(rg)
Ausgabe:
2
=== Inverse Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
mi = np.linalg.inv(m)
print(mi)
Ausgabe:
[[ 1. 0.6]
[-0. -0.2]]
=== Multiplikation von Matrizen (falksches Schema) ===
import numpy as np
m1 = np.matrix([[1, 3, 4], [0, -5, 1]])
m2 = np.matrix([[1, 2], [2, 3], [0, 2]])
print(m1 @ m2)
Ausgabe:
[[ 7 19]
[-10 -13]]
=== Eigenwerte und Eigenvektoren ===
import numpy as np
m = np.matrix([[5, 8], [1, 3]])
D,V = np.linalg.eig(m)
# Eigenwerte
print(D)
# Eigenvektoren
print(V)
Ausgabe:
[7. 1.]
[[ 0.9701425 -0.89442719]
[ 0.24253563 0.4472136 ]]
=== Teilmatrizen ===
import numpy as np
m = np.matrix([[1, 3, 4], [0, -5, 1]])
print("m = ", m)
# Erste Zeile extrahieren
m1 = m[0,:]
print("m1 = ", m1)
# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
m2 = m[0,1]
print("m2 = ", m2)
# Zweite Spalte extrahieren
m3 = m[:, 1]
print("m3 = ", m3)
Ausgabe:
m = [[ 1 3 4]
[ 0 -5 1]]
m1 = [ [1 3 4] ]
m2 = 3
m3 = [[ 3]
[-5]]
=== Spezielle Matrizen ===
==== Nullmatrix ====
import numpy as np
z = np.zeros((3, 2))
print(z)
Ausgabe:
[[0. 0.]
[0. 0.]
[0. 0.]]
==== Einheitsmatrix ====
import numpy as np
z = np.eye(3)
print(z)
Ausgabe:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
==== Matrix mit lauter Einsen ====
import numpy as np
z = np.ones((3, 2))
print(z)
Ausgabe:
[[1. 1.]
[1. 1.]
[1. 1.]]
=== Spärlich besetzte Matrizen ===
Das Thema spärlich besetzter Matrizen wird hier nur kurz angerissen. Nähere Details siehe unter dem Weblink [https://docs.scipy.org/doc/scipy/reference/sparse.html#module-scipy.sparse].
Beispiel:
import numpy as np
import scipy
A = scipy.sparse.csr_array(np.eye(5))
print(A)
Ausgabe:
<Compressed Sparse Row sparse array of dtype 'float64'
with 5 stored elements and shape (5, 5)>
Coords Values
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
(4, 4) 1.0
csr steht für '''c'''ompressed '''s'''parse '''r'''ow.
Andere Möglichkeiten:
* coo-Format ('''coo'''rdinate Format): <code>scipy.sparse.coo_array()</code>
* lil-Format ('''li'''st of '''l'''ists): <code>scipy.sparse.lil_array()</code>
* csc-Format ('''c'''ompressed '''s'''parse '''c'''olumn): <code>scipy.sparse.csc_array()</code>
Es gibt auch <code>scipy.sparse.csr_matrix()</code> etc. Diese Befehle sind aber veraltet und es wird empfohlen, statt dessen die <code>..._array()</code>-Funktionen zu verwenden.
<u>Aufgaben:</u>
Recherchieren Sie im Internet
* generell zum Thema "spärlich besetzte Matrizen mit Python".
* Was sind die Vor-/Nachteile von csr-arrays gegenüber coo- und lil-arrays?
* Wann verwendet man sinnvollerweise csr- und wann csc-arrays?
* Wie wandelt man coo-arrays in csr-arrays um?
= Lineare Gleichungssysteme =
Sei <math>Ax = b</math> ein lineares Gleichungssystem. <math>A</math> sei die Koeffizientenmatrix, <math>x</math> der Lösungsvektor und <math>b</math> ein bekannter Vektor.
Beispiel:
import numpy as np
A = np.array([[5, 1], [0, 2]])
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)
Ausgabe:
[0. 1.]
Siehe dazu auch das Kapitel [[Ing Mathematik: Numerisches Lösen von linearen Gleichungssystemen]]. Dort wird dieses Themengebiet u.a. mit weitergehenden Python-Skripten vertieft.
== Aufgabe ==
* Lösen Sie folgendes Gleichungssystem mittels Python (und zur Kontrolle auch händisch):
5x + 6y - 2z = 12
3x - y - 3z = 6
2x + 2y + 4z = 5
= Polynome =
== Ein erstes einfaches Beispiel ==
Gegeben sei das Polynom <math>7x^3+5x^2+1</math>. In Python:
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p)
Ausgabe:
3 2
7 x + 5 x + 1
== Einzelne Polynomwerte berechnen ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p(1.5))
Ausgabe:
35.875
== Polynome integrieren und differenzieren ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
# 1. Ableitung
p1 = p.deriv()
p2 = p.deriv(1)
# 2. Ableitung
p3 = p.deriv(2)
# Integral
p4 = p.integ()
print(p1)
print(p2)
print(p3)
print(p4)
Ausgabe:
2
21 x + 10 x
2
21 x + 10 x
42 x + 10
4 3
1.75 x + 1.667 x + 1 x
== Nullstellen bestimmen ==
import numpy as np
p = np.poly1d([2, 5, 0, 4])
r = np.roots(p)
print(r)
Ausgabe:
[-2.7621427 +0.j 0.13107135+0.84077099j 0.13107135-0.84077099j]
== Aufgaben ==
* Berechnen Sie den Wert für x = 3 des Polynoms <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Differenzieren und integrieren Sie das Polynom <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Berechnen Sie die Nullstellen von <math>y = 7x^5 - 3x^2 + 12</math>.
= Nichtlineare Gleichungen und Gleichungssysteme =
== Nullstellenbestimmung ==
Löse eine beliebige Gleichung f(x) = 0, z.B. <math> f(x) = x^2 - 5\cos(x) - 10 = 0 </math>:
import scipy
import numpy as np
def f(x):
return x**2 - 5*np.cos(x) - 10
xstart = [-1, 1] # Startwerte
xn = scipy.optimize.root(f, xstart)
print(xn.x)
Ausgabe:
[-2.46813009 2.46813009]
Funktionsgraph:
[[Datei:octave_nichtlin2.jpg]]
== Gleichungssysteme ==
SymPy ist ein externes Modul, das symbolisches Rechnen ('''Sym'''bolic '''Py'''thon) ermöglicht.
Folgende Aufgabe ist dem Buch "Knorrenschild: Numerische Mathematik, Hanser, 2017, Seite 72" entnommen. Zu lösen ist das nichtlineare Gleichungssystem
<math>f_1 = 2x_1 + 4x_2 = 0 </math>
<math>f_2 = 4x_1 + 8x_2^3 = 0</math>
Mit Python ist das so möglich:
import sympy
x1, x2 = sympy.symbols("x1 x2")
f1 = 2*x1 + 4*x2
f2 = 4*x1 + 8*x2**3
s = sympy.solve((f1, f2), x1, x2)
print(s)
Ausgabe:
[(-2, 1), (0, 0), (2, -1)]
Plot:
[[Datei:IngPython_nl_gleichung1.svg|500px]]
= Komplexe Zahlen =
Die imaginäre Einheit wird in Python durch den Buchstaben <code>j</code> symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:
* Kartesische Darstellung <math>z = \Re(z) + j \cdot \Im(z)</math>
* Polardarstellungen <math>z = r \cdot (\cos(\phi) + j \cdot \sin(\phi)) = r \cdot e^{j\cdot \phi}</math>
Die konjugiert komplexe Zahl ist <math>z^* = \Re(z) - j \cdot \Im(z)</math>
Nachfolgend einige mathematische Operationen mit Python und NumPy.
import numpy as np
z1 = 2 + 5j # kartesische Darstellung
z2 = 3 * np.exp(3j) # Polardarstellung
# Addition
res = z1 + z2
print("z1 + z2 = ", res)
# Multiplikation
res = z1 * z2
print("z1 * z2 = ", res)
# Realteil
res = np.real(z2)
print("Realteil von z2 = ", res)
# Imaginärteil
res = np.imag(z2)
print("Imaginaerteil von z2 = ", res)
# Betrag
res = np.abs(z1)
print("Betrag von z1 = ", res)
# Argument
res = np.angle(z1)
print("Argument von z1 = ", res)
# Konjugiert komplexe Zahl
res = np.conj(z1)
print("Konjugiert komplexe Zahl von z1 = ", res)
Ausgabe:
z1 + z2 = (-0.9699774898013365+5.423360024179601j)
z1 * z2 = (-8.05675510050068-14.003167400647481j)
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = (2-5j)
= Interpolation =
import numpy as np
import scipy
import matplotlib.pyplot as plt
# Stützpunkte
xp = np.arange(1, 6)
yp = (0, -5, 2, 7, 6)
ti = np.arange(1, 5, 0.01)
i1 = scipy.interpolate.interp1d(xp, yp, kind = "linear")
i2 = scipy.interpolate.interp1d(xp, yp, kind = "cubic")
plt.plot(xp, yp, "rx")
plt.plot(xp, i1(xp))
plt.plot(ti, i2(ti))
plt.show()
Ausgabe:
[[Datei:PythonIng_interpol1.png]]
= Differenzialrechnung =
== Numerisches Differenzieren ==
Als Beispiel differenzieren wir <math>y = 5x\sin{x}</math> und stellen das Ganze grafisch dar.
from findiff import Diff
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
f = 5 * x * np.sin(x)
dx = x[1] - x[0]
# Ableitung
d_dx = Diff(0, dx)
df_dx = d_dx(f)
# Grafik
plt.plot(x, f, label = "y")
plt.plot(x, df_dx, label = "y'")
plt.grid()
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:octave_diff1.jpg]]
<small>findiff ist ein externes Modul. Dieses muss installiert werden (z.B. so: ...\Python\Scripts\pip.exe install --upgrade findiff). Für die Vorgehensweise unter openSUSE Tumbleweed siehe das Kapitel [[Ing_Mathematik:_Python#Mit_VPython | VPython]], nur dass das Ganze mit einer aktuelleren Python-Version exekutiert wird, z.B. mit Python 3.13. Das im Buch "Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler, Rheinwerk" verwendete Modul "scipy.misc" ist veraltet (deprecated ... missbilligt). Lt. [https://docs.scipy.org/doc/scipy-1.17.0/dev/roadmap-detailed.html#misc SciPy-Dokumentation für die Version 1.17.0] wurden alle entsprechenden Features schon entfernt.</small>
== Symbolisches Differenzieren ==
Differenzieren Sie die Funktionen <math>f_1(x) = x^2</math> und <math>f_2(x) = \sin(x)\cos\left(\frac{x}{2}\right)</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2;
f2 = sympy.sin(x) * sympy.cos(x/2.)
d1 = sympy.diff(f1, x)
d2 = sympy.diff(f2, x)
print(d1)
print(d2)
Ausgabe:
2*x
-0.5*sin(0.5*x)*sin(x) + cos(0.5*x)*cos(x)
== Aufgaben ==
* Differenzieren Sie die Funktion <math>y = \log(x) + 10x</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
* Differenzieren Sie die Funktion <math>y = \frac{\sinh(x)}{(1+x)}</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
= Integralrechnung =
== Numerisches Integrieren ==
Berechnen Sie das Integral <math>\int_{0}^{3}x^2 dx</math>.
import scipy
def f(x):
return x**2
i = scipy.integrate.quad(f, 0, 3)
print(i)
Ausgabe:
(9.000000000000002, 9.992007221626411e-14)
Das trifft den exakten Wert 9.0 ziemlich genau.
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} dx</math>.
import scipy
import numpy as np
def f(x):
return 2**(-x)
i = scipy.integrate.quad(f, 0, np.inf)
print(i)
Ausgabe:
(1.4426950408889556, 4.486558477977586e-09)
== Symbolisches Integrieren ==
Berechnen Sie <math>\int x^2 \text{d}x</math> und <math>\int \sin{x}\cos{\frac{x}{2}} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2
f2 = sympy.sin(x) * sympy.cos(x/2.)
i1 = sympy.integrate(f1, x)
i2 = sympy.integrate(f2, x)
print(i1)
print(i2)
Ausgabe:
x**3/3
-0.666666666666667*sin(0.5*x)*sin(x) - 1.33333333333333*cos(0.5*x)*cos(x)
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f = 2**(-x)
i = sympy.integrate(f, (x, 0, sympy.oo))
print(i)
Ausgabe:
1/log(2)
<code>sympy.oo</code> steht für das {{W|Unendlichzeichen}} <math>\infty</math> (die liegende Acht oder das Möbiusband). Mit <code>sympy.pprint(i)</code> ließe sich letzere Ausgabe etwas schöner schreiben:
1
──────
log(2)
Man beachtete, <code>log</code> steht hier für den natürlichen Logarithmus <code>ln</code>.
== Aufgaben ==
* Integrieren Sie die Funktion <math>y = \log(x) + 10x</math> von 1 bis 5.
* Integrieren Sie die Funktion <math>y = x^3</math> von 0 bis 4.
* Integrieren Sie <math>\int x^x(\log (x) + 1)\mathrm dx</math> symbolisch.
= Gewöhnliche Differenzialgleichungen =
== DGL numerisch lösen ==
Für die Lösung von Differenzialgleichungen steht u.a. die Funktion scipy.integrate.solve_ivp() zur Verfügung. Diese Funktion implementiert auch das Runge-Kutta-Verfahren (RK45).
{{Wikipedia | Runge-Kutta-Verfahren}}
Beispiel <math>y' = x^2 + y^3</math>:
import scipy
import numpy as np
import matplotlib.pyplot as plt
def dy_dx(x, y):
return x**2 + y**3
y0 = [1]
xi = [0, 1]
x = np.arange(0, 1, 0.01)
z = scipy.integrate.solve_ivp(dy_dx, xi, y0, method="RK45", dense_output=True)
y = z.sol(x)
plt.plot(x, y.T)
plt.grid()
plt.show()
[[Datei:PythonIng_dgl1.png]]
== DGL symbolisch lösen ==
Beispiel <math>y' = x^2 + y^3</math>:
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
print(lsg)
Ausgabe:
[Eq(f(x), (-x**2)**(1/3)), Eq(f(x), (-x**2)**(1/3)*(-1 - sqrt(3)*I)/2), Eq(f(x), (-x**2)**(1/3)*(-1 + sqrt(3)*I)/2)]
Mit <code>sympy.pprint</code> (pretty print) lässt sich die Ausgabe etwas übersichtlicher darstellen.
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
sympy.pprint(lsg)
Ausgabe:
⎡ _____ _____ ⎤
⎢ _____ 3 ╱ 2 3 ╱ 2 ⎥
⎢ 3 ╱ 2 ╲╱ -x ⋅(-1 - √3⋅ⅈ) ╲╱ -x ⋅(-1 + √3⋅ⅈ)⎥
⎢f(x) = ╲╱ -x , f(x) = ────────────────────, f(x) = ────────────────────⎥
⎣ 2 2 ⎦
== Aufgaben ==
* Lösen Sie die Differenzialgleichung <math>y' = \frac{1}{x\cdot y}</math> mit Python. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>m' = -k\cdot m</math>. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>y' = \sqrt{|y|}</math>.
=Laplace-Transformation=
Laplace-Transformation:
<math>F(s) =\mathcal{L} \left\{f\right\}(s) = \int_{0}^{\infty} f(t) \mathrm e^{-st} \,\mathrm{d}t, \qquad s\in\mathbb{C}
</math>
Inverse Laplace-Transformation:
<math>\mathcal{L}^{-1} \left\{F\right\}(t)
= \frac{1}{2 \pi \mathrm j} \int_{ \gamma - \mathrm j \infty}^{ \gamma + \mathrm j \infty} \mathrm e^{st} F(s)\,\mathrm ds
= \begin{cases}
f(t) & \text{für } t \geq 0 \\
0 & \text{für } t < 0
\end{cases}
</math>
Siehe auch [[Ing_Mathematik:_Laplace-Transformation]]
Code:
import sympy
from sympy.abc import t, s
# Laplace-Transformation der Funktion f(t) = 1 (Heaviside-Fkt.)
f = 1
# alternativ: f = sympy.Heaviside(t)
F = sympy.laplace_transform(f, t, s, noconds=True)
print("Laplace-Transformierte F(s):", F)
# Inverse Laplace-Transformation zurück in den Zeitbereich
f_inv = sympy.inverse_laplace_transform(F, s, t)
print("Inverse Transformation f(t):", f_inv)
Ausgabe:
Laplace-Transformierte F(s): 1/s
Inverse Transformation f(t): Heaviside(t)
Die Zeile
from sympy.abc import t, s
steht alternativ für
t = sympy.symbols("t")
s = sympy.symbols("s")
<u>Aufgaben</u>: Ermitteln Sie mittels SymPy die <math>\mathcal{L}</math>-Transformierten und dann wieder die <math>\mathcal{L}^{-1}</math>-Transformationen (ähnlich wie beim obigen Beispiel):
* <math>\sin(t) \circ\! -\! \bullet \ ?</math>
* <math>t^3 \circ\! -\! \bullet \ ?</math>
* <math>\text{e}^{\omega t} \circ\! -\! \bullet \ ?</math>
=Fourier-Reihen=
<math>
f(x)\approx \frac{a_{0}}{2}+\sum_{k=1}^{\infty}\left(a_{k}\cos\left(kx\right)+b_{k}\sin\left(kx\right)\right)
</math>
<math>
a_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\cos\left(kx\right)\mathrm dx\quad\text{für }k\geq0
</math>
<math>
b_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\sin\left(kx\right)\mathrm dx\quad\text{für }k\geq1
</math>
Für die Sägezahnfunktion <math>y=x;\, 0 < x < 2\pi</math> sei die Fourierreihe mit einem Python-Programm (unter Mithilfe von sympy) hergeleitet.
Code:
from sympy import fourier_series, pi, symbols, pprint
x = symbols('x')
f = x
s = fourier_series(f, (x, 0, 2*pi))
pprint(s.truncate(n=4))
Ausgabe:
2⋅sin(3⋅x)
-2⋅sin(x) - sin(2⋅x) - ────────── + π
3
Siehe auch [[Ing Mathematik: Fourierreihen]].
Ein komplizierteres Beispiel:
[[Datei:IngMath fourier bsp13.svg | 300px]]
<math>0\le t < T/2\text{:}\quad f(t) = H</math>
<math>T/2 \le t \le T\text{:}\quad f(t) = \frac{2H}{T}\left( t-\frac{T}{2}\right)</math>
Code:
import sympy as sp
H = sp.Symbol('H', positive=True)
T = sp.Symbol('T', positive=True)
t = sp.Symbol('t')
f = sp.Piecewise(
(H, (t > 0) & (t < T/2)),
(2*H/T*(t-T/2), (t > T/2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Ausgabe:
⎛2⋅π⋅t⎞ ⎛4⋅π⋅t⎞ ⎛6⋅π⋅t⎞ ⎛2⋅π⋅t⎞ ⎛6⋅π⋅t⎞
H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ 2⋅H⋅cos⎜─────⎟ 2⋅H⋅cos⎜─────⎟
⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ 3⋅H
──────────── - ──────────── + ──────────── + ────────────── + ────────────── + ───
π 2⋅π 3⋅π 2 2 4
π 9⋅π
=Rechnen mit wirklich großen Zahlen=
Bekannt ist, dass Python kaum Einschränkungen beim Wertebereich von Ganzzahlen hat, z.B.
print(10**300)
Ausgabe (gekürzt):
100000000000000000000...00000000000000000000000000000000000000000000000000000000000000000000000
Ähnliches geht auch mit Gleitpunktzahlen, z.B. durch die Verwendung des Moduls [https://mpmath.org/ mpmath]:
import mpmath
print(mpmath.mpf(1500.4)**mpmath.mpf(300))
Ausgabe:
7.27975299218612e+952
Anderes Beispiel:
from mpmath import mp, pi
mp.dps = 100
print(pi)
Ausgabe:
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
mpmath kann noch einiges mehr, dazu sei aber auf die entsprechende Dokumentation auf der mpmath-Homepage verwiesen. mpmath ist Bestandteil von SymPy, kann aber auch separat installiert werden.
Aber auch Python selbst besitzt eine Möglichkeit, um mit großen bzw. exakten Gleitpunktzahlen zu rechnen, nämlich das interne Modul decimal. Dieses hat einige Vorteile gegenüber mpmath, aber auch gravierende Nachteile. Diese seien hier nicht detailliert aufgezählt. Grob gesagt hat decimal im Finanzwesen seine Berechtigung. Für wissenschaftliche Anwendungen wird aber mpmath vorzuziehen sein, da es u.a. vielfältige mathematische Funktionen bereit stellt. Nachfolgend ein einfaches Beispiel mit decimal:
import decimal
print("Potenzierung:", decimal.Decimal(1500.4) ** decimal.Decimal(300.0))
print("Einfache Addition:", 0.1 + 0.2)
decimal.getcontext().prec = 50
print("Addition mit decimal:", decimal.Decimal("0.1") + decimal.Decimal("0.2"))
Ausgabe:
Potenzierung: 7.279752992186121551039839134E+952
Einfache Addition: 0.30000000000000004
Addition mit decimal: 0.3
<u>Aufgabe:</u> Recherchieren Sie im Internet die genauen Vor- und Nachteile von decimal und mpmath. Verwenden Sie dazu auch KI (z.B. von Google, chatgpt).
= pint - mit physikalischen Größen rechnen =
[[File:Pint-Glas_UK.jpg|right|100px]]
pint ist ein externes Python-Paket zur Manipulation von physikalischen Einheiten. Es muss vor der ersten Benutzung installiert werden (Vorgehensweise wie immer: pip, YaST, via venv etc.).
Beispiel:
import pint
import numpy as np
ureg = pint.UnitRegistry()
# Einfache Berechnung
print(3 * ureg.meter + 4 * ureg.cm)
# Mit NumPy
npeinzel = [3, 4] * ureg.meter + [2, 5] * ureg.cm
print(npeinzel)
npsum = np.sum(npeinzel)
print(npsum)
# Konvertierung von Einheiten
npsum_inch = npsum.to(ureg.inch)
print(npsum_inch)
print(npeinzel.magnitude)
print(npeinzel.units)
print(npeinzel.dimensionality)
Ausgabe:
3.04 meter
[3.02 4.05] meter
7.07 meter
278.3464566929134 inch
[3.02 4.05]
meter
[length]
Die Dokumentation zu pint findet sich auf [https://pint.readthedocs.io/en/stable/].
=Regelungstechnische Aufgabenstellungen=
Für regelungstechnische Aufgaben gibt es u.a. das externe Paket <code>control</code>. Hier soll nicht detailliert darauf eingegangen werden. Anhand eines Beispiels soll anschließend nur die Visualisierung in Form eines Bode-Diagramms und der Sprungantwort gezeigt werden. Gegeben sei ein P-Regler mit <math>R = \frac{5}{2}</math> und eine Strecke <math>S= \frac{1}{30s^3+20s^2+10s+1,5}</math>. Gesucht sei vorerst ein Bode-Diagramm für den offenen Regelkreis und das Führungsverhalten.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke # oder: G0 = ct.series(regler, strecke)
Gw = ct.feedback(G0)
ct.bode_plot(G0, label='G0')
ct.bode_plot(Gw, label='Gw')
plt.show()
[[Datei:PythonIng_bode1.svg]]
Nun noch für obiges Beispiel die Sprungantwort. Diese zeigt einige große Überschwinger, d.h. der Regler kann sicher noch optimiert werden.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke
Gw = ct.feedback(G0)
t, y = ct.step_response(Gw)
plt.plot(t,y)
plt.title('Sprungantwort')
plt.xlabel('t')
plt.ylabel('h(t)')
plt.grid()
plt.show()
[[Datei:PythonIng_bode3.svg]]
Einige weitere wichtige Daten (Phasenreserve, Amplitudenreserve, Durchtrittsfrequenz) lassen sich mittels der <code>control</code>-Funktion <code>margin()</code> ermitteln. Die Ortskurve lässt sich mit der Funktion <code>nyquist_plot()</code> zeichnen. Dies sei hier aber nicht weiter ausgeführt.
==Aufgaben==
* Zeichen Sie mit Python die Ortskurve für obiges Beispiel.
* Was passiert, wenn man die Reglerverstärkung weiter aufdreht (z.B. auf <math>R = \frac{25}{2}</math>)?
* Wie sehen das Bode-Diagramm und die Sprungantwort aus, wenn ein PI-Regler verwendet wird?
= Stereostatik etc. =
Das Modul SymPy bietet einige Möglichkeiten einfache Bauwerke zu berechnen, z.B. Balken oder Fachwerke. Nachfolgend wird ein einfaches Fachwerk berechnet und gezeichnet.
Python-Code:
from sympy.physics.continuum_mechanics.truss import Truss
t = Truss()
# Knoten
t.add_node(("A", -3, 0), ("B", 0, 0), ("C", 4, 0), ("D", 7, 0),
("E", 6, 1.5), ("F", 2, 3), ("G", -2, 1.5))
# Stäbe
t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D"))
t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F"))
t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E"))
t.add_member(("FE","F","E"), ("DE","D","E"))
# Auflager; roller ... Loslager, pinned ... Festlager
t.apply_support(("A","roller"), ("D","pinned"))
# Einwirkende Kräfte
t.apply_load(("G", 5, 270), ("E", 3, 90))
# Berechnung
t.solve()
print("Reaction Forces: ", t.reaction_loads)
print("Internal Forces: ", t.internal_forces)
# Fachwerk zeichnen
p = t.draw()
p.show()
Ausgabe auf der Konsole:
Reaction Forces: {'R_A_y': 4.20000000000000, 'R_D_x': 0, 'R_D_y': -2.20000000000000}
Internal Forces: {'AB': 2.80000000000000, 'BC': 0.333333333333333, 'CD': -1.46666666666667,
'AG': -5.04777178564958, 'GB': -2.05555555555556, 'GF': -1.23413387432364,
'BF': 0.411111111111111*sqrt(13), 'FC': -0.3*sqrt(13), 'CE': 1.50000000000000,
'FE': 0.284800124843917, 'DE': 2.64407093534026}
Zeichnung:
[[File:PythonIng_fachwerk1.svg|300px]]
Details zu diesem Thema siehe z.B. [https://docs.sympy.org/latest/modules/physics/continuum_mechanics/index.html Continuum Mechanics] oder [https://docs.sympy.org/latest/tutorials/physics/continuum_mechanics/index.html Continuum Mechanics Tutorials]. Auch andere mechanische Probleme werden von SymPy abgehandelt ([https://docs.sympy.org/latest/tutorials/physics/index.html Physics Tutorials]).
== Aufgabe ==
Gegeben sei ein einseitig eingespannter Kragträger. Belastet wird er durch eine Einzellast am Trägerende. Für die Daten siehe folgende ASCII-Skizze:
| 20 kN
//|---> x |
//| V
//|----------------------
//| 10 m |
Elastizitätsmodul E = 2,1*10⁵ N/mm²
Flächenträgheitsmoment I = 0.001 m⁴
Berechnen Sie die Auflagerreaktionen, den Querkraft- und Biegemomentenverlauf, sowie die Verformungen.
Stellen Sie dies mit Hilfe von SymPy graphisch und auch mittels Formeln dar. Verwenden Sie dazu auch pprint (pretty print) aus dem SymPy-Modul. Zwecks Lösungsansatz siehe die oben aufgeführte Seite "Continuum Mechanics Tutorials". Achten Sie auch auf die Einheiten! Kontrollieren Sie das Ganze mittels händischer Rechnung. In dem genannten Tutorial ist von "Singularity Functions" die Rede. Gemeint ist damit in diesem Kontext die {{W|Föppl-Klammer}}.
Einige Python-Programme, vorrangig zu Maschinenelementen, finden sich auf [https://baymp.de/download_python.html BayMP für Python] (Balken, Zahnräder, Stabknickung usw.).
=Thermodynamik=
== PYroMat ==
Für thermodynamische Aufgabenstellungen gibt es verschiedene externe Module. Eines davon ist PYroMat (siehe auch [http://pyromat.org]). Damit lassen sich thermodynamische Stoffdaten für viele Substanzen berechnen.
Beispiel (einige Stoffdaten für Wasser bei 400°C und 20 bar berechnen):
import pyromat as pm
# Wasserdaten laden:
H2O = pm.get('mp.H2O')
# Stoffdaten berechnen:
T = 673.15 # Temperatur in Kelvin
p = 20 # Druck in bar
v = H2O.v(T, p)
h = H2O.h(T, p)
s = H2O.s(T, p)
print(f"Spezifisches Volumen: {v} m³/kg")
print(f"Spezifische Enthalpie: {h} kJ/kg")
print(f"Spezifische Entropie: {s} kJ/(kg K)")
Ausgabe:
Spezifisches Volumen: [0.1512163] m³/kg
Spezifische Enthalpie: [3248.3789473] kJ/kg
Spezifische Entropie: [7.12924142] kJ/(kg K)
<small>
PYroMat muss vorab installiert werden (z.B. mittels pip, in eine virtuelle Umgebung)
</small>
<code>mp</code> steht für "multi phase". Für ein ideales Gas wäre <code>ig</code> zuständig, z.B. <code>'ig.O2'</code>.
Beispiel (T-s-Diagramm für Wasser zeichnen):
import numpy as np
import matplotlib.pyplot as plt
import pyromat as pm
# Konfigurieren
pm.config["unit_pressure"] = "bar"
pm.config["unit_temperature"] = "K"
fluid = pm.get("mp.H2O")
# Temperaturbereich für das Nassdampfgebiet
T_tripel = 273.16
T_crit = 647.096
T = np.linspace(T_tripel, T_crit - 0.1, 200)
# Sättigungslinien berechnen und zeichnen
for x in np.linspace(0.0, 1.0, 5):
s = fluid.s(T=T, x=x)
if(x<=0.0):
plt.plot(s, T, label="Siedelinie x=%3.1f" % x, linewidth=2.0)
elif(x>=1.0):
plt.plot(s, T, label="Taulinie x=%3.1f" % x, linewidth=2.0)
else:
plt.plot(s, T, label="x=%3.1f" % x, linewidth=1.0)
# Isobaren zeichnen
p_values = [0.1, 1, 10, 50, 100]
T_isobar = np.linspace(T_tripel, 1000, 200)
t = 0.7
for p in p_values:
s_iso = fluid.s(T=T_isobar, p=p)
plt.plot(s_iso, T_isobar, 'k-', alpha=0.8, linewidth=0.8)
t += .05
idx = int(len(s_iso) * t)
plt.text(s_iso[idx], T_isobar[idx], f"{p} bar", fontsize=9, alpha=0.8)
# Diagramm zeichnen
plt.title("T-s-Diagramm für Wasser")
plt.xlabel("Spezifische Entropie s in kJ/kg K", fontsize=10)
plt.ylabel("Temperatur T in K", fontsize=10)
plt.legend(loc="best")
plt.grid(True)
plt.show()
Ausgabe (in etwa so):
[[Datei:T-s-Diagramm fuer Wasser.svg|400px]]
== CoolProp ==
Auch mit CoolProp können Stoffdaten berechnet werden. Siehe auch [https://coolprop.org/coolprop/wrappers/Python/index.html]
Beispiel (Wasser bei 20bar und 400°C):
import CoolProp.CoolProp as CP
fluid = 'Water'
T = 673.15 # Temperatur in Kelvin
P = 20e5 # Druck in Pascal
dichte = CP.PropsSI('D', 'T', T, 'P', P, fluid)
enthalpie = CP.PropsSI('H', 'T', T, 'P', P, fluid)
entropie = CP.PropsSI('S', 'T', T, 'P', P, fluid)
print(f"Spez. Volumen: {1/dichte:.6f} m³/kg")
print(f"Spez. Enthalpie: {enthalpie:.2f} J/kg")
print(f"Spez. Entropie: {entropie:.2f} J/kgK")
Ausgabe:
Spez. Volumen: 0.151215 m³/kg
Spez. Enthalpie: 3248344.02 J/kg
Spez. Entropie: 7129.16 J/kgK
== iapws ==
Um Werte für Wasser(dampf) zu erhalten (IAPWS; '''I'''nternational '''A'''ssociation for the '''P'''roperties of '''W'''ater and '''S'''team) gibt es die Bibliothek iapws. Siehe auch [https://iapws.org/] und [https://pypi.org/project/iapws/]
Beispiel (Wasser für 20bar und 400°C):
from iapws import IAPWS97
dampf = IAPWS97(P=2.0, T=673.15)
print(f"Spezifisches Volumen: {dampf.v:.6f} m³/kg")
print(f"Spezifische Enthalpie: {dampf.h:.2f} kJ/kg")
print(f"Spezifische Entropie: {dampf.s:.4f} kJ/(kgK)")
print(f"Phase: {dampf.phase}")
Ausgabe:
Spezifisches Volumen: 0.151208 m³/kg
Spezifische Enthalpie: 3248.23 kJ/kg
Spezifische Entropie: 7.1290 kJ/(kgK)
Phase: Gas
== TESPy ==
Ein anderes Modul für einen anderen Aufgabenzweck ist TESPy ('''T'''hermal '''E'''ngineering '''S'''ystems in '''Py'''thon). Dieses Modul ist für die Anlagensimulation zuständig. Für nähere Informationen siehe [https://tespy.readthedocs.io/en/main/getting_started/introduction.html]. Als Beipiel sei hier vorerst Code, der von der Google KI generiert wurde, angeführt. Der Code wurde überarbeitet, damit keine Warnungen auftreten. Bitte aber den Code trotzdem mit Vorsicht genießen, auch KI-generierter Code kann Fehler aufweisen. Eine Pumpe wird berechnet:
from tespy.components import Sink, Source, Pump
from tespy.connections import Connection
from tespy.networks import Network
# 1. Netzwerk definieren (Zentrales Steuerungselement)
# Wir wählen Wasser als Fluid und bar/Celsius als Einheiten
nw = Network(fluids=["water"])
nw.units.set_defaults(pressure="bar", pressure_difference="bar",
temperature="°C", enthalpy="kJ / kg")
# 2. Komponenten erstellen
eingang = Source("Wasserquelle")
ausgang = Sink("Wasserspeicher")
pumpe = Pump("Speisewasserpumpe")
# 3. Verbindungen definieren (Komponenten miteinander verknüpfen)
c1 = Connection(eingang, "out1", pumpe, "in1")
c2 = Connection(pumpe, "out1", ausgang, "in1")
# Verbindungen dem Netzwerk hinzufügen
nw.add_conns(c1, c2)
# 4. Randbedingungen und Parameter festlegen
# Zustand am Eingang (Druck, Temperatur, Massenstrom, Fluid-Zusammensetzung)
c1.set_attr(
v=1, # Massenstrom: 1 kg/s
T=20, # Temperatur: 20 °C
p=1, # Druck: 1 bar
fluid={"water": 1}, # 100% Wasser
)
# Zustand am Ausgang / Zielwerte der Pumpe
c2.set_attr(p=10) # Ziel-Druck nach der Pumpe: 10 bar
# Pumpeneigenschaften festlegen
pumpe.set_attr(eta_s=0.8) # Isentroper Wirkungsgrad von 80%
# 5. Simulation ausführen
nw.solve(mode="design")
# 6. Ergebnisse ausgeben
nw.print_results()
# Spezifische Werte direkt auslesen
print("\n--- Auswertung ---")
print(f"Erforderliche Pumpenleistung: {pumpe.P.val / 1000:.2f} kW")
print(f"Temperatur nach der Pumpe: {c2.T.val:.2f} °C")
Ausgabe (gekürzt):
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 7.04e+04 | 12 % | 9.96e+02 | 0.00e+00 | 8.81e+04 | 0.00e+00 | 0.00e+00
2 | 5.91e-12 | 100 % | 1.11e-13 | 0.00e+00 | 7.39e-12 | 0.00e+00 | 0.00e+00
3 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
4 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.01 s, Iterations per second: 480.85
##### RESULTS (Pump) #####
+-------------------+----------+----------+-----------+----------+----------+----------+
| | P | pr | dp | eta | eta_s | head |
|-------------------+----------+----------+-----------+----------+----------+----------|
| Speisewasserpumpe | 1.12e+06 | 1.00e+01 | -9.00e+00 | 8.00e-01 | 8.00e-01 | 9.19e+01 |
+-------------------+----------+----------+-----------+----------+----------+----------+
...
...
--- Auswertung ---
Erforderliche Pumpenleistung: 1124.77 kW
Temperatur nach der Pumpe: 20.07 °C
= Stochastik =
Die {{W|Stochastik}} ist ein sehr weites Feld. Hier werden etliche wichtige Themen kurz angerissen. Python stellt mit den Moduln math und statistics Software zu diesem Zwecke bereit. math und statistics sind bereits im Lieferumfang von Python enthalten. Aber auch mit den externen Modulen NumPy, SciPy, stochastic und pandas kann man Stochastik in Python betreiben. Die Theorie der Wahrscheinlichkeitsrechnung und Statistik soll etwas später in Band 5 dieser Buchreihe behandelt werden.
== Lageparameter ==
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
m1 = statistics.mean(werte)
m2 = statistics.mode(werte)
m3 = statistics.median(werte)
print("Arithmetischer Mittelwert = ", m1)
print("Modalwert = ", m2)
print("Median = ", m3)
Ausgabe:
Arithmetischer Mittelwert = 3.5
Modalwert = 1
Median = 3.0
== Streuungsparameter ==
Beispiel (Berechnung der Standardabweichung):
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
s = statistics.stdev(werte)
print("Standardabweichung = ", s)
Ausgabe:
Standardabweichung = 2.6770630673681683
Beispiel (Berechnung des Variationskoeffizienten V = Standardabweichung/Mittelwert)
import numpy as np
from scipy import stats
import statistics
k = 50
dat1 = [14, 21, 18, 25, 30, 17, 20]
dat = np.array(dat1)
# Mit SciPy
v = stats.variation(dat)
vddof = stats.variation(dat, ddof=1)
print("V SciPy: ", v)
print("V DDOF SciPy: ", vddof)
print(k*"-")
# mit NumPy
mittelwert1 = np.mean(dat)
std_abw1 = np.std(dat)
std_abw1ddof = np.std(dat, ddof=1)
v1= std_abw1 / mittelwert1
v1ddof = std_abw1ddof / mittelwert1
print("Mittelwert NumPy: ", mittelwert1)
print("Std.abw. NumPy: ", std_abw1)
print("Std.abw. DDOF NumPy: ", std_abw1ddof)
print("V NumPy: ", v1)
print("V DDOF NumPy: ", v1ddof)
print(k*"-")
# nur mit reinem Python
mittelwert2 = statistics.mean(dat1)
std_abw2 = statistics.stdev(dat1)
v2 = std_abw2 / mittelwert2
print("Mittelwert Python: ", mittelwert2)
print("Std.abw. Python: ", std_abw2)
print("V Python:", v2)
print(k*"-")
Ausgabe:
V SciPy: 0.23890355966467272
V DDOF SciPy: 0.25804533701889254
--------------------------------------------------
Mittelwert NumPy: 20.714285714285715
Std.abw. NumPy: 4.948716593053935
Std.abw. DDOF NumPy: 5.3452248382484875
V NumPy: 0.23890355966467272
V DDOF NumPy: 0.2580453370188925
--------------------------------------------------
Mittelwert Python: 20.714285714285715
Std.abw. Python: 5.3452248382484875
V Python: 0.2580453370188925
--------------------------------------------------
Der Unterschied bei der Standardabweichung zwischen reinem Python und den externen Bibliotheken SciPy und NumPy entsteht dadurch, dass einmal durch (n-1) und das andere Mal nur durch n dividiert wird. Dies kann bei NumPy und SciPy dadurch entschärft werden, indem <code>ddof=1</code> gesetzt wird. ddof steht für '''D'''elta '''D'''egrees '''o'''f '''F'''reedom. <small>Je größer die Anzahl der Datensätze n wird, umso weniger spielt das eine Rolle.</small>
== Kombinatorik ==
Beispiel:
import math
n = 7
k = 5
print("n! = ", math.factorial(n))
print("Kombinationen (n über k) = ", math.comb(n, k))
Ausgabe:
n! = 5040
Kombinationen (n über k) = 21
Siehe zu diesem Thema auch [[Ing Mathematik: Permutationen, Kombinationen, binomischer Lehrsatz]]. Die Anzahlen lassen sich einfach aus den dortigen Formeln ermitteln, z.B. bei Permutationen mit <math>n!</math> oder Variationen mit Wiederholungen als <math>n^k</math>. Will man die Kombinationen oder Variationen aber auch als Liste ausgeben, so kann das Modul <code>itertools</code> nützlich sein.
Beispiel (Variationen ohne Wiederholung):
from itertools import permutations
menge = ["A", "B", "C", "D"] # n = 4
k = 3
variationen = list(permutations(menge, k))
for v in variationen:
print("".join(v))
print(50*"-")
print(len(variationen))
Ausgabe (gekürzt):
ABC
ABD
ACB
...
DCA
DCB
--------------------------------------------------
24
Siehe zum Modul <code>itertools</code> auch die Website [https://docs.python.org/3/library/itertools.html].
* Variationen mit Wiederholung: <code>itertools.product()</code>
* Kombinationen ohne Wiederholung: <code>itertools.combinations()</code>
* Kombinationen mit Wiederholung: <code>itertools.combinations_with_replacement()</code>
== Zufallszahlen ==
Beispiel:
import random
# Ganzzahlige Zufallszahl von 1 bis 10
zufallszahl1 = random.randint(1, 10)
# Gleitpunktzahlen
# zwischen 0.0 und 1.0
zufallszahl2 = random.random()
# Zahl zwischen 1.5 und 9.5
zufallszahl3 = random.uniform(1.5, 9.5)
# aus Liste auswählen
farbe = ["Rot", "Grün", "Blau"]
zufallswert = random.choice(farbe)
print(zufallszahl1)
print(zufallszahl2)
print(zufallszahl3)
print(zufallswert)
Ausgabe, z.B.:
5
0.14147945849015753
6.894003397570905
Rot
Benötigt man mehrere Zufallszahlen, so ist das Modul <code>numpy</code> zu bevorzugen, z.B.:
* Normalverteilung: <code>np.random.normal(...)</code>
* Gleichverteilung: <code>np.random.uniform(...)</code>
== Histogramm ==
Zum Thema Histogramm siehe {{W|Histogramm}}.
Beispiel (mit Matplotlib):
import matplotlib.pyplot as plt
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
plt.hist(daten, bins=25, edgecolor='darkgray')
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm.svg|300px]]
Beispiel (mit Seaborn):
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
sns.set_theme(style="darkgrid")
sns.histplot(data=daten)
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm2.svg|300px]]
Das Kürzel <code>sns</code> ist Konvention und steht für die fiktive Figur '''S'''amuel '''N'''orman '''S'''eaborn aus der US-Fernsehserie {{W|The West Wing – Im Zentrum der Macht | The West Wing}}.
== Box-Plot ==
[[File:Elements of a boxplot.svg|400px]]
Siehe auch {{W|Box-Plot}}.
Beispiel (mit Seaborn erstellt):
import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("tips")
sns.boxplot(data=df, x="day", y="tip", hue="day", legend=False)
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot.svg|400px]]
Beispiel (mit Matplotlib erstellt):
import matplotlib.pyplot as plt
daten = [12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25]
plt.boxplot(daten, patch_artist=True)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot2.svg|300px]]
Um mehrere Box-Plots unterschiedlicher Farbe mit Matplotlib in einem Diagramm zu zeichnen, können Sie folgendermaßen vorgehen:
import matplotlib.pyplot as plt
daten = [[12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25],
[10, 19, 20, 21, 20, 30, 19, 40, 11, 17, 19, 21]]
farben = ["green", "blue"]
boxplot = plt.boxplot(daten, patch_artist=True)
for patch, farbe in zip(boxplot['boxes'], farben):
patch.set_facecolor(farbe)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
== Regressionsrechnung ==
Beispiel:
import numpy as np
import matplotlib.pyplot as plt
# Messpunkte
x = np.array([1, 3, 5, 6, 8, 10, 20])
y = np.array([3, 4, 5, 5, 7, 9, 11])
# Regressionskurve (Grad 1 = lineare Regression, 2 = Polynom-Regression 2. Gr.)
# y = kx + d
k, d = np.polyfit(x, y, deg=1)
# y = ax**2 + bx + c
a, b, c = np.polyfit(x, y, deg=2)
x_l = np.linspace(1, 20, 100)
y_p = a * x_l**2 + b * x_l + c
# Zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.plot(x, k*x + d, color='blue', label='Regressionsgerade')
plt.plot(x_l, y_p, color='red', label='Regressionspolynom 2. Gr.')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:IngMath_regression.svg|400px]]
== Korrelationsrechnung ==
Beispiel:
import pandas as pd
import matplotlib.pyplot as plt
# Messdaten
x = [1, 3, 4, 5, 6]
y = [2, 4, 6, 8, 5]
daten = {'X': x, 'Y': y}
df = pd.DataFrame(daten)
# Korrelation
korr = df['X'].corr(df['Y'])
print(f"Korrelationskoeff.: {korr}")
# Messpunkte zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
Korrelationskoeff.: 0.7556096518348252
[[Datei:IngMath_korrelation.svg|300px]]
== Mengen und Venn-Diagramme ==
Beispiel:
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
menge_a = {1, 2, 3, 4, 5, 6}
menge_b = {4, 5, 6, 7, 8}
vereinigung = menge_a | menge_b
schnitt = menge_a & menge_b
print("Vereinigungsmenge = ", vereinigung)
print("Schnittmenge = ", schnitt)
venn2([menge_a, menge_b], set_labels=('Menge A', 'Menge B'))
plt.show()
Ausgabe:
Vereinigungsmenge = {1, 2, 3, 4, 5, 6, 7, 8}
Schnittmenge = {4, 5, 6}
[[Datei:IngMath_venn.svg|300px]]
Siehe auch {{W|Mengendiagramm#Venn-Diagramme}}.
== Verteilungs- und Dichtefunktion ==
* CDF ... '''C'''umulative '''D'''istribution '''F'''unction, Verteilungsfunktion
* PDF ... '''P'''robability '''D'''ensity '''F'''unction, Dichtefunktion
Beispiel (Normalverteilung):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
my, sigma = 0, 1
x = np.linspace(-4, 4, 50)
pdf = norm.pdf(x, my, sigma)
cdf = norm.cdf(x, my, sigma)
plt.plot(x, pdf, lw=2, label="Dichtefunktion")
plt.plot(x, cdf, lw=2, label="Verteilungsfunktion")
plt.legend()
plt.grid()
plt.show()
Ausgabe:
[[Datei:IngMath_cdf_pdf.svg|300px]]
Beispiel (<math>\chi^2</math>-Verteilung):
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
x = np.linspace(0, 20, 500)
# df ... degree of freedom, Freiheitsgrad
pdf = (stats.chi2.pdf(x, df=2), stats.chi2.pdf(x, df=5), stats.chi2.pdf(x, df=10))
for i in range(0,3):
if(i==0):
lab = "Freiheitsgrad 2"
elif(i==1):
lab = "Freiheitsgrad 5"
else:
lab = "Freiheitsgrad 10"
plt.plot(x, pdf[i], label=lab, lw=2)
plt.grid()
plt.legend()
plt.show()
Ausgabe:
[[Datei:IngMath_chi2.svg | 300px]]
== Schätzen und Testen ==
=== Intervallschätzung ===
Als Beispiel seien Daten gegeben, die von ''Dürr, Mayer: Wahrscheinlichkeitsrechnung und Schließende Statistik; 7. Aufl., Hanser, 2014, Seite 137'' stammen. Und zwar soll das 95%-Vertrauensintervall für den Mittelwert des Kaloriengehalts (kcal/100g) von Hähnchen ermittelt werden. Wir wollen das mit Python inkl. NumPy und SciPy durchführen. Die Stichprobe ist groß (50 Hähnchen):
Python-Code:
import numpy as np
import scipy.stats as stats
# Stichprobe
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203]
# Parameter definieren
konfidenzniveau = 0.95
mean = np.mean(daten)
std = np.std(daten, ddof=1)
stdfehler = stats.sem(daten)
intervall = stats.norm.interval(confidence=konfidenzniveau, loc=mean, scale=stdfehler)
print(f"Mittelwert: {mean}")
print(f"Standardabweichung: {std}")
print(f"Konfidenzintervall: {intervall}")
Ausgabe:
Mittelwert: 215.48
Standardabweichung: 33.14238915925757
Konfidenzintervall: (np.float64(206.29356722321992), np.float64(224.66643277678006))
Diese Werte stimmen gerundet mit denen im genannten Buch überein. Zum Code selbst:
* sem steht für '''s'''tandard '''e'''rror of the '''m'''ean.
* <code>scipy.stats.norm</code> ... Modul für die Normalverteilung.
=== Punktschätzung ===
Gleiche Daten wie oben bei der Intervallschätzung.
Python-Code:
import numpy as np
from scipy import stats
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203
]
mu_hat, sigma_hat = stats.norm.fit(daten)
print(f"Schätzer für den Erwartungswert (μ): {mu_hat:.4f}")
print(f"Schätzer für die Standardabweichung (σ): {sigma_hat:.4f}")
Ausgabe:
Schätzer für den Erwartungswert (μ): 215.4800
Schätzer für die Standardabweichung (σ): 32.8093
=== Hypothesentests ===
Beispiel:
import numpy as np
import scipy.stats as stats
x_quer = 12.075 # Stichproben-Mittelwert
var = 0.069 # Stichproben-Varianz
n = 90 # Stichprobengröße
my_0 = 12.0 # Nullhypothese
alpha = 0.05 # Signifikanzniveau
z_stat = (x_quer - my_0) / np.sqrt(var / n)
p_val = 2 * (1 - stats.norm.cdf(np.abs(z_stat)))
print(f"Z-Statistik: {z_stat:.4f}")
if p_val < alpha:
print(f"p-Wert: {p_val:.6f} < alpha:", alpha)
print("Die Nullhypothese wird verworfen.")
else:
print(f"p-Wert: {p_val:.6f} > alpha:", alpha)
print("Die Nullhypothese wird nicht verworfen.")
Ausgabe:
Z-Statistik: 2.7087
p-Wert: 0.006755 < alpha: 0.05
Die Nullhypothese wird verworfen.
== Statistische Qualitätskontrolle ==
Beispiel (Mittelwertkarte):
import numpy as np
import matplotlib.pyplot as plt
# Gegeben
sollwert = 50.0
varianz = 4.0
stichproben_umfang = 1
daten = [49.5, 50.2, 53.0, 48.1, 52.6, 53.4, 49.8]
# Berechnung
standardabweichung = np.sqrt(varianz)
streuung = standardabweichung / np.sqrt(stichproben_umfang)
cl = sollwert
ucl = cl + 3 * streuung
lcl = cl - 3 * streuung
# Darstellung
plt.plot(daten, marker='o', linestyle='-', color='b', label='Messdaten')
plt.axhline(cl, color='green', linestyle='-', label=f'CL: {cl}')
plt.axhline(ucl, color='red', linestyle='--', label=f'UCL: {ucl:.2f}')
plt.axhline(lcl, color='red', linestyle='--', label=f'LCL: {lcl:.2f}')
plt.title('Mittelwertkarte')
plt.xlabel('Stichprobe')
plt.ylabel('Wert')
plt.legend(loc='lower left')
plt.grid(True)
plt.show()
Ausgabe:
[[Datei:IngMath_mittelwertkarte.svg|300px]]
Siehe auch {{W|Shewhart-Regelkarte}} und {{W|Qualitätsregelkarte}}.
* UCL ... '''U'''pper '''C'''ontrol '''Limit''', Obere Eingriffsgrenze
* LCL ... '''L'''ower '''C'''ontrol '''Limit''', Untere Eingriffsgrenze
* CL ... '''C'''enter '''L'''ine, Mittellinie
= Ein- und Ausgabe =
== print ==
Die Anweisung print haben wir schon oft verwendet. Hier soll anhand von Beispielen kurz beschrieben werden, was der Befehl print leisten kann.
print("Hallo", "Welt", 1, sep="-")
print("Hallo", end=" ")
print("Welt")
Ausgabe:
Hallo-Welt-1
Hallo Welt
== input ==
a = int(input("Zahl 1: "))
b = int(input("Zahl 2: "))
print("a + b = ", a+b)
Ausgabe (nach Eingabe der beiden Ganzzahlen):
Zahl 1: 4
Zahl 2: 5
a + b = 9
== Aus Dateien lesen ==
Es seinen die datei.txt
Hallo Welt.
Wie geht es dir?
...
und test1.py
dat = open("datei.txt", mode = "r")
print(dat.read())
dat.close()
Ausgabe
Hallo Welt.
Wie geht es dir?
...
Mit dem open()-Befehl wird die Datei datei.txt im Lesemodus geöffnet (r ... read). Mit dem read()-Befehl wird die Datei eingelesen und mittels print ausgegeben.
== In Dateien schreiben ==
dat = open("datei.txt", mode = "a", encoding = "utf-8")
dat.write("Hänge Zeile an\n")
dat.close()
Die Datei datei.txt sieht nach Abarbeitung des obigen Skripts nun so aus
Hallo Welt.
Wie geht es dir?
...
Hänge Zeile an
Es wird die Datei im Schreibmodus geöffnet (a ... append (anhängend), w ... write (überschreibend)).
write() fügt hier also eine Zeile Text am Dateiende ein. close() schließt die Datei wieder.
Das close() kann man sich mit der with-Anweisung auch sparen.
with open("datei.txt", mode="a", encoding="utf-8") as dat:
dat.write("Hänge Zeile an\n")
= Benutzeroberflächen erstellen =
== tkinter ==
{{Wikipedia | Tkinter}}
Python bietet standardmäßig das Modul tkinter zur Programmierung von Benutzeroberflächen. Es müssen also bei der Verwendung von tkinter keine externen Module installiert werden. Hier wird eine (sehr) kurze Einführung in das Erstellen von grafischen Oberflächen mittels tkinter gegeben.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
win.minsize(300, 50)
but = tk.Button(win, text = "Push the button")
but.pack()
win.mainloop()
Ausgabe:
[[Datei:PythonIng_gui1.jpg]]
Ein etwas komplizierteres Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
def on_button_clicked():
str = ent1.get() + ent2.get()
lab2["text"] = str
ent1 = tk.Entry(win)
ent2 = tk.Entry(win)
lab1 = tk.Label(win, text="verknuepfen mit")
lab2 = tk.Label(win, text="")
but = tk.Button(win, text = "=", command=on_button_clicked)
ent1.pack(side="left")
lab1.pack(side="left")
ent2.pack(side="left")
but.pack(side="left")
ent2.pack(side="left")
lab2.pack(side="left")
win.mainloop()
Ausgabe (vor der Eingabe der Teilstrings):
[[Datei:PythonIng_gui2.jpg]]
Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):
[[Datei:PythonIng_gui3.jpg]]
== curses ==
{{Wikipedia | curses}}
Mit dem curses-Modul lassen sich u.a. TUIs ('''T'''ext '''U'''ser '''I'''nterfaces) erstellen. Ein sehr einfaches Beispiel zur allgemeinen Funktionsweise wird nachstehend geliefert.
import curses
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
stdscr.clear()
stdscr.addstr("Hallo Welt", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.endwin()
Als Ausgabe sollte <span style="color:#FF0000;">Hallo Welt</span> (rote Schrift auf weißem Hintergrund) auf dem Terminal/der Konsole erscheinen. Getestet wurde dies mit openSUSE Tumbleweed, Python-Version 3.13.12. Das entsprechende Python-curses-Package muss installiert sein.
Allgemeine Informationen zur Terminal-/Konsolengröße und Cursorposition liefert folgendes Programm:
import curses
stdscr = curses.initscr()
stdscr.addstr(3, 5, "LINES: %d" % curses.LINES)
stdscr.addstr(4, 5, "COLS: %d" % curses.COLS)
(y,x) = stdscr.getyx()
stdscr.addstr(5, 5, "Momentane Cursorposition: [%d, %d]" % (y, x))
(y,x) = stdscr.getbegyx()
stdscr.addstr(6, 5, "Koordinatenursprung: [%d, %d]" % (y, x))
(y,x) = stdscr.getmaxyx()
stdscr.addstr(7, 5, "Fenstergröße: [%d, %d]" % (y, x))
stdscr.addstr(11, 2, "Taste drücken -> Ende")
stdscr.refresh()
stdscr.getch()
curses.endwin()
Es sollte sich in etwa folgende Ausgabe ergeben:
LINES: 44
COLS: 110
Momentane Cursorposition: [4, 15]
Koordinatenursprung: [0, 0]
Fenstergröße: [44, 110]
Taste drücken -> Ende
Zur Funktionsweise von curses siehe auch das Wikibook [[ncurses]]. Zum Verständnis sind dort allerdings elementare Kenntnisse in der Programmiersprache C erforderlich.
== Qt ==
{{Wikipedia | Qt (Bibliothek)}}
Auch für das Qt-Framework gibt es eine Anbindung an Python. Nachfolgend ein einfaches Beispiel.
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hallo Welt!")
label.show()
sys.exit(app.exec())
Ausgabe:
[[Datei:PythonIng_gui10.png]]
== Gtk ==
{{Wikipedia | GTK (Programmbibliothek)}}
Eine idente Ausgabe, wie oben für Qt gezeigt, erzeugt z.B. folgendes Gtk-Programm:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
lab = Gtk.Label(label="Hallo Welt!")
win.set_child(lab)
win.present()
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
Auch für die Benutzung von Qt und Gtk müssen die jeweiligen Packages installiert sein. Getestet wurden die entsprechenden Python-Programme nur unter openSUSE Tumbleweed. Wie das GTK-Paket unter MS Windows 11 installiert wird, siehe z.B. [https://www.gtk.org/docs/installations/windows Setting up GTK for Windows].
Damit sei aber das Thema "Benutzeroberflächen erstellen" hier abgeschlossen, da dies schon ein sehr spezielles Aufgabengebiet ist, das eher Informatiker und nicht so sehr Ingenieure anspricht. Bei Bedarf siehe aber ggf. die entsprechenden Links unten in diesem Tutorial. Dort sind weiterführende Informationen zu finden.
= Pandas kurz erklärt =
Hier wird kurz auf das externe Modul Pandas eingegangen. Pandas steht für '''Pan'''el '''Da'''ta und ist ein Modul für die Datenanalyse und -manipulation.
== Series ==
Vorstellbar ist eine "Series" wie eine einzelne Spalte in einem Tabellenkalkulationsprogramm.
Beispiel (Index implizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5]) # Temperaturwerte
print(temp)
Ausgabe:
0 8.5
1 11.0
2 12.5
3 10.0
4 13.0
5 11.0
6 14.5
dtype: float64
Das Kürzel <code>pd</code> ist Konvention. Es seien Temperaturwerte gegeben. Die erste Spalte bei der Ausgabe ist der Index. Die zweite Spalte enthält die Werte.
Beispiel (separater Zugriff auf den Index und auf die Werte):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5])
print(temp.index)
print(temp.values)
Ausgabe:
RangeIndex(start=0, stop=7, step=1)
[ 8.5 11. 12.5 10. 13. 11. 14.5]
Beispiel (Index explizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
print("*** Die gesamte Series ***")
print(temp)
print("*** Temperatur am Donnerstag ***")
print(temp["Do"])
print("*** Tage wärmer als 12 Grad ***")
temp_gr_12 = temp[temp > 12]
print(temp_gr_12)
Ausgabe:
*** Die gesamte Series ***
Mo 8.5
Di 11.0
Mi 12.5
Do 10.0
Fr 13.0
Sa 11.0
So 14.5
dtype: float64
*** Temperatur am Donnerstag ***
10.0
*** Tage wärmer als 12 Grad ***
Mi 12.5
Fr 13.0
So 14.5
dtype: float64
== DataFrame ==
Ein DataFrame entspricht einer Tabelle.
Beispiel (Erzeugen eines DataFrames):
import pandas as pd
tag = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
v1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=tag)
v2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=tag)
v3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=tag)
tab = pd.concat([v1, v2, v3], axis=1)
tab.columns = stadt
print(tab)
print(type(tab))
Ausgabe:
Linz Salzburg Innsbruck
Mo 1 8 Hallo
Di 2 9 16
Mi 3 10 17
Do 4 11 18
Fr 5 12 19
Sa 6 13 20
So 7 14 21
<class 'pandas.core.frame.DataFrame'>
Wir haben hier drei Datenspalten (v1, v2, v3) mit den Spaltennamen "Linz", "Salzburg" und "Innsbruck", sowie sieben Zeilen "Mo" bis "So".
Beispiel (Zugriff auf eine Spalte):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab["Salzburg"])
Ausgabe:
Mo 8
Di 9
Mi 10
Do 11
Fr 12
Sa 13
So 14
Name: Salzburg, dtype: int64
Beispiel (Zugriff auf eine Zeile):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab.loc["Di"])
Ausgabe:
Linz 2
Salzburg 9
Innsbruck 16
Name: Di, dtype: object
== Grafiken erstellen ==
Hier sei nur ein Torten- oder Kreisdiagramm gezeichnet:
import pandas as pd
import matplotlib.pyplot as plt
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
expl = [0, 0.2, 0, 0, 0, 0, 0]
temp.plot.pie(figsize=(5,5), explode=expl)
plt.show()
Ausgabe:
[[Datei:IngPython_pandas1.svg|350px]]
Die <code>figsize</code> hat nichts mit der Spaltenanzahl zu tun, sondern setzt die Fenster- oder Diagrammgröße in Inches (Breite * Höhe).
Mit Pandas kann man auch noch andere Diagrammarten erstellen, z.B. Linien- oder Balkendiagramme. Dies wird hier aber nicht vorgeführt.
== Arbeiten mit CSV- und LibreOffice-Dateien ==
Gegeben sei eine CSV-Datei test1.csv:
Mai;Juni;Juli
12;17;45
15;65;65
16;32;23
4;14;7
23;17;Keine Daten verfügbar
67;Keine Daten verfügbar;45
15;24;12
Lesen von dieser CSV-Datei:
import pandas as pd
tab = pd.read_csv("test1.csv", sep=";")
print(tab)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Schreiben in eine CSV-Datei test2.csv:
import pandas as pd
val = pd.read_csv("test1.csv", sep=";")
val.to_csv("test2.csv", index=False)
Ausgabedatei:
Mai,Juni,Juli
12,17,45
15,65,65
16,32,23
4,14,7
23,17,Keine Daten verfügbar
67,Keine Daten verfügbar,45
15,24,12
Die Ausgabedatei ist beinahe gleich wie die Eingabedatei. Es werden aber Kommas statt Strichpunkten verwendet. Daher kommt auch der Name CSV ('''C'''omma '''S'''eparated '''V'''alue). Will man wieder Strichpunkte, so kann man dies über den Parameter <code>sep=";"</code> in der <code>to_csv</code>-Funktion machen.
Um direkt von einer ODS-Datei (LibreOffice Calc, '''O'''pen '''D'''ocument '''S'''preadsheet) zu lesen muss das Modul odfpy extra installiert sein (per YaST, pip etc.). Gelesen wird dann folgendermaßen:
import pandas as pd
df = pd.read_excel('test1.ods', engine='odf')
print(df)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Die Datei "test1.ods" sei die Datei, aus der das obige "test1.csv" generiert wurde. Schreiben kann man ebenfalls in eine ODS-Datei:
import pandas as pd
daten = {
"Name": ["Hugo", "Richie", "Wilhelmine"],
"Alter": [38, 30, 29],
"Ort": ["Linz", "Innsbruck", "Salzburg"]
}
tab = pd.DataFrame(daten)
with pd.ExcelWriter("test2.ods", engine="odf") as writer:
tab.to_excel(writer, sheet_name="Daten", index=False)
Es ergibt sich eine "test2.ods"-Datei (Screenshot):
[[Datei:IngPython_pandas2.png|250px]]
== Sonstiges ==
Hier seien stichpunktartig einige weitere Features von Pandas angeführt:
* {{W|Pivot-Tabelle|Pivot-Tabellen}} (pivot ... Dreh-, Angelpunkt): Zweck - große Datenmengen schnell zusammenfassen, filtern und analysieren.
* NaN ('''n'''ot '''a''' '''n'''umber): In einem Datensatz fehlt ein Wert oder ist nicht definiert.
* groupby-Funktion: Daten strukturieren, aggregieren oder Zwischensummen bilden.
* {{W|Binning#Datenverarbeitung_und_-analyse|Binning}}: Klassenbildung.
* Mehrstufige Indizierung (Hierarchical Indexing oder MultiIndex)
* Zeitreihen (Time Series)
Für tiefergehende und weiterführende Informationen wird auf das Buch von ''Klein: Numerisches Python; Hanser, 2023'' und [https://pandas.pydata.org/ pandas] verwiesen.
= Style Guide, flake8, pylint, Black etc. =
== Style Guide ==
Wie man schönen und richtigen Python-Code schreibt, erfahren Sie in
* [https://peps.python.org/pep-0008/ PEP 8 – Style Guide for Python Code]
== Formatter und Linter ==
Ein Modul, das prüft, ob die Richtlinien im Style Guide eingehalten wurden, ist ''flake8'':
* [https://flake8.pycqa.org/en/latest/ Flake8: Your Tool For Style Guide Enforcement]
Code formatieren kann man auch mit [https://pypi.org/project/black/ Black]. Z.B. übersetzt <code>black test1.py</code> die Datei <code>test1.py</code>
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)),
(2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
in
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)), (2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Die Programmausgabe ist
reformatted test1.py
All done! ✨ 🍰 ✨
1 file reformatted.
Der Unterschied zwischen Black und Flake8:
* Black ist ein Code-Formatter. Er formatiert Ihren Code um, sodass er im Einklang mit PEP 8 steht.
* Flake8 ist ein {{W|Lint (Programmierwerkzeug) | Code-Linter}}. Flake8 verändert Ihren Code nicht, sondern durchsucht ihn nach potenziellen Fehlern etc.
Am obigen Beispiel sieht man auch, dass flake8 und Black nicht immer einer Meinung sind. Flake8 (<code>flake8 test1.py</code>) würde standardmäßig den mit Black formatierten Code bemängeln:
test1.py:8:80: E501 line too long (80 > 79 characters)
Diese Diskrepanz kann beseitigt werden. Da 79 Zeichen auf modernen Bildschirmen meist als zu kurz empfunden werden, ist ein Limit von 88 Zeichen (Black-Standard) oder mehr empfehlenswert. Um dies zu implementieren, erstellen Sie in Ihrem Projektverzeichnis eine <code>.flake8</code>-Datei mit dem Inhalt
[flake8]
max-line-length = 88
Und schon ignoriert Flake8 dieses Problem.
Ein anderer Linter ist pylint. Der würde beim Abarbeiten des obigen Beispiels, z.B. mit <code>pylint test1.py</code> noch eine Kleinigkeit bemängeln:
************* Module test1
/home/hr/tmp/test1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)
Auch pylint muss vor der ersten Verwendung installiert werden (z.B. mittels pip, virtuelle Umgebung, YaST). Die Dokumentation zu pylint findet sich auf [https://pylint.readthedocs.io/en/latest/].
<u>Aufgabe:</u> Fügen Sie einen "module docstring" in die <code>test1.py</code>-Datei ein und testen Sie erneut mit flake8, Black und pylint. <small>Sehen Sie zum Thema docstrings auch [https://peps.python.org/pep-0257/#what-is-a-docstring PEP 257 – Docstring Conventions].</small>
Es gibt noch weitere Formatierungswerkzeuge für Python-Code. Z.B. [https://docs.astral.sh/ruff/ Ruff], ein moderner Code-Formatter und -Linter. Mittels <code>ruff check test1.py</code> würde obiger Code geprüft (Linter). <code>ruff format test1.py</code> formatiert den Code (Formatter).
== Type Checker ==
"Type Checker" sind z.B.
* mypy
* pyright
* ty
Diese prüfen die Datentypen, z.B. in folgendem Code
def greetings(name: str) -> str:
return "Hello, %s" % name
print(greetings(42))
Python selbst, flake8, ruff oder black würden diesen Code ohne zu murren akzeptieren. "Type Checker" würden aber sehr wohl Alarm schlagen, z.B. liefert <code>mypy</code> folgende Ausgabe
test1.py:5: error: Argument 1 to "greetings" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Das funktioniert übrigens nicht nur bei Funktionsannotationen, sondern auch mit Variablen etc.
from typing import Final
# "Konstante", ab Python 3.8
NUMBER: Final = 123
print(NUMBER)
NUMBER = 125
print(NUMBER)
# Variable
a: int = 345
print(a)
a = "Irgendwas"
print(a)
# Variable (Pipe-Symbol), ab Python 3.10
b : int|str = 567
print(b)
b = "sonstiges"
print(b)
Ausgabe mit python:
123
125
345
Irgendwas
567
sonstiges
Ausgabe mit mypy:
test3.py:6: error: Cannot assign to final name "NUMBER" [misc]
test3.py:12: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
Found 2 errors in 1 file (checked 1 source file)
Python kennt übrigens keine Konstanten. Man kann diese mittels Großbuchstaben andeuten. Das ist aber nur Konvention, hat aber keine sonstigen Auswirkungen. Oder man verwendet wie oben gezeigt <code>Final</code>. Dann werfen Typchecker Errors aus.
==pydoc==
pydoc ist ein Werkzeug, um Python-Module, -Funktionen und -Klassen zu dokumentieren.
Beispiel <code>test1.py</code>:
"""Rechen-Modul.
Funktionen die von pydoc gelesen werden.
"""
def multiply(a, b):
"""Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a * b
def add(a, b):
"""Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a + b
if __name__ == '__main__':
print(multiply(3, 5))
print(add(4, 6))
Ausgabe mit <code>python3.13 -m pydoc test1</code> auf der Konsole:
Help on module test1:
NAME
test1 - Rechen-Modul.
DESCRIPTION
Funktionen die von pydoc gelesen werden.
FUNCTIONS
add(a, b)
Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
multiply(a, b)
Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
FILE
/home/xyz/tmp/test1.py
Siehe zu diesem Thema z.B. auch [https://docs.python.org/3/library/pydoc.html]. Mittels <code>python3.13 -m pydoc -w test1</code> kann man auch eine HTML-Dokumentation erstellen.
Wofür <code>if __name__ == '__main__':</code> steht, siehe z.B. etwas später im Abschnitt [[Ing_Mathematik:_Python#Doctests]].
== Sonstige Tools ==
Andere Tools für die {{W|Statische Code-Analyse|statische Codeanalyse}}, die aber für Ingenieure weniger interessant sein dürften, sind z.B.
* Radon: Liefert verschiedene {{W|Softwaremetrik|Codemetriken}} (Komplexität, Wartbarkeitsindex ...)
* Bandit: Findet Sicherheitslücken
Tools für die {{W|Dynamisches Software-Testverfahren|dynamische Codeanalyse}}, z.B.:
* DynaPyt (Framework zur dynamischen Programmanalyse)
* cProfile (Profiler)
* Memory Profiler (Speicheranalyse)
* Memray (Speicheranalyse)
* tracemalloc (Speicheranalyse)
Paket- und Projektmanagement (pip-Ersatz etc.):
* uv
* Poetry
* Conda
* pipx
Packaging-Tools (Freezer) und {{W|Compiler#Sonderformen|Transpiler}} :
* pyinstaller
** erstellt eigenständige, ausführbare Binärdatei
** kein Cross-Compiler
** kein Schutz vor Reverse-Engineering
** langsam
** packt alles in eine Datei
** sehr große Datei
** Befehl, z.B.: <code>pyinstaller --onefile test1.py</code>
** GUI: <code>auto-py-to-exe</code>
* cx_Freeze
* nuitka
** Übersetzt Python-Code in C/C++-Code und weiter in eine ausführbare Datei
** kein Cross-Compiler
** Schutz vor Reverse-Engineering
** Befehl, z.B.: <code>nuitka --standalone --onefile test1.py</code>
* cython
= Einige Integrierte Entwicklungsumgebungen (IDEs)=
Werden Programmtexte größer und umfangreicher, so ist das Arbeiten mit der interaktiven Programmierumgebung bzw. das direkte Ausführen von Python-Skripten mühsam. Man wünscht sich z.B. Hilfen zum Debuggen oder die automatische Code-Vervollständigung. Zu diesem Zweck wurden IDEs (Integrated Development Environments) geschaffen. Von diesen seinen nachfolgend auszugsweise einige kurz beschrieben. Testen Sie einfach aus, welche davon für Sie bzw. für Ihr Python-Projekt geeignet sind.
== IDLE ==
IDLE ist die mit dem Python-Programmpaket mitgelieferte IDE. Der Name leitet sich einerseits ab vom Monty-Python-Mitglied Eric Idle, andererseits steht es als Abkürzung für "'''I'''ntegrated '''D'''evelopment and '''L'''earning '''E'''nvironment. IDLE ist einfach zu bedienen, bietet aber schon einen beachtlichen Leistungsumfang. Nachfolgend wird ein Screenshot zu IDLE geliefert. Rechts ist das Editor-Fenster zu sehen, links die interaktive Programmierumgebung. Um das Beispiel selbst nachvollziehen zu können, starten Sie IDLE. Das geht ähnlich, wie Sie die interaktive Programmierumgebung von Python starten (nur, dass Sie eben das IDLE-Icon doppelklicken und nicht das Python-Icon. Unter Linux geben Sie einfach in einem Terminal <code>idle3.13</code> o. Ä. ein). Weiter geht es mit "File - Open - ...". Die auszuführende Datei auswählen (im konkreten Fall ein "Hallo-Welt"-Programm). Es erscheint das rechte Fenster. Dort "Run - Run Module" auswählen. Und schon wird im linken Fenster "Hallo Welt!" ausgegeben.
[[Datei:PythonIng_idle1.jpg | 600px]]
Siehe auch {{W|IDLE}}.
== PyCharm ==
PyCharm ist ein kommerzielles Produkt. Es gab aber auch eine kostenlose Community Edition. Seit 2025 sind beide Varianten vereint. Für die ersten 30 Tage sind die Pro-Funktionen frei verfügbar, danach nur noch die Kernfunktionalitäten (oder man bezieht kostenpflichtig die Pro-Version). Zu beziehen ist PyCharm unter dem Weblink [https://www.jetbrains.com/pycharm/]. Nachfolgend ein etwas abgewandeltes "Hallo Welt"-Programm, editiert und ausgeführt mit PyCharm.
[[Datei:PyCharm_IDE_2023_screenshot.png | 600px]]
Siehe auch {{W|PyCharm}}.
== Eric ==
Auch eric ist Open Source und steht unter der GNU General Public License Version 3 oder später. Zu beziehen ist diese Software unter [https://eric-ide.python-projects.org/].
[[Datei:Screenshot_Eric_4.png | 600px]]
Siehe auch {{W|eric (Software)}}.
<small>
Unter openSUSE Tumbleweed sollte sich eric auch mit YaST installieren lassen. Bei mir gibt es aber dann beim Ausführen des eric-Programms eine Fehlermeldung (Stand März 2026):
...
ModuleNotFoundError: No module named 'PyQt6.QtPdfWidgets'
Umgehen kann man dieses Problem aber wieder mit dem Erstellen einer virtuellen Umgebung, in etwa so
python3.13 -m venv ~/tmp/venv1
cd ~/tmp/venv1/bin
./python3.13 -m pip install --upgrade --prefer-binary eric-ide
./eric7_ide
</small>
== PyScripter ==
Vom Funktionsumfang vergleichbar mit den vorherigen IDEs ist PyScripter. Auch PyScripter ist Open Source. Die Projekt-Homepage findet sich auf [https://sourceforge.net/projects/pyscripter/]. PyScripter ist nur für MS Windows verfügbar.
[[Datei:PythonIng_pyscripter1.jpg | 600px]]
== Spyder IDE ==
Spyder enthält bereits eine stabile Python-Version und etliche Module (z.B. matplotlib, numpy, control). Ansonsten kann dieses Softwarepaket vom Funktionsumfang her mit den anderen genannten IDEs locker mithalten. Spyder wurde unter der MIT-Lizenz veröffentlicht. Diese Software findet sich auf [https://www.spyder-ide.org].
[[Datei:Spyder-windows-screenshot.png | 600px]]
Siehe auch {{W|Spyder (Software)}}
== Eclipse IDE==
Die {{W|Eclipse_(IDE)|Eclipse-IDE}} kann für Python aufgerüstet werden. Dazu gibt es das PyDev-Plugin. Installiert wird es über
* Help > Eclipse Marketplace...
* Find - PyDev - Install
Danach muss noch der Pfad zum Python-Interpreter festgelegt werden
* Window > Preferences > PyDev > Interpreters > Python Interpreter > New ...
Das Ergebnis ist ähnlich wie im folgenden Bild, nur dass statt C/C++ Python Verwendung findet.
[[Datei:Setting Up Eclipse CDT helloout.png | 600px]]
== Sonstige ==
Die genannten IDEs sind nicht die Einzigen. Es gibt, um dem Image Pythons als beliebteste Programmiersprache gerecht zu werden, noch einige andere. Sowohl Open Source-Programme als auch kommerzielle Programme sind im Web zu finden, z.B. Thonny oder {{W|Visual Studio Code}}. Unter Linux kann man auch {{W|KDevelop}}, ausgestattet mit dem Python3-Plugin, einsetzen. Braucht man den Umfang von ausgewachsenen IDEs nicht, so kann man auch normale Texteditoren verwenden (z.B. {{W|Geany}} oder {{W|Kate_(Texteditor)|Kate}}).
= Debuggen und Testen =
Das Debuggen und Testen von Programmen sind wichtige Bestandteile der Programmierung. Syntaxfehler lassen sich i.A. leicht beheben. Schwieriger ist das Eingrenzen von logischen Fehlern, die ev. nur in bestimmten Situationen auftreten und keine explizite Fehlermeldung hervorrufen. Das Programm liefert falsche Ergebnisse oder es stürzt aus heiterem Himmel ab. Um das zu verhindern gibt es verschiedene Werkzeuge, die bei der Fehlersuche behilflich sein können. Vorerst siehe aber zwecks Begriffsklärung noch folgende Links:
* {{W|Debuggen}}
* {{W|Debugger}}
* {{W|Softwaretest}}
<gallery>
First Computer Bug, 1947.jpg
Test ganzheitlich.png
V-Modell.svg
</gallery>
== Das Modul pdb ==
Python bringt schon ein Modul zum Debuggen mit. Siehe z.B. [https://docs.python.org/3/library/pdb.html pdb — The Python Debugger].
Komfortabler lässt sich das aber mittels Integrierter Entwicklungsumgebungen (IDEs) angehen.
== Debuggen mit IDEs ==
Für die IDEs IDLE und Spyder sei kurz auf die entsprechenden Webseiten verwiesen:
* [https://www.cs.uky.edu/~keen/help/debug-tutorial/debug.html Debugging under IDLE].
* [https://docs.spyder-ide.org/current/panes/debugging.html Spyder Debugger]
Dort wird die Vorgehensweise auch mittels Screenshots erläutert.
== assert ==
assert ... behaupten, zusichern ({{W|Assertion (Informatik)}})
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10., 0.)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10., 0.)
File "/home/hr/Develop/test1.py", line 4, in print1
assert y != 0.0
^^^^^^^^
AssertionError
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1("10.", "5.")
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Aber auch bei nachfolgendem Code gibt es eine Fehlermeldung:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10, 5)
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Damit letzteres funktioniert, kann man den Programmcode so umschreiben:
def print1(x, y):
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
2.0
Und jetzt fangen wir den <code>AssertionError</code> auf:
def print1(x, y):
try:
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
except(AssertionError):
print("Hallo")
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Hallo
Ich hoffe, es ist wenigstens im Ansatz klar geworden, wofür <code>assert</code> gut sein kann. Ausschalten kann man die <code>assert</code>-Überprüfung übrigens mit dem Python-Schalter <code>-O</code>.
== Doctests ==
Innerhalb eines Docstrings kann die Arbeit im interaktiven Modus simuliert werden. Nach den Promptzeichen (>>>) erfolgen dann bei unserem Beispiel innerhalb des Docstrings simulierte Aufrufe der Funktion <code>print1()</code>. Danach folgen jeweils die Sollresultate. Wird das Modul oder die Datei als Hauptprogramm aufgerufen, so wird die Funktion <code>doctest.testmode()</code> aufgerufen und ein Bericht auf der Konsole ausgegeben. Wird das Modul nicht als Hauptprogramm aufgerufen, sondern importiert, dann wird diese <code>testmod</code>-Funktion nicht aufgerufen. D.h. dieser Code kann sowohl für Testzwecke als auch für den produktiven Einsatz verwendet werden. Das ist auch sinnvoll, weil wenn man Teile der Datei immer löschen bzw. einfügen müsste, so würden sich Fehlerquellen auftun. Das würde den Sinn und Zweck von Doctests konterkarieren.
def print1(x=0., y=1.):
""" Dividiere zwei Zahlen
Autor: Intruder
Datum: 12.08.2025
>>> print1(2., 1.)
2.0
>>> print1(5., 2.)
2.5
>>> print1(5.)
5.0
"""
print(x/y)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Ausgabe:
Trying:
print1(2., 1.)
Expecting:
2.0
ok
Trying:
print1(5., 2)
Expecting:
2.5
ok
Trying:
print1(5.)
Expecting:
5.0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.print1
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Das gezeigte Beispiel ist so ziemlich das einfachste, das es gibt. Für weiterführende Details siehe z.B.:
* [https://peps.python.org/pep-0257/ PEP 257 – Docstring Conventions]
* [https://docs.python.org/3/library/doctest.html doctest — Test interactive Python examples]
''Einschub:'' Ganz ähnlich kann man auch Klassen testen, z.B. in folgendem Code-Fragment
class Fahrzeug:
# siehe Abschnitt "Objektorientierte Programmierung"
# ...
if __name__ == "__main__":
vauweh = Fahrzeug(170, 90)
beemweh = Fahrzeug(200, 120)
print(vauweh.convertGeschw())
print(beemweh.convertGeschw())
Wird das Script als Hauptprogramm ausgeführt (z.B. zu Testzwecken), so erfolgt die Ausgabe der zwei, via <code>convertGeschw()</code>, umgerechneten Geschwindigkeiten. Wird es aber als Modul eingebunden, so wird der letzte Programmabschnitt nicht ausgeführt (<code>__name__ == "__main__"</code> ergibt <code>False</code>).
== pytest ==
Siehe zu diesem Thema auch {{W|Modultest}}.
pytest ist ein externes Modul und muss vorab installiert werden, z.B. mittels
pip install -U pytest
pip install -U pytest-html
Python-Code, Datei test1.py:
def add(x, y):
return x + y
def test_answer():
assert add(1, 1) == 3
Starten von pytest in der Konsole:
pytest test1.py
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py F [100%]
========================================================= FAILURES ==========================================================
________________________________________________________ test_answer ________________________________________________________
def test_answer():
> assert add(1, 1) == 3
E assert 2 == 3
E + where 2 = add(1, 1)
test1.py:6: AssertionError
================================================== short test summary info ==================================================
FAILED test1.py::test_answer - assert 2 == 3
===================================================== 1 failed in 0.09s =====================================================
Hier erhalten wir einen Fehler, da 1+1 eindeutig ungleich 3 ist. Aber aus irgendeinem Grund wollte der Programmierer oder Tester in diesem Fall, dass dies so ist. Testfälle werden übrigens mit dem Präfix <code>test_</code> eingeleitet.
Python-Code:
def add(x, y):
return x + y + 1
def test_answer():
assert add(1, 1) == 3
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py . [100%]
===================================================== 1 passed in 0.01s =====================================================
Jetzt ist alles in Ordnung. Weiterführendes siehe z.B.
* [https://docs.pytest.org/en/stable/ pytest: helps you write better programs]
== unittest ==
Auch unittest dient zur Durchführung von Testreihen, ist aber Bestandteil von Python. Hier wird vorerst nicht näher darauf eingegangen. Siehe z.B.
* [https://docs.python.org/3/library/unittest.html unittest — Unit testing framework]
Lt. ''Inden: Python Challenge; dpunkt, 2021, Seite 481'' soll unittest weniger komfortabel als pytest sein.
Einen Vergleich von unittest mit pytest findet man in
* [https://knapsackpro.com/testing_frameworks/difference_between/pytest/vs/unittest pytest vs unittest]
= Python und Anwendungsprogramme =
Bisher stand immer alleine die Programmiersprache Python (ev. unter Einbeziehung von Modulen) im Mittelpunkt der Betrachtungen. Aber Python kann auch als Makrosprache für Anwendungsprogramme auftreten. Als Beispiele seien {{W|FreeCAD}} und {{W|LibreOffice}} genannt.
== FreeCAD ==
FreeCAD ist ein freies 3D-CAD-Programm. Hier soll nicht auf die Bedienung dieses CAD-Pakets eingegangen werden, sondern nur auf die Möglichkeit, mittels Python Makros zu schreiben. Als einfacher Einstieg soll ein Makro erstellt werden, welches eine Kugel (rot) und einen Quader (blau) zeichnet. Folgende Vorbereitungsschritte sind erforderlich (es sei vorausgesetzt, dass FreeCAD schon am Rechner installiert ist. Downloaden können Sie das Programm von der Website [https://www.freecad.org/downloads.php?lang=en]):
* FreeCAD starten
* Leere Datei erstellen
* Makro > Makros > Erstellen ...
Es öffnet sich ein leeres Editorfenster, in das Sie folgenden Code eingeben können:
import FreeCAD
import Part
doc = FreeCAD.newDocument()
# Kugel
kugel = Part.makeSphere(10)
form_element = doc.addObject("Part::Feature", "Kugel")
form_element.Shape = kugel
kug = FreeCAD.ActiveDocument.getObject("Kugel")
kug.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
neuePosition = App.Vector(5, 2.5, 2.5)
kug.Placement = App.Placement(neuePosition, kug.Placement.Rotation)
# Quader
quader = Part.makeBox(5, 5, 50)
form_element = doc.addObject("Part::Feature", "Quader")
form_element.Shape = quader
quad = FreeCAD.ActiveDocument.getObject("Quader")
quad.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
doc.recompute()
Diesen Code können Sie nun ausführen:
* Makro > Makro ausführen
Es ergibt sich folgende Ausgabe (gedreht und gezoomt):
[[Datei: PythonIng_freecad1.png|500px]]
Siehe auch [https://wiki.freecad.org/Python_scripting_tutorial/de# Anleitung Skripterstellung mit Python]. Getestet wurde obiges Beispiel mit FreeCAD 1.1.3 unter Linux und 1.1.1 unter MS Windows.
== LibreOffice ==
LibreOffice ist ein freies Officepaket ([https://de.libreoffice.org/]). Hier soll nur das Tabellenkalkulationsprogramm Calc kurz betrachtet werden. Es seinen in den ersten 3 Zellen (A1 bis A3) Zahlen gegeben. Diese sollen mit einem Python-Makro addiert und das Resultat in der Zelle A5 ausgegeben werden. Auch hier sind Vorbereitungsarbeiten nötig:
* zuerst muss unter Linux das Verzeichnis <code>~/.config/libreoffice/4/user/Scripts/python</code> erstellt werden
* für MS Windows ist es das Verzeichnis <code>%APPDATA%\LibreOffice\4\user\Scripts\python</code>
** drücken Sie zuerst Win + R (es öffnet sich das Ausführen-Fenster)
** geben Sie <code>%appdata%</code> ein, danach drücken Sie Enter (es öffnet sich der Explorer)
** navigieren Sie zu dem genannten Verzeichnis bzw. erstellen Sie das Verzeichnis
* in diesem Verzeichnis wird dann mit einem beliebigen Texteditor das Python-Makro erstellt, in unserem Fall die Datei <code>summiere_zellen.py</code>:
import uno
def summiere_zellen(*args):
# Zugriff auf das aktuelle Dokument und das aktive Tabellenblatt
ctx = uno.getComponentContext()
smgr = ctx.getServiceManager()
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.getCurrentController().getActiveSheet()
# Werte aus den Zellen A1 bis A3 auslesen
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
# Addition der drei Werte
summe = w1 + w2 + w3
# Ergebnis in die Zelle A5 schreiben
sheet.getCellRangeByName("A5").Value = summe
* siehe dazu ggf. auch [https://help.libreoffice.org/latest/de/text/sbasic/python/python_locations.html?DbPAR=BASIC].
Weiter geht es in LibreOffice Calc mit dem Menü ''Extras > Makros > Makros verwalten > Python''. Dort wird das Makro <code>summiere_zellen</code> ausgeführt. Es ergibt sich z.B. folgendes Resultat
[[Datei:PythonIng_libreoffice1.png]]
Das Kürzel <code>uno</code> steht für '''U'''niversal '''N'''etwork '''O'''bjects. Etwas einfacher geht's auch so:
def summiere_zellen():
desktop = XSCRIPTCONTEXT.getDesktop()
model = desktop.getCurrentComponent()
sheets = model.getSheets()
sheet = sheets.getByIndex(0)
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
cell = sheet.getCellRangeByName("A5")
cell.setValue(w1 + w2 + w3)
Empfohlen wird auch, das Erweiterungspaket APSO ('''A'''lternative '''P'''ython '''S'''cript '''O'''rganizer, apso.oxt) zu installieren. Die Vorgehensweise wird hier nicht gezeigt, sondern nur darauf hingewiesen, dass man das einfach "googeln" kann. Siehe zur Python-Programmierung für LibreOffice auch [https://wiki.documentfoundation.org/Macros/Python_Guide/de Makros/Python-Handbuch]. Getestet wurden obige Beispiele mit LibreOffice 26.2.5.1 unter Linux und 26.2.1.2 unter MS Windows.
= Ausblick =
Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Python. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks, Bücher und die Python-Hilfefunktion verwiesen. Python kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Module fast beliebig erweiterbar.
= Weblinks=
== Python allgemein ==
* [https://www.python.org/ Python Homepage]
== Externe mathematische Module ==
* [https://numpy.org/ NumPy]
* [https://numpy.org/doc/stable/user/numpy-for-matlab-users.html NumPy for MATLAB users]
* [https://scipy.org/ SciPy]
* [https://www.sympy.org/en/index.html SymPy]
* [https://pandas.pydata.org/ pandas]
* [https://github.com/maroba/findiff findiff]
* [https://mpmath.org/ mpmath]
== Externe Module für Grafiken ==
* [https://matplotlib.org/ Matplotlib]
* [https://vpython.org/ VPython]
* [https://build123d.readthedocs.io/en/latest/ build123d]
* [https://docs.vtk.org/en/latest/api/python.html VTK]
* [https://docs.bokeh.org/en/latest/docs/first_steps.html bokeh]
* [https://py5coding.org/ py5]
== Erstellung von User Interfaces ==
* [https://docs.python.org/3/library/tkinter.html tkinter - Python interface to Tcl/Tk]
* [https://docs.python.org/3/library/curses.html curses - Terminal handling for character-cell displays]
* [https://wiki.qt.io/Qt_for_Python Qt for Python]
* [https://www.gtk.org/docs/language-bindings/python GTK and Python]
== Erstellen virtueller Umgebungen ==
* [https://docs.python.org/3/library/venv.html venv - Creation of virtual environments]
== Sonstige ==
* [https://python-control.readthedocs.io/en/stable/ Python Control Systems Library]
* [https://pypi.org/project/regex/ regex - Regular Expressions]
* [http://pyromat.org/ PYroMat]
* [https://coolprop.org/coolprop/wrappers/Python/index.html CoolProp]
* [https://pypi.org/project/iapws/ iapws]
* [https://tespy.readthedocs.io/en/main/getting_started/introduction.html TESPy - Thermal Engineering Systems in Python]
* [https://pint.readthedocs.io/en/stable/ pint]
= Bücher =
== Gedruckte Bücher, OpenBooks, Magazine ==
* Diverse: c't Python Lernen, Verstehen, Anwenden; Heise, 2022
* Ernesti, Kaiser: Python3 - das umfassende Handbuch; 5. Aufl., Rheinwerk, [https://openbook.rheinwerk-verlag.de/python/ OpenBook]
* Iacono et al.: Programmieren trainieren; 3. Aufl., Hanser, 2023, ISBN 978-3-446-47766-7
* Inden: Python Challenge; dpunkt, 2021, ISBN 978-3-86490-809-5
* Klein: Numerisches Python; 2. Aufl., Hanser, 2023, ISBN 978-3-446-47170-2
* Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler; Rheinwerk, 2021, ISBN 978-3-8362-7316-9
* Weigend: Python 3 - Das umfassende Praxisbuch; 9. Aufl., mitp, 2022, ISBN 978-3-7475-0544-1
* Woyand: Python für Ingenieure und Naturwissenschaftler; 4. Aufl., Hanser, 2021, ISBN 978-3-446-46483-4
== Andere Wikibooks ==
* [[:en:Subject:Python_programming_language | Englische Wikibooks zum Thema Python]]
* [[Python|Deutschsprachiges Python-Wikibook]] [[Bild:2von10.png|20%]]
* [[Python unter Linux|Python 2.7 unter Linux]] [[Bild:10von10.png|100%]]
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
76k8auccrsz6hgu327cdxs3luy1yyml
1091903
1091893
2026-10-03T19:46:14Z
Intruder
1513
/* Py5 */
1091903
wikitext
text/x-wiki
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
= Hallo Welt und allgemeine Hinweise =
== Was ist Python ==
* Python ist eine universelle höhere Programmiersprache.
* Python ist objektorientiert.
* Python ist Open-Source (Python Software Foundation License).
* Python ist für viele Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
* Python ist ein Interpreter.
* Python ist durch Module fast beliebig erweiterbar.
* Python als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
* Python ist in etlichen Anwendungsprogrammen (z.B. {{W|FreeCAD}}, {{W|LibreOffice}}, {{W|GIMP}}, {{W|Blender (Software) | Blender}}) als Makrosprache verwendbar.
{{Wikipedia | Python (Programmiersprache)}}
== Python installieren ==
=== MS Windows ===
Laden Sie das aktuelle Python-Paket von der Webseite [https://www.python.org/] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.
=== Linux ===
Entweder ist Python bereits standardmäßig installiert, ansonsten ist die Installation mittels Paketmanagementsystem einfach möglich. Aber auch die Spyder-Entwicklungsumgebung ([https://www.spyder-ide.org]) bietet einen guten Einstieg mit Python (das gilt auch für MS Windows). Spyder bringt auch schon etliche wichtige Module standardmäßig mit.
== Python starten ==
=== MS Windows ===
Das Icon für das Python-Programm doppelklicken. Und schon startet das Programm.
[[Datei:PythonIng_start1.jpg]]
Python im interaktiven Modus präsentiert sich dann so:
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Alternativ kann das Programm auch über die Eingabeaufforderung oder die PowerShell gestartet werden:
c:\devel\Python>python.exe
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
=== Linux ===
Tippen Sie einfach das Wort „python“ (oder unter openSUSE Tumbleweed z.B. auch „python3.11“ oder „python3.13“) in einem Linux-Terminal ein, schließen den Befehl mit der RETURN-Taste ab, und schon startet Python im interaktiven Modus:
Python 3.13.12 (main, Feb 09 2026, 22:37:44) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Es gibt auch noch andere Möglichkeiten Python zwecks Programmausführung zu starten, z. B. den {{W|Shebang}} (<code>#!</code>) am Beginn eines Python-Scripts. Das Script sei als Script.py gespeichert. Dann kann das Script mit ./Script.py ausgeführt werden. Für openSUSE Tumbleweed sei nachfolgend ein lauffähiges "Hallo Welt!"-Script angegeben. Es wird in diesem Script der Python-Interpreter in der Version 3.13 verwendet :
#!/usr/bin/python3.13
print("Hallo Welt!")
Die Berechtigungen zum Ausführen der Datei müssen natürlich noch richtig gesetzt werden, z.B. mittels <code>chmod 777 Script.py</code>. <small><code>chmod</code> ist die Abkürzung für"'''ch'''ange file '''mod'''e bits".</small>
<small>Die "Maske" <code>777</code> ist nur für Testzwecke sinnvoll, weil sie leicht zu merken ist und für alle Benutzer alle Zugriffsberechtigungen ('''r'''ead/'''w'''rite/e'''x'''ecute für owner/group/others) setzt. Im richtigen Einsatz wird man das aus Sicherheitsgründen nicht so handhaben, sondern nur die Berechtigungen setzen, die unbedingt erforderlich sind. Welche Zugriffsberechtigungen gesetzt sind, kann man z.B. mit dem Befehl <code>ls -l</code> oder <code>ll</code> ('''l'''i'''s'''t directory contents) erfragen. Aber dazu im Moment genug. Erfahrene Linux-Nutzer kennen das ohnehin und Anfänger sollen jetzt nicht mit Linux-Interna überfordert werden. Bei Bedarf siehe die Linux-Man-Pages oder dezidierte Bücher zu Linux.</code></small>
<small>Oder das Script wird in einen Pfad verschoben, in dem sich ausführbare Programme generell befinden (welche Verzeichnisse im PATH liegen, kann bspw. mit <code>echo $PATH</code> abgefragt werden). Das Script kann dann wie ein normales Programm ohne weitere Angaben mit Script.py gestartet werden. Alternativ wird nicht das Script an sich verschoben, sondern nur ein symbolischer Link angelegt, z.B. mit <code>ln -s ~/tmp/Script.py ~/.local/bin/Script.py</code>. <code>~/.local/bin</code> sei ein im PATH gelegenes Verzeichnis. Dies sind aber schon Features für fortgeschrittene Linux-Benutzer und werden am Anfang eher selten benötigt.</small>
== Ein paar Worte zur Erklärung ==
=== Tests ===
Getestet wurden die Beispiele unter den Betriebssystemen
* MS Windows 10 mit der Python-Version 3.12.0 (teilweise auch mit 3.12.2 und 3.13.1; nur die Inhalte die bis spätestens Juli 2025 erstellt wurden)
* MS Windows 11 ab der Python-Version 3.13.4 (nur zum Teil; ab Juli 2025)
* openSUSE Leap 15.6 mit der Python-Version 3.11.12 (Spyder, nur vereinzelt) und zum Teil mit 3.12.11 (ab Juli 2025 bis November 2025).
* openSUSE Tumbleweed ab der Python-Version 3.13.9 (nur vereinzelt, ab November 2025)
=== Popularität ===
* An Beliebtheit rangiert Python mit Stand September 2026 mit einem Rating von 17,76% an 1. Stelle vor C und C++ (lt. [https://www.tiobe.com/tiobe-index/ TPCI - TIOBE Programming Community Index]).
* Lt. [https://innovationgraph.github.com/global-metrics/programming-languages GitHub Top 50 Programming Languages Globally] lag Python im Q1/2026 auf Rang 2, vor TypeScript und hinter JavaScript.
* [https://pypl.github.io/PYPL.html PYPL] (Popularity of Programming Language Index) ist ein anderer Popularitätsindex für Programmiersprachen. Auch hier liegt Python mit großem Vorsprung auf dem ersten Platz (52,08%), gefolgt von Java (13,34%) und C/C++ (7,99%) (Stand September 2026).
=== Namensgebung ===
Der Name "Python" rührt von der Komikertruppe {{W|Monty Python}} her. Die Icons für Python (z.B. Python selbst, Eric IDE, IDLE) sind aber durch die Python-Schlangenart symbolisiert.
<gallery>
Python-logo-notext.svg|Python-Logo
Guido van Rossum in PyConUS24.jpg|{{W|Guido van Rossum}} (geb. 1956), der Erfinder von Python
</gallery>
== Ein erstes Programm ==
Kommentare werden in Python mit der Raute (#) eingeleitet. Sie werden vom Python-Interpreter ignoriert. Text kann mit der print-Funktion ausgegeben werden. Starten Sie Python und geben sie folgende Anweisungen zeilenweise ein
>>> # Das ist ein Kommentar
>>> print("Hallo Welt!")
Als Ergebnis erhalten Sie
Hallo Welt!
Der Prompt (>>>) ist selbstverständlich nicht einzutippen, sondern wird vom Python-System geliefert.
Strings können in Python entweder in Anführungszeichen (") gesetzt werden oder in Hochkommatas('). In diesem Text wird die erste Variante bevorzugt eingesetzt.
Im Gegensatz zu Julia ist es hier egal, ob zwischen <code>print</code> und der öffnenden Klammer Leerzeichen stehen.
= Python als Taschenrechner =
== Allgemeines ==
Wir wollen 3 * 5 berechnen. Dazu starten wir Python im interaktiven Modus. Geben Sie dann die Formel
>>> 3 * 5
ein, drücken die Taste ENTER/RETURN ({{Taste|↵}}) und erhalten als Ergebnis
15
Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck <math>\sin\sqrt{15}</math> berechnen :
>>> import math
>>> math.sin(math.sqrt(15))
-0.6679052983383519
Als erstes wird das math-Modul importiert. Dann wird der mathematische Ausdruck berechnet.
Eine andere Variante, die dasselbe Ergebnis liefert, ist
>>> from math import *
>>> sin(sqrt(15))
-0.6679052983383519
Es wird also aus dem Modul <code>math</code> alles importiert (erkennbar am <code>*</code>). Will man nicht alles importieren, so kann man das auch einschränken:
>>> from math import sin, sqrt
Beenden lässt sich das Python-Programm durch Eingabe von <code>exit()</code> (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken).
== Die Hilfefunktion von Python ==
Bei Eingabe der Anweisung <code>help</code> oder <code>help()</code> springt Python in den Hilfemodus.
Eingabe:
>>> help()
Eingabe:
help> math.sin
Ausgabe:
Help on built-in function sin in math:
math.sin = sin(x, /)
Return the sine of x (measured in radians).
Für die komplette Python-Dokumentation siehe [https://docs.python.org/3/]. Verlassen kann man den Hilfemodus durch das Drücken von STRG-C, bzw. der Eingabe von q, quit oder exit mit anschließendem Drücken der RETURN-Taste.
== Aufgaben ==
* Erkunden Sie die Tangensfunktion "tan" mittels Python-Hilfe (vergessen Sie nicht das math-Modul zu importieren und das <code>math.</code> vor <code>tan</code>)
* Berechnen Sie mit Python den Ausdruck <math>\frac{1}{2}\cdot \text{e}^2 \cdot \tan(\pi/3)</math>. Siehe für die Exponentialfunktion im Python-Hilfesystem auch den Befehl <code>math.exp</code>. Alternativ kann auch die Konstante <code>math.e</code> eingesetzt werden. Potenzieren kann man bei Python mit dem **-Operator (z.B. 2**3 = 8). Für <math>\pi</math> gibt es <code>math.pi</code>.
= Python als Scriptsprache =
Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.py
# Das ist ein Kommentar
print("Hallo Welt!")
Python-Dateien werden mit der Dateiendung .py versehen. Achten Sie darauf, dass vor dem print keine Leerzeichen vorhanden sind. Das ist eine Python-Eigenheit. Wie wir später sehen werden, nutzt Python Einrückungen als syntaktisches Mittel, z.B. um bei Schleifen den Schleifenkörper zu kennzeichnen.
Danach bringen Sie die Skriptdatei test1.py (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:
1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ auch die Windows PowerShell). Das sieht dann etwa so aus:
Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\xyz>
: <small>Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol ([[Image:Windows_logo_-_2021_(Black).svg|10px]]) mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell unter Windows 10 den Eintrag "Windows PowerShell", unter Windows 11 den Eintrag "Terminal"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort <code>cmd</code> ein und mit "OK" wird das Ganze bestätigt.</small>
2) Wechseln Sie mittels <code>cd c:\tmp</code> in das Verzeichnis c:\tmp
3) Angenommen, Sie haben Python unter dem Pfad <code>c:\devel\Python\</code> installiert. Starten Sie das Programm so (der Prompt <code>c:\tmp></code>ist natürlich nicht mit einzutippen):
c:\tmp>c:\devel\Python\python.exe test1.py
4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm
Hallo Welt!
Die Vorgehensweise unter Linux ist prinzipiell gleich. Die kleinen Unterschiede, wie z.B. der Slash statt dem Backslash in Pfadangaben, sollten für Linux-Benutzer keine Hürde darstellen.
== Variablen ==
Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9) und Underscores (_) bestehen, dürfen aber nicht mit einer Zahl beginnen. Führende Underscores haben u.a. im Kontext mit der Objektorientierten Programmierung eine spezielle Bedeutung und sollten nicht für "normale" Variablenbezeichner verwendet werden.
Gültige Variablenbezeichner wären also:
xyz
x1
_wert
name_anzahl
Theoretisch kann man auch Umlaute, griechische Buchstaben u.ä. in Variablenbezeichnern nutzen, z.B.
ößÜ = 16
α = 134
print(ößÜ)
print(α)
Ausgabe:
16
134
Davon wird aber aus offensichtlichen Gründen ({{W|Englisch als Lingua franca}}) abgeraten. Das Eurozeichen (€) etc. darf man ohnehin nicht in Variablenbezeichnern verwenden, dies ergäbe einen Syntaxfehler. Siehe dazu auch [https://peps.python.org/pep-3131/].
Es gibt in Python etliche Schlüsselwörter (z.B. for, if oder return). Diese dürfen nicht als eigene Variablenbezeichner verwendet werden. Eine Liste aller Schlüsselwörter liefert das Script
import keyword
print(keyword.kwlist)
<small>Übung: Speichern Sie dieses Script in eine Datei, z.B. in c:\tmp\test1.py. Führen Sie diese Datei aus, um die Liste der Schlüsselwörter auszugeben.</small>
Da Python case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:
xyz
XYZ
xYz
Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.py gespeichert.
x = 5
y = 10
z = x*y
print(z)
Bringen Sie die Datei test1.py zur Ausführung, so erhalten Sie folgende Bildschirmausgabe
50
Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben. Dies führt aber zu unübersichtlichem Code.
x = 5; y = 10; z = x*y; print(z)
Ausgabe:
50
Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.
x = 5
# x = x - 2
x -= 2
print(x)
Bildschirmausgabe:
3
Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Den Inkrement-/Dekrementoperator (z.B. x++ oder x--) aus C/C++ oder Java kennt Python aber nicht.
Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Python problemlos möglich:
import math
wert = 10
print(wert)
wert = 35.5
print(wert)
wert = "Hallo"
print(wert)
wert = math.pi
print(wert)
Ausgabe:
10
35.5
Hallo
3.141592653589793
== Physische und logische Zeilen ==
In Python muss eine Anweisung in einer logischen Zeile Platz finden. Wird eine Anweisung aber zu lang für eine Zeile, dann kann sie in mehrere physische Zeilen unterteilt werden. Dies kann einerseits durch einen Backslash am Ende einer Zeile geschehen, z.B.
a = 2 + \
5
Dies stellt eine logische Zeile dar, die in zwei physische Zeilen unterbrochen ist.
Geklammerte Ausdrücke werden automatisch zu einer logischen Zeile verbunden, z.B.
a = (2 +
5)
Achtung: Im ersten Beispiel darf nach dem Backslash nichts mehr stehen, auch kein Kommentar. Dies trifft im zweiten Bespiel nicht zu, hier könnte noch ein Kommentar folgen, z.B.
a = (2 + # Kommentar
5)
Auch für Strings gibt es Möglichkeiten, diese auf mehrere Zeilen aufzuspalten.
# Kurzer String
str1 = "ABC"
# Langer String
str2 = """Hallo Welt,
Grüetzi Schwyzer,
Servus an alle"""
# Backslash
str3 = "UVW\
XYZ"
# Mit Klammern
str4 = ("Sehr langer Text, der automatisch .............. "
"in einer einzigen Variable zusammengefügt wird."
)
print(str1)
print(str2)
print(str3)
print(str4)
Ausgabe:
ABC
Hallo Welt,
Grüetzi Schwyzer,
Servus an alle
UVWXYZ
Sehr langer Text, der automatisch .............. in einer einzigen Variable zusammengefügt wird.
==Hexadezimale, oktale, binäre und andere Zahlen==
d = 1050 # Dezimalzahl
h = 0xAA2 # Hexadezimalzahl
o = 0o12 # Oktalzahl
b = 0b100001101 # Binärzahl
print(d)
print(h)
print(o)
print(b)
Ausgabe:
1050
2722
10
269
Groß- und Kleinbuchstaben sind in obigen Literalen übrigens egal. So kann man z.B. statt <code>0b1001</code> auch <code>0B1001</code> schreiben (siehe dazu [https://docs.python.org/3/reference/lexical_analysis.html#integer-literals]).
Sie können auch dezimale in hexadezimale Zahlen umwandeln, usw.:
h = hex(1050) # Dezimalzahl -> Hexadezimalzahl
b = bin(1050) # Dezimalzahl -> Binärzahl
o = oct(1050) # Dezimalzahl -> Oktalzahl
print(h)
print(b)
print(o)
Ausgabe:
0x41a
0b10000011010
0o2032
Gegeben sei die Zahl 121 zur Basis 3. Diese soll in eine Dezimalzahl umgewandelt werden. Das kann so geschehen:
z = int("121", 3)
print(z)
Ausgabe:
16
Dass dies richtig ist, davon kann man sich folgendermaßen überzeugen:
<math> 1 \cdot 3^2 + 2 \cdot 3^1 + 1 \cdot 3^0 = 9 + 6+ 1 = 16 </math>
Zahlen übersichtlicher schreiben kann man auch mittels Underscore, z.B.:
print("Eine Million (Variante 1) =", 1000000)
print("Eine Million (Variante 2) =", 1_000_000)
print("Eine Rechnung:", 2_000 * 400_000);
Es ergibt sich bei beiden Varianten die gleiche Ausgabe. Variante 2 ist aber im Sourcecode leichter lesbar, detto die Zahlen in der Rechnung:
Eine Million (Variante 1) = 1000000
Eine Million (Variante 2) = 1000000
Eine Rechnung: 800000000
== Strings und Platzhalter==
Ein paar einfache Beispiele:
print("Hallo {}" . format("Hugo"))
print("Hallo {:s}" . format("Hugo"))
print("Hallo %s" % "Hugo")
Ausgabe:
Hallo Hugo
Hallo Hugo
Hallo Hugo
Python-Code (formatted string literals, Beispiel 1):
str1 = "Hallo"
str2 = "Hugo"
print(f"{str1} {str2}")
Ausgabe:
Hallo Hugo
Python-Code (formatted string literals, Beispiel 2):
wert = 11.567
print(f"Ausgabe: {wert:.5f}")
Ausgabe:
Ausgabe: 11.56700
Komplexere Beispiele:
print("Hallo {} und {}" . format("Hugo", "Mike"))
print("Hallo {name1} und {name2}" . format(name2="Hugo", name1="Mike"))
# Füllzeichen: *
# Bündigkeit: > (=rechts), < (=links), ^ (=zentriert)
# Feldweite: 10
# Typ: s (=String), f (=Gleitkommazahl), d (=Dezimalzahl) etc.
print("Hallo {:*>10s}" . format("Hugo"))
print("Hallo {:*<10s}" . format("Hugo"))
Ausgabe:
Hallo Hugo und Mike
Hallo Mike und Hugo
Hallo ******Hugo
Hallo Hugo******
Python-Code:
str = "Hallo\t%s\t%7.2f\t%10.2e\t%i" % ("Hugo", 12.34567, 34.567, 264)
print(str)
Ausgabe:
Hallo Hugo 12.35 3.46e+01 264
== Unicode ==
Neben den bekannten ASCII-Zeichen lassen sich Zeichen auch mittels Unicode beschreiben. Griechische Buchstaben oder komplexere mathematische Operatoren - all das sollte kein Problem sein. Siehe auch {{W|Unicode}}, {{W|Liste der Unicodeblöcke}} und {{W|Unicodeblock Mathematische Operatoren}}. Im Folgenden werden ein paar Zeichen (Allquantor, Nabla-Operator, Existenzquantor), die man aus der Mathematik kennt, erzeugt.
ch1 = "\N{FOR ALL}"
ch2 = "\N{NABLA}"
ch3 = "\u2203"
print(ch1, ch2, ch3)
Ausgabe:
∀ ∇ ∃
<small>Diese Ausgabe ergibt sich z.B. mit der IDLE-Shell oder mit Cygwin. Beim Ausführen über die Windows-Eingabeaufforderung oder Windows PowerShell unter MS Windows 10 erfolgt keine korrekte Darstellung. IDLE ist die mit Python mitgelieferte IDE ('''I'''ntegrated '''D'''evelopment '''E'''nvironment, Integrierte Entwicklungsumgebung). Gegen Ende dieses Textes wird IDLE kurz beschrieben.
Das Problem mit der Windows Eingabeaufforderung lässt sich aber umgehen. Man muss nur eine Schriftart auswählen, die die Zeichen kennt, z.B. "DejaVu Sans Mono". Dazu klicken Sie einfach bei der Eingabeaufforderung mit der rechten Maustaste oben auf die weiße Leiste und wählen im aufpoppenden Fenster den Menüpunkt "Eigenschaften". Es öffnet sich ein Dialogfenster. Über den Reiter "Schriftart" lässt sich nun die Schriftart einstellen. Unter MS Windows 11 oder openSUSE Leap 15.6 (bash-Konsole) gibt es dieses Problem ohnehin nicht.</small>
== Reguläre Ausdrücke ==
Python kennt auch {{W|Regulärer Ausdruck|reguläre Ausdrücke}}. Dazu gibt es in Python das Modul <code>re</code>. Beipielsweise sollen alle Zahlen (<math>\text{zahl}\in\mathbb{N}_0</math>) in einem String gesucht und ausgegeben werden. Als String sei gegeben: <code>3x Grüße und 100 Kekse.</code> Das Muster (Pattern) ist <code>\d+</code>. <code>\d</code> steht für eine Dezimalziffer 0-9. Das Plus-Zeichen (+) steht symbolisch für ein oder mehrere Zeichen des vorherigen Ausdrucks. Hier also ein oder mehrere Dezimalziffern. Es wird die Funktion <code>findall</code> aus dem Modul <code>re</code>verwendet.
Python-Code:
from re import findall
str = "3x Grüße und 100 Kekse."
pat = "\\d+" # Doppel-Backslashes müssen verwendet werden, sonst gibt Python eine Warnung aus!
# alternativ: pat = r"\d+"
# oder: pat = "[0-9]+"
numb = findall(pat, str)
print(numb)
Ausgabe:
['3', '100']
Python kennt noch viele weitere Möglichkeiten mittels regulärer Ausdrücke zu hantieren. Dies soll hier aber nicht vertieft werden, da das Thema schon ziemlich speziell und komplex ist. Bei Bedarf siehe aber z.B. die Bücher ''Weigend, Seite 380ff'' und ''Ernesti, Kaiser'' [https://openbook.rheinwerk-verlag.de/python/28_001.html] oder die Python-Dokumentation [https://docs.python.org/3/library/re.html]. Auch [[Python unter Linux: Reguläre Ausdrücke]] liefert ein umfangreiches und brauchbares Python-2-Kapitel zu den regulären Ausdrücken. Die dort gelisteten Beispiele müssten ggf. vor Verwendung auf Python-3 umgeschrieben werden. <small>Wie macht man das? Dazu siehe z.B. [https://openbook.rheinwerk-verlag.de/python/43_001.html], [https://portingguide.readthedocs.io/en/latest/] oder [https://www.digitalocean.com/community/tutorials/how-to-port-python-2-code-to-python-3]</small>
<small>Es gibt auch ein externes Modul ''regex'', das bei Bedarf extra installiert werden muss ([https://pypi.org/project/regex/]). Es bietet zusätzliche Funktionalität und gründlicheren Unicode-Support. Dies sei hier aber nur der Vollständigkeit halber erwähnt.</small>
== Verzweigungen ==
=== if ===
Die IF-Verzweigung sei aus anderen Programmiersprachen bereits bekannt. In {{W|Pseudocode}} lässt sie sich folgendermaßen darstellen:
WENN bedingung TRUE
führe block1 aus
SONST
führe block2 aus
ENDE
Als {{W|Aktivitätsdiagramm|UML-Aktivitätsdiagramm}} sieht das in etwa so aus:
[[File:If-Then-Else-diagram.svg|200px]]
Und als {{W|Nassi-Shneiderman-Diagramm|Nassi-Shneiderman-Struktogramm}} so:
[[File:Zweiseitige Auswahl.png|250px]]
In Python gibt es keinen expliziten ENDE-Kennzeichner. Stattdessen wird der Code durch Einrückungen strukturiert. Alles mit der gleichen Einrückungstiefe gehört zum selben Block. Dies zeichnet Python vor anderen Programmiersprachen aus.
Die test1.py-Datei laute also wie folgt:
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4
Man achte auch auf die Doppelpunkte in der if- und else-Zeile. Darauf vergisst man gerne, wenn man von anderen Programmiersprachen kommt.
Folgendes wäre in Python ein Fehler (genauer gesagt ein IndentationError).
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Auch Nachstehendes würde nicht zum gewünschten Ergebnis führen (löst aber keine Fehlermeldung aus). Der letzte print-Befehl ist schon außerhalb der IF-ELSE-Verzweigung.
x = 3
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
x ist kleiner als 4
x ist groesser oder gleich 4
Python kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:
<, <= ... kleiner (gleich)
>, >= ... größer (gleich)
== ... gleich
!= ... ungleich
is ... identisch
is not ... nicht identisch
and ... AND
or ... OR
not ... NOT
Beispielsweise:
a = 5
b = 9
if a<=10 and b!=7:
print("OK")
else
print("Nicht OK")
Ausgabe:
OK
Der else-Block kann übrigens auch ersatzlos entfallen. Als Pseudocode sieht das so aus
WENN bedingung TRUE
führe block aus
ENDE
Mehrfache Verzweigungen werden durch das elif-Konstrukt erstellt. In Pseudocode:
WENN bedingung1 TRUE
führe block1 aus
SONST WENN bedingung2 TRUE
führe block2 aus
SONST WENN bedingung3 TRUE
führe block3 aus
SONST
führe block4 aus
ENDE
Ein Python-Beispiel:
a = 14
if a<=10:
print("<=5")
elif a>11 and a<15:
print("11 bis 15")
elif a>16 and a<20:
print("16 bis 20")
else:
print(">=20")
Ausgabe:
11 bis 15
In Python gibt es auch die Schlüsselwörter <code>True</code> (für wahr) und <code>False</code> (für falsch). Man beachte, dass sie mit Großbuchstaben beginnen. Andere Schreibweisen wären ein Fehler. Sie gehören zum Datentyp <code>bool</code>. Ihnen sind auch die Zahlen <code>1</code> und <code>0</code> zugewiesen.
Man beachte, dass {{W|Rundungsfehler}} auftreten können. D.h. man sollte bei der Verwendung von {{W|Gleitkommazahl|Gleitpunktzahlen}} niemals auf absolute Genauigkeit prüfen, sondern eine Toleranz (einen <math>\varepsilon</math>-Wert) vorgeben.
Ein klassisches Beispiel, das ein falsches Ergebnis liefert, ist:
i = 0.1 + 0.2
print(i)
if i == 0.3:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
NOK
Und das, obwohl man schon in der Volksschule lernt, dass 0.1 + 0.2 gleich 0.3 ist.
Korrekt muss das obige Beispiel z.B. so umgeschrieben werden:
ist = 0.1 + 0.2
soll = 0.3
epsilon = 0.000001
print(ist)
if abs(ist-soll) < epsilon:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
OK
Alternativ kann auch die <code>math.isclose()</code>-Funktion verwendet werden. Das sei aber hier nur erwähnt und nicht konkret ausgeführt.
<u>Aufgabe:</u> Recherchieren Sie im Internet zum Thema <code>math.isclose()</code>-Funktion.
=== match ===
Ab Python 3.10 gibt es auch die match-Anweisung. Dies ist das Python-Pendant für die switch-Anweisung in anderen Programmiersprachen, geht aber bei näherer Betrachtung weit darüber hinaus. Hier nur ein einfaches Beispiel:
x = "Hello"
match x:
case "Servus" | "Ciao": # or
print("Servus an alle")
case "Grüetzi":
print("Grüetzi Schwyzer")
case _: # other, default, sonstiges ...
print("Hallo Welt")
Ausgabe:
Hallo Welt
Als Struktogramm sieht das in etwa so aus:
[[File:Mehrseitige Auswahl.png|250px]]
Für nähere Details siehe z.B. [https://www.geeksforgeeks.org/python-match-case-statement/], [https://learnpython.com/blog/python-match-case-statement/], [https://docs.python.org/3/tutorial/controlflow.html#match-statements] und das Python Enhancement Proposal (PEP) 636 – Structural Pattern Matching: Tutorial [https://peps.python.org/pep-0636] und dort insbesondere den Anhang A - Quick Intro.
<small><code>match, case, _</code> etc. sind sogenannte ''soft keywords''. Im Gegensatz zu den normalen Schlüsselwörtern dürfen ihnen auch Werte zugewiesen werden. Eine Liste der weichen Schlüsselwörter lässt sich durch <code>keyword.softkwlist</code> erstellen (die Anweisung gibt es seit Python 3.9). Siehe dazu auch [https://stackoverflow.com/questions/65800344/what-are-soft-keywords] und [https://docs.python.org/3/library/keyword.html#keyword.softkwlist].</small>
== Schleifen ==
Kopfgesteuerte Schleife, Endlosschleife und fußgesteuerte Schleife:
[[File:Programmingloops.svg|450px]]
=== while ===
Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert wie aus anderen Programmiersprachen bekannt.
In Pseudocode:
SOLANGE bedingung TRUE
führe block aus
ENDE
In Python:
x = 0
while x <= 10:
print(x)
x += 1
Ausgabe:
0
1
2
3
4
5
6
7
8
9
10
Eine Endlosschleife ergibt sich z.B. so:
i = 5
while True:
print(i)
i-=1
Beendet werden kann sie mit der Tastenkombination STRG-C.
Eine fußgesteuerte Schleife kann so simuliert werden:
i = 5
while True:
print(i)
i-=1
if i<=0:
print("Fire")
break
Ausgabe:
5
4
3
2
1
Fire
Der <code>break</code>-Befehl wird etwas später noch einmal kurz thematisiert.
=== for ===
Struktogramm einer for-Schleife:
[[File:Zählschleife.png|200px]]
In Python bspw. so:
for x in range(6):
print(x*2)
Ausgabe:
0
2
4
6
8
10
Die Schleife läuft von 0 bis 5. Ausgegeben wird jeweils der Wert x*2. Aquivalent kann diese Schleife auch so geschrieben werden:
for x in range(0, 11, 2):
print(x)
Die Ausgabe ist wie oben. Der Startwert sei 0, der Endwert ist 11-1 und die Schrittweite ist 2.
Ein anderes Beispiel sei
for x in "text":
print(x)
Ausgabe:
t
e
x
t
== Schleifen abbrechen ==
=== break ===
<code>break</code> bricht die Schleife ab und setzt mit dem nächsten Befehl außerhalb der Schleife fort.
for var in range(100):
print(var)
if var == 5:
break
Ausgabe:
0
1
2
3
4
5
=== continue ===
<code>continue</code> bricht den aktuellen Schleifendurchlauf ab und setzt mit dem nächsten Schleifendurchlauf fort.
for var in range (11):
if var == 5:
continue
print(var)
Ausgabe:
0
1
2
3
4
6
7
8
9
10
== try - except ==
try:
z1 = 12 / 0
print(z1)
except ZeroDivisionError:
print("Das Ergebnis ist unendlich")
except:
print("Kann nicht berechnet werden!")
print("Bitte die Formel korrigieren!")
print("Setze Programm fort!")
Ausgabe:
Das Ergebnis ist unendlich
Setze Programm fort!
Es wird versucht, eine Zahl durch Null zu dividieren. Das ist nicht möglich, es wird eine Ausnahme ausgelöst. Das Programm springt daher in den except-ZeroDivisionError-Block und führt die dort gelisteten Anweisungen aus (in unserem Fall eine print-Anweisung). Danach wird das Programm fortgesetzt. Würden wir dieses Programm ohne try-except ausführen, so ergibt sich aus
z1 = 12 / 0
print(z1)
folgende Fehlermeldung und ein unmittelbarer Programmabbruch
Traceback (most recent call last):
File "C:\tmp\test1.py", line 1, in <module>
z1 = 12 / 0
ZeroDivisionError: division by zero
Mit dem try-except-Mechanismus können also Ausnahmen oder Fehler aufgefangen und behandelt werden. In unserem Beispiel ist das eher trivial, aber bei größeren Programmen kann das durchaus Sinn machen.
Neu in Python 3.14 ist, dass mehrere Ausnahmen auch ohne Klammern angegeben werden können, z.B.:
bis inkl. Python 3.13 nur:
except (ZeroDivisionError, ValueError):
ab Python 3.14 auch:
except ZeroDivisionError, ValueError:
== pass ==
Ein leerer Block muss in Python mittels dem Schlüsselwort <code>pass</code> dargestellt werden. Z.B.
x = 2
if x == 1:
print("Wert ist ", x)
else:
pass
Würde man das <code>pass</code> im else-Block weglassen, so würde man eine Fehlermeldung erhalten:
IndentationError: expected an indented block after 'else' statement on line 5
= Funktionen =
== Aufrufen von Funktionen ==
Funktionen sind uns im Rahmen dieses Kurses schon zuhauf begegnet. Sei es die print()-, die math.sin()- oder die hex()-Funktion. All diese Funktionen werden von Python zur Verfügung gestellt, ohne dass man sie explizit programmieren müsste. Aufgerufen werden diese Funktionen, indem man ihren Namen eintippt, gefolgt von runden Klammern. In diesen Klammern können noch Argumente übergeben werden. Auch Rückgabewerte sind möglich.
== Funktionen selber schreiben ==
Funktionen werden mit dem def-Schlüsselwort (man definiert die Funktion) eingeleitet, danach folgt der Funktionsname, danach wiederum runde Klammern, in denen formale Argumente stehen können. Abgeschlossen wird die def-Zeile mit einem Doppelpunkt. Danach folgt der Funktionskörper. Dieser Funktionskörper muss wiederum eingerückt werden (wie von den Verzweigungen und Schleifen bekannt). Aufgerufen wird diese Funktion, indem man ihren Funktionsnamen eingibt, gefolgt von runden Klammern (ggf. mit den aktuellen Parametern). Z.B.
# Funktion definieren
def halloWelt(i):
# i ... beliebige Ganzzahl
print("Hallo " * i, end="")
print("Welt!")
# Funktion aufrufen
halloWelt(3)
Ausgabe:
Hallo Hallo Hallo Welt!
Unterschied zwischen formalen und aktuellen Parametern:
[[Datei:PythonIng_func1.jpg]]
<small>Aktuelle Parameter werden auch Argumente genannt.</small>
Rückgabe von Funktionswerten:
# Funktion definieren
def mathFunc(a, b):
r1 = a + b
r2 = a * b
return r1, r2
# Funktion aufrufen
c, d = mathFunc(3, 5)
# Ausgabe der zurückgegebenen Werte
print(c)
print(d)
Ausgabe:
8
15
Es werden r1 und r2 zurückgegeben und den Variablen c und d zugewiesen. (r1, r2) und (c, d) sind Tupel. Was Tupel konkret sind, siehe etwas später in diesem Kapitel. 3 und 5 sind die aktuellen Parameter (die Argumente). a und b sind die formalen Parameter. Die Zuweisung der aktuellen zu den formalen Parametern erfolgt in der gegebenen Reihenfolge, also die Zahl 3 wird an a übergeben und die Zahl 5 an b.
Vorgabeparameter, z.B.:
def mathFunc(a=10, b=20):
r1 = a + b
r2 = a * b
return r1, r2
c, d = mathFunc(3, 5)
print(c)
print(d)
e, f = mathFunc(5)
print(e)
print(f)
g, h = mathFunc(b=6)
print(g)
print(h)
Ausgabe:
8
15
25
100
16
60
Erklärung:
* Erster <code>mathFunc</code>-Aufruf: Es werden, wie weiter oben, die Argumente 3 und 5 an die formalen Parameter a und b übergeben. Die Rückgabewerte r1 und r2 werden an c und d übergeben. Somit ist c=8 und d=15.
* Zweiter <code>mathFunc</code>-Aufruf: Es wird nur das Argment 5 an a übergeben. b behält den Vorgabewert 20. D.h. e= 25 und f=100.
* Dritter <code>mathFunc</code>-Aufruf: Es wird nur die Zahl 6 an b übergeben, a behält seinen Vorgabewert 10. Somit ergibt sich g=16 und h=60.
Beispiel (Schlüsselwortargumente vs. Positionsargumente):
def mathFunc(a, b):
r1 = a - b
r2 = a / b
return r1, r2
c, d = mathFunc(b=3, a=5) # Schlüsselwortargumente
e, f = mathFunc(3, 5) # Positionsargumente
print(c)
print(d)
print(e)
print(f)
Ausgabe:
2
1.6666666666666667
-2
0.6
Durch die Verwendung von Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge angegeben werden. Bei den Positionsargumenten ist die Reihenfolge vorgegeben. Daraus resultiert auch der Unterschied bei den obigen Ausgaben. Werden beide Arten in einem Aufruf gemischt, so müssen die Positionsargumente zuerst angegeben werden. Den Unterschied zwischen beiden Argumentarten zu kennen ist wichtig, nicht nur bei selbst erstellten Funktionen. Auch beim Aufruf von Python-Funktionen verfolgt einen die Mischung von Schlüsselwort- und Positionsargumenten auf Schritt und Tritt, z.B. beim etwas später folgenden Abschnitt über "Grafiken zeichnen":
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
Bei dieser <code>plot</code>-Funktion aus dem Modul <code>matplotlib.pyplot</code> sind <code>x</code> und <code>y1</code> Positionsargumente. <code>label, lw</code> und <code>ls</code> sind die Namen der Schlüsselwortargumente. Die Schlüsselwortargumente könnten auch in anderer Reihenfolge angeschrieben werden, nicht jedoch die Positionsargumente!
Siehe zu <code>matplotlib.pyplot.plot</code> auch die Seite [https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html].
== Lambda-Funktionen ==
print((lambda a, b: a*b) (3, 5))
Ausgabe:
15
Eingeleitet wird eine Lambda-Funktion (auch Lambda-Form, Lambda-Operator oder anonyme Funktion genannt) mit dem Schlüsselwort <code>lambda</code>. Es folgen die formalen Argumente, danach ein Doppelpunkt, die Berechnungsvorschrift und ggf. abschliessend in Klammern die aktuellen Parameter.
Man kann einer Lambda-Funktion auch einen Funktionsnamen geben und die Funktion über diesen Namen aufrufen, z.B.
prod = lambda a, b: a*b
print(prod(3, 5))
Als Ausgabe wird wieder die Zahl 15 geliefert.
== Rekursive Funktionen ==
Funktionen können wiederum andere Funktionen aufrufen. Von einem rekursiven Funktionsaufruf spricht man, wenn die aufgerufene Funktion gleich der aufrufenden ist.
def printFunc(i):
if (i >= 5):
return
else:
print("Hallo Welt")
printFunc(i+1)
printFunc(1)
Ausgabe:
Hallo Welt
Hallo Welt
Hallo Welt
Hallo Welt
== Funktionsannotationen ==
Python ist sehr flexibel, was Typen angeht. Im Vorhergehenden haben wir generell keine Typangaben gemacht. Will man Typen angeben, so bietet Python das Konzept der Funktionsannotation.
def calcFunc(a: int, b: int) -> int:
return a+b
r1 = calcFunc(8, 9)
r2 = calcFunc(8.0, 9.0)
r3 = calcFunc("Hallo", "Welt")
print(r1)
print(r2)
print(r3)
Ausgabe:
17
17.0
HalloWelt
Jetzt sieht man auf den ersten Blick, welche Typen der Programmierer im Sinn hatte, als er die Funktion erstellte. Das Problem dabei ist nur, dass es Python ziemlich egal ist, welche Typen man im Endeffekt eingibt. Im obigen Beispiel können statt Integer-Typen u.a. auch Float- oder String-Typen eingegeben werden.
<small>
Siehe zum Thema "Type Checking" aber auch den später folgenden Abschnitt [[Ing_Mathematik:_Python#Type_Checker]].
</small>
== Variadische Funktionen ==
Python-Code:
def test1(a, *b):
print(a);
for c in b:
print(c);
test1("Hallo", "Welt", "Schweizer", "und alle anderen")
Ausgabe:
Hallo
Welt
Schweizer
und alle anderen
Mit dem Stern (auch als Splat-Operator bezeichnet) in der formalen Parameterliste bei der Funktion <code>test1</code> wird angezeigt, dass eine beliebige Anzahl von Argumenten übergeben wird. <small> Dies entspricht in etwa dem, was in anderen Programmiersprachen (PHP etc.) mittels Ellipse (<code>...</code>) angezeigt wird.</small>
= Tupel, Listen und andere =
[[Datei:Python 3. The standard type hierarchy.png|mini|hochkant=1.7|Datentypen und Strukturen]]
== Tupel und Listen ==
Tupel, Listen und einige andere sind Datenstrukturen oder Sequenzen.
Listen (z.B. eine Einkaufsliste) sind veränderbar (mutable). Ein Tupel kann dagegen nicht verändert werden (immutable). Listen werden beim Anlegen in eckige Klammern eingeschlossen, Tupel in runde Klammern. Beim Tupel können die Klammern auch weggelassen werden. Ein Tupel mit nur einem Element muss mit einem Beistrich abgeschlossen werden. Der Grund ist, dass Python sonst nicht entscheiden kann, ob ein Tupel angelegt werden soll, oder nur ein geklammerter Wert.
Als Gedächtnisstütze kann man sich den Unterschied zwischen Tupel und Liste ev. so leichter merken:
: T'''u'''pel ... r'''u'''nde Klammern, '''u'''nveränderlich
: L'''i'''ste ... eck'''i'''ge Klammern, veränderl'''i'''ch.
Nachfolgend werden einige Operationen mit Listen und Tupel dargestellt.
# Liste und Tupel
liste = [1, 2, "Hallo"]
tupel = (1, 2, "Hallo")
# Ausgabe von liste und tupel
print(liste)
print(tupel)
# Ausgabe von Einzelelementen
print(liste[1])
print(tupel[2])
# Element an Liste anhängen und einfügen
liste.append(55)
liste.insert(4, "Welt")
print(liste)
# Element aus Liste entfernen
liste.remove(1)
print(liste)
# einige weitere Beispiele
liste2 = [1,]
tupel2 = 1, 2
tupel3 = (1,)
print(liste2)
print(tupel2)
print(tupel3)
Ausgabe:
[1, 2, 'Hallo']
(1, 2, 'Hallo')
2
Hallo
[1, 2, 'Hallo', 55, 'Welt']
[2, 'Hallo', 55, 'Welt']
[1]
(1, 2)
(1,)
Beispiel (eine Liste von Wörtern zu einem einzigen zusammenhängenden Text verbinden):
woerter = ["Hallo", "Welt"]
satz = " ".join(woerter)
print(satz)
Ausgabe:
Hallo Welt
== Dictionaries und Mengen ==
Zu den Datenstrukturen gehören weiters auch Mengen und Dictionaries. Mengen sind von der Mathematik bekannt, sie sind ungeordnet und es kommen keine mehrfachen Elemente vor. Dictionaries sind durch Schlüssel :Wert-Paare gekennzeichnet. Mengen werden beim Anlegen wie Dictionaries in geschweifte Klammern eingeschlossen.
dict = {"vorname":"Hugo", "nachname":"Meister" }
menge = {1, 1, 3, 4, 4, 4, "Hallo"}
print(dict)
print(menge)
print(dict["vorname"])
Ausgabe:
{'vorname': 'Hugo', 'nachname': 'Meister'}
{1, 3, 4, 'Hallo'}
Hugo
Geschweifte Klammern ohne Inhalt stellen Dictionaries dar und keine Mengen:
di = {}
print(type(di))
Ausgabe:
<class 'dict'>
Leere Mengen lassen sich mit <code>set()</code> erzeugen:
menge = set() # leere Menge
print(menge)
menge.add("Hallo") # Element hinzufügen
print(menge)
Ausgabe:
set()
{'Hallo'}
Beispiel (einige Mengenoperationen):
mengeA = {"Hallo", "Welt"}
mengeB = {1, 2, "Welt", 3}
# Vereinigung
print(mengeA | mengeB)
print(mengeA.union(mengeB))
# Durchschnitt
print(mengeA & mengeB)
print(mengeA.intersection(mengeB))
# Differenz
print(mengeA - mengeB)
print(mengeA.difference(mengeB))
# Symmetrische Differenz
print(mengeA ^ mengeB)
print(mengeA.symmetric_difference(mengeB))
# Teilmenge
print(mengeA.issubset(mengeB))
# Mehrere Elemente hinzu
mengeA.update(["Super", 67, 125])
print(mengeA)
# Element löschen
mengeA.discard("Hallo")
print(mengeA)
Ausgabe:
{1, 2, 3, 'Welt', 'Hallo'}
{1, 2, 3, 'Welt', 'Hallo'}
{'Welt'}
{'Welt'}
{'Hallo'}
{'Hallo'}
{1, 2, 3, 'Hallo'}
{1, 2, 3, 'Hallo'}
False
{67, 'Super', 'Welt', 'Hallo', 125}
{67, 'Super', 'Welt', 125}
Es gibt schon seit "ewigen" Zeiten unveränderbare Mengen, die mittels <code>frozenset</code> eingeleitet werden. Neu ab Python 3.15 ist dagegen das Pendant <code>frozendict</code>, das unveränderbare Dictionaries darstellt.
fdict = frozendict({"vorname":"Hugo", "nachname":"Meister"})
fset = frozenset({"A", 1, "A"})
print(fdict)
print(fdict["vorname"])
print (fset)
try:
fdict["vorname"] = "Max"
print(fdict["vorname"])
except TypeError as e:
print(f"Fehler: {e}")
try:
fset.add("B")
print(fset)
except AttributeError as e:
print(f"Fehler: {e}")
Ausgabe:
frozendict({'vorname': 'Hugo', 'nachname': 'Meister'})
Hugo
frozenset({1, 'A'})
Fehler: 'frozendict' object does not support item assignment
Fehler: 'frozenset' object has no attribute 'add'
== List Comprehensions ==
Aus einer Eingabeliste soll eine Ausgabeliste erzeugt werden. Das kann folgendermaßen geschehen.
Mathematische Schreibweise: <math>lc = \{2x|x\in\ \mathbb{N}, 1\le x < 11\}</math>
Python-Code:
lc = [x*2 for x in range(1,11)]
print(lc)
Ausgabe:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Mathematische Schreibweise: <math>lc = \{2x | x \in \mathbb{N}, 1\le x < 11, x \bmod 2 = 0 \}</math>
Python-Code:
lc = [x*2 for x in range(1,11) if x%2 == 0]
print(lc)
Ausgabe:
[4, 8, 12, 16, 20]
Siehe auch {{W|List Comprehension}}.
== Set Comprehensions ==
Dies ist sehr ähnlich wie im vorigen Abschnitt beschrieben. Es wird aber keine Liste, sondern eine Menge erzeugt.
sc = {x*2 for x in range(1,11)}
print(sc)
Ausgabe:
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
== Listen zusammenführen - zip() ==
li1 = ["A", "B", "C", "D"]
li2 = [1, 2, 3, 4]
li3 = [5.5, 6.6, 7.7, 8.8]
z = zip(li1, li2, li3)
print(z)
li4 = list(z)
print(li4)
Ausgabe:
<zip object at 0x00000283B6C6AC80>
[('A', 1, 5.5), ('B', 2, 6.6), ('C', 3, 7.7), ('D', 4, 8.8)]
== Generatorausdruck ==
g = (i*2 for i in range(1,11))
print(g)
t = tuple(g)
print(t)
print(t[1:3])
Ausgabe:
<generator object <genexpr> at 0x00000241D2A4A5A0>
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
(4, 6)
== Slicing ==
slice ... Scheibe, Teil, in Scheiben schneiden
Beispiel: Zugriff auf Elemente eines geordneten sequentiellen Objekttyps (Liste, Tupel oder String):
str1 = "Hallo"
# Das erste Element wird mit dem Index 0 angesprochen
# [start (inkl.) : stop (exkl.) : step (default=1)]
str2 = str1[0:2]
# Alternativ auch: str2 = str1[:2]
print(str2)
tup1 = (0,1,2,3)
# Das letzte Element hat auch den Index -1, das vorletzte den Index -2 usw.
tup2 = tup1[-3:-1]
print(tup2)
lst1 = [[1, 5, 10, 20],
[30, 40, 50, 60]]
lst2 = lst1[1][1]
print(lst2)
Ausgabe:
Ha
(1, 2)
40
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2])
print(x[-3])
print(x)
print(x[:])
print(x[2:])
print(x[:2])
print(x[::-1])
Ausgabe:
c
c
('a', 'b', 'c', 'd', 'e')
('a', 'b', 'c', 'd', 'e')
('c', 'd', 'e')
('a', 'b')
('e', 'd', 'c', 'b', 'a')
Visualisierung:
'''a''' '''b''' '''c''' '''d''' '''e'''
+-----------------------------+
| 0 | 1 |//'''2'''//| 3 | 4 |
+-----------------------------+
| -5 | -4 |/'''-3'''//| -2 | -1 |
+-----------------------------+
|/////////////////////////////|
+-----------------------------+
|/////////////''':'''///////////////|
+-----------------------------+
| | |///////'''2:'''////////|
+-----------------------------+
|////''':2'''/////| | | |
+-----------------------------+
|\\\\\<--\\\\\'''::-1'''\\\\<--\\\\\|
+-----------------------------+
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2::2])
print(x[2::-1])
print(x[2:0:-1])
Ausgabe:
('c', 'e')
('c', 'b', 'a')
('c', 'b')
Hier sieht man sehr schön, dass beim letzen <code>print</code>-Befehl die 0, die in diesem Fall den Buchstaben "a" repräsentiert, als letzer Wert nicht mehr dazugehört (wie weiter oben angedeutet ist der End- oder Stoppwert exklusiv). Will man den Buchstaben "a" dazunehmen, so ist die vorletzte Zeile die richtige.
Beispiel: Umdrehen von Strings
str1 = "Hallo"
str2 = str1[::-1]
print(str2)
Ausgabe:
ollaH
Mit zweidimensionalen Listen/Tupels wird das Ganze schon bedeutend komplexer.
Beispiel: Verkettetes Slicing
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
print(A[2::][::2])
Ausgabe:
[['20', '21', '22', '23'], ['40', '41', '42', '43']]
Das erste Slicing erstellt folgenden Slice:
[["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
Das zweite Slicing wird dann auf diesen Slice angewendet und ergibt das genannte Endergebnis. Will man Spalten statt Zeilen, so funktioniert dieser direkte Weg nicht. Man verwendet dann List Comprehensions oder die NumPy-Bibliothek. Diese Bibliothek erlaubt zweidimensionales Slicing. Sie wird erst später bei den Grafiken eingeführt. Deshalb wird hier dazu noch kein Beispiel gezeigt.
= Objektorientierte Programmierung =
{{Wikipedia|Objektorientierte Programmierung}}
* {{W|Klasse (Objektorientierung)|Klasse}} ... die Schablone oder der Bauplan, enthält Methoden und Attribute
* {{W|Objekt (Programmierung)|Objekt}} ... eine Klasseninstanz (die konkrete Ausprägung der Klasse)
* {{W|Attribut (Programmierung)|Attribute}} ... die Eigenschaften eines Objekts
* {{W|Methode (Programmierung)|Methoden}} ... die Aktionen (Operationen), die ein Objekt ausführen kann
* {{W|Vererbung (Programmierung)|Vererbung}} ... neue Klassen (Subklassen, Unterklassen, abgeleitete Klassen) aus vorhandenen Klassen (Superklassen, Oberklassen, Basisklassen, Elternklassen) ableiten. Ermöglicht den Aufbau von Klassenhierarchien. Die Subklasse "erbt" Attribute und Methoden von der Superklasse. Python unterstützt (so wie C++, aber im Gegensatz zu Java) Mehrfachvererbung.
== UML ==
* {{W|Unified Modeling Language|UML}} ... '''U'''nified '''M'''odeling '''L'''anguage, eine Modellierungssprache. Die UML enthält zahlreiche Diagrammarten, um Programme zu modellieren. Im Nachfolgenden wird nur das {{W|Klassendiagramm}} verwendet.
[[File:UmlCd Klasse-3.svg|300px]]
* {{W|Sichtbarkeit (Programmierung)|Sichtbarkeit}}:
** + ... public (öffentlich)
** - ... private
** # ... protected
* {{W|Attribut_(UML)#Attribute_für_Instanzen_und_für_Klassen|Klassenattribute}} (statische Attribute): Werden nur einmal pro Klasse angelegt. Im Klassendiagramm werden sie unterstrichen.
[[File:Attribute-3.png|200px]]
* Vererbung:
<gallery>
InheritancePgmUML.svg | Abgeleitete Klasse erbt von Basisklasse (Einfachvererbung)
Diamond inheritance.svg | D erbt von B und C (Mehrfachvererbung). B und C erben von A (Einfachvererbung)
</gallery>
Für weitergehende Betrachtungen zur UML wird auf Spezialliteratur verwiesen, z.B.:
* Seidl et al.: UML@Classroom. dpunkt, 2012, ISBN 978-3-89864-776-2
* Rupp et al.: UML 2 glasklar. Hanser, 4. Aufl., 2012, ISBN 978-3-446-43057-0
== Eine einfache Klasse ==
[[Datei:PythonIng_uml1.svg | 200px]]
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
fahr = Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die Klasse Fahrzeug wird durch das class-Schlüsselwort eingeleitet. raeder ist ein Klassenattribut und public. __init__ wird bei der Objekterzeugung automatisch aufgerufen (ist der sogenannte Konstruktor). Man achte darauf, dass diese Methode immer mit zwei Unterstrichen eingeleitet und abgeschlossen wird. Instanzattributen wird das Wort self vorangestellt. Wir sehen uns z.B. das Attribut self.__geschwind an. Auch hier werden zwei Unterstriche verwendet. Das bedeutet, dass dieses Attribut strikt/stark private ist. Wird nur ein Unterstrich verwendet, so deutet dies auf schwach/weakly private hin. Letzteres wird in Python deutlich häufiger verwendet. Bei den Methoden wird immer self als erster Parameter angegeben. Beim Aufruf der entsprechenden Funktion wird das self aber nicht berücksichtigt.
Besonderheiten bei stark und schwach private:
* '''stark private''':
** zwei führende Unterstriche
** Name Mangling: Name wird zu <code>_Klassenname__variablenname</code>
** Schutz vor Namenskollisionen bei Vererbung
** am Ende des Namens dürfen keine zwei Unterstriche verwendet werden. Das wären dann Magic Methods oder Dunder-Methods (z.B. __init__). Diese sind public.
* '''schwach private''':
** ein führender Unterstrich
** Name bleibt gleich
** ist nur ein Hinweis an die Programmierer, kein starker Schutz
** <code>from modul import *</code>: Objekte mit einem führenden Unterstrich werden standardmäßig nicht importiert
** Standard für die Kapselung bei Python. Schätzung: Weit mehr als 80% der nicht-öffentlichen Attribute/Methoden werden als schwach private deklariert. Weniger als 5-10% als stark private (Quelle: Google KI)
== Klassen importieren ==
Häufig ist es sinnvoll und übersichtlicher Klassen in eigenen Dateien zu speichern. Das sind dann eigene Module. Abgespeichert werden Sie mit der Endung py, wie bisher auch praktiziert. Aufgerufen werden Sie mit der import-Anweisung. Dann ist aber nur der Dateiname ohne Endung py zu verwenden. Klarer wird das mit einem Beispiel.
Datei c:\tmp\fahrzeug.py
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
Datei c:\tmp\test1.py
import fahrzeug
fahr = fahrzeug.Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die üblichen import-Anweisungen lauten wie folgt:
{| {{prettytable}}
! import-Befehl
! Instanz
|-
| import xyz || xyz.Klasse
|-
| import xyz as x || x.Klasse
|-
| from xyz import Klasse || Klasse
|-
| from xyz import * || Klasse
|}
Der Vorteil der ersten beiden import-Anweisungen ist, dass es kaum zu Namenskollisionen kommen kann. Dafür hat man bei den letzten beiden Varianten weniger Tipparbeit.
== Vererbung ==
=== Einfachvererbung ===
[[Datei:PythonIng_uml2.svg | 200px]]
Datei fahrzeug.py:
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
class Luftfahrzeug(Fahrzeug):
def __init__(self, geschwindigkeit, leistung, fluegel):
super().__init__(geschwindigkeit, leistung)
self.__flueg = fluegel
def getFlueg(self):
return self.__flueg
Datei test1.py:
import fahrzeug
fahr = fahrzeug.Luftfahrzeug(150, 90, 4)
print(fahr.getFlueg())
Ausgabe:
4
=== Mehrfachvererbung ===
Mit Python ist auch Mehrfachvererbung möglich, z.B.:
class A:
def _printA(self):
print("Klasse A")
class B:
def _printB(self):
print("Klasse B")
class C(A,B):
def __init__(self):
self._printA()
self._printB()
c = C()
Ausgabe:
Klasse A
Klasse B
Die Klasse C erbt von A und B. In UML sieht das in etwa so aus:
+-----------------------------+ +-------------------------+
| A | | B |
+-----------------------------+ +-------------------------+
| | | |
+-----------------------------+ +-------------------------+
| # printA() | | # printB() |
+-----------------------------+ +-------------------------+
. .
/ \ / \
--- ---
| |
| |
+---------------------+
| C |
+---------------------+
| |
+---------------------+
| |
+---------------------+
<code>printA()</code> und <code>printB()</code> sind schwach private (in UML als <code>protected</code> mit einem # dargestellt). Es ist aber zu beachten, dass schwach private nur Konvention ist. Praktisch könnte man auch von außerhalb auf diese Methoden zugreifen. Das soll man aber nicht tun, und das wird in Python durch einen Unterstrich angedeutet.
= Grafiken zeichnen =
Für das Zeichnen von Grafiken wird hier das Modul <code>matplotlib</code> verwendet. <code>matplotlib</code> ist ein externes Modul und muss vor der ersten Verwendung installiert werden. Das geht so:
# Starten Sie ein Terminal (bei Windows die Eingabeaufforderung).
# Führen Sie darin folgenden Befehl aus <code>c:\devel\Python\Scripts\pip.exe install matplotlib</code>
pip ist übrigens der Paketmanager von Python ({{W|Pip_(Python)}}).
Optimalerweise installieren wir auch gleich das Modul <code>numpy</code> (Numerical Python). Wir werden es im Folgenden oft benötigen (nicht nur bei den Grafiken). Das funktioniert vom Prinzip her genauso, wie für <code>matplotlib</code> gezeigt.
<small>Verwenden Sie Spyder, so sind diese Schritte nicht nötig. Spyder inkludiert diese Pakete standardmäßig. Unter openSUSE Tumbleweed lassen sich diese Pakete mittels YaST oder zypper installieren.</small>
== 2D ==
=== Graph einer Funktion ===
Es soll die cosh-Funktion im Intervall <math>x\in[-3,3]</math> gezeichnet werden. Der Programmcode lautet in der einfachsten Form:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x)
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh1.jpg]]
Der Code ist quasi selbsterklärend. Das Untermodul pyplot des matplotlib-Moduls und das numpy-Modul werden importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plt.plot()" ist der Zeichenbefehl. "plt.show" ist notwendig, um das Fenster mit der Grafik anzuzeigen.
Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen. "plt.grid()" zeichnet ein Gitter in die Grafik (kann auch weggelassen werden).
Die Bezeichnungen plt und np könnten auch anders gewählt werden. Es ist aber Konvention, diese so wie hier gezeigt zu wählen. Die "arange"-Funktion aus der NumPy-Bibliothek wird später ein bisschen genauer behandelt (siehe [[Ing_Mathematik:_Python#Zahlenfolgen|Zahlenfolgen]]).
<small>Mit der im obigen Bild gezeigten Menüleiste kann die dargestellte Grafik nachträglich noch geändert werden (Zoom, Pan, Achsenparameter, Kurvenparameter etc.). Natürlich kann man das alles auch direkt programmieren. Wie das funktioniert wird ansatzweise etwas später gezeigt.</small>
Ein etwas komplexeres Beispiel ist Folgendes:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x) + 2**x
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh4.png]]
Man beachte, dass im Gegensatz zu Octave und Julia der ominöse Punkt (.) bei 2**x mit Python nicht benötigt wird. Das macht das Programmiererleben etwas einfacher.
Die Farbe des Graphen kann man über den <code>color</code>-Schalter einstellen, z.B. auf rot setzen:
plt.plot(x, y, color="red")
Das ist nur eine Möglichkeit, es gibt auch andere, z.B. mittels
* hexadezimaler Zahl, z.B. <code>color="#ff0000"</code>
* Kurzform, z.B. <code>"r"</code>
Statt <code>color</code> kann auch die Kurzform <code>c</code> verwendet werden.
<u>Kleine Aufgabe:</u> Probieren Sie diese "Farbspielereien" am Computer aus.
=== Graphen mehrerer Funktionen und weiteres ===
==== Mehrere Funktionen in einen Plot zeichnen ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x")
plt.plot(x, y2, label = "sin(x) * cos(x)")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh2.png]]
Um die Linienstile etwas individueller zu gestalten, ist folgender Programmcode gedacht:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
plt.plot(x, y2, label = "sin(x) * cos(x)", lw=3, ls="--")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh3.png]]
Einige weitere Bespiele zu <code>ls</code></code>:
* - ... durchgezogene Linie
* -. ... Strichpunkt-Linie
* dashed ... gestrichelte Linie
==== Marker ====
Desweiteren kann man Marker verwenden.
Beispiel:
import matplotlib.pyplot as plt
plt.plot(10, 10, "ob", markersize=30)
plt.plot(20,20, ".r")
plt.plot(30,30, "Dg", ms=15)
plt.plot(40, 40, "ok", ms=20, mec="#FF5733", mew=3)
plt.plot(50, 50, "vk", ms=20, mec="yellow", mew=3)
plt.grid()
plt.show()
Das erste Zeichen im String nach den Koordinaten im plot-Befehl symbolisiert die Form (z.B. o für einen Kreis). Das zweite Zeichen steht für die Farbe (z.B. b für blue). <code>markersize</code> oder <code>ms</code> setzt die Größe des Markers.
Ausgabe:
[[Bild:PythonIng_formatpara1.svg|200px]]
Einige weitere Marker:
* * ... Stern
* + ... Plus
* h oder H ... Sechseck
Man kann mit den Parametern
* <code>markeredgecolor</code> oder kurz <code>mec</code> die Farbe des Markerrandes
* <code>markeredgewidth</code> oder kurz <code>mew</code> die Dicke des Randes
* <code>markerfacecolor</code> oder kurz <code>mfc</code> die Innenfarbe des Markers
bestimmen.
=== Funktion in Parameterdarstellung ===
Es soll die archimedische Spirale <math>x = t \cos(t), y = t \sin(t)</math> im Intervall <math>[0, 6\pi[</math> gezeichnet werden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.show()
[[Datei:PythonIng_spirale1.png]]
Diese Darstellung erscheint verzerrt. Will man gleiche Achsenskalierungen, so kann man den plt.axis()-Befehl verwenden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.axis("equal")
plt.show()
[[Datei:PythonIng_spirale2.png]]
=== Funktion in Polardarstellung ===
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
r = np.arange(0, 1, 0.01)
theta = r**3
line = ax.plot(theta, r)
plt.show()
[[Datei:PythonIng_polar1.png]]
=== Logarithmische Achsenskalierung ===
==== Semilog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.semilogy()
plt.show()
Ausgabe:
[[Datei:PythonIng_semilog1.png]]
==== LogLog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.loglog()
plt.show()
[[Datei:PythonIng_loglog1.png]]
=== Gefüllte Fläche ===
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 3, 0.1)
y1 = 3*x - 1
y2 = x**2
plt.plot(x, y1, x, y2, color='black')
plt.fill_between(x, y1, y2, where=y1>=y2)
plt.show()
[[Datei:PythonIng_gefuellt.png]]
=== Linien, Pfeile, Rechtecke, Kreise und Texte ===
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
r = mpl.patches.Rectangle((0, 0), 3, 3, angle=30, fill=False)
c = mpl.patches.Circle((4, 4), 2, fill=False)
ax.add_patch(r)
ax.add_patch(c)
ax.plot([-2, 7], [-2, 0], color="black")
ax.arrow(0, 7, 5, 0, length_includes_head=True, head_width=0.5, head_length=1.5,
color="black")
ax.set_aspect("equal")
plt.axis([-3, 8, -3, 8])
plt.show()
[[Datei:PythonIng_linien_pfeile_etc.png]]
Text kann mit <code>ax.text(x, y, "Text")</code> hinzugefügt werden, bspw.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
ax.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
Oder einfacher auch ohne <code>subplots</code>
import matplotlib.pyplot as plt
plt.text(0.1, 0.1, "Hallo")
plt.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text1.png]]
Auch Sonderzeichen (griechische Buchstaben etc.) können verwendet werden (siehe dazu auch [https://matplotlib.org/stable/users/explain/text/mathtext.html]).
import matplotlib.pyplot as plt
plt.text(.3, .5,
r'$\Omega\ \psi\ \oint\ \nabla\ \dot a\ \frac{a}{b}\ a_b$',
size="20")
plt.show()
[[Datei:PythonIng_text20.svg]]
Jetzt wird noch gezeigt, wofür <code>subplots</code> sinnvoll eingesetzt werden können.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(0.1, 0.1, "Hallo")
ax[1].text(0.1, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text2.png]]
=== Anmerkungen hinzufügen ===
Anmerkungen (engl. annotations) lassen sich mit matplotlib einfach hinzufügen. Unter Anmerkung wird hier ein Pfeil mit Text verstanden.
Beispiel:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1,10], [1,10])
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0))
plt.show()
Ausgabe:
[[Datei: PythonIng_ann1.svg|400px]]
<code>shrink</code> verkürzt den Pfeil. Sinnvoll sind beim obigen Beispiel Werte irgendwo zwischen 0.0 und 0.3.
<u>Kleine Aufgabe:</u> Probieren Sie verschiedene Pfeillängen aus.
Die Schriftgröße verändern können Sie übrigens mit <code>fontsize</code> oder <code>size</code>, z.B.
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0), fontsize=25)
Eine andere Schreibweise für Dictionaries, die wir weiter oben schon kennengelernt haben, die wir aber nochmals explizit aufschreiben wollen, ist
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops={"facecolor":"red", "shrink":0.0})
=== Figure, Axes etc.===
[[Bild:PythonIng_figure33.svg|350px]]
* fig (figure) ... das übergeordnete Fenster
* ax (axes) ... "Plot", das eigentliche Zeichenfenster
* axis ... die Koordinatenachsen
* spine ... Begrenzungslinien des Zeichenfensters
* tick ... Markierung an den Achsen des Zeichenfensters
Beispiel (eine figure mit 6 axes, ax-Titel, y-axis-Titel):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=3, ncols=2)
ax[0][0].text(0.1, 0.5, "11")
ax[0][1].text(0.1, 0.5, "12")
ax[1][0].text(0.1, 0.5, "21")
ax[1][1].text(0.1, 0.5, "22")
ax[2][0].text(0.1, 0.5, "31")
ax[2][1].text(0.1, 0.5, "32")
ax[0][0].set(ylabel="y-label", title="axes 1")
plt.show()
[[Bild:PythonIng_figure34.png|350px]]
Beispiel (Achsenbereiche setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-1, 10, 1, 12))
plt.show()
[[Bild:PythonIng_figure35.svg|350px]]
Beispiel (Gitter einschalten):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-5, 10, 1, 12))
ax[0].minorticks_on()
ax[0].grid(which='minor')
ax[1].grid(which='major')
plt.show()
[[Bild:PythonIng_figure36.svg|350px]]
Beispiel (ticks setzen)
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
pos = [0, .2, .5]
lab = ["a", "b", "c"]
ax.xaxis.set_major_locator(tick.FixedLocator(pos))
ax.xaxis.set_major_formatter(tick.FixedFormatter(lab))
plt.show()
[[Bild:PythonIng_figure37.svg|350px]]
Beispiel (Achsenkreuz beliebig setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position(('data', 0.3))
ax.spines['left'].set_position(('data', 0.5))
plt.show()
[[Bild:PythonIng_figure38.svg|350px]]
Beispiel (Inset):
import matplotlib.pyplot as plt
# Hauptplot erstellen
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
# Inset hinzu:
axin = ax.inset_axes([0.4, 0.4, 0.3, 0.3])
axin.text(0, 0, "Servus")
axin.plot()
plt.show()
[[Bild:PythonIng_figure40.svg|350px]]
Beispiel (Hintergrundfarben setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_facecolor("green")
fig.set_facecolor("yellow")
plt.plot([1, 3], [6, 8])
plt.show()
[[Bild:PythonIng_figure39.svg|300px]]
=== GridSpec ===
Mit figures und axes lassen sich schon jede Menge an Grafikdetails einstellen. GridSpec ist dann der Turbo oder Raketenantrieb den matplotlib eingebaut hat. Naja, vielleicht ist das etwas übertrieben, aber GridSpec ist sozusagen ein flexibler Layout-Manager. Bisher haben wir immer gleich große axes gezeichnet. Mit GridSpec können wir Subplots über mehrere Zeilen und Spalten ziehen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(3, 3)
ax1 = fig.add_subplot(gs[0, :])
ax1.set_title("Bereich 1: gs[0, :]")
ax2 = fig.add_subplot(gs[1:, 0])
ax2.set_title("Bereich 2: gs[1:, 0]")
ax3 = fig.add_subplot(gs[1, 1:])
ax3.set_title("Bereich 3: gs[1, 1:]")
ax4 = fig.add_subplot(gs[2, 1:])
ax4.set_title("Bereich 4: gs[2, 1:]")
plt.show()
[[Bild:PythonIng_gridspec1.svg|350px]]
Erklärung zu <code>(gs[zeile, spalte])</code>: Slicing; damit legen Sie fest, welche Zellen ein Subplot belegt. Achtung! Die Indizes beginnen bei 0 und nicht bei 1 (d.h., die erste Zeile/Spalte hat den Index 0)
* : ... alle
* 1: ... 1 bis Ende
* etc.
<code>constrained_layout=True</code> sorgt dafür, dass sich die Subplots nicht überlappen.
Aber auch die Spaltenbreiten und Zeilenhöhen lassen sich anpassen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
# Verhältnis erste zu zweite Zeile = 1.5:1
# Verhältnis erste zu zweite Spalte = 1:4
gs = fig.add_gridspec(2, 2, figure=fig, height_ratios=[1.5, 1], width_ratios=[1, 4])
ax1 = fig.add_subplot(gs[0, 0])
ax1.set_title("Bereich 1: gs[0, 0]")
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_title("Bereich 2: gs[0, 0]")
ax3 = fig.add_subplot(gs[1, 0])
ax3.set_title("Bereich 3: gs[1, 0]")
ax4 = fig.add_subplot(gs[1, 1:])
ax4.set_title("Bereich 4: gs[1, 1]")
plt.show()
[[Bild:PythonIng_gridspec2.svg|350px]]
Auch die Ränder lassen sich einstellen.
Beispiel 1:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.1, right=0.9, bottom=0.1,
top=0.9, wspace=0.2, hspace=0.2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec3.svg|300px]]
* hspace ... height space, vertikaler Abstand zwischen den Zeilen
* wspace ... width space, horizontaler Abstand zwischen den Spalten
Und im Vergleich dazu Beispiel 2:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.3, right=0.7, bottom=0.3,
top=0.7, wspace=0.3, hspace=0.3)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec4.svg|300px]]
Es gibt noch einige weitere Details, die sich mit GridSpec variieren lassen (z.B. SubGridSpec ... verschachtelte Grid-Layouts). Aber wir belassen es vorerst dabei. Das bisher Gezeigte sollte für die meisten Probleme ausreichend sein.
=== Aufgaben ===
* Zeichnen Sie die Strophoide <math>x = \frac{a(t^2-1)}{t^2+1}, y = \frac{at(t^2-1)}{t^2+1}, a = 2, -3 \leq t \leq 3</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_strophoide.jpg|300px|center]]
* Zeichnen Sie die verschlungene Hypozykloide <math>x = (R-r)\cos t + c\cos\frac{R-r}{r}t, y = (R-r)\sin t - c\sin\frac{R-r}{r}t, c = 3, r = 2, R = 6, -15 \leq t \leq 15</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_hypozykloide.jpg|300px|center]]
* Testen Sie bei den obigen Übungsaufgaben verschiedene Linienstile und Farben. Farben können mit dem plt.plot()-Parameter color gewählt werden.
* Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.
* Zeichnen Sie folgendes Bild (die Achsenbeschriftungen positionieren Sie z.B. mit den Befehlen <code>ax.set_xlabel("x", loc="right"); ax.set_ylabel("y", loc="top")</code>):
[[Bild:PythonIng_aufgabe24.svg|400px|center]]
* Zeichnen Sie mit Python, matplotlib und NumPy folgendes Bild:
[[Bild:PythonIng_figure41.svg|400px|center]]
* Zeichnen Sie mit GridSpec ein Layout, das in etwa wie folgendes aussieht (<code>height_ratios=[1, 2], width_ratios=[2, 1]</code>):
[[Bild:PythonIng_aufgabe23.svg|300px|center]]
== 3D ==
=== Räumliche Kurven ===
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0, 6*np.pi, 0.1)
x = t * np.cos(t)
y = t * np.sin(t)
z = t
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot(x, y, z)
plt.show()
[[Datei:PythonIng_raumkurve1.png]]
=== Flächen ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z)
plt.show()
[[Datei:PythonIng_fläche1.png]]
Das Ganze in Netzdarstellung läßt sich so programmieren:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = np.arange(0, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_wireframe(x, y, z)
plt.show()
[[Datei:PythonIng_fläche2.png]]
Ein etwas komplexeres Beispiel:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.1, 10, 0.1)
y = np.arange(0.1, 10, 0.1)
x, y = np.meshgrid(x, y)
z1 = np.sin(x) + 3 * np.cos(y)
z2 = np.sin(x) + np.log(y)
z3 = x + np.cos(y)
z4 = x**2 - y
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, nrows=2, ncols=2)
ax[0][0].plot_surface(x, y, z1)
ax[0][1].plot_surface(x, y, z2)
ax[1][0].plot_surface(x, y, z3)
ax[1][1].plot_surface(x, y, z4)
plt.show()
[[Datei:PythonIng_subplot1.png]]
Man beachte, dass man die Unterbilder im Bild nach dem Ausführen des Scripts z.B. mit der mittleren Maustaste einzeln drehen, oder über die Einträge in der Menüzeile einzeln bearbeiten kann. Mit ein paar Zeilen Programmtext lässt sich also eine Menge an Funktionalität generieren.
Die Farbgebung lässt sich über <code>colormaps</code> variieren.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm)
plt.show()
[[Datei:PythonIng_colormap1.png]]
Es gibt eine Menge an Colormaps, z.B. <code>plasma, Greys, Dark2, ocean</code>. Zwecks detaillierterer Infos siehe die matplotlib-Dokumentation. <small>Verwendet man die IDE namens IDLE, so gibt es dort auch die automatische Codevervollständigung. D.h. es werden alle Möglichkeiten (in unserem Fall nach dem Eintippen von <code>cm.</code> alle verfügbaren Colormaps) angezeigt.</small>
Die "edgecolor" und Linienbreite können auch frei gewählt werden:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm, edgecolor="black", linewidth=1.0)
plt.show()
[[Datei:PythonIng_colormap2.png]]
=== Höhenlinien ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
ax.contour(x, y, z)
plt.show()
[[Datei:PythonIng_höhenlinien1.png|400px]]
Etwas abgewandelt sieht das so aus:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contour(x, y, z)
ax.clabel(hl, inline = True)
plt.show()
[[Datei:PythonIng_höhenlinien2.png|400px]]
Und noch eine Variante (mit einem Farbbalken) sei gezeigt.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contourf(x, y, z)
fig.colorbar(hl)
plt.show()
[[Datei:PythonIng_höhenlinien5.svg|400px]]
=== Aufgaben ===
* Zeichnen Sie die räumliche Kurve <math>x = 2 \cdot \cosh(t)</math>, <math>y = 5 \cdot \sin(t)</math>, <math> z = t^{2} - t</math>, <math>0 \leq t \leq 3\pi</math>.
* Zeichnen Sie die Fläche <math>z = \log(x) + \cos(y)</math>.
== Animationen und fortgeschrittenes 3D ==
=== Mit matplotlib ===
Auch mit matplotlib sind Animationen möglich. Das ist ein bisschen komplizierter und wird deshalb hier nur mit einem sehr einfachen Beispiel dargestellt (bei Interesse siehe z.B. auch das [https://matplotlib.org/stable/users/explain/animations/animations.html#animations Animations using Matplotlib-Tutorial]).
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib
import numpy as np
def update(frame):
line.set_xdata(x[:frame])
line.set_ydata(y[:frame])
return (line)
fig, ax = plt.subplots()
x = np.arange(0, 10, .1)
y = np.sin(x)
line, = ax.plot(x[0], y[0])
ax.set(xlim=[0, 10], ylim=[-1, 1])
a = ani.FuncAnimation(fig=fig, func=update, frames=100, interval=20)
plt.show()
# Speichere die Animation in einem animierten GIF (optional)
a.save(filename="c:/tmp/PythonIng_anim5.gif", writer="pillow")
[[Datei:PythonIng_anim5.gif]]
Es wird eine Sinuskurve auf den Bildschirm gezeichnet. In der letzten Zeile wird diese Animation in ein animiertes GIF gespeichert. Das ist natürlich optional und kann auch weggelassen werden.
=== Mit VPython ===
Aber auch mit dem Modul VPython lassen sich einfache 3D-Animationen erstellen. VPython ist ein externes Modul, das vorab installiert werden muss. Unter openSUSE Tumbleweed gibt es dzt. kein entsprechendes rpm-Paket. Die übliche Methode der Installation mittels YaST oder zypper ist somit nicht möglich. Auch eine direkte Verwendung von pip führt nur zu einer Fehlermeldung (<code>error: externally-managed-environment</code>). Es empfiehlt sich dort folgende Vorgehensweise:
# Erstelle zuerst eine virtuelle Umgebung, z.B.: <code>python3.11 -m venv ~/tmp/venv1</code>
# Wechsle das Verzeichnis: <code>cd ~/tmp/venv1/bin</code>
# Installiere das entsprechende Paket: <code>./pip install vpython</code>
# Führe das entsprechende Skript aus: <code>./python ~/tmp/test1.py</code>
Aktuell (März 2026) ist dieses Programmpaket lt. der [https://vpython.org/presentation2018/install.html VPython-Homepage] nur für die Python-Versionen 3.8 bis 3.12 verfügbar.
Ein Beispiel zu einer einfachen Animation wird nachfolgend geliefert.
from vpython import *
scene.width = 1200
scene.height = 600
scene.center = vector(20,0,0)
scene.background = color.white
cylinder(pos=vector(0,0,0), axis=vector(20,0,0), radius=5,
color=color.blue)
cone(pos=vector(0,0,0), axis=vector(-10,0,0), radius=5,
color=color.blue)
helix(pos=vector(20,0,0), axis=vector(40,0,0), radius=2,
coils=10, thickness=0.5, color=color.blue)
ball = sphere(pos=vector(20,0,0), color = color.green, radius = 1)
ball.p = vector(0.15, 0, 0)
toc = True
while True:
rate(200)
if(ball.pos.x <= 60 and toc == True):
ball.pos += ball.p
else:
toc = False
ball.pos -= ball.p
if(ball.pos.x <= 20 and toc == False):
toc = True
[[Datei:PythonIng_vpython_anim.JPG]]
Idealerweise öffnet sich beim Ausführen des Scripts ein Browserfenster. Darin wird die programmierte Animation gezeigt (siehe auch den obigen Screenshot). Eine Größenänderung können Sie mit der mittleren Maustaste initiieren. Die Szenerie drehen können Sie mit der rechten Maustaste.
=== Mit build123d ===
Hiermit lassen sich einfach 3D-Modelle für CAD-Systeme erstellen. [https://build123d.readthedocs.io/en/latest/ build123d] ist ein externes Modul und muss vorab, wie schon für mehrere andere Module gezeigt, installiert werden (pip, venv etc.).
Beispielcode:
from build123d import *
# Bauteil
with BuildPart() as bauteil:
# Zylinder erstellen
Cylinder(100, 60)
# Bohrung
with BuildSketch(bauteil.faces().sort_by(Axis.Z)[-1]) as loch:
Circle(radius=10)
# negativ extrudieren
extrude(amount=-60, mode=Mode.SUBTRACT)
# Dem Bauteil z.B. die Farbe rot zuweisen
# bauteil.part.color = Color("red", alpha=1.0)
# Fertiges Modell exportieren
export_step(bauteil.part, "bauteil.step")
Ausgabe ({{W|Standard for the exchange of product model data | STEP}}-Datei, z.B. in {{W|FreeCAD}} importiert, Screenshot):
[[Datei:PythonIng_build123d.jpg | 300px]]
FreeCAD ist ein freies 3D-CAD-System. Die [[Ing_Mathematik:_Python#FreeCAD | Makroprogrammierung]] in diesem System wird später noch gezeigt. STEP steht für "'''St'''andard for the '''e'''xchange of '''p'''roduct model data" und ist ein Datenaustauschformat.
=== Mit VTK ===
Komplexer, aber auch mächtiger als VPython ist die Verwendung von VTK ('''V'''isualization '''T'''ool'''k'''it). Genauer gesagt des Python-Wrappers von VTK. Dieses externe Python-Modul muss vorab installiert werden (z.B. mittels YaST, pip oder in eine virtuelle Umgebung). VTK ist eine Softwarebibliothek zur 3D-Visualisierung und wurde ursprünglich in C++ geschrieben. Verbreitet eingesetzt wird diese Bibliothek in der Wissenschaft und Forschung, z.B.
* in der medizinischen Bildgebung
* für Strömungssimulationen
* für Klimadaten
VTK funktioniert nach dem {{W|Grafikpipeline|Pipeline-Prinzip}}:
Source (Quellen) -> Filter -> Mapper (Senken) -> Actor/Renderer
Daten fließen von den Quellen zu den Senken.
Als einfaches Beispiel wird die Darstellung eines Zylinders gezeigt, der mit den Maustasten gedreht oder in der Größe geändert werden kann:
import vtk
# Zylinder erzeugen
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
# Geometrie in darstellbare Daten umwandeln
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
# Objekt in der Szene
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Szene verwalten
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# Render-Fenster
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
# Maus/Tastatur-Steuerung
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Starten
render_window.Render()
interactor.Start()
Ausgabe:
[[Datei:PythonIng_VTK_1.png]]
Gleiches Beispiel wie oben, aber mit einer Animationssequenz:
import vtk
import time
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
render_window.Render()
time.sleep(0.01)
Das Grafikfenster schließt sich nach Ablauf der Schleife. Das Fenster bleibt geöffnet, wenn Sie am Programmende folgenden Befehl hinschreiben
interactor.Start()
Um den animierten Zylinder grün einzufärben, müssen Sie Folgendes im obigen Programm ergänzen (Farbnamen):
colors = vtk.vtkNamedColors()
actor.GetProperty().SetColor(colors.GetColor3d("Green"))
Als Namen können Sie u.a. die CSS3 Web-Farben verwenden (siehe z.B. [https://wiki.selfhtml.org/wiki/Farbe/Farbangaben] und {{W|Webfarbe#CSS_3}}).
Alternativ funktioniert auch das ({{W|RGB-Farbraum|RGB}}):
actor.GetProperty().SetColor(0.0, 0.6, 0.0)
Wie der Zylinder mit einer Textur versehen wird, zeigt folgendes Programm:
import vtk
import time
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(30)
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.CappingOn()
texture_coords = vtk.vtkTextureMapToCylinder()
texture_coords.SetInputConnection(cylinder.GetOutputPort())
texture_coords.PreventSeamOn()
reader = vtk.vtkJPEGReader()
reader.SetFileName("PythonIng_textur.jpg")
texture = vtk.vtkTexture()
texture.SetInputConnection(reader.GetOutputPort())
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(texture_coords.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.SetTexture(texture)
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
renderWindow.Render()
time.sleep(0.01)
interactor.Start()
<gallery>
PythonIng_textur.jpg | Textur-Datei
PythonIng_VTK_2.png | Ausgabe (Screenshot)
</gallery>
== Sonstige Grafikbibliotheken ==
=== Py5 ===
Im Buch ''Iacono et al.: Programmieren trainieren, mit über 150 Workouts in Java und Python; 3. Aufl., Hanser, 2023'' werden zahlreiche Aufgaben gestellt, die u.a. mit Processing zu lösen sind. Processing ist eine einfache Programmiersprache und Entwicklungsumgebung. Warum ich das erwähne? Weil in älteren Processing-Versionen auch die Programmiersprache Python 2 abgedeckt war. Bei neueren Versionen gibt es keine Python-Anbindung mehr (getestet nur mit openSUSE Tumbleweed und Python 3). Somit funktioniert der Python-Teil im genannten Buch zum Teil nicht mehr. Ist das tragisch, oder kann das Buch weggeschmissen werden? Nein! Es gibt Alternativen zu Processing. Zum einen die im Buch selbst genannten Bibliotheken tkinter oder pygame. Pygame wird dort auch kurz anhand eines Beispiels thematisiert. Aber noch besser ist es, die py5-Bibliothek zu verwenden (lt. Google KI vom 30. Sept. 2026: ''Der echte, moderne „spirituelle Nachfolger“''). Damit ist die Funktionalität von Processing gewährleistet. Man kann aber beliebige Editoren oder IDEs zur Programmerstellung verwenden, ohne an Processing als IDE gebunden zu sein. Nachfolgend werden ein paar Beispiele zu dieser externen Bibliothek gegeben. Der erste Schritt ist wieder, die py5-Bibliothek zu installieren (z.B. mittels pip in eine virtuelle Umgebung; Python>=3.10 und ein JDK>=17 müssen auch installiert sein (Stand Okt. 2026)). Dann kann es schon mit dem Programmieren losgehen.
Beispiel (angelehnt an die ''Aufgabe W.2.3 Haus'' des genannten Buchs, jedoch etwas erweitert):
import py5
def setup():
py5.size(600, 600) # Fenstergröße 600px x 600px
py5.background(255, 255, 255) # Hintergrundfarbe ... weiss
def draw():
# Haus zeichnen
py5.fill(255, 255, 255) # Hintergrundfarbe ... weiss
py5.stroke(255, 0, 0) # Linienfarbe ... rot
py5.stroke_weight(3) # Linienbreite ... 3px
py5.rect(150, 200, 300, 300) # Rechteck zeichnen (x, y, b, h)
py5.triangle(150, 200, 300, 100, 450, 200) # Dreieck zeichnen
py5.circle(250, 300, 70) # Kreis zeichnen (x, y, d)
# Bemassung zeichnen
py5.stroke(0, 255, 0)
py5.stroke_weight(1)
py5.line(300, 100, 550, 100) # Linie zeichnen
py5.line(450, 200, 550, 200)
py5.line(450, 500, 550, 500)
py5.line(150, 500, 150, 550)
py5.line(450, 500, 450, 550)
py5.text_size(20) # Textgroesse
py5.fill(0, 255, 0) # Textfarbe
py5.text("300", 280, 550) # Text zeichnen
py5.text("100", 500, 150)
py5.text("300", 500, 350)
# Gedrehtes Rechteck zeichnen
py5.stroke(255, 255, 0)
py5.stroke_weight(3)
py5.fill(200, 200, 200)
py5.translate(320, 260)
py5.rotate(0.3) # Drehung (in Radiant)
py5.rect(0, 0, 100, 50)
# Startet den Sketch
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_1.png|300px]]
Das skizzierte Haus ist mit einer rudimentären Bemaßung versehen und hat zwei Fenster, ein rundes und ein gedrehtes, trübes rechteckiges.
Beispiel (Mausoperationen):
import py5
def setup():
py5.size(600, 600)
py5.background(255, 255, 255)
def draw():
pass
def mouse_pressed():
py5.text_size(15)
py5.fill(0, 0, 255)
x = py5.mouse_x
y = py5.mouse_y
py5.text("(%d, %d)" %(x, y), x, y) # Positionsdaten bei Maus-Klick schreiben
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_2.png|300px]]
Obiges Bild zeigt das Resultat nach einigen Mausklicks. Man erkennt, dass links-oben der Koordinatennullpunkt ist. Die x-Achse zeigt nach rechts, die y-Achse nach unten.
Beispiel (Fünfeck):
import py5
import random
def setup():
py5.size(400, 400)
py5.no_loop() # statisches Bild (schont die Ressourcen)
def draw():
py5.translate(py5.width / 2, py5.height / 2) # KS setzen
radius = 150
eck_anzahl = 5
py5.fill(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255)) # Füllfarbe auf Zufallswert setzen
py5.stroke(155, 0, 0)
py5.stroke_weight(5)
# Fünfeck als Polygon zeichnen
py5.begin_shape()
for i in range(eck_anzahl):
winkel = i * py5.TWO_PI / eck_anzahl - py5.HALF_PI
x = py5.cos(winkel) * radius
y = py5.sin(winkel) * radius
py5.vertex(x, y)
py5.end_shape(py5.CLOSE)
py5.run_sketch()
Ausgabe, bspw.:
[[Datei:PythonIng_py5_5.png|200px]]
<u>Kleine Aufgaben:</u>
* Um die Funktionsweise von <code>py5.no_loop()</code> zu verstehen, kommentieren Sie die Anweisung im Beispiel einfach aus, und starten Sie das Programm erneut.
* Zeichnen Sie ein Siebeneck.
* Was passiert, wenn man <code>py5.CLOSE</code> im <code>py5.end_shape()</code>-Befehl weglässt?
Beispiel (Grafik laden und zeichnen):
import py5
image1 = None
def setup():
global image1
py5.size(600, 600)
py5.no_loop()
image1 = py5.load_image("PythonIng_py5_1.png")
def draw():
py5.image(image1, 0, 0)
py5.run_sketch()
Hier wird einfach das Bild vom Haus-Beispiel (Screenshot von weiter oben) geladen und gezeichnet.
Beispiel (angelehnt an ''W.5.10 Wurfparabel'' des genannten Buches; mit OOP erstellt):
import py5
class Wurfparabel(py5.Sketch):
def __init__(self, v0, angle):
super().__init__()
self.v0 = v0
self.angle = self.radians(angle)
self.g = 9.81
self.t = 0.0
self.scale = 1.5
def settings(self):
self.size(800, 600)
def setup(self):
self.background(0, 0, 0)
def draw(self):
self.t += 0.1
self.translate(50, 500)
# KS Zeichnen
self.fill(255, 255, 0)
self.stroke(255, 255, 0)
self.stroke_weight(1)
self.line(0, 0, 0, -300)
self.line(0, 0, 700, 0)
# Punkt zeichnen
cx = self.v0 * self.cos(self.angle) * self.t * self.scale
cy = -(self.v0 * self.sin(self.angle) * self.t - \
self.g/2 * self.t**2) * self.scale
self.fill(255, 0, 0)
self.stroke(255, 0, 0)
self.circle(cx, cy, 3)
# Stoppen bei Bodenkontakt
if cy >= -5:
self.no_loop()
def wurfparabel(v0=50, angle=45):
sketch = Wurfparabel(v0, angle)
sketch.run_sketch()
v0 = float(input("v0 = "))
winkel = float(input("winkel = "))
wurfparabel(v0=v0, angle=winkel)
Eingabe auf der Konsole:
v0 = 60
winkel = 45
Ausgabe:
[[Datei:PythonIng_py5_13.png|200px]]
Hiermit belassen wir es mit der py5-Bibliothek und wenden uns wieder "mathematischeren" Themen zu.
= Vektoren und Matrizen =
== Zahlenfolgen ==
Für das Erstellen von Zahlenfolgen bieten sich die Funktionen <code>arange</code> und <code>linspace</code> aus dem <code>numpy</code>-Modul an.
from numpy import *
start = 0
stop = 10
step = 2
num = 10
r = arange(start, stop, step) # step ... Schrittweite
l = linspace(start, stop, num) # num ... Anzahl der Werte
print("r = ", r)
print("l = ", l)
Ausgabe:
r = [0 2 4 6 8]
l = [ 0. 1.11111111 2.22222222 3.33333333 4.44444444 5.55555556
6.66666667 7.77777778 8.88888889 10. ]
Bei <code>arange</code> ist der <code>stop</code>-Wert nicht im Ergebnis enthalten, bei <code>linspace</code> standardmäßig aber sehr wohl. Jedoch kann man das bei <code>linspace</code> auch ändern. Dann ist der Stoppwert nicht mehr enthalten:
linspace(start, stop, num, endpoint=False)
== Vektoren ==
Vektoren sollten jedem aus der Linearen Algebra bekannt sein.
=== Arrays ===
In Python mit NumPy kann man Vektoren durch die Funktion array erzeugen.
import numpy as np
l1 = (-5, 3, 2)
l2 = (1, 1, 4)
a1 = np.array(l1)
a2 = np.array(l2)
a3 = a1 + a2
a4 = 2 * a2
print(a1)
print(a2)
print(a3)
print(a3[2])
print(a4)
Ausgabe:
[-5 3 2]
[1 1 4]
[-4 4 6]
6
[2 2 8]
=== Zeilen- und Spaltenvektoren ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
print(z)
print(s)
Ausgabe:
[ [-5 3 2] ]
[[1]
[1]
[4]]
=== Skalarprodukt ===
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
skalarprodukt = np.dot(a1, a2)
print(skalarprodukt)
Ausgabe:
6
=== Vektorprodukt ===
<math>a\ast b=\left(\begin{array}{c}
a_{1}\\
a_{2}\\
a_{3}
\end{array}\right)\ast\left(\begin{array}{c}
b_{1}\\
b_{2}\\
b_{3}
\end{array}\right)=\left(\begin{array}{c}
a_{2}b_{3}-a_{3}b_{2}\\
a_{3}b_{1}-a_{1}b_{3}\\
a_{1}b_{2}-a_{2}b_{1}
\end{array}\right)
</math>
Python-Code:
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
vektorprodukt = np.cross(a1, a2)
print(vektorprodukt)
Ausgabe:
[10 22 -8]
=== Transponierter Vektor ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
# transponierter Vektor
z_tp = np.transpose(z)
# transponierter Vektor
s_tp = np.transpose(s)
print(z_tp)
print(s_tp)
Ausgabe:
[[-5]
[ 3]
[ 2]]
[ [1 1 4] ]
=== Vektorfelder visualisieren ===
import matplotlib.pyplot as plt
import numpy as np
# Daten generieren
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
X, Y = np.meshgrid(x, y)
U = X * Y
V = Y + X
# Plotten
fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='xy')
plt.show()
Ausgabe:
[[Datei:PythonIng_quiver1.png]]
== Matrizen==
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
print(m1)
Ausgabe:
[[1 2 3]
[4 5 6]]
=== Zugriff auf Matrizenelemente ===
Beispiel:
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
# Element aus Zeile 2 und Spalte 3 (Achtung! Index startet bei Null)
print(m1[1,2])
Ausgabe:
6
Visualisierung:
0 1 2
+-----------+
0 | 1 | 2 | 3 |
+-----------+
1 | 4 | 5 | '''6''' |
+-----------+
Beispiel:
import numpy as np
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
B = np.matrix(A)
print(B[2::, ::2])
Ausgabe:
[['20' '22']
['30' '32']
['40' '42']]
Mit der NumPy-Bibliothek funktioniert das zweidimensionale Slicing. Mit normalen Listen/Tupels geht das nicht, was wir schon früher thematisiert haben.
=== Addition und Subtraktion von Matrizen ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
m2 = np.matrix([[0, 0, 2], [1, 3, 2]])
print(m1 + m2)
print(m1 - m2)
Ausgabe:
[[1 2 5]
[5 8 8]]
[[1 2 1]
[3 2 4]]
=== Transponierte Matrix ===
import numpy as np
m = np.matrix([[1, 2, 3], [4, 5, 6]])
mt = np.transpose(m)
print(m)
print(mt)
Ausgabe:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]
=== Rang einer Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
rg = np.linalg.matrix_rank(m)
print(rg)
Ausgabe:
2
=== Inverse Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
mi = np.linalg.inv(m)
print(mi)
Ausgabe:
[[ 1. 0.6]
[-0. -0.2]]
=== Multiplikation von Matrizen (falksches Schema) ===
import numpy as np
m1 = np.matrix([[1, 3, 4], [0, -5, 1]])
m2 = np.matrix([[1, 2], [2, 3], [0, 2]])
print(m1 @ m2)
Ausgabe:
[[ 7 19]
[-10 -13]]
=== Eigenwerte und Eigenvektoren ===
import numpy as np
m = np.matrix([[5, 8], [1, 3]])
D,V = np.linalg.eig(m)
# Eigenwerte
print(D)
# Eigenvektoren
print(V)
Ausgabe:
[7. 1.]
[[ 0.9701425 -0.89442719]
[ 0.24253563 0.4472136 ]]
=== Teilmatrizen ===
import numpy as np
m = np.matrix([[1, 3, 4], [0, -5, 1]])
print("m = ", m)
# Erste Zeile extrahieren
m1 = m[0,:]
print("m1 = ", m1)
# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
m2 = m[0,1]
print("m2 = ", m2)
# Zweite Spalte extrahieren
m3 = m[:, 1]
print("m3 = ", m3)
Ausgabe:
m = [[ 1 3 4]
[ 0 -5 1]]
m1 = [ [1 3 4] ]
m2 = 3
m3 = [[ 3]
[-5]]
=== Spezielle Matrizen ===
==== Nullmatrix ====
import numpy as np
z = np.zeros((3, 2))
print(z)
Ausgabe:
[[0. 0.]
[0. 0.]
[0. 0.]]
==== Einheitsmatrix ====
import numpy as np
z = np.eye(3)
print(z)
Ausgabe:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
==== Matrix mit lauter Einsen ====
import numpy as np
z = np.ones((3, 2))
print(z)
Ausgabe:
[[1. 1.]
[1. 1.]
[1. 1.]]
=== Spärlich besetzte Matrizen ===
Das Thema spärlich besetzter Matrizen wird hier nur kurz angerissen. Nähere Details siehe unter dem Weblink [https://docs.scipy.org/doc/scipy/reference/sparse.html#module-scipy.sparse].
Beispiel:
import numpy as np
import scipy
A = scipy.sparse.csr_array(np.eye(5))
print(A)
Ausgabe:
<Compressed Sparse Row sparse array of dtype 'float64'
with 5 stored elements and shape (5, 5)>
Coords Values
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
(4, 4) 1.0
csr steht für '''c'''ompressed '''s'''parse '''r'''ow.
Andere Möglichkeiten:
* coo-Format ('''coo'''rdinate Format): <code>scipy.sparse.coo_array()</code>
* lil-Format ('''li'''st of '''l'''ists): <code>scipy.sparse.lil_array()</code>
* csc-Format ('''c'''ompressed '''s'''parse '''c'''olumn): <code>scipy.sparse.csc_array()</code>
Es gibt auch <code>scipy.sparse.csr_matrix()</code> etc. Diese Befehle sind aber veraltet und es wird empfohlen, statt dessen die <code>..._array()</code>-Funktionen zu verwenden.
<u>Aufgaben:</u>
Recherchieren Sie im Internet
* generell zum Thema "spärlich besetzte Matrizen mit Python".
* Was sind die Vor-/Nachteile von csr-arrays gegenüber coo- und lil-arrays?
* Wann verwendet man sinnvollerweise csr- und wann csc-arrays?
* Wie wandelt man coo-arrays in csr-arrays um?
= Lineare Gleichungssysteme =
Sei <math>Ax = b</math> ein lineares Gleichungssystem. <math>A</math> sei die Koeffizientenmatrix, <math>x</math> der Lösungsvektor und <math>b</math> ein bekannter Vektor.
Beispiel:
import numpy as np
A = np.array([[5, 1], [0, 2]])
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)
Ausgabe:
[0. 1.]
Siehe dazu auch das Kapitel [[Ing Mathematik: Numerisches Lösen von linearen Gleichungssystemen]]. Dort wird dieses Themengebiet u.a. mit weitergehenden Python-Skripten vertieft.
== Aufgabe ==
* Lösen Sie folgendes Gleichungssystem mittels Python (und zur Kontrolle auch händisch):
5x + 6y - 2z = 12
3x - y - 3z = 6
2x + 2y + 4z = 5
= Polynome =
== Ein erstes einfaches Beispiel ==
Gegeben sei das Polynom <math>7x^3+5x^2+1</math>. In Python:
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p)
Ausgabe:
3 2
7 x + 5 x + 1
== Einzelne Polynomwerte berechnen ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p(1.5))
Ausgabe:
35.875
== Polynome integrieren und differenzieren ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
# 1. Ableitung
p1 = p.deriv()
p2 = p.deriv(1)
# 2. Ableitung
p3 = p.deriv(2)
# Integral
p4 = p.integ()
print(p1)
print(p2)
print(p3)
print(p4)
Ausgabe:
2
21 x + 10 x
2
21 x + 10 x
42 x + 10
4 3
1.75 x + 1.667 x + 1 x
== Nullstellen bestimmen ==
import numpy as np
p = np.poly1d([2, 5, 0, 4])
r = np.roots(p)
print(r)
Ausgabe:
[-2.7621427 +0.j 0.13107135+0.84077099j 0.13107135-0.84077099j]
== Aufgaben ==
* Berechnen Sie den Wert für x = 3 des Polynoms <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Differenzieren und integrieren Sie das Polynom <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Berechnen Sie die Nullstellen von <math>y = 7x^5 - 3x^2 + 12</math>.
= Nichtlineare Gleichungen und Gleichungssysteme =
== Nullstellenbestimmung ==
Löse eine beliebige Gleichung f(x) = 0, z.B. <math> f(x) = x^2 - 5\cos(x) - 10 = 0 </math>:
import scipy
import numpy as np
def f(x):
return x**2 - 5*np.cos(x) - 10
xstart = [-1, 1] # Startwerte
xn = scipy.optimize.root(f, xstart)
print(xn.x)
Ausgabe:
[-2.46813009 2.46813009]
Funktionsgraph:
[[Datei:octave_nichtlin2.jpg]]
== Gleichungssysteme ==
SymPy ist ein externes Modul, das symbolisches Rechnen ('''Sym'''bolic '''Py'''thon) ermöglicht.
Folgende Aufgabe ist dem Buch "Knorrenschild: Numerische Mathematik, Hanser, 2017, Seite 72" entnommen. Zu lösen ist das nichtlineare Gleichungssystem
<math>f_1 = 2x_1 + 4x_2 = 0 </math>
<math>f_2 = 4x_1 + 8x_2^3 = 0</math>
Mit Python ist das so möglich:
import sympy
x1, x2 = sympy.symbols("x1 x2")
f1 = 2*x1 + 4*x2
f2 = 4*x1 + 8*x2**3
s = sympy.solve((f1, f2), x1, x2)
print(s)
Ausgabe:
[(-2, 1), (0, 0), (2, -1)]
Plot:
[[Datei:IngPython_nl_gleichung1.svg|500px]]
= Komplexe Zahlen =
Die imaginäre Einheit wird in Python durch den Buchstaben <code>j</code> symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:
* Kartesische Darstellung <math>z = \Re(z) + j \cdot \Im(z)</math>
* Polardarstellungen <math>z = r \cdot (\cos(\phi) + j \cdot \sin(\phi)) = r \cdot e^{j\cdot \phi}</math>
Die konjugiert komplexe Zahl ist <math>z^* = \Re(z) - j \cdot \Im(z)</math>
Nachfolgend einige mathematische Operationen mit Python und NumPy.
import numpy as np
z1 = 2 + 5j # kartesische Darstellung
z2 = 3 * np.exp(3j) # Polardarstellung
# Addition
res = z1 + z2
print("z1 + z2 = ", res)
# Multiplikation
res = z1 * z2
print("z1 * z2 = ", res)
# Realteil
res = np.real(z2)
print("Realteil von z2 = ", res)
# Imaginärteil
res = np.imag(z2)
print("Imaginaerteil von z2 = ", res)
# Betrag
res = np.abs(z1)
print("Betrag von z1 = ", res)
# Argument
res = np.angle(z1)
print("Argument von z1 = ", res)
# Konjugiert komplexe Zahl
res = np.conj(z1)
print("Konjugiert komplexe Zahl von z1 = ", res)
Ausgabe:
z1 + z2 = (-0.9699774898013365+5.423360024179601j)
z1 * z2 = (-8.05675510050068-14.003167400647481j)
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = (2-5j)
= Interpolation =
import numpy as np
import scipy
import matplotlib.pyplot as plt
# Stützpunkte
xp = np.arange(1, 6)
yp = (0, -5, 2, 7, 6)
ti = np.arange(1, 5, 0.01)
i1 = scipy.interpolate.interp1d(xp, yp, kind = "linear")
i2 = scipy.interpolate.interp1d(xp, yp, kind = "cubic")
plt.plot(xp, yp, "rx")
plt.plot(xp, i1(xp))
plt.plot(ti, i2(ti))
plt.show()
Ausgabe:
[[Datei:PythonIng_interpol1.png]]
= Differenzialrechnung =
== Numerisches Differenzieren ==
Als Beispiel differenzieren wir <math>y = 5x\sin{x}</math> und stellen das Ganze grafisch dar.
from findiff import Diff
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
f = 5 * x * np.sin(x)
dx = x[1] - x[0]
# Ableitung
d_dx = Diff(0, dx)
df_dx = d_dx(f)
# Grafik
plt.plot(x, f, label = "y")
plt.plot(x, df_dx, label = "y'")
plt.grid()
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:octave_diff1.jpg]]
<small>findiff ist ein externes Modul. Dieses muss installiert werden (z.B. so: ...\Python\Scripts\pip.exe install --upgrade findiff). Für die Vorgehensweise unter openSUSE Tumbleweed siehe das Kapitel [[Ing_Mathematik:_Python#Mit_VPython | VPython]], nur dass das Ganze mit einer aktuelleren Python-Version exekutiert wird, z.B. mit Python 3.13. Das im Buch "Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler, Rheinwerk" verwendete Modul "scipy.misc" ist veraltet (deprecated ... missbilligt). Lt. [https://docs.scipy.org/doc/scipy-1.17.0/dev/roadmap-detailed.html#misc SciPy-Dokumentation für die Version 1.17.0] wurden alle entsprechenden Features schon entfernt.</small>
== Symbolisches Differenzieren ==
Differenzieren Sie die Funktionen <math>f_1(x) = x^2</math> und <math>f_2(x) = \sin(x)\cos\left(\frac{x}{2}\right)</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2;
f2 = sympy.sin(x) * sympy.cos(x/2.)
d1 = sympy.diff(f1, x)
d2 = sympy.diff(f2, x)
print(d1)
print(d2)
Ausgabe:
2*x
-0.5*sin(0.5*x)*sin(x) + cos(0.5*x)*cos(x)
== Aufgaben ==
* Differenzieren Sie die Funktion <math>y = \log(x) + 10x</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
* Differenzieren Sie die Funktion <math>y = \frac{\sinh(x)}{(1+x)}</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
= Integralrechnung =
== Numerisches Integrieren ==
Berechnen Sie das Integral <math>\int_{0}^{3}x^2 dx</math>.
import scipy
def f(x):
return x**2
i = scipy.integrate.quad(f, 0, 3)
print(i)
Ausgabe:
(9.000000000000002, 9.992007221626411e-14)
Das trifft den exakten Wert 9.0 ziemlich genau.
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} dx</math>.
import scipy
import numpy as np
def f(x):
return 2**(-x)
i = scipy.integrate.quad(f, 0, np.inf)
print(i)
Ausgabe:
(1.4426950408889556, 4.486558477977586e-09)
== Symbolisches Integrieren ==
Berechnen Sie <math>\int x^2 \text{d}x</math> und <math>\int \sin{x}\cos{\frac{x}{2}} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2
f2 = sympy.sin(x) * sympy.cos(x/2.)
i1 = sympy.integrate(f1, x)
i2 = sympy.integrate(f2, x)
print(i1)
print(i2)
Ausgabe:
x**3/3
-0.666666666666667*sin(0.5*x)*sin(x) - 1.33333333333333*cos(0.5*x)*cos(x)
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f = 2**(-x)
i = sympy.integrate(f, (x, 0, sympy.oo))
print(i)
Ausgabe:
1/log(2)
<code>sympy.oo</code> steht für das {{W|Unendlichzeichen}} <math>\infty</math> (die liegende Acht oder das Möbiusband). Mit <code>sympy.pprint(i)</code> ließe sich letzere Ausgabe etwas schöner schreiben:
1
──────
log(2)
Man beachtete, <code>log</code> steht hier für den natürlichen Logarithmus <code>ln</code>.
== Aufgaben ==
* Integrieren Sie die Funktion <math>y = \log(x) + 10x</math> von 1 bis 5.
* Integrieren Sie die Funktion <math>y = x^3</math> von 0 bis 4.
* Integrieren Sie <math>\int x^x(\log (x) + 1)\mathrm dx</math> symbolisch.
= Gewöhnliche Differenzialgleichungen =
== DGL numerisch lösen ==
Für die Lösung von Differenzialgleichungen steht u.a. die Funktion scipy.integrate.solve_ivp() zur Verfügung. Diese Funktion implementiert auch das Runge-Kutta-Verfahren (RK45).
{{Wikipedia | Runge-Kutta-Verfahren}}
Beispiel <math>y' = x^2 + y^3</math>:
import scipy
import numpy as np
import matplotlib.pyplot as plt
def dy_dx(x, y):
return x**2 + y**3
y0 = [1]
xi = [0, 1]
x = np.arange(0, 1, 0.01)
z = scipy.integrate.solve_ivp(dy_dx, xi, y0, method="RK45", dense_output=True)
y = z.sol(x)
plt.plot(x, y.T)
plt.grid()
plt.show()
[[Datei:PythonIng_dgl1.png]]
== DGL symbolisch lösen ==
Beispiel <math>y' = x^2 + y^3</math>:
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
print(lsg)
Ausgabe:
[Eq(f(x), (-x**2)**(1/3)), Eq(f(x), (-x**2)**(1/3)*(-1 - sqrt(3)*I)/2), Eq(f(x), (-x**2)**(1/3)*(-1 + sqrt(3)*I)/2)]
Mit <code>sympy.pprint</code> (pretty print) lässt sich die Ausgabe etwas übersichtlicher darstellen.
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
sympy.pprint(lsg)
Ausgabe:
⎡ _____ _____ ⎤
⎢ _____ 3 ╱ 2 3 ╱ 2 ⎥
⎢ 3 ╱ 2 ╲╱ -x ⋅(-1 - √3⋅ⅈ) ╲╱ -x ⋅(-1 + √3⋅ⅈ)⎥
⎢f(x) = ╲╱ -x , f(x) = ────────────────────, f(x) = ────────────────────⎥
⎣ 2 2 ⎦
== Aufgaben ==
* Lösen Sie die Differenzialgleichung <math>y' = \frac{1}{x\cdot y}</math> mit Python. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>m' = -k\cdot m</math>. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>y' = \sqrt{|y|}</math>.
=Laplace-Transformation=
Laplace-Transformation:
<math>F(s) =\mathcal{L} \left\{f\right\}(s) = \int_{0}^{\infty} f(t) \mathrm e^{-st} \,\mathrm{d}t, \qquad s\in\mathbb{C}
</math>
Inverse Laplace-Transformation:
<math>\mathcal{L}^{-1} \left\{F\right\}(t)
= \frac{1}{2 \pi \mathrm j} \int_{ \gamma - \mathrm j \infty}^{ \gamma + \mathrm j \infty} \mathrm e^{st} F(s)\,\mathrm ds
= \begin{cases}
f(t) & \text{für } t \geq 0 \\
0 & \text{für } t < 0
\end{cases}
</math>
Siehe auch [[Ing_Mathematik:_Laplace-Transformation]]
Code:
import sympy
from sympy.abc import t, s
# Laplace-Transformation der Funktion f(t) = 1 (Heaviside-Fkt.)
f = 1
# alternativ: f = sympy.Heaviside(t)
F = sympy.laplace_transform(f, t, s, noconds=True)
print("Laplace-Transformierte F(s):", F)
# Inverse Laplace-Transformation zurück in den Zeitbereich
f_inv = sympy.inverse_laplace_transform(F, s, t)
print("Inverse Transformation f(t):", f_inv)
Ausgabe:
Laplace-Transformierte F(s): 1/s
Inverse Transformation f(t): Heaviside(t)
Die Zeile
from sympy.abc import t, s
steht alternativ für
t = sympy.symbols("t")
s = sympy.symbols("s")
<u>Aufgaben</u>: Ermitteln Sie mittels SymPy die <math>\mathcal{L}</math>-Transformierten und dann wieder die <math>\mathcal{L}^{-1}</math>-Transformationen (ähnlich wie beim obigen Beispiel):
* <math>\sin(t) \circ\! -\! \bullet \ ?</math>
* <math>t^3 \circ\! -\! \bullet \ ?</math>
* <math>\text{e}^{\omega t} \circ\! -\! \bullet \ ?</math>
=Fourier-Reihen=
<math>
f(x)\approx \frac{a_{0}}{2}+\sum_{k=1}^{\infty}\left(a_{k}\cos\left(kx\right)+b_{k}\sin\left(kx\right)\right)
</math>
<math>
a_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\cos\left(kx\right)\mathrm dx\quad\text{für }k\geq0
</math>
<math>
b_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\sin\left(kx\right)\mathrm dx\quad\text{für }k\geq1
</math>
Für die Sägezahnfunktion <math>y=x;\, 0 < x < 2\pi</math> sei die Fourierreihe mit einem Python-Programm (unter Mithilfe von sympy) hergeleitet.
Code:
from sympy import fourier_series, pi, symbols, pprint
x = symbols('x')
f = x
s = fourier_series(f, (x, 0, 2*pi))
pprint(s.truncate(n=4))
Ausgabe:
2⋅sin(3⋅x)
-2⋅sin(x) - sin(2⋅x) - ────────── + π
3
Siehe auch [[Ing Mathematik: Fourierreihen]].
Ein komplizierteres Beispiel:
[[Datei:IngMath fourier bsp13.svg | 300px]]
<math>0\le t < T/2\text{:}\quad f(t) = H</math>
<math>T/2 \le t \le T\text{:}\quad f(t) = \frac{2H}{T}\left( t-\frac{T}{2}\right)</math>
Code:
import sympy as sp
H = sp.Symbol('H', positive=True)
T = sp.Symbol('T', positive=True)
t = sp.Symbol('t')
f = sp.Piecewise(
(H, (t > 0) & (t < T/2)),
(2*H/T*(t-T/2), (t > T/2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Ausgabe:
⎛2⋅π⋅t⎞ ⎛4⋅π⋅t⎞ ⎛6⋅π⋅t⎞ ⎛2⋅π⋅t⎞ ⎛6⋅π⋅t⎞
H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ 2⋅H⋅cos⎜─────⎟ 2⋅H⋅cos⎜─────⎟
⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ 3⋅H
──────────── - ──────────── + ──────────── + ────────────── + ────────────── + ───
π 2⋅π 3⋅π 2 2 4
π 9⋅π
=Rechnen mit wirklich großen Zahlen=
Bekannt ist, dass Python kaum Einschränkungen beim Wertebereich von Ganzzahlen hat, z.B.
print(10**300)
Ausgabe (gekürzt):
100000000000000000000...00000000000000000000000000000000000000000000000000000000000000000000000
Ähnliches geht auch mit Gleitpunktzahlen, z.B. durch die Verwendung des Moduls [https://mpmath.org/ mpmath]:
import mpmath
print(mpmath.mpf(1500.4)**mpmath.mpf(300))
Ausgabe:
7.27975299218612e+952
Anderes Beispiel:
from mpmath import mp, pi
mp.dps = 100
print(pi)
Ausgabe:
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
mpmath kann noch einiges mehr, dazu sei aber auf die entsprechende Dokumentation auf der mpmath-Homepage verwiesen. mpmath ist Bestandteil von SymPy, kann aber auch separat installiert werden.
Aber auch Python selbst besitzt eine Möglichkeit, um mit großen bzw. exakten Gleitpunktzahlen zu rechnen, nämlich das interne Modul decimal. Dieses hat einige Vorteile gegenüber mpmath, aber auch gravierende Nachteile. Diese seien hier nicht detailliert aufgezählt. Grob gesagt hat decimal im Finanzwesen seine Berechtigung. Für wissenschaftliche Anwendungen wird aber mpmath vorzuziehen sein, da es u.a. vielfältige mathematische Funktionen bereit stellt. Nachfolgend ein einfaches Beispiel mit decimal:
import decimal
print("Potenzierung:", decimal.Decimal(1500.4) ** decimal.Decimal(300.0))
print("Einfache Addition:", 0.1 + 0.2)
decimal.getcontext().prec = 50
print("Addition mit decimal:", decimal.Decimal("0.1") + decimal.Decimal("0.2"))
Ausgabe:
Potenzierung: 7.279752992186121551039839134E+952
Einfache Addition: 0.30000000000000004
Addition mit decimal: 0.3
<u>Aufgabe:</u> Recherchieren Sie im Internet die genauen Vor- und Nachteile von decimal und mpmath. Verwenden Sie dazu auch KI (z.B. von Google, chatgpt).
= pint - mit physikalischen Größen rechnen =
[[File:Pint-Glas_UK.jpg|right|100px]]
pint ist ein externes Python-Paket zur Manipulation von physikalischen Einheiten. Es muss vor der ersten Benutzung installiert werden (Vorgehensweise wie immer: pip, YaST, via venv etc.).
Beispiel:
import pint
import numpy as np
ureg = pint.UnitRegistry()
# Einfache Berechnung
print(3 * ureg.meter + 4 * ureg.cm)
# Mit NumPy
npeinzel = [3, 4] * ureg.meter + [2, 5] * ureg.cm
print(npeinzel)
npsum = np.sum(npeinzel)
print(npsum)
# Konvertierung von Einheiten
npsum_inch = npsum.to(ureg.inch)
print(npsum_inch)
print(npeinzel.magnitude)
print(npeinzel.units)
print(npeinzel.dimensionality)
Ausgabe:
3.04 meter
[3.02 4.05] meter
7.07 meter
278.3464566929134 inch
[3.02 4.05]
meter
[length]
Die Dokumentation zu pint findet sich auf [https://pint.readthedocs.io/en/stable/].
=Regelungstechnische Aufgabenstellungen=
Für regelungstechnische Aufgaben gibt es u.a. das externe Paket <code>control</code>. Hier soll nicht detailliert darauf eingegangen werden. Anhand eines Beispiels soll anschließend nur die Visualisierung in Form eines Bode-Diagramms und der Sprungantwort gezeigt werden. Gegeben sei ein P-Regler mit <math>R = \frac{5}{2}</math> und eine Strecke <math>S= \frac{1}{30s^3+20s^2+10s+1,5}</math>. Gesucht sei vorerst ein Bode-Diagramm für den offenen Regelkreis und das Führungsverhalten.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke # oder: G0 = ct.series(regler, strecke)
Gw = ct.feedback(G0)
ct.bode_plot(G0, label='G0')
ct.bode_plot(Gw, label='Gw')
plt.show()
[[Datei:PythonIng_bode1.svg]]
Nun noch für obiges Beispiel die Sprungantwort. Diese zeigt einige große Überschwinger, d.h. der Regler kann sicher noch optimiert werden.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke
Gw = ct.feedback(G0)
t, y = ct.step_response(Gw)
plt.plot(t,y)
plt.title('Sprungantwort')
plt.xlabel('t')
plt.ylabel('h(t)')
plt.grid()
plt.show()
[[Datei:PythonIng_bode3.svg]]
Einige weitere wichtige Daten (Phasenreserve, Amplitudenreserve, Durchtrittsfrequenz) lassen sich mittels der <code>control</code>-Funktion <code>margin()</code> ermitteln. Die Ortskurve lässt sich mit der Funktion <code>nyquist_plot()</code> zeichnen. Dies sei hier aber nicht weiter ausgeführt.
==Aufgaben==
* Zeichen Sie mit Python die Ortskurve für obiges Beispiel.
* Was passiert, wenn man die Reglerverstärkung weiter aufdreht (z.B. auf <math>R = \frac{25}{2}</math>)?
* Wie sehen das Bode-Diagramm und die Sprungantwort aus, wenn ein PI-Regler verwendet wird?
= Stereostatik etc. =
Das Modul SymPy bietet einige Möglichkeiten einfache Bauwerke zu berechnen, z.B. Balken oder Fachwerke. Nachfolgend wird ein einfaches Fachwerk berechnet und gezeichnet.
Python-Code:
from sympy.physics.continuum_mechanics.truss import Truss
t = Truss()
# Knoten
t.add_node(("A", -3, 0), ("B", 0, 0), ("C", 4, 0), ("D", 7, 0),
("E", 6, 1.5), ("F", 2, 3), ("G", -2, 1.5))
# Stäbe
t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D"))
t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F"))
t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E"))
t.add_member(("FE","F","E"), ("DE","D","E"))
# Auflager; roller ... Loslager, pinned ... Festlager
t.apply_support(("A","roller"), ("D","pinned"))
# Einwirkende Kräfte
t.apply_load(("G", 5, 270), ("E", 3, 90))
# Berechnung
t.solve()
print("Reaction Forces: ", t.reaction_loads)
print("Internal Forces: ", t.internal_forces)
# Fachwerk zeichnen
p = t.draw()
p.show()
Ausgabe auf der Konsole:
Reaction Forces: {'R_A_y': 4.20000000000000, 'R_D_x': 0, 'R_D_y': -2.20000000000000}
Internal Forces: {'AB': 2.80000000000000, 'BC': 0.333333333333333, 'CD': -1.46666666666667,
'AG': -5.04777178564958, 'GB': -2.05555555555556, 'GF': -1.23413387432364,
'BF': 0.411111111111111*sqrt(13), 'FC': -0.3*sqrt(13), 'CE': 1.50000000000000,
'FE': 0.284800124843917, 'DE': 2.64407093534026}
Zeichnung:
[[File:PythonIng_fachwerk1.svg|300px]]
Details zu diesem Thema siehe z.B. [https://docs.sympy.org/latest/modules/physics/continuum_mechanics/index.html Continuum Mechanics] oder [https://docs.sympy.org/latest/tutorials/physics/continuum_mechanics/index.html Continuum Mechanics Tutorials]. Auch andere mechanische Probleme werden von SymPy abgehandelt ([https://docs.sympy.org/latest/tutorials/physics/index.html Physics Tutorials]).
== Aufgabe ==
Gegeben sei ein einseitig eingespannter Kragträger. Belastet wird er durch eine Einzellast am Trägerende. Für die Daten siehe folgende ASCII-Skizze:
| 20 kN
//|---> x |
//| V
//|----------------------
//| 10 m |
Elastizitätsmodul E = 2,1*10⁵ N/mm²
Flächenträgheitsmoment I = 0.001 m⁴
Berechnen Sie die Auflagerreaktionen, den Querkraft- und Biegemomentenverlauf, sowie die Verformungen.
Stellen Sie dies mit Hilfe von SymPy graphisch und auch mittels Formeln dar. Verwenden Sie dazu auch pprint (pretty print) aus dem SymPy-Modul. Zwecks Lösungsansatz siehe die oben aufgeführte Seite "Continuum Mechanics Tutorials". Achten Sie auch auf die Einheiten! Kontrollieren Sie das Ganze mittels händischer Rechnung. In dem genannten Tutorial ist von "Singularity Functions" die Rede. Gemeint ist damit in diesem Kontext die {{W|Föppl-Klammer}}.
Einige Python-Programme, vorrangig zu Maschinenelementen, finden sich auf [https://baymp.de/download_python.html BayMP für Python] (Balken, Zahnräder, Stabknickung usw.).
=Thermodynamik=
== PYroMat ==
Für thermodynamische Aufgabenstellungen gibt es verschiedene externe Module. Eines davon ist PYroMat (siehe auch [http://pyromat.org]). Damit lassen sich thermodynamische Stoffdaten für viele Substanzen berechnen.
Beispiel (einige Stoffdaten für Wasser bei 400°C und 20 bar berechnen):
import pyromat as pm
# Wasserdaten laden:
H2O = pm.get('mp.H2O')
# Stoffdaten berechnen:
T = 673.15 # Temperatur in Kelvin
p = 20 # Druck in bar
v = H2O.v(T, p)
h = H2O.h(T, p)
s = H2O.s(T, p)
print(f"Spezifisches Volumen: {v} m³/kg")
print(f"Spezifische Enthalpie: {h} kJ/kg")
print(f"Spezifische Entropie: {s} kJ/(kg K)")
Ausgabe:
Spezifisches Volumen: [0.1512163] m³/kg
Spezifische Enthalpie: [3248.3789473] kJ/kg
Spezifische Entropie: [7.12924142] kJ/(kg K)
<small>
PYroMat muss vorab installiert werden (z.B. mittels pip, in eine virtuelle Umgebung)
</small>
<code>mp</code> steht für "multi phase". Für ein ideales Gas wäre <code>ig</code> zuständig, z.B. <code>'ig.O2'</code>.
Beispiel (T-s-Diagramm für Wasser zeichnen):
import numpy as np
import matplotlib.pyplot as plt
import pyromat as pm
# Konfigurieren
pm.config["unit_pressure"] = "bar"
pm.config["unit_temperature"] = "K"
fluid = pm.get("mp.H2O")
# Temperaturbereich für das Nassdampfgebiet
T_tripel = 273.16
T_crit = 647.096
T = np.linspace(T_tripel, T_crit - 0.1, 200)
# Sättigungslinien berechnen und zeichnen
for x in np.linspace(0.0, 1.0, 5):
s = fluid.s(T=T, x=x)
if(x<=0.0):
plt.plot(s, T, label="Siedelinie x=%3.1f" % x, linewidth=2.0)
elif(x>=1.0):
plt.plot(s, T, label="Taulinie x=%3.1f" % x, linewidth=2.0)
else:
plt.plot(s, T, label="x=%3.1f" % x, linewidth=1.0)
# Isobaren zeichnen
p_values = [0.1, 1, 10, 50, 100]
T_isobar = np.linspace(T_tripel, 1000, 200)
t = 0.7
for p in p_values:
s_iso = fluid.s(T=T_isobar, p=p)
plt.plot(s_iso, T_isobar, 'k-', alpha=0.8, linewidth=0.8)
t += .05
idx = int(len(s_iso) * t)
plt.text(s_iso[idx], T_isobar[idx], f"{p} bar", fontsize=9, alpha=0.8)
# Diagramm zeichnen
plt.title("T-s-Diagramm für Wasser")
plt.xlabel("Spezifische Entropie s in kJ/kg K", fontsize=10)
plt.ylabel("Temperatur T in K", fontsize=10)
plt.legend(loc="best")
plt.grid(True)
plt.show()
Ausgabe (in etwa so):
[[Datei:T-s-Diagramm fuer Wasser.svg|400px]]
== CoolProp ==
Auch mit CoolProp können Stoffdaten berechnet werden. Siehe auch [https://coolprop.org/coolprop/wrappers/Python/index.html]
Beispiel (Wasser bei 20bar und 400°C):
import CoolProp.CoolProp as CP
fluid = 'Water'
T = 673.15 # Temperatur in Kelvin
P = 20e5 # Druck in Pascal
dichte = CP.PropsSI('D', 'T', T, 'P', P, fluid)
enthalpie = CP.PropsSI('H', 'T', T, 'P', P, fluid)
entropie = CP.PropsSI('S', 'T', T, 'P', P, fluid)
print(f"Spez. Volumen: {1/dichte:.6f} m³/kg")
print(f"Spez. Enthalpie: {enthalpie:.2f} J/kg")
print(f"Spez. Entropie: {entropie:.2f} J/kgK")
Ausgabe:
Spez. Volumen: 0.151215 m³/kg
Spez. Enthalpie: 3248344.02 J/kg
Spez. Entropie: 7129.16 J/kgK
== iapws ==
Um Werte für Wasser(dampf) zu erhalten (IAPWS; '''I'''nternational '''A'''ssociation for the '''P'''roperties of '''W'''ater and '''S'''team) gibt es die Bibliothek iapws. Siehe auch [https://iapws.org/] und [https://pypi.org/project/iapws/]
Beispiel (Wasser für 20bar und 400°C):
from iapws import IAPWS97
dampf = IAPWS97(P=2.0, T=673.15)
print(f"Spezifisches Volumen: {dampf.v:.6f} m³/kg")
print(f"Spezifische Enthalpie: {dampf.h:.2f} kJ/kg")
print(f"Spezifische Entropie: {dampf.s:.4f} kJ/(kgK)")
print(f"Phase: {dampf.phase}")
Ausgabe:
Spezifisches Volumen: 0.151208 m³/kg
Spezifische Enthalpie: 3248.23 kJ/kg
Spezifische Entropie: 7.1290 kJ/(kgK)
Phase: Gas
== TESPy ==
Ein anderes Modul für einen anderen Aufgabenzweck ist TESPy ('''T'''hermal '''E'''ngineering '''S'''ystems in '''Py'''thon). Dieses Modul ist für die Anlagensimulation zuständig. Für nähere Informationen siehe [https://tespy.readthedocs.io/en/main/getting_started/introduction.html]. Als Beipiel sei hier vorerst Code, der von der Google KI generiert wurde, angeführt. Der Code wurde überarbeitet, damit keine Warnungen auftreten. Bitte aber den Code trotzdem mit Vorsicht genießen, auch KI-generierter Code kann Fehler aufweisen. Eine Pumpe wird berechnet:
from tespy.components import Sink, Source, Pump
from tespy.connections import Connection
from tespy.networks import Network
# 1. Netzwerk definieren (Zentrales Steuerungselement)
# Wir wählen Wasser als Fluid und bar/Celsius als Einheiten
nw = Network(fluids=["water"])
nw.units.set_defaults(pressure="bar", pressure_difference="bar",
temperature="°C", enthalpy="kJ / kg")
# 2. Komponenten erstellen
eingang = Source("Wasserquelle")
ausgang = Sink("Wasserspeicher")
pumpe = Pump("Speisewasserpumpe")
# 3. Verbindungen definieren (Komponenten miteinander verknüpfen)
c1 = Connection(eingang, "out1", pumpe, "in1")
c2 = Connection(pumpe, "out1", ausgang, "in1")
# Verbindungen dem Netzwerk hinzufügen
nw.add_conns(c1, c2)
# 4. Randbedingungen und Parameter festlegen
# Zustand am Eingang (Druck, Temperatur, Massenstrom, Fluid-Zusammensetzung)
c1.set_attr(
v=1, # Massenstrom: 1 kg/s
T=20, # Temperatur: 20 °C
p=1, # Druck: 1 bar
fluid={"water": 1}, # 100% Wasser
)
# Zustand am Ausgang / Zielwerte der Pumpe
c2.set_attr(p=10) # Ziel-Druck nach der Pumpe: 10 bar
# Pumpeneigenschaften festlegen
pumpe.set_attr(eta_s=0.8) # Isentroper Wirkungsgrad von 80%
# 5. Simulation ausführen
nw.solve(mode="design")
# 6. Ergebnisse ausgeben
nw.print_results()
# Spezifische Werte direkt auslesen
print("\n--- Auswertung ---")
print(f"Erforderliche Pumpenleistung: {pumpe.P.val / 1000:.2f} kW")
print(f"Temperatur nach der Pumpe: {c2.T.val:.2f} °C")
Ausgabe (gekürzt):
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 7.04e+04 | 12 % | 9.96e+02 | 0.00e+00 | 8.81e+04 | 0.00e+00 | 0.00e+00
2 | 5.91e-12 | 100 % | 1.11e-13 | 0.00e+00 | 7.39e-12 | 0.00e+00 | 0.00e+00
3 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
4 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.01 s, Iterations per second: 480.85
##### RESULTS (Pump) #####
+-------------------+----------+----------+-----------+----------+----------+----------+
| | P | pr | dp | eta | eta_s | head |
|-------------------+----------+----------+-----------+----------+----------+----------|
| Speisewasserpumpe | 1.12e+06 | 1.00e+01 | -9.00e+00 | 8.00e-01 | 8.00e-01 | 9.19e+01 |
+-------------------+----------+----------+-----------+----------+----------+----------+
...
...
--- Auswertung ---
Erforderliche Pumpenleistung: 1124.77 kW
Temperatur nach der Pumpe: 20.07 °C
= Stochastik =
Die {{W|Stochastik}} ist ein sehr weites Feld. Hier werden etliche wichtige Themen kurz angerissen. Python stellt mit den Moduln math und statistics Software zu diesem Zwecke bereit. math und statistics sind bereits im Lieferumfang von Python enthalten. Aber auch mit den externen Modulen NumPy, SciPy, stochastic und pandas kann man Stochastik in Python betreiben. Die Theorie der Wahrscheinlichkeitsrechnung und Statistik soll etwas später in Band 5 dieser Buchreihe behandelt werden.
== Lageparameter ==
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
m1 = statistics.mean(werte)
m2 = statistics.mode(werte)
m3 = statistics.median(werte)
print("Arithmetischer Mittelwert = ", m1)
print("Modalwert = ", m2)
print("Median = ", m3)
Ausgabe:
Arithmetischer Mittelwert = 3.5
Modalwert = 1
Median = 3.0
== Streuungsparameter ==
Beispiel (Berechnung der Standardabweichung):
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
s = statistics.stdev(werte)
print("Standardabweichung = ", s)
Ausgabe:
Standardabweichung = 2.6770630673681683
Beispiel (Berechnung des Variationskoeffizienten V = Standardabweichung/Mittelwert)
import numpy as np
from scipy import stats
import statistics
k = 50
dat1 = [14, 21, 18, 25, 30, 17, 20]
dat = np.array(dat1)
# Mit SciPy
v = stats.variation(dat)
vddof = stats.variation(dat, ddof=1)
print("V SciPy: ", v)
print("V DDOF SciPy: ", vddof)
print(k*"-")
# mit NumPy
mittelwert1 = np.mean(dat)
std_abw1 = np.std(dat)
std_abw1ddof = np.std(dat, ddof=1)
v1= std_abw1 / mittelwert1
v1ddof = std_abw1ddof / mittelwert1
print("Mittelwert NumPy: ", mittelwert1)
print("Std.abw. NumPy: ", std_abw1)
print("Std.abw. DDOF NumPy: ", std_abw1ddof)
print("V NumPy: ", v1)
print("V DDOF NumPy: ", v1ddof)
print(k*"-")
# nur mit reinem Python
mittelwert2 = statistics.mean(dat1)
std_abw2 = statistics.stdev(dat1)
v2 = std_abw2 / mittelwert2
print("Mittelwert Python: ", mittelwert2)
print("Std.abw. Python: ", std_abw2)
print("V Python:", v2)
print(k*"-")
Ausgabe:
V SciPy: 0.23890355966467272
V DDOF SciPy: 0.25804533701889254
--------------------------------------------------
Mittelwert NumPy: 20.714285714285715
Std.abw. NumPy: 4.948716593053935
Std.abw. DDOF NumPy: 5.3452248382484875
V NumPy: 0.23890355966467272
V DDOF NumPy: 0.2580453370188925
--------------------------------------------------
Mittelwert Python: 20.714285714285715
Std.abw. Python: 5.3452248382484875
V Python: 0.2580453370188925
--------------------------------------------------
Der Unterschied bei der Standardabweichung zwischen reinem Python und den externen Bibliotheken SciPy und NumPy entsteht dadurch, dass einmal durch (n-1) und das andere Mal nur durch n dividiert wird. Dies kann bei NumPy und SciPy dadurch entschärft werden, indem <code>ddof=1</code> gesetzt wird. ddof steht für '''D'''elta '''D'''egrees '''o'''f '''F'''reedom. <small>Je größer die Anzahl der Datensätze n wird, umso weniger spielt das eine Rolle.</small>
== Kombinatorik ==
Beispiel:
import math
n = 7
k = 5
print("n! = ", math.factorial(n))
print("Kombinationen (n über k) = ", math.comb(n, k))
Ausgabe:
n! = 5040
Kombinationen (n über k) = 21
Siehe zu diesem Thema auch [[Ing Mathematik: Permutationen, Kombinationen, binomischer Lehrsatz]]. Die Anzahlen lassen sich einfach aus den dortigen Formeln ermitteln, z.B. bei Permutationen mit <math>n!</math> oder Variationen mit Wiederholungen als <math>n^k</math>. Will man die Kombinationen oder Variationen aber auch als Liste ausgeben, so kann das Modul <code>itertools</code> nützlich sein.
Beispiel (Variationen ohne Wiederholung):
from itertools import permutations
menge = ["A", "B", "C", "D"] # n = 4
k = 3
variationen = list(permutations(menge, k))
for v in variationen:
print("".join(v))
print(50*"-")
print(len(variationen))
Ausgabe (gekürzt):
ABC
ABD
ACB
...
DCA
DCB
--------------------------------------------------
24
Siehe zum Modul <code>itertools</code> auch die Website [https://docs.python.org/3/library/itertools.html].
* Variationen mit Wiederholung: <code>itertools.product()</code>
* Kombinationen ohne Wiederholung: <code>itertools.combinations()</code>
* Kombinationen mit Wiederholung: <code>itertools.combinations_with_replacement()</code>
== Zufallszahlen ==
Beispiel:
import random
# Ganzzahlige Zufallszahl von 1 bis 10
zufallszahl1 = random.randint(1, 10)
# Gleitpunktzahlen
# zwischen 0.0 und 1.0
zufallszahl2 = random.random()
# Zahl zwischen 1.5 und 9.5
zufallszahl3 = random.uniform(1.5, 9.5)
# aus Liste auswählen
farbe = ["Rot", "Grün", "Blau"]
zufallswert = random.choice(farbe)
print(zufallszahl1)
print(zufallszahl2)
print(zufallszahl3)
print(zufallswert)
Ausgabe, z.B.:
5
0.14147945849015753
6.894003397570905
Rot
Benötigt man mehrere Zufallszahlen, so ist das Modul <code>numpy</code> zu bevorzugen, z.B.:
* Normalverteilung: <code>np.random.normal(...)</code>
* Gleichverteilung: <code>np.random.uniform(...)</code>
== Histogramm ==
Zum Thema Histogramm siehe {{W|Histogramm}}.
Beispiel (mit Matplotlib):
import matplotlib.pyplot as plt
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
plt.hist(daten, bins=25, edgecolor='darkgray')
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm.svg|300px]]
Beispiel (mit Seaborn):
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
sns.set_theme(style="darkgrid")
sns.histplot(data=daten)
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm2.svg|300px]]
Das Kürzel <code>sns</code> ist Konvention und steht für die fiktive Figur '''S'''amuel '''N'''orman '''S'''eaborn aus der US-Fernsehserie {{W|The West Wing – Im Zentrum der Macht | The West Wing}}.
== Box-Plot ==
[[File:Elements of a boxplot.svg|400px]]
Siehe auch {{W|Box-Plot}}.
Beispiel (mit Seaborn erstellt):
import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("tips")
sns.boxplot(data=df, x="day", y="tip", hue="day", legend=False)
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot.svg|400px]]
Beispiel (mit Matplotlib erstellt):
import matplotlib.pyplot as plt
daten = [12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25]
plt.boxplot(daten, patch_artist=True)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot2.svg|300px]]
Um mehrere Box-Plots unterschiedlicher Farbe mit Matplotlib in einem Diagramm zu zeichnen, können Sie folgendermaßen vorgehen:
import matplotlib.pyplot as plt
daten = [[12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25],
[10, 19, 20, 21, 20, 30, 19, 40, 11, 17, 19, 21]]
farben = ["green", "blue"]
boxplot = plt.boxplot(daten, patch_artist=True)
for patch, farbe in zip(boxplot['boxes'], farben):
patch.set_facecolor(farbe)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
== Regressionsrechnung ==
Beispiel:
import numpy as np
import matplotlib.pyplot as plt
# Messpunkte
x = np.array([1, 3, 5, 6, 8, 10, 20])
y = np.array([3, 4, 5, 5, 7, 9, 11])
# Regressionskurve (Grad 1 = lineare Regression, 2 = Polynom-Regression 2. Gr.)
# y = kx + d
k, d = np.polyfit(x, y, deg=1)
# y = ax**2 + bx + c
a, b, c = np.polyfit(x, y, deg=2)
x_l = np.linspace(1, 20, 100)
y_p = a * x_l**2 + b * x_l + c
# Zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.plot(x, k*x + d, color='blue', label='Regressionsgerade')
plt.plot(x_l, y_p, color='red', label='Regressionspolynom 2. Gr.')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:IngMath_regression.svg|400px]]
== Korrelationsrechnung ==
Beispiel:
import pandas as pd
import matplotlib.pyplot as plt
# Messdaten
x = [1, 3, 4, 5, 6]
y = [2, 4, 6, 8, 5]
daten = {'X': x, 'Y': y}
df = pd.DataFrame(daten)
# Korrelation
korr = df['X'].corr(df['Y'])
print(f"Korrelationskoeff.: {korr}")
# Messpunkte zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
Korrelationskoeff.: 0.7556096518348252
[[Datei:IngMath_korrelation.svg|300px]]
== Mengen und Venn-Diagramme ==
Beispiel:
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
menge_a = {1, 2, 3, 4, 5, 6}
menge_b = {4, 5, 6, 7, 8}
vereinigung = menge_a | menge_b
schnitt = menge_a & menge_b
print("Vereinigungsmenge = ", vereinigung)
print("Schnittmenge = ", schnitt)
venn2([menge_a, menge_b], set_labels=('Menge A', 'Menge B'))
plt.show()
Ausgabe:
Vereinigungsmenge = {1, 2, 3, 4, 5, 6, 7, 8}
Schnittmenge = {4, 5, 6}
[[Datei:IngMath_venn.svg|300px]]
Siehe auch {{W|Mengendiagramm#Venn-Diagramme}}.
== Verteilungs- und Dichtefunktion ==
* CDF ... '''C'''umulative '''D'''istribution '''F'''unction, Verteilungsfunktion
* PDF ... '''P'''robability '''D'''ensity '''F'''unction, Dichtefunktion
Beispiel (Normalverteilung):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
my, sigma = 0, 1
x = np.linspace(-4, 4, 50)
pdf = norm.pdf(x, my, sigma)
cdf = norm.cdf(x, my, sigma)
plt.plot(x, pdf, lw=2, label="Dichtefunktion")
plt.plot(x, cdf, lw=2, label="Verteilungsfunktion")
plt.legend()
plt.grid()
plt.show()
Ausgabe:
[[Datei:IngMath_cdf_pdf.svg|300px]]
Beispiel (<math>\chi^2</math>-Verteilung):
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
x = np.linspace(0, 20, 500)
# df ... degree of freedom, Freiheitsgrad
pdf = (stats.chi2.pdf(x, df=2), stats.chi2.pdf(x, df=5), stats.chi2.pdf(x, df=10))
for i in range(0,3):
if(i==0):
lab = "Freiheitsgrad 2"
elif(i==1):
lab = "Freiheitsgrad 5"
else:
lab = "Freiheitsgrad 10"
plt.plot(x, pdf[i], label=lab, lw=2)
plt.grid()
plt.legend()
plt.show()
Ausgabe:
[[Datei:IngMath_chi2.svg | 300px]]
== Schätzen und Testen ==
=== Intervallschätzung ===
Als Beispiel seien Daten gegeben, die von ''Dürr, Mayer: Wahrscheinlichkeitsrechnung und Schließende Statistik; 7. Aufl., Hanser, 2014, Seite 137'' stammen. Und zwar soll das 95%-Vertrauensintervall für den Mittelwert des Kaloriengehalts (kcal/100g) von Hähnchen ermittelt werden. Wir wollen das mit Python inkl. NumPy und SciPy durchführen. Die Stichprobe ist groß (50 Hähnchen):
Python-Code:
import numpy as np
import scipy.stats as stats
# Stichprobe
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203]
# Parameter definieren
konfidenzniveau = 0.95
mean = np.mean(daten)
std = np.std(daten, ddof=1)
stdfehler = stats.sem(daten)
intervall = stats.norm.interval(confidence=konfidenzniveau, loc=mean, scale=stdfehler)
print(f"Mittelwert: {mean}")
print(f"Standardabweichung: {std}")
print(f"Konfidenzintervall: {intervall}")
Ausgabe:
Mittelwert: 215.48
Standardabweichung: 33.14238915925757
Konfidenzintervall: (np.float64(206.29356722321992), np.float64(224.66643277678006))
Diese Werte stimmen gerundet mit denen im genannten Buch überein. Zum Code selbst:
* sem steht für '''s'''tandard '''e'''rror of the '''m'''ean.
* <code>scipy.stats.norm</code> ... Modul für die Normalverteilung.
=== Punktschätzung ===
Gleiche Daten wie oben bei der Intervallschätzung.
Python-Code:
import numpy as np
from scipy import stats
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203
]
mu_hat, sigma_hat = stats.norm.fit(daten)
print(f"Schätzer für den Erwartungswert (μ): {mu_hat:.4f}")
print(f"Schätzer für die Standardabweichung (σ): {sigma_hat:.4f}")
Ausgabe:
Schätzer für den Erwartungswert (μ): 215.4800
Schätzer für die Standardabweichung (σ): 32.8093
=== Hypothesentests ===
Beispiel:
import numpy as np
import scipy.stats as stats
x_quer = 12.075 # Stichproben-Mittelwert
var = 0.069 # Stichproben-Varianz
n = 90 # Stichprobengröße
my_0 = 12.0 # Nullhypothese
alpha = 0.05 # Signifikanzniveau
z_stat = (x_quer - my_0) / np.sqrt(var / n)
p_val = 2 * (1 - stats.norm.cdf(np.abs(z_stat)))
print(f"Z-Statistik: {z_stat:.4f}")
if p_val < alpha:
print(f"p-Wert: {p_val:.6f} < alpha:", alpha)
print("Die Nullhypothese wird verworfen.")
else:
print(f"p-Wert: {p_val:.6f} > alpha:", alpha)
print("Die Nullhypothese wird nicht verworfen.")
Ausgabe:
Z-Statistik: 2.7087
p-Wert: 0.006755 < alpha: 0.05
Die Nullhypothese wird verworfen.
== Statistische Qualitätskontrolle ==
Beispiel (Mittelwertkarte):
import numpy as np
import matplotlib.pyplot as plt
# Gegeben
sollwert = 50.0
varianz = 4.0
stichproben_umfang = 1
daten = [49.5, 50.2, 53.0, 48.1, 52.6, 53.4, 49.8]
# Berechnung
standardabweichung = np.sqrt(varianz)
streuung = standardabweichung / np.sqrt(stichproben_umfang)
cl = sollwert
ucl = cl + 3 * streuung
lcl = cl - 3 * streuung
# Darstellung
plt.plot(daten, marker='o', linestyle='-', color='b', label='Messdaten')
plt.axhline(cl, color='green', linestyle='-', label=f'CL: {cl}')
plt.axhline(ucl, color='red', linestyle='--', label=f'UCL: {ucl:.2f}')
plt.axhline(lcl, color='red', linestyle='--', label=f'LCL: {lcl:.2f}')
plt.title('Mittelwertkarte')
plt.xlabel('Stichprobe')
plt.ylabel('Wert')
plt.legend(loc='lower left')
plt.grid(True)
plt.show()
Ausgabe:
[[Datei:IngMath_mittelwertkarte.svg|300px]]
Siehe auch {{W|Shewhart-Regelkarte}} und {{W|Qualitätsregelkarte}}.
* UCL ... '''U'''pper '''C'''ontrol '''Limit''', Obere Eingriffsgrenze
* LCL ... '''L'''ower '''C'''ontrol '''Limit''', Untere Eingriffsgrenze
* CL ... '''C'''enter '''L'''ine, Mittellinie
= Ein- und Ausgabe =
== print ==
Die Anweisung print haben wir schon oft verwendet. Hier soll anhand von Beispielen kurz beschrieben werden, was der Befehl print leisten kann.
print("Hallo", "Welt", 1, sep="-")
print("Hallo", end=" ")
print("Welt")
Ausgabe:
Hallo-Welt-1
Hallo Welt
== input ==
a = int(input("Zahl 1: "))
b = int(input("Zahl 2: "))
print("a + b = ", a+b)
Ausgabe (nach Eingabe der beiden Ganzzahlen):
Zahl 1: 4
Zahl 2: 5
a + b = 9
== Aus Dateien lesen ==
Es seinen die datei.txt
Hallo Welt.
Wie geht es dir?
...
und test1.py
dat = open("datei.txt", mode = "r")
print(dat.read())
dat.close()
Ausgabe
Hallo Welt.
Wie geht es dir?
...
Mit dem open()-Befehl wird die Datei datei.txt im Lesemodus geöffnet (r ... read). Mit dem read()-Befehl wird die Datei eingelesen und mittels print ausgegeben.
== In Dateien schreiben ==
dat = open("datei.txt", mode = "a", encoding = "utf-8")
dat.write("Hänge Zeile an\n")
dat.close()
Die Datei datei.txt sieht nach Abarbeitung des obigen Skripts nun so aus
Hallo Welt.
Wie geht es dir?
...
Hänge Zeile an
Es wird die Datei im Schreibmodus geöffnet (a ... append (anhängend), w ... write (überschreibend)).
write() fügt hier also eine Zeile Text am Dateiende ein. close() schließt die Datei wieder.
Das close() kann man sich mit der with-Anweisung auch sparen.
with open("datei.txt", mode="a", encoding="utf-8") as dat:
dat.write("Hänge Zeile an\n")
= Benutzeroberflächen erstellen =
== tkinter ==
{{Wikipedia | Tkinter}}
Python bietet standardmäßig das Modul tkinter zur Programmierung von Benutzeroberflächen. Es müssen also bei der Verwendung von tkinter keine externen Module installiert werden. Hier wird eine (sehr) kurze Einführung in das Erstellen von grafischen Oberflächen mittels tkinter gegeben.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
win.minsize(300, 50)
but = tk.Button(win, text = "Push the button")
but.pack()
win.mainloop()
Ausgabe:
[[Datei:PythonIng_gui1.jpg]]
Ein etwas komplizierteres Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
def on_button_clicked():
str = ent1.get() + ent2.get()
lab2["text"] = str
ent1 = tk.Entry(win)
ent2 = tk.Entry(win)
lab1 = tk.Label(win, text="verknuepfen mit")
lab2 = tk.Label(win, text="")
but = tk.Button(win, text = "=", command=on_button_clicked)
ent1.pack(side="left")
lab1.pack(side="left")
ent2.pack(side="left")
but.pack(side="left")
ent2.pack(side="left")
lab2.pack(side="left")
win.mainloop()
Ausgabe (vor der Eingabe der Teilstrings):
[[Datei:PythonIng_gui2.jpg]]
Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):
[[Datei:PythonIng_gui3.jpg]]
== curses ==
{{Wikipedia | curses}}
Mit dem curses-Modul lassen sich u.a. TUIs ('''T'''ext '''U'''ser '''I'''nterfaces) erstellen. Ein sehr einfaches Beispiel zur allgemeinen Funktionsweise wird nachstehend geliefert.
import curses
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
stdscr.clear()
stdscr.addstr("Hallo Welt", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.endwin()
Als Ausgabe sollte <span style="color:#FF0000;">Hallo Welt</span> (rote Schrift auf weißem Hintergrund) auf dem Terminal/der Konsole erscheinen. Getestet wurde dies mit openSUSE Tumbleweed, Python-Version 3.13.12. Das entsprechende Python-curses-Package muss installiert sein.
Allgemeine Informationen zur Terminal-/Konsolengröße und Cursorposition liefert folgendes Programm:
import curses
stdscr = curses.initscr()
stdscr.addstr(3, 5, "LINES: %d" % curses.LINES)
stdscr.addstr(4, 5, "COLS: %d" % curses.COLS)
(y,x) = stdscr.getyx()
stdscr.addstr(5, 5, "Momentane Cursorposition: [%d, %d]" % (y, x))
(y,x) = stdscr.getbegyx()
stdscr.addstr(6, 5, "Koordinatenursprung: [%d, %d]" % (y, x))
(y,x) = stdscr.getmaxyx()
stdscr.addstr(7, 5, "Fenstergröße: [%d, %d]" % (y, x))
stdscr.addstr(11, 2, "Taste drücken -> Ende")
stdscr.refresh()
stdscr.getch()
curses.endwin()
Es sollte sich in etwa folgende Ausgabe ergeben:
LINES: 44
COLS: 110
Momentane Cursorposition: [4, 15]
Koordinatenursprung: [0, 0]
Fenstergröße: [44, 110]
Taste drücken -> Ende
Zur Funktionsweise von curses siehe auch das Wikibook [[ncurses]]. Zum Verständnis sind dort allerdings elementare Kenntnisse in der Programmiersprache C erforderlich.
== Qt ==
{{Wikipedia | Qt (Bibliothek)}}
Auch für das Qt-Framework gibt es eine Anbindung an Python. Nachfolgend ein einfaches Beispiel.
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hallo Welt!")
label.show()
sys.exit(app.exec())
Ausgabe:
[[Datei:PythonIng_gui10.png]]
== Gtk ==
{{Wikipedia | GTK (Programmbibliothek)}}
Eine idente Ausgabe, wie oben für Qt gezeigt, erzeugt z.B. folgendes Gtk-Programm:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
lab = Gtk.Label(label="Hallo Welt!")
win.set_child(lab)
win.present()
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
Auch für die Benutzung von Qt und Gtk müssen die jeweiligen Packages installiert sein. Getestet wurden die entsprechenden Python-Programme nur unter openSUSE Tumbleweed. Wie das GTK-Paket unter MS Windows 11 installiert wird, siehe z.B. [https://www.gtk.org/docs/installations/windows Setting up GTK for Windows].
Damit sei aber das Thema "Benutzeroberflächen erstellen" hier abgeschlossen, da dies schon ein sehr spezielles Aufgabengebiet ist, das eher Informatiker und nicht so sehr Ingenieure anspricht. Bei Bedarf siehe aber ggf. die entsprechenden Links unten in diesem Tutorial. Dort sind weiterführende Informationen zu finden.
= Pandas kurz erklärt =
Hier wird kurz auf das externe Modul Pandas eingegangen. Pandas steht für '''Pan'''el '''Da'''ta und ist ein Modul für die Datenanalyse und -manipulation.
== Series ==
Vorstellbar ist eine "Series" wie eine einzelne Spalte in einem Tabellenkalkulationsprogramm.
Beispiel (Index implizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5]) # Temperaturwerte
print(temp)
Ausgabe:
0 8.5
1 11.0
2 12.5
3 10.0
4 13.0
5 11.0
6 14.5
dtype: float64
Das Kürzel <code>pd</code> ist Konvention. Es seien Temperaturwerte gegeben. Die erste Spalte bei der Ausgabe ist der Index. Die zweite Spalte enthält die Werte.
Beispiel (separater Zugriff auf den Index und auf die Werte):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5])
print(temp.index)
print(temp.values)
Ausgabe:
RangeIndex(start=0, stop=7, step=1)
[ 8.5 11. 12.5 10. 13. 11. 14.5]
Beispiel (Index explizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
print("*** Die gesamte Series ***")
print(temp)
print("*** Temperatur am Donnerstag ***")
print(temp["Do"])
print("*** Tage wärmer als 12 Grad ***")
temp_gr_12 = temp[temp > 12]
print(temp_gr_12)
Ausgabe:
*** Die gesamte Series ***
Mo 8.5
Di 11.0
Mi 12.5
Do 10.0
Fr 13.0
Sa 11.0
So 14.5
dtype: float64
*** Temperatur am Donnerstag ***
10.0
*** Tage wärmer als 12 Grad ***
Mi 12.5
Fr 13.0
So 14.5
dtype: float64
== DataFrame ==
Ein DataFrame entspricht einer Tabelle.
Beispiel (Erzeugen eines DataFrames):
import pandas as pd
tag = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
v1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=tag)
v2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=tag)
v3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=tag)
tab = pd.concat([v1, v2, v3], axis=1)
tab.columns = stadt
print(tab)
print(type(tab))
Ausgabe:
Linz Salzburg Innsbruck
Mo 1 8 Hallo
Di 2 9 16
Mi 3 10 17
Do 4 11 18
Fr 5 12 19
Sa 6 13 20
So 7 14 21
<class 'pandas.core.frame.DataFrame'>
Wir haben hier drei Datenspalten (v1, v2, v3) mit den Spaltennamen "Linz", "Salzburg" und "Innsbruck", sowie sieben Zeilen "Mo" bis "So".
Beispiel (Zugriff auf eine Spalte):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab["Salzburg"])
Ausgabe:
Mo 8
Di 9
Mi 10
Do 11
Fr 12
Sa 13
So 14
Name: Salzburg, dtype: int64
Beispiel (Zugriff auf eine Zeile):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab.loc["Di"])
Ausgabe:
Linz 2
Salzburg 9
Innsbruck 16
Name: Di, dtype: object
== Grafiken erstellen ==
Hier sei nur ein Torten- oder Kreisdiagramm gezeichnet:
import pandas as pd
import matplotlib.pyplot as plt
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
expl = [0, 0.2, 0, 0, 0, 0, 0]
temp.plot.pie(figsize=(5,5), explode=expl)
plt.show()
Ausgabe:
[[Datei:IngPython_pandas1.svg|350px]]
Die <code>figsize</code> hat nichts mit der Spaltenanzahl zu tun, sondern setzt die Fenster- oder Diagrammgröße in Inches (Breite * Höhe).
Mit Pandas kann man auch noch andere Diagrammarten erstellen, z.B. Linien- oder Balkendiagramme. Dies wird hier aber nicht vorgeführt.
== Arbeiten mit CSV- und LibreOffice-Dateien ==
Gegeben sei eine CSV-Datei test1.csv:
Mai;Juni;Juli
12;17;45
15;65;65
16;32;23
4;14;7
23;17;Keine Daten verfügbar
67;Keine Daten verfügbar;45
15;24;12
Lesen von dieser CSV-Datei:
import pandas as pd
tab = pd.read_csv("test1.csv", sep=";")
print(tab)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Schreiben in eine CSV-Datei test2.csv:
import pandas as pd
val = pd.read_csv("test1.csv", sep=";")
val.to_csv("test2.csv", index=False)
Ausgabedatei:
Mai,Juni,Juli
12,17,45
15,65,65
16,32,23
4,14,7
23,17,Keine Daten verfügbar
67,Keine Daten verfügbar,45
15,24,12
Die Ausgabedatei ist beinahe gleich wie die Eingabedatei. Es werden aber Kommas statt Strichpunkten verwendet. Daher kommt auch der Name CSV ('''C'''omma '''S'''eparated '''V'''alue). Will man wieder Strichpunkte, so kann man dies über den Parameter <code>sep=";"</code> in der <code>to_csv</code>-Funktion machen.
Um direkt von einer ODS-Datei (LibreOffice Calc, '''O'''pen '''D'''ocument '''S'''preadsheet) zu lesen muss das Modul odfpy extra installiert sein (per YaST, pip etc.). Gelesen wird dann folgendermaßen:
import pandas as pd
df = pd.read_excel('test1.ods', engine='odf')
print(df)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Die Datei "test1.ods" sei die Datei, aus der das obige "test1.csv" generiert wurde. Schreiben kann man ebenfalls in eine ODS-Datei:
import pandas as pd
daten = {
"Name": ["Hugo", "Richie", "Wilhelmine"],
"Alter": [38, 30, 29],
"Ort": ["Linz", "Innsbruck", "Salzburg"]
}
tab = pd.DataFrame(daten)
with pd.ExcelWriter("test2.ods", engine="odf") as writer:
tab.to_excel(writer, sheet_name="Daten", index=False)
Es ergibt sich eine "test2.ods"-Datei (Screenshot):
[[Datei:IngPython_pandas2.png|250px]]
== Sonstiges ==
Hier seien stichpunktartig einige weitere Features von Pandas angeführt:
* {{W|Pivot-Tabelle|Pivot-Tabellen}} (pivot ... Dreh-, Angelpunkt): Zweck - große Datenmengen schnell zusammenfassen, filtern und analysieren.
* NaN ('''n'''ot '''a''' '''n'''umber): In einem Datensatz fehlt ein Wert oder ist nicht definiert.
* groupby-Funktion: Daten strukturieren, aggregieren oder Zwischensummen bilden.
* {{W|Binning#Datenverarbeitung_und_-analyse|Binning}}: Klassenbildung.
* Mehrstufige Indizierung (Hierarchical Indexing oder MultiIndex)
* Zeitreihen (Time Series)
Für tiefergehende und weiterführende Informationen wird auf das Buch von ''Klein: Numerisches Python; Hanser, 2023'' und [https://pandas.pydata.org/ pandas] verwiesen.
= Style Guide, flake8, pylint, Black etc. =
== Style Guide ==
Wie man schönen und richtigen Python-Code schreibt, erfahren Sie in
* [https://peps.python.org/pep-0008/ PEP 8 – Style Guide for Python Code]
== Formatter und Linter ==
Ein Modul, das prüft, ob die Richtlinien im Style Guide eingehalten wurden, ist ''flake8'':
* [https://flake8.pycqa.org/en/latest/ Flake8: Your Tool For Style Guide Enforcement]
Code formatieren kann man auch mit [https://pypi.org/project/black/ Black]. Z.B. übersetzt <code>black test1.py</code> die Datei <code>test1.py</code>
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)),
(2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
in
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)), (2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Die Programmausgabe ist
reformatted test1.py
All done! ✨ 🍰 ✨
1 file reformatted.
Der Unterschied zwischen Black und Flake8:
* Black ist ein Code-Formatter. Er formatiert Ihren Code um, sodass er im Einklang mit PEP 8 steht.
* Flake8 ist ein {{W|Lint (Programmierwerkzeug) | Code-Linter}}. Flake8 verändert Ihren Code nicht, sondern durchsucht ihn nach potenziellen Fehlern etc.
Am obigen Beispiel sieht man auch, dass flake8 und Black nicht immer einer Meinung sind. Flake8 (<code>flake8 test1.py</code>) würde standardmäßig den mit Black formatierten Code bemängeln:
test1.py:8:80: E501 line too long (80 > 79 characters)
Diese Diskrepanz kann beseitigt werden. Da 79 Zeichen auf modernen Bildschirmen meist als zu kurz empfunden werden, ist ein Limit von 88 Zeichen (Black-Standard) oder mehr empfehlenswert. Um dies zu implementieren, erstellen Sie in Ihrem Projektverzeichnis eine <code>.flake8</code>-Datei mit dem Inhalt
[flake8]
max-line-length = 88
Und schon ignoriert Flake8 dieses Problem.
Ein anderer Linter ist pylint. Der würde beim Abarbeiten des obigen Beispiels, z.B. mit <code>pylint test1.py</code> noch eine Kleinigkeit bemängeln:
************* Module test1
/home/hr/tmp/test1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)
Auch pylint muss vor der ersten Verwendung installiert werden (z.B. mittels pip, virtuelle Umgebung, YaST). Die Dokumentation zu pylint findet sich auf [https://pylint.readthedocs.io/en/latest/].
<u>Aufgabe:</u> Fügen Sie einen "module docstring" in die <code>test1.py</code>-Datei ein und testen Sie erneut mit flake8, Black und pylint. <small>Sehen Sie zum Thema docstrings auch [https://peps.python.org/pep-0257/#what-is-a-docstring PEP 257 – Docstring Conventions].</small>
Es gibt noch weitere Formatierungswerkzeuge für Python-Code. Z.B. [https://docs.astral.sh/ruff/ Ruff], ein moderner Code-Formatter und -Linter. Mittels <code>ruff check test1.py</code> würde obiger Code geprüft (Linter). <code>ruff format test1.py</code> formatiert den Code (Formatter).
== Type Checker ==
"Type Checker" sind z.B.
* mypy
* pyright
* ty
Diese prüfen die Datentypen, z.B. in folgendem Code
def greetings(name: str) -> str:
return "Hello, %s" % name
print(greetings(42))
Python selbst, flake8, ruff oder black würden diesen Code ohne zu murren akzeptieren. "Type Checker" würden aber sehr wohl Alarm schlagen, z.B. liefert <code>mypy</code> folgende Ausgabe
test1.py:5: error: Argument 1 to "greetings" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Das funktioniert übrigens nicht nur bei Funktionsannotationen, sondern auch mit Variablen etc.
from typing import Final
# "Konstante", ab Python 3.8
NUMBER: Final = 123
print(NUMBER)
NUMBER = 125
print(NUMBER)
# Variable
a: int = 345
print(a)
a = "Irgendwas"
print(a)
# Variable (Pipe-Symbol), ab Python 3.10
b : int|str = 567
print(b)
b = "sonstiges"
print(b)
Ausgabe mit python:
123
125
345
Irgendwas
567
sonstiges
Ausgabe mit mypy:
test3.py:6: error: Cannot assign to final name "NUMBER" [misc]
test3.py:12: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
Found 2 errors in 1 file (checked 1 source file)
Python kennt übrigens keine Konstanten. Man kann diese mittels Großbuchstaben andeuten. Das ist aber nur Konvention, hat aber keine sonstigen Auswirkungen. Oder man verwendet wie oben gezeigt <code>Final</code>. Dann werfen Typchecker Errors aus.
==pydoc==
pydoc ist ein Werkzeug, um Python-Module, -Funktionen und -Klassen zu dokumentieren.
Beispiel <code>test1.py</code>:
"""Rechen-Modul.
Funktionen die von pydoc gelesen werden.
"""
def multiply(a, b):
"""Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a * b
def add(a, b):
"""Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a + b
if __name__ == '__main__':
print(multiply(3, 5))
print(add(4, 6))
Ausgabe mit <code>python3.13 -m pydoc test1</code> auf der Konsole:
Help on module test1:
NAME
test1 - Rechen-Modul.
DESCRIPTION
Funktionen die von pydoc gelesen werden.
FUNCTIONS
add(a, b)
Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
multiply(a, b)
Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
FILE
/home/xyz/tmp/test1.py
Siehe zu diesem Thema z.B. auch [https://docs.python.org/3/library/pydoc.html]. Mittels <code>python3.13 -m pydoc -w test1</code> kann man auch eine HTML-Dokumentation erstellen.
Wofür <code>if __name__ == '__main__':</code> steht, siehe z.B. etwas später im Abschnitt [[Ing_Mathematik:_Python#Doctests]].
== Sonstige Tools ==
Andere Tools für die {{W|Statische Code-Analyse|statische Codeanalyse}}, die aber für Ingenieure weniger interessant sein dürften, sind z.B.
* Radon: Liefert verschiedene {{W|Softwaremetrik|Codemetriken}} (Komplexität, Wartbarkeitsindex ...)
* Bandit: Findet Sicherheitslücken
Tools für die {{W|Dynamisches Software-Testverfahren|dynamische Codeanalyse}}, z.B.:
* DynaPyt (Framework zur dynamischen Programmanalyse)
* cProfile (Profiler)
* Memory Profiler (Speicheranalyse)
* Memray (Speicheranalyse)
* tracemalloc (Speicheranalyse)
Paket- und Projektmanagement (pip-Ersatz etc.):
* uv
* Poetry
* Conda
* pipx
Packaging-Tools (Freezer) und {{W|Compiler#Sonderformen|Transpiler}} :
* pyinstaller
** erstellt eigenständige, ausführbare Binärdatei
** kein Cross-Compiler
** kein Schutz vor Reverse-Engineering
** langsam
** packt alles in eine Datei
** sehr große Datei
** Befehl, z.B.: <code>pyinstaller --onefile test1.py</code>
** GUI: <code>auto-py-to-exe</code>
* cx_Freeze
* nuitka
** Übersetzt Python-Code in C/C++-Code und weiter in eine ausführbare Datei
** kein Cross-Compiler
** Schutz vor Reverse-Engineering
** Befehl, z.B.: <code>nuitka --standalone --onefile test1.py</code>
* cython
= Einige Integrierte Entwicklungsumgebungen (IDEs)=
Werden Programmtexte größer und umfangreicher, so ist das Arbeiten mit der interaktiven Programmierumgebung bzw. das direkte Ausführen von Python-Skripten mühsam. Man wünscht sich z.B. Hilfen zum Debuggen oder die automatische Code-Vervollständigung. Zu diesem Zweck wurden IDEs (Integrated Development Environments) geschaffen. Von diesen seinen nachfolgend auszugsweise einige kurz beschrieben. Testen Sie einfach aus, welche davon für Sie bzw. für Ihr Python-Projekt geeignet sind.
== IDLE ==
IDLE ist die mit dem Python-Programmpaket mitgelieferte IDE. Der Name leitet sich einerseits ab vom Monty-Python-Mitglied Eric Idle, andererseits steht es als Abkürzung für "'''I'''ntegrated '''D'''evelopment and '''L'''earning '''E'''nvironment. IDLE ist einfach zu bedienen, bietet aber schon einen beachtlichen Leistungsumfang. Nachfolgend wird ein Screenshot zu IDLE geliefert. Rechts ist das Editor-Fenster zu sehen, links die interaktive Programmierumgebung. Um das Beispiel selbst nachvollziehen zu können, starten Sie IDLE. Das geht ähnlich, wie Sie die interaktive Programmierumgebung von Python starten (nur, dass Sie eben das IDLE-Icon doppelklicken und nicht das Python-Icon. Unter Linux geben Sie einfach in einem Terminal <code>idle3.13</code> o. Ä. ein). Weiter geht es mit "File - Open - ...". Die auszuführende Datei auswählen (im konkreten Fall ein "Hallo-Welt"-Programm). Es erscheint das rechte Fenster. Dort "Run - Run Module" auswählen. Und schon wird im linken Fenster "Hallo Welt!" ausgegeben.
[[Datei:PythonIng_idle1.jpg | 600px]]
Siehe auch {{W|IDLE}}.
== PyCharm ==
PyCharm ist ein kommerzielles Produkt. Es gab aber auch eine kostenlose Community Edition. Seit 2025 sind beide Varianten vereint. Für die ersten 30 Tage sind die Pro-Funktionen frei verfügbar, danach nur noch die Kernfunktionalitäten (oder man bezieht kostenpflichtig die Pro-Version). Zu beziehen ist PyCharm unter dem Weblink [https://www.jetbrains.com/pycharm/]. Nachfolgend ein etwas abgewandeltes "Hallo Welt"-Programm, editiert und ausgeführt mit PyCharm.
[[Datei:PyCharm_IDE_2023_screenshot.png | 600px]]
Siehe auch {{W|PyCharm}}.
== Eric ==
Auch eric ist Open Source und steht unter der GNU General Public License Version 3 oder später. Zu beziehen ist diese Software unter [https://eric-ide.python-projects.org/].
[[Datei:Screenshot_Eric_4.png | 600px]]
Siehe auch {{W|eric (Software)}}.
<small>
Unter openSUSE Tumbleweed sollte sich eric auch mit YaST installieren lassen. Bei mir gibt es aber dann beim Ausführen des eric-Programms eine Fehlermeldung (Stand März 2026):
...
ModuleNotFoundError: No module named 'PyQt6.QtPdfWidgets'
Umgehen kann man dieses Problem aber wieder mit dem Erstellen einer virtuellen Umgebung, in etwa so
python3.13 -m venv ~/tmp/venv1
cd ~/tmp/venv1/bin
./python3.13 -m pip install --upgrade --prefer-binary eric-ide
./eric7_ide
</small>
== PyScripter ==
Vom Funktionsumfang vergleichbar mit den vorherigen IDEs ist PyScripter. Auch PyScripter ist Open Source. Die Projekt-Homepage findet sich auf [https://sourceforge.net/projects/pyscripter/]. PyScripter ist nur für MS Windows verfügbar.
[[Datei:PythonIng_pyscripter1.jpg | 600px]]
== Spyder IDE ==
Spyder enthält bereits eine stabile Python-Version und etliche Module (z.B. matplotlib, numpy, control). Ansonsten kann dieses Softwarepaket vom Funktionsumfang her mit den anderen genannten IDEs locker mithalten. Spyder wurde unter der MIT-Lizenz veröffentlicht. Diese Software findet sich auf [https://www.spyder-ide.org].
[[Datei:Spyder-windows-screenshot.png | 600px]]
Siehe auch {{W|Spyder (Software)}}
== Eclipse IDE==
Die {{W|Eclipse_(IDE)|Eclipse-IDE}} kann für Python aufgerüstet werden. Dazu gibt es das PyDev-Plugin. Installiert wird es über
* Help > Eclipse Marketplace...
* Find - PyDev - Install
Danach muss noch der Pfad zum Python-Interpreter festgelegt werden
* Window > Preferences > PyDev > Interpreters > Python Interpreter > New ...
Das Ergebnis ist ähnlich wie im folgenden Bild, nur dass statt C/C++ Python Verwendung findet.
[[Datei:Setting Up Eclipse CDT helloout.png | 600px]]
== Sonstige ==
Die genannten IDEs sind nicht die Einzigen. Es gibt, um dem Image Pythons als beliebteste Programmiersprache gerecht zu werden, noch einige andere. Sowohl Open Source-Programme als auch kommerzielle Programme sind im Web zu finden, z.B. Thonny oder {{W|Visual Studio Code}}. Unter Linux kann man auch {{W|KDevelop}}, ausgestattet mit dem Python3-Plugin, einsetzen. Braucht man den Umfang von ausgewachsenen IDEs nicht, so kann man auch normale Texteditoren verwenden (z.B. {{W|Geany}} oder {{W|Kate_(Texteditor)|Kate}}).
= Debuggen und Testen =
Das Debuggen und Testen von Programmen sind wichtige Bestandteile der Programmierung. Syntaxfehler lassen sich i.A. leicht beheben. Schwieriger ist das Eingrenzen von logischen Fehlern, die ev. nur in bestimmten Situationen auftreten und keine explizite Fehlermeldung hervorrufen. Das Programm liefert falsche Ergebnisse oder es stürzt aus heiterem Himmel ab. Um das zu verhindern gibt es verschiedene Werkzeuge, die bei der Fehlersuche behilflich sein können. Vorerst siehe aber zwecks Begriffsklärung noch folgende Links:
* {{W|Debuggen}}
* {{W|Debugger}}
* {{W|Softwaretest}}
<gallery>
First Computer Bug, 1947.jpg
Test ganzheitlich.png
V-Modell.svg
</gallery>
== Das Modul pdb ==
Python bringt schon ein Modul zum Debuggen mit. Siehe z.B. [https://docs.python.org/3/library/pdb.html pdb — The Python Debugger].
Komfortabler lässt sich das aber mittels Integrierter Entwicklungsumgebungen (IDEs) angehen.
== Debuggen mit IDEs ==
Für die IDEs IDLE und Spyder sei kurz auf die entsprechenden Webseiten verwiesen:
* [https://www.cs.uky.edu/~keen/help/debug-tutorial/debug.html Debugging under IDLE].
* [https://docs.spyder-ide.org/current/panes/debugging.html Spyder Debugger]
Dort wird die Vorgehensweise auch mittels Screenshots erläutert.
== assert ==
assert ... behaupten, zusichern ({{W|Assertion (Informatik)}})
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10., 0.)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10., 0.)
File "/home/hr/Develop/test1.py", line 4, in print1
assert y != 0.0
^^^^^^^^
AssertionError
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1("10.", "5.")
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Aber auch bei nachfolgendem Code gibt es eine Fehlermeldung:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10, 5)
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Damit letzteres funktioniert, kann man den Programmcode so umschreiben:
def print1(x, y):
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
2.0
Und jetzt fangen wir den <code>AssertionError</code> auf:
def print1(x, y):
try:
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
except(AssertionError):
print("Hallo")
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Hallo
Ich hoffe, es ist wenigstens im Ansatz klar geworden, wofür <code>assert</code> gut sein kann. Ausschalten kann man die <code>assert</code>-Überprüfung übrigens mit dem Python-Schalter <code>-O</code>.
== Doctests ==
Innerhalb eines Docstrings kann die Arbeit im interaktiven Modus simuliert werden. Nach den Promptzeichen (>>>) erfolgen dann bei unserem Beispiel innerhalb des Docstrings simulierte Aufrufe der Funktion <code>print1()</code>. Danach folgen jeweils die Sollresultate. Wird das Modul oder die Datei als Hauptprogramm aufgerufen, so wird die Funktion <code>doctest.testmode()</code> aufgerufen und ein Bericht auf der Konsole ausgegeben. Wird das Modul nicht als Hauptprogramm aufgerufen, sondern importiert, dann wird diese <code>testmod</code>-Funktion nicht aufgerufen. D.h. dieser Code kann sowohl für Testzwecke als auch für den produktiven Einsatz verwendet werden. Das ist auch sinnvoll, weil wenn man Teile der Datei immer löschen bzw. einfügen müsste, so würden sich Fehlerquellen auftun. Das würde den Sinn und Zweck von Doctests konterkarieren.
def print1(x=0., y=1.):
""" Dividiere zwei Zahlen
Autor: Intruder
Datum: 12.08.2025
>>> print1(2., 1.)
2.0
>>> print1(5., 2.)
2.5
>>> print1(5.)
5.0
"""
print(x/y)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Ausgabe:
Trying:
print1(2., 1.)
Expecting:
2.0
ok
Trying:
print1(5., 2)
Expecting:
2.5
ok
Trying:
print1(5.)
Expecting:
5.0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.print1
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Das gezeigte Beispiel ist so ziemlich das einfachste, das es gibt. Für weiterführende Details siehe z.B.:
* [https://peps.python.org/pep-0257/ PEP 257 – Docstring Conventions]
* [https://docs.python.org/3/library/doctest.html doctest — Test interactive Python examples]
''Einschub:'' Ganz ähnlich kann man auch Klassen testen, z.B. in folgendem Code-Fragment
class Fahrzeug:
# siehe Abschnitt "Objektorientierte Programmierung"
# ...
if __name__ == "__main__":
vauweh = Fahrzeug(170, 90)
beemweh = Fahrzeug(200, 120)
print(vauweh.convertGeschw())
print(beemweh.convertGeschw())
Wird das Script als Hauptprogramm ausgeführt (z.B. zu Testzwecken), so erfolgt die Ausgabe der zwei, via <code>convertGeschw()</code>, umgerechneten Geschwindigkeiten. Wird es aber als Modul eingebunden, so wird der letzte Programmabschnitt nicht ausgeführt (<code>__name__ == "__main__"</code> ergibt <code>False</code>).
== pytest ==
Siehe zu diesem Thema auch {{W|Modultest}}.
pytest ist ein externes Modul und muss vorab installiert werden, z.B. mittels
pip install -U pytest
pip install -U pytest-html
Python-Code, Datei test1.py:
def add(x, y):
return x + y
def test_answer():
assert add(1, 1) == 3
Starten von pytest in der Konsole:
pytest test1.py
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py F [100%]
========================================================= FAILURES ==========================================================
________________________________________________________ test_answer ________________________________________________________
def test_answer():
> assert add(1, 1) == 3
E assert 2 == 3
E + where 2 = add(1, 1)
test1.py:6: AssertionError
================================================== short test summary info ==================================================
FAILED test1.py::test_answer - assert 2 == 3
===================================================== 1 failed in 0.09s =====================================================
Hier erhalten wir einen Fehler, da 1+1 eindeutig ungleich 3 ist. Aber aus irgendeinem Grund wollte der Programmierer oder Tester in diesem Fall, dass dies so ist. Testfälle werden übrigens mit dem Präfix <code>test_</code> eingeleitet.
Python-Code:
def add(x, y):
return x + y + 1
def test_answer():
assert add(1, 1) == 3
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py . [100%]
===================================================== 1 passed in 0.01s =====================================================
Jetzt ist alles in Ordnung. Weiterführendes siehe z.B.
* [https://docs.pytest.org/en/stable/ pytest: helps you write better programs]
== unittest ==
Auch unittest dient zur Durchführung von Testreihen, ist aber Bestandteil von Python. Hier wird vorerst nicht näher darauf eingegangen. Siehe z.B.
* [https://docs.python.org/3/library/unittest.html unittest — Unit testing framework]
Lt. ''Inden: Python Challenge; dpunkt, 2021, Seite 481'' soll unittest weniger komfortabel als pytest sein.
Einen Vergleich von unittest mit pytest findet man in
* [https://knapsackpro.com/testing_frameworks/difference_between/pytest/vs/unittest pytest vs unittest]
= Python und Anwendungsprogramme =
Bisher stand immer alleine die Programmiersprache Python (ev. unter Einbeziehung von Modulen) im Mittelpunkt der Betrachtungen. Aber Python kann auch als Makrosprache für Anwendungsprogramme auftreten. Als Beispiele seien {{W|FreeCAD}} und {{W|LibreOffice}} genannt.
== FreeCAD ==
FreeCAD ist ein freies 3D-CAD-Programm. Hier soll nicht auf die Bedienung dieses CAD-Pakets eingegangen werden, sondern nur auf die Möglichkeit, mittels Python Makros zu schreiben. Als einfacher Einstieg soll ein Makro erstellt werden, welches eine Kugel (rot) und einen Quader (blau) zeichnet. Folgende Vorbereitungsschritte sind erforderlich (es sei vorausgesetzt, dass FreeCAD schon am Rechner installiert ist. Downloaden können Sie das Programm von der Website [https://www.freecad.org/downloads.php?lang=en]):
* FreeCAD starten
* Leere Datei erstellen
* Makro > Makros > Erstellen ...
Es öffnet sich ein leeres Editorfenster, in das Sie folgenden Code eingeben können:
import FreeCAD
import Part
doc = FreeCAD.newDocument()
# Kugel
kugel = Part.makeSphere(10)
form_element = doc.addObject("Part::Feature", "Kugel")
form_element.Shape = kugel
kug = FreeCAD.ActiveDocument.getObject("Kugel")
kug.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
neuePosition = App.Vector(5, 2.5, 2.5)
kug.Placement = App.Placement(neuePosition, kug.Placement.Rotation)
# Quader
quader = Part.makeBox(5, 5, 50)
form_element = doc.addObject("Part::Feature", "Quader")
form_element.Shape = quader
quad = FreeCAD.ActiveDocument.getObject("Quader")
quad.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
doc.recompute()
Diesen Code können Sie nun ausführen:
* Makro > Makro ausführen
Es ergibt sich folgende Ausgabe (gedreht und gezoomt):
[[Datei: PythonIng_freecad1.png|500px]]
Siehe auch [https://wiki.freecad.org/Python_scripting_tutorial/de# Anleitung Skripterstellung mit Python]. Getestet wurde obiges Beispiel mit FreeCAD 1.1.3 unter Linux und 1.1.1 unter MS Windows.
== LibreOffice ==
LibreOffice ist ein freies Officepaket ([https://de.libreoffice.org/]). Hier soll nur das Tabellenkalkulationsprogramm Calc kurz betrachtet werden. Es seinen in den ersten 3 Zellen (A1 bis A3) Zahlen gegeben. Diese sollen mit einem Python-Makro addiert und das Resultat in der Zelle A5 ausgegeben werden. Auch hier sind Vorbereitungsarbeiten nötig:
* zuerst muss unter Linux das Verzeichnis <code>~/.config/libreoffice/4/user/Scripts/python</code> erstellt werden
* für MS Windows ist es das Verzeichnis <code>%APPDATA%\LibreOffice\4\user\Scripts\python</code>
** drücken Sie zuerst Win + R (es öffnet sich das Ausführen-Fenster)
** geben Sie <code>%appdata%</code> ein, danach drücken Sie Enter (es öffnet sich der Explorer)
** navigieren Sie zu dem genannten Verzeichnis bzw. erstellen Sie das Verzeichnis
* in diesem Verzeichnis wird dann mit einem beliebigen Texteditor das Python-Makro erstellt, in unserem Fall die Datei <code>summiere_zellen.py</code>:
import uno
def summiere_zellen(*args):
# Zugriff auf das aktuelle Dokument und das aktive Tabellenblatt
ctx = uno.getComponentContext()
smgr = ctx.getServiceManager()
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.getCurrentController().getActiveSheet()
# Werte aus den Zellen A1 bis A3 auslesen
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
# Addition der drei Werte
summe = w1 + w2 + w3
# Ergebnis in die Zelle A5 schreiben
sheet.getCellRangeByName("A5").Value = summe
* siehe dazu ggf. auch [https://help.libreoffice.org/latest/de/text/sbasic/python/python_locations.html?DbPAR=BASIC].
Weiter geht es in LibreOffice Calc mit dem Menü ''Extras > Makros > Makros verwalten > Python''. Dort wird das Makro <code>summiere_zellen</code> ausgeführt. Es ergibt sich z.B. folgendes Resultat
[[Datei:PythonIng_libreoffice1.png]]
Das Kürzel <code>uno</code> steht für '''U'''niversal '''N'''etwork '''O'''bjects. Etwas einfacher geht's auch so:
def summiere_zellen():
desktop = XSCRIPTCONTEXT.getDesktop()
model = desktop.getCurrentComponent()
sheets = model.getSheets()
sheet = sheets.getByIndex(0)
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
cell = sheet.getCellRangeByName("A5")
cell.setValue(w1 + w2 + w3)
Empfohlen wird auch, das Erweiterungspaket APSO ('''A'''lternative '''P'''ython '''S'''cript '''O'''rganizer, apso.oxt) zu installieren. Die Vorgehensweise wird hier nicht gezeigt, sondern nur darauf hingewiesen, dass man das einfach "googeln" kann. Siehe zur Python-Programmierung für LibreOffice auch [https://wiki.documentfoundation.org/Macros/Python_Guide/de Makros/Python-Handbuch]. Getestet wurden obige Beispiele mit LibreOffice 26.2.5.1 unter Linux und 26.2.1.2 unter MS Windows.
= Ausblick =
Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Python. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks, Bücher und die Python-Hilfefunktion verwiesen. Python kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Module fast beliebig erweiterbar.
= Weblinks=
== Python allgemein ==
* [https://www.python.org/ Python Homepage]
== Externe mathematische Module ==
* [https://numpy.org/ NumPy]
* [https://numpy.org/doc/stable/user/numpy-for-matlab-users.html NumPy for MATLAB users]
* [https://scipy.org/ SciPy]
* [https://www.sympy.org/en/index.html SymPy]
* [https://pandas.pydata.org/ pandas]
* [https://github.com/maroba/findiff findiff]
* [https://mpmath.org/ mpmath]
== Externe Module für Grafiken ==
* [https://matplotlib.org/ Matplotlib]
* [https://vpython.org/ VPython]
* [https://build123d.readthedocs.io/en/latest/ build123d]
* [https://docs.vtk.org/en/latest/api/python.html VTK]
* [https://docs.bokeh.org/en/latest/docs/first_steps.html bokeh]
* [https://py5coding.org/ py5]
== Erstellung von User Interfaces ==
* [https://docs.python.org/3/library/tkinter.html tkinter - Python interface to Tcl/Tk]
* [https://docs.python.org/3/library/curses.html curses - Terminal handling for character-cell displays]
* [https://wiki.qt.io/Qt_for_Python Qt for Python]
* [https://www.gtk.org/docs/language-bindings/python GTK and Python]
== Erstellen virtueller Umgebungen ==
* [https://docs.python.org/3/library/venv.html venv - Creation of virtual environments]
== Sonstige ==
* [https://python-control.readthedocs.io/en/stable/ Python Control Systems Library]
* [https://pypi.org/project/regex/ regex - Regular Expressions]
* [http://pyromat.org/ PYroMat]
* [https://coolprop.org/coolprop/wrappers/Python/index.html CoolProp]
* [https://pypi.org/project/iapws/ iapws]
* [https://tespy.readthedocs.io/en/main/getting_started/introduction.html TESPy - Thermal Engineering Systems in Python]
* [https://pint.readthedocs.io/en/stable/ pint]
= Bücher =
== Gedruckte Bücher, OpenBooks, Magazine ==
* Diverse: c't Python Lernen, Verstehen, Anwenden; Heise, 2022
* Ernesti, Kaiser: Python3 - das umfassende Handbuch; 5. Aufl., Rheinwerk, [https://openbook.rheinwerk-verlag.de/python/ OpenBook]
* Iacono et al.: Programmieren trainieren; 3. Aufl., Hanser, 2023, ISBN 978-3-446-47766-7
* Inden: Python Challenge; dpunkt, 2021, ISBN 978-3-86490-809-5
* Klein: Numerisches Python; 2. Aufl., Hanser, 2023, ISBN 978-3-446-47170-2
* Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler; Rheinwerk, 2021, ISBN 978-3-8362-7316-9
* Weigend: Python 3 - Das umfassende Praxisbuch; 9. Aufl., mitp, 2022, ISBN 978-3-7475-0544-1
* Woyand: Python für Ingenieure und Naturwissenschaftler; 4. Aufl., Hanser, 2021, ISBN 978-3-446-46483-4
== Andere Wikibooks ==
* [[:en:Subject:Python_programming_language | Englische Wikibooks zum Thema Python]]
* [[Python|Deutschsprachiges Python-Wikibook]] [[Bild:2von10.png|20%]]
* [[Python unter Linux|Python 2.7 unter Linux]] [[Bild:10von10.png|100%]]
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
k7zc8feyj4cj59u076fat3duesg89mm
1091905
1091903
2026-10-04T07:14:37Z
Intruder
1513
/* Py5 */
1091905
wikitext
text/x-wiki
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
= Hallo Welt und allgemeine Hinweise =
== Was ist Python ==
* Python ist eine universelle höhere Programmiersprache.
* Python ist objektorientiert.
* Python ist Open-Source (Python Software Foundation License).
* Python ist für viele Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
* Python ist ein Interpreter.
* Python ist durch Module fast beliebig erweiterbar.
* Python als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
* Python ist in etlichen Anwendungsprogrammen (z.B. {{W|FreeCAD}}, {{W|LibreOffice}}, {{W|GIMP}}, {{W|Blender (Software) | Blender}}) als Makrosprache verwendbar.
{{Wikipedia | Python (Programmiersprache)}}
== Python installieren ==
=== MS Windows ===
Laden Sie das aktuelle Python-Paket von der Webseite [https://www.python.org/] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.
=== Linux ===
Entweder ist Python bereits standardmäßig installiert, ansonsten ist die Installation mittels Paketmanagementsystem einfach möglich. Aber auch die Spyder-Entwicklungsumgebung ([https://www.spyder-ide.org]) bietet einen guten Einstieg mit Python (das gilt auch für MS Windows). Spyder bringt auch schon etliche wichtige Module standardmäßig mit.
== Python starten ==
=== MS Windows ===
Das Icon für das Python-Programm doppelklicken. Und schon startet das Programm.
[[Datei:PythonIng_start1.jpg]]
Python im interaktiven Modus präsentiert sich dann so:
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Alternativ kann das Programm auch über die Eingabeaufforderung oder die PowerShell gestartet werden:
c:\devel\Python>python.exe
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
=== Linux ===
Tippen Sie einfach das Wort „python“ (oder unter openSUSE Tumbleweed z.B. auch „python3.11“ oder „python3.13“) in einem Linux-Terminal ein, schließen den Befehl mit der RETURN-Taste ab, und schon startet Python im interaktiven Modus:
Python 3.13.12 (main, Feb 09 2026, 22:37:44) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Es gibt auch noch andere Möglichkeiten Python zwecks Programmausführung zu starten, z. B. den {{W|Shebang}} (<code>#!</code>) am Beginn eines Python-Scripts. Das Script sei als Script.py gespeichert. Dann kann das Script mit ./Script.py ausgeführt werden. Für openSUSE Tumbleweed sei nachfolgend ein lauffähiges "Hallo Welt!"-Script angegeben. Es wird in diesem Script der Python-Interpreter in der Version 3.13 verwendet :
#!/usr/bin/python3.13
print("Hallo Welt!")
Die Berechtigungen zum Ausführen der Datei müssen natürlich noch richtig gesetzt werden, z.B. mittels <code>chmod 777 Script.py</code>. <small><code>chmod</code> ist die Abkürzung für"'''ch'''ange file '''mod'''e bits".</small>
<small>Die "Maske" <code>777</code> ist nur für Testzwecke sinnvoll, weil sie leicht zu merken ist und für alle Benutzer alle Zugriffsberechtigungen ('''r'''ead/'''w'''rite/e'''x'''ecute für owner/group/others) setzt. Im richtigen Einsatz wird man das aus Sicherheitsgründen nicht so handhaben, sondern nur die Berechtigungen setzen, die unbedingt erforderlich sind. Welche Zugriffsberechtigungen gesetzt sind, kann man z.B. mit dem Befehl <code>ls -l</code> oder <code>ll</code> ('''l'''i'''s'''t directory contents) erfragen. Aber dazu im Moment genug. Erfahrene Linux-Nutzer kennen das ohnehin und Anfänger sollen jetzt nicht mit Linux-Interna überfordert werden. Bei Bedarf siehe die Linux-Man-Pages oder dezidierte Bücher zu Linux.</code></small>
<small>Oder das Script wird in einen Pfad verschoben, in dem sich ausführbare Programme generell befinden (welche Verzeichnisse im PATH liegen, kann bspw. mit <code>echo $PATH</code> abgefragt werden). Das Script kann dann wie ein normales Programm ohne weitere Angaben mit Script.py gestartet werden. Alternativ wird nicht das Script an sich verschoben, sondern nur ein symbolischer Link angelegt, z.B. mit <code>ln -s ~/tmp/Script.py ~/.local/bin/Script.py</code>. <code>~/.local/bin</code> sei ein im PATH gelegenes Verzeichnis. Dies sind aber schon Features für fortgeschrittene Linux-Benutzer und werden am Anfang eher selten benötigt.</small>
== Ein paar Worte zur Erklärung ==
=== Tests ===
Getestet wurden die Beispiele unter den Betriebssystemen
* MS Windows 10 mit der Python-Version 3.12.0 (teilweise auch mit 3.12.2 und 3.13.1; nur die Inhalte die bis spätestens Juli 2025 erstellt wurden)
* MS Windows 11 ab der Python-Version 3.13.4 (nur zum Teil; ab Juli 2025)
* openSUSE Leap 15.6 mit der Python-Version 3.11.12 (Spyder, nur vereinzelt) und zum Teil mit 3.12.11 (ab Juli 2025 bis November 2025).
* openSUSE Tumbleweed ab der Python-Version 3.13.9 (nur vereinzelt, ab November 2025)
=== Popularität ===
* An Beliebtheit rangiert Python mit Stand September 2026 mit einem Rating von 17,76% an 1. Stelle vor C und C++ (lt. [https://www.tiobe.com/tiobe-index/ TPCI - TIOBE Programming Community Index]).
* Lt. [https://innovationgraph.github.com/global-metrics/programming-languages GitHub Top 50 Programming Languages Globally] lag Python im Q1/2026 auf Rang 2, vor TypeScript und hinter JavaScript.
* [https://pypl.github.io/PYPL.html PYPL] (Popularity of Programming Language Index) ist ein anderer Popularitätsindex für Programmiersprachen. Auch hier liegt Python mit großem Vorsprung auf dem ersten Platz (52,08%), gefolgt von Java (13,34%) und C/C++ (7,99%) (Stand September 2026).
=== Namensgebung ===
Der Name "Python" rührt von der Komikertruppe {{W|Monty Python}} her. Die Icons für Python (z.B. Python selbst, Eric IDE, IDLE) sind aber durch die Python-Schlangenart symbolisiert.
<gallery>
Python-logo-notext.svg|Python-Logo
Guido van Rossum in PyConUS24.jpg|{{W|Guido van Rossum}} (geb. 1956), der Erfinder von Python
</gallery>
== Ein erstes Programm ==
Kommentare werden in Python mit der Raute (#) eingeleitet. Sie werden vom Python-Interpreter ignoriert. Text kann mit der print-Funktion ausgegeben werden. Starten Sie Python und geben sie folgende Anweisungen zeilenweise ein
>>> # Das ist ein Kommentar
>>> print("Hallo Welt!")
Als Ergebnis erhalten Sie
Hallo Welt!
Der Prompt (>>>) ist selbstverständlich nicht einzutippen, sondern wird vom Python-System geliefert.
Strings können in Python entweder in Anführungszeichen (") gesetzt werden oder in Hochkommatas('). In diesem Text wird die erste Variante bevorzugt eingesetzt.
Im Gegensatz zu Julia ist es hier egal, ob zwischen <code>print</code> und der öffnenden Klammer Leerzeichen stehen.
= Python als Taschenrechner =
== Allgemeines ==
Wir wollen 3 * 5 berechnen. Dazu starten wir Python im interaktiven Modus. Geben Sie dann die Formel
>>> 3 * 5
ein, drücken die Taste ENTER/RETURN ({{Taste|↵}}) und erhalten als Ergebnis
15
Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck <math>\sin\sqrt{15}</math> berechnen :
>>> import math
>>> math.sin(math.sqrt(15))
-0.6679052983383519
Als erstes wird das math-Modul importiert. Dann wird der mathematische Ausdruck berechnet.
Eine andere Variante, die dasselbe Ergebnis liefert, ist
>>> from math import *
>>> sin(sqrt(15))
-0.6679052983383519
Es wird also aus dem Modul <code>math</code> alles importiert (erkennbar am <code>*</code>). Will man nicht alles importieren, so kann man das auch einschränken:
>>> from math import sin, sqrt
Beenden lässt sich das Python-Programm durch Eingabe von <code>exit()</code> (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken).
== Die Hilfefunktion von Python ==
Bei Eingabe der Anweisung <code>help</code> oder <code>help()</code> springt Python in den Hilfemodus.
Eingabe:
>>> help()
Eingabe:
help> math.sin
Ausgabe:
Help on built-in function sin in math:
math.sin = sin(x, /)
Return the sine of x (measured in radians).
Für die komplette Python-Dokumentation siehe [https://docs.python.org/3/]. Verlassen kann man den Hilfemodus durch das Drücken von STRG-C, bzw. der Eingabe von q, quit oder exit mit anschließendem Drücken der RETURN-Taste.
== Aufgaben ==
* Erkunden Sie die Tangensfunktion "tan" mittels Python-Hilfe (vergessen Sie nicht das math-Modul zu importieren und das <code>math.</code> vor <code>tan</code>)
* Berechnen Sie mit Python den Ausdruck <math>\frac{1}{2}\cdot \text{e}^2 \cdot \tan(\pi/3)</math>. Siehe für die Exponentialfunktion im Python-Hilfesystem auch den Befehl <code>math.exp</code>. Alternativ kann auch die Konstante <code>math.e</code> eingesetzt werden. Potenzieren kann man bei Python mit dem **-Operator (z.B. 2**3 = 8). Für <math>\pi</math> gibt es <code>math.pi</code>.
= Python als Scriptsprache =
Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.py
# Das ist ein Kommentar
print("Hallo Welt!")
Python-Dateien werden mit der Dateiendung .py versehen. Achten Sie darauf, dass vor dem print keine Leerzeichen vorhanden sind. Das ist eine Python-Eigenheit. Wie wir später sehen werden, nutzt Python Einrückungen als syntaktisches Mittel, z.B. um bei Schleifen den Schleifenkörper zu kennzeichnen.
Danach bringen Sie die Skriptdatei test1.py (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:
1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ auch die Windows PowerShell). Das sieht dann etwa so aus:
Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\xyz>
: <small>Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol ([[Image:Windows_logo_-_2021_(Black).svg|10px]]) mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell unter Windows 10 den Eintrag "Windows PowerShell", unter Windows 11 den Eintrag "Terminal"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort <code>cmd</code> ein und mit "OK" wird das Ganze bestätigt.</small>
2) Wechseln Sie mittels <code>cd c:\tmp</code> in das Verzeichnis c:\tmp
3) Angenommen, Sie haben Python unter dem Pfad <code>c:\devel\Python\</code> installiert. Starten Sie das Programm so (der Prompt <code>c:\tmp></code>ist natürlich nicht mit einzutippen):
c:\tmp>c:\devel\Python\python.exe test1.py
4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm
Hallo Welt!
Die Vorgehensweise unter Linux ist prinzipiell gleich. Die kleinen Unterschiede, wie z.B. der Slash statt dem Backslash in Pfadangaben, sollten für Linux-Benutzer keine Hürde darstellen.
== Variablen ==
Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9) und Underscores (_) bestehen, dürfen aber nicht mit einer Zahl beginnen. Führende Underscores haben u.a. im Kontext mit der Objektorientierten Programmierung eine spezielle Bedeutung und sollten nicht für "normale" Variablenbezeichner verwendet werden.
Gültige Variablenbezeichner wären also:
xyz
x1
_wert
name_anzahl
Theoretisch kann man auch Umlaute, griechische Buchstaben u.ä. in Variablenbezeichnern nutzen, z.B.
ößÜ = 16
α = 134
print(ößÜ)
print(α)
Ausgabe:
16
134
Davon wird aber aus offensichtlichen Gründen ({{W|Englisch als Lingua franca}}) abgeraten. Das Eurozeichen (€) etc. darf man ohnehin nicht in Variablenbezeichnern verwenden, dies ergäbe einen Syntaxfehler. Siehe dazu auch [https://peps.python.org/pep-3131/].
Es gibt in Python etliche Schlüsselwörter (z.B. for, if oder return). Diese dürfen nicht als eigene Variablenbezeichner verwendet werden. Eine Liste aller Schlüsselwörter liefert das Script
import keyword
print(keyword.kwlist)
<small>Übung: Speichern Sie dieses Script in eine Datei, z.B. in c:\tmp\test1.py. Führen Sie diese Datei aus, um die Liste der Schlüsselwörter auszugeben.</small>
Da Python case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:
xyz
XYZ
xYz
Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.py gespeichert.
x = 5
y = 10
z = x*y
print(z)
Bringen Sie die Datei test1.py zur Ausführung, so erhalten Sie folgende Bildschirmausgabe
50
Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben. Dies führt aber zu unübersichtlichem Code.
x = 5; y = 10; z = x*y; print(z)
Ausgabe:
50
Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.
x = 5
# x = x - 2
x -= 2
print(x)
Bildschirmausgabe:
3
Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Den Inkrement-/Dekrementoperator (z.B. x++ oder x--) aus C/C++ oder Java kennt Python aber nicht.
Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Python problemlos möglich:
import math
wert = 10
print(wert)
wert = 35.5
print(wert)
wert = "Hallo"
print(wert)
wert = math.pi
print(wert)
Ausgabe:
10
35.5
Hallo
3.141592653589793
== Physische und logische Zeilen ==
In Python muss eine Anweisung in einer logischen Zeile Platz finden. Wird eine Anweisung aber zu lang für eine Zeile, dann kann sie in mehrere physische Zeilen unterteilt werden. Dies kann einerseits durch einen Backslash am Ende einer Zeile geschehen, z.B.
a = 2 + \
5
Dies stellt eine logische Zeile dar, die in zwei physische Zeilen unterbrochen ist.
Geklammerte Ausdrücke werden automatisch zu einer logischen Zeile verbunden, z.B.
a = (2 +
5)
Achtung: Im ersten Beispiel darf nach dem Backslash nichts mehr stehen, auch kein Kommentar. Dies trifft im zweiten Bespiel nicht zu, hier könnte noch ein Kommentar folgen, z.B.
a = (2 + # Kommentar
5)
Auch für Strings gibt es Möglichkeiten, diese auf mehrere Zeilen aufzuspalten.
# Kurzer String
str1 = "ABC"
# Langer String
str2 = """Hallo Welt,
Grüetzi Schwyzer,
Servus an alle"""
# Backslash
str3 = "UVW\
XYZ"
# Mit Klammern
str4 = ("Sehr langer Text, der automatisch .............. "
"in einer einzigen Variable zusammengefügt wird."
)
print(str1)
print(str2)
print(str3)
print(str4)
Ausgabe:
ABC
Hallo Welt,
Grüetzi Schwyzer,
Servus an alle
UVWXYZ
Sehr langer Text, der automatisch .............. in einer einzigen Variable zusammengefügt wird.
==Hexadezimale, oktale, binäre und andere Zahlen==
d = 1050 # Dezimalzahl
h = 0xAA2 # Hexadezimalzahl
o = 0o12 # Oktalzahl
b = 0b100001101 # Binärzahl
print(d)
print(h)
print(o)
print(b)
Ausgabe:
1050
2722
10
269
Groß- und Kleinbuchstaben sind in obigen Literalen übrigens egal. So kann man z.B. statt <code>0b1001</code> auch <code>0B1001</code> schreiben (siehe dazu [https://docs.python.org/3/reference/lexical_analysis.html#integer-literals]).
Sie können auch dezimale in hexadezimale Zahlen umwandeln, usw.:
h = hex(1050) # Dezimalzahl -> Hexadezimalzahl
b = bin(1050) # Dezimalzahl -> Binärzahl
o = oct(1050) # Dezimalzahl -> Oktalzahl
print(h)
print(b)
print(o)
Ausgabe:
0x41a
0b10000011010
0o2032
Gegeben sei die Zahl 121 zur Basis 3. Diese soll in eine Dezimalzahl umgewandelt werden. Das kann so geschehen:
z = int("121", 3)
print(z)
Ausgabe:
16
Dass dies richtig ist, davon kann man sich folgendermaßen überzeugen:
<math> 1 \cdot 3^2 + 2 \cdot 3^1 + 1 \cdot 3^0 = 9 + 6+ 1 = 16 </math>
Zahlen übersichtlicher schreiben kann man auch mittels Underscore, z.B.:
print("Eine Million (Variante 1) =", 1000000)
print("Eine Million (Variante 2) =", 1_000_000)
print("Eine Rechnung:", 2_000 * 400_000);
Es ergibt sich bei beiden Varianten die gleiche Ausgabe. Variante 2 ist aber im Sourcecode leichter lesbar, detto die Zahlen in der Rechnung:
Eine Million (Variante 1) = 1000000
Eine Million (Variante 2) = 1000000
Eine Rechnung: 800000000
== Strings und Platzhalter==
Ein paar einfache Beispiele:
print("Hallo {}" . format("Hugo"))
print("Hallo {:s}" . format("Hugo"))
print("Hallo %s" % "Hugo")
Ausgabe:
Hallo Hugo
Hallo Hugo
Hallo Hugo
Python-Code (formatted string literals, Beispiel 1):
str1 = "Hallo"
str2 = "Hugo"
print(f"{str1} {str2}")
Ausgabe:
Hallo Hugo
Python-Code (formatted string literals, Beispiel 2):
wert = 11.567
print(f"Ausgabe: {wert:.5f}")
Ausgabe:
Ausgabe: 11.56700
Komplexere Beispiele:
print("Hallo {} und {}" . format("Hugo", "Mike"))
print("Hallo {name1} und {name2}" . format(name2="Hugo", name1="Mike"))
# Füllzeichen: *
# Bündigkeit: > (=rechts), < (=links), ^ (=zentriert)
# Feldweite: 10
# Typ: s (=String), f (=Gleitkommazahl), d (=Dezimalzahl) etc.
print("Hallo {:*>10s}" . format("Hugo"))
print("Hallo {:*<10s}" . format("Hugo"))
Ausgabe:
Hallo Hugo und Mike
Hallo Mike und Hugo
Hallo ******Hugo
Hallo Hugo******
Python-Code:
str = "Hallo\t%s\t%7.2f\t%10.2e\t%i" % ("Hugo", 12.34567, 34.567, 264)
print(str)
Ausgabe:
Hallo Hugo 12.35 3.46e+01 264
== Unicode ==
Neben den bekannten ASCII-Zeichen lassen sich Zeichen auch mittels Unicode beschreiben. Griechische Buchstaben oder komplexere mathematische Operatoren - all das sollte kein Problem sein. Siehe auch {{W|Unicode}}, {{W|Liste der Unicodeblöcke}} und {{W|Unicodeblock Mathematische Operatoren}}. Im Folgenden werden ein paar Zeichen (Allquantor, Nabla-Operator, Existenzquantor), die man aus der Mathematik kennt, erzeugt.
ch1 = "\N{FOR ALL}"
ch2 = "\N{NABLA}"
ch3 = "\u2203"
print(ch1, ch2, ch3)
Ausgabe:
∀ ∇ ∃
<small>Diese Ausgabe ergibt sich z.B. mit der IDLE-Shell oder mit Cygwin. Beim Ausführen über die Windows-Eingabeaufforderung oder Windows PowerShell unter MS Windows 10 erfolgt keine korrekte Darstellung. IDLE ist die mit Python mitgelieferte IDE ('''I'''ntegrated '''D'''evelopment '''E'''nvironment, Integrierte Entwicklungsumgebung). Gegen Ende dieses Textes wird IDLE kurz beschrieben.
Das Problem mit der Windows Eingabeaufforderung lässt sich aber umgehen. Man muss nur eine Schriftart auswählen, die die Zeichen kennt, z.B. "DejaVu Sans Mono". Dazu klicken Sie einfach bei der Eingabeaufforderung mit der rechten Maustaste oben auf die weiße Leiste und wählen im aufpoppenden Fenster den Menüpunkt "Eigenschaften". Es öffnet sich ein Dialogfenster. Über den Reiter "Schriftart" lässt sich nun die Schriftart einstellen. Unter MS Windows 11 oder openSUSE Leap 15.6 (bash-Konsole) gibt es dieses Problem ohnehin nicht.</small>
== Reguläre Ausdrücke ==
Python kennt auch {{W|Regulärer Ausdruck|reguläre Ausdrücke}}. Dazu gibt es in Python das Modul <code>re</code>. Beipielsweise sollen alle Zahlen (<math>\text{zahl}\in\mathbb{N}_0</math>) in einem String gesucht und ausgegeben werden. Als String sei gegeben: <code>3x Grüße und 100 Kekse.</code> Das Muster (Pattern) ist <code>\d+</code>. <code>\d</code> steht für eine Dezimalziffer 0-9. Das Plus-Zeichen (+) steht symbolisch für ein oder mehrere Zeichen des vorherigen Ausdrucks. Hier also ein oder mehrere Dezimalziffern. Es wird die Funktion <code>findall</code> aus dem Modul <code>re</code>verwendet.
Python-Code:
from re import findall
str = "3x Grüße und 100 Kekse."
pat = "\\d+" # Doppel-Backslashes müssen verwendet werden, sonst gibt Python eine Warnung aus!
# alternativ: pat = r"\d+"
# oder: pat = "[0-9]+"
numb = findall(pat, str)
print(numb)
Ausgabe:
['3', '100']
Python kennt noch viele weitere Möglichkeiten mittels regulärer Ausdrücke zu hantieren. Dies soll hier aber nicht vertieft werden, da das Thema schon ziemlich speziell und komplex ist. Bei Bedarf siehe aber z.B. die Bücher ''Weigend, Seite 380ff'' und ''Ernesti, Kaiser'' [https://openbook.rheinwerk-verlag.de/python/28_001.html] oder die Python-Dokumentation [https://docs.python.org/3/library/re.html]. Auch [[Python unter Linux: Reguläre Ausdrücke]] liefert ein umfangreiches und brauchbares Python-2-Kapitel zu den regulären Ausdrücken. Die dort gelisteten Beispiele müssten ggf. vor Verwendung auf Python-3 umgeschrieben werden. <small>Wie macht man das? Dazu siehe z.B. [https://openbook.rheinwerk-verlag.de/python/43_001.html], [https://portingguide.readthedocs.io/en/latest/] oder [https://www.digitalocean.com/community/tutorials/how-to-port-python-2-code-to-python-3]</small>
<small>Es gibt auch ein externes Modul ''regex'', das bei Bedarf extra installiert werden muss ([https://pypi.org/project/regex/]). Es bietet zusätzliche Funktionalität und gründlicheren Unicode-Support. Dies sei hier aber nur der Vollständigkeit halber erwähnt.</small>
== Verzweigungen ==
=== if ===
Die IF-Verzweigung sei aus anderen Programmiersprachen bereits bekannt. In {{W|Pseudocode}} lässt sie sich folgendermaßen darstellen:
WENN bedingung TRUE
führe block1 aus
SONST
führe block2 aus
ENDE
Als {{W|Aktivitätsdiagramm|UML-Aktivitätsdiagramm}} sieht das in etwa so aus:
[[File:If-Then-Else-diagram.svg|200px]]
Und als {{W|Nassi-Shneiderman-Diagramm|Nassi-Shneiderman-Struktogramm}} so:
[[File:Zweiseitige Auswahl.png|250px]]
In Python gibt es keinen expliziten ENDE-Kennzeichner. Stattdessen wird der Code durch Einrückungen strukturiert. Alles mit der gleichen Einrückungstiefe gehört zum selben Block. Dies zeichnet Python vor anderen Programmiersprachen aus.
Die test1.py-Datei laute also wie folgt:
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4
Man achte auch auf die Doppelpunkte in der if- und else-Zeile. Darauf vergisst man gerne, wenn man von anderen Programmiersprachen kommt.
Folgendes wäre in Python ein Fehler (genauer gesagt ein IndentationError).
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Auch Nachstehendes würde nicht zum gewünschten Ergebnis führen (löst aber keine Fehlermeldung aus). Der letzte print-Befehl ist schon außerhalb der IF-ELSE-Verzweigung.
x = 3
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
x ist kleiner als 4
x ist groesser oder gleich 4
Python kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:
<, <= ... kleiner (gleich)
>, >= ... größer (gleich)
== ... gleich
!= ... ungleich
is ... identisch
is not ... nicht identisch
and ... AND
or ... OR
not ... NOT
Beispielsweise:
a = 5
b = 9
if a<=10 and b!=7:
print("OK")
else
print("Nicht OK")
Ausgabe:
OK
Der else-Block kann übrigens auch ersatzlos entfallen. Als Pseudocode sieht das so aus
WENN bedingung TRUE
führe block aus
ENDE
Mehrfache Verzweigungen werden durch das elif-Konstrukt erstellt. In Pseudocode:
WENN bedingung1 TRUE
führe block1 aus
SONST WENN bedingung2 TRUE
führe block2 aus
SONST WENN bedingung3 TRUE
führe block3 aus
SONST
führe block4 aus
ENDE
Ein Python-Beispiel:
a = 14
if a<=10:
print("<=5")
elif a>11 and a<15:
print("11 bis 15")
elif a>16 and a<20:
print("16 bis 20")
else:
print(">=20")
Ausgabe:
11 bis 15
In Python gibt es auch die Schlüsselwörter <code>True</code> (für wahr) und <code>False</code> (für falsch). Man beachte, dass sie mit Großbuchstaben beginnen. Andere Schreibweisen wären ein Fehler. Sie gehören zum Datentyp <code>bool</code>. Ihnen sind auch die Zahlen <code>1</code> und <code>0</code> zugewiesen.
Man beachte, dass {{W|Rundungsfehler}} auftreten können. D.h. man sollte bei der Verwendung von {{W|Gleitkommazahl|Gleitpunktzahlen}} niemals auf absolute Genauigkeit prüfen, sondern eine Toleranz (einen <math>\varepsilon</math>-Wert) vorgeben.
Ein klassisches Beispiel, das ein falsches Ergebnis liefert, ist:
i = 0.1 + 0.2
print(i)
if i == 0.3:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
NOK
Und das, obwohl man schon in der Volksschule lernt, dass 0.1 + 0.2 gleich 0.3 ist.
Korrekt muss das obige Beispiel z.B. so umgeschrieben werden:
ist = 0.1 + 0.2
soll = 0.3
epsilon = 0.000001
print(ist)
if abs(ist-soll) < epsilon:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
OK
Alternativ kann auch die <code>math.isclose()</code>-Funktion verwendet werden. Das sei aber hier nur erwähnt und nicht konkret ausgeführt.
<u>Aufgabe:</u> Recherchieren Sie im Internet zum Thema <code>math.isclose()</code>-Funktion.
=== match ===
Ab Python 3.10 gibt es auch die match-Anweisung. Dies ist das Python-Pendant für die switch-Anweisung in anderen Programmiersprachen, geht aber bei näherer Betrachtung weit darüber hinaus. Hier nur ein einfaches Beispiel:
x = "Hello"
match x:
case "Servus" | "Ciao": # or
print("Servus an alle")
case "Grüetzi":
print("Grüetzi Schwyzer")
case _: # other, default, sonstiges ...
print("Hallo Welt")
Ausgabe:
Hallo Welt
Als Struktogramm sieht das in etwa so aus:
[[File:Mehrseitige Auswahl.png|250px]]
Für nähere Details siehe z.B. [https://www.geeksforgeeks.org/python-match-case-statement/], [https://learnpython.com/blog/python-match-case-statement/], [https://docs.python.org/3/tutorial/controlflow.html#match-statements] und das Python Enhancement Proposal (PEP) 636 – Structural Pattern Matching: Tutorial [https://peps.python.org/pep-0636] und dort insbesondere den Anhang A - Quick Intro.
<small><code>match, case, _</code> etc. sind sogenannte ''soft keywords''. Im Gegensatz zu den normalen Schlüsselwörtern dürfen ihnen auch Werte zugewiesen werden. Eine Liste der weichen Schlüsselwörter lässt sich durch <code>keyword.softkwlist</code> erstellen (die Anweisung gibt es seit Python 3.9). Siehe dazu auch [https://stackoverflow.com/questions/65800344/what-are-soft-keywords] und [https://docs.python.org/3/library/keyword.html#keyword.softkwlist].</small>
== Schleifen ==
Kopfgesteuerte Schleife, Endlosschleife und fußgesteuerte Schleife:
[[File:Programmingloops.svg|450px]]
=== while ===
Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert wie aus anderen Programmiersprachen bekannt.
In Pseudocode:
SOLANGE bedingung TRUE
führe block aus
ENDE
In Python:
x = 0
while x <= 10:
print(x)
x += 1
Ausgabe:
0
1
2
3
4
5
6
7
8
9
10
Eine Endlosschleife ergibt sich z.B. so:
i = 5
while True:
print(i)
i-=1
Beendet werden kann sie mit der Tastenkombination STRG-C.
Eine fußgesteuerte Schleife kann so simuliert werden:
i = 5
while True:
print(i)
i-=1
if i<=0:
print("Fire")
break
Ausgabe:
5
4
3
2
1
Fire
Der <code>break</code>-Befehl wird etwas später noch einmal kurz thematisiert.
=== for ===
Struktogramm einer for-Schleife:
[[File:Zählschleife.png|200px]]
In Python bspw. so:
for x in range(6):
print(x*2)
Ausgabe:
0
2
4
6
8
10
Die Schleife läuft von 0 bis 5. Ausgegeben wird jeweils der Wert x*2. Aquivalent kann diese Schleife auch so geschrieben werden:
for x in range(0, 11, 2):
print(x)
Die Ausgabe ist wie oben. Der Startwert sei 0, der Endwert ist 11-1 und die Schrittweite ist 2.
Ein anderes Beispiel sei
for x in "text":
print(x)
Ausgabe:
t
e
x
t
== Schleifen abbrechen ==
=== break ===
<code>break</code> bricht die Schleife ab und setzt mit dem nächsten Befehl außerhalb der Schleife fort.
for var in range(100):
print(var)
if var == 5:
break
Ausgabe:
0
1
2
3
4
5
=== continue ===
<code>continue</code> bricht den aktuellen Schleifendurchlauf ab und setzt mit dem nächsten Schleifendurchlauf fort.
for var in range (11):
if var == 5:
continue
print(var)
Ausgabe:
0
1
2
3
4
6
7
8
9
10
== try - except ==
try:
z1 = 12 / 0
print(z1)
except ZeroDivisionError:
print("Das Ergebnis ist unendlich")
except:
print("Kann nicht berechnet werden!")
print("Bitte die Formel korrigieren!")
print("Setze Programm fort!")
Ausgabe:
Das Ergebnis ist unendlich
Setze Programm fort!
Es wird versucht, eine Zahl durch Null zu dividieren. Das ist nicht möglich, es wird eine Ausnahme ausgelöst. Das Programm springt daher in den except-ZeroDivisionError-Block und führt die dort gelisteten Anweisungen aus (in unserem Fall eine print-Anweisung). Danach wird das Programm fortgesetzt. Würden wir dieses Programm ohne try-except ausführen, so ergibt sich aus
z1 = 12 / 0
print(z1)
folgende Fehlermeldung und ein unmittelbarer Programmabbruch
Traceback (most recent call last):
File "C:\tmp\test1.py", line 1, in <module>
z1 = 12 / 0
ZeroDivisionError: division by zero
Mit dem try-except-Mechanismus können also Ausnahmen oder Fehler aufgefangen und behandelt werden. In unserem Beispiel ist das eher trivial, aber bei größeren Programmen kann das durchaus Sinn machen.
Neu in Python 3.14 ist, dass mehrere Ausnahmen auch ohne Klammern angegeben werden können, z.B.:
bis inkl. Python 3.13 nur:
except (ZeroDivisionError, ValueError):
ab Python 3.14 auch:
except ZeroDivisionError, ValueError:
== pass ==
Ein leerer Block muss in Python mittels dem Schlüsselwort <code>pass</code> dargestellt werden. Z.B.
x = 2
if x == 1:
print("Wert ist ", x)
else:
pass
Würde man das <code>pass</code> im else-Block weglassen, so würde man eine Fehlermeldung erhalten:
IndentationError: expected an indented block after 'else' statement on line 5
= Funktionen =
== Aufrufen von Funktionen ==
Funktionen sind uns im Rahmen dieses Kurses schon zuhauf begegnet. Sei es die print()-, die math.sin()- oder die hex()-Funktion. All diese Funktionen werden von Python zur Verfügung gestellt, ohne dass man sie explizit programmieren müsste. Aufgerufen werden diese Funktionen, indem man ihren Namen eintippt, gefolgt von runden Klammern. In diesen Klammern können noch Argumente übergeben werden. Auch Rückgabewerte sind möglich.
== Funktionen selber schreiben ==
Funktionen werden mit dem def-Schlüsselwort (man definiert die Funktion) eingeleitet, danach folgt der Funktionsname, danach wiederum runde Klammern, in denen formale Argumente stehen können. Abgeschlossen wird die def-Zeile mit einem Doppelpunkt. Danach folgt der Funktionskörper. Dieser Funktionskörper muss wiederum eingerückt werden (wie von den Verzweigungen und Schleifen bekannt). Aufgerufen wird diese Funktion, indem man ihren Funktionsnamen eingibt, gefolgt von runden Klammern (ggf. mit den aktuellen Parametern). Z.B.
# Funktion definieren
def halloWelt(i):
# i ... beliebige Ganzzahl
print("Hallo " * i, end="")
print("Welt!")
# Funktion aufrufen
halloWelt(3)
Ausgabe:
Hallo Hallo Hallo Welt!
Unterschied zwischen formalen und aktuellen Parametern:
[[Datei:PythonIng_func1.jpg]]
<small>Aktuelle Parameter werden auch Argumente genannt.</small>
Rückgabe von Funktionswerten:
# Funktion definieren
def mathFunc(a, b):
r1 = a + b
r2 = a * b
return r1, r2
# Funktion aufrufen
c, d = mathFunc(3, 5)
# Ausgabe der zurückgegebenen Werte
print(c)
print(d)
Ausgabe:
8
15
Es werden r1 und r2 zurückgegeben und den Variablen c und d zugewiesen. (r1, r2) und (c, d) sind Tupel. Was Tupel konkret sind, siehe etwas später in diesem Kapitel. 3 und 5 sind die aktuellen Parameter (die Argumente). a und b sind die formalen Parameter. Die Zuweisung der aktuellen zu den formalen Parametern erfolgt in der gegebenen Reihenfolge, also die Zahl 3 wird an a übergeben und die Zahl 5 an b.
Vorgabeparameter, z.B.:
def mathFunc(a=10, b=20):
r1 = a + b
r2 = a * b
return r1, r2
c, d = mathFunc(3, 5)
print(c)
print(d)
e, f = mathFunc(5)
print(e)
print(f)
g, h = mathFunc(b=6)
print(g)
print(h)
Ausgabe:
8
15
25
100
16
60
Erklärung:
* Erster <code>mathFunc</code>-Aufruf: Es werden, wie weiter oben, die Argumente 3 und 5 an die formalen Parameter a und b übergeben. Die Rückgabewerte r1 und r2 werden an c und d übergeben. Somit ist c=8 und d=15.
* Zweiter <code>mathFunc</code>-Aufruf: Es wird nur das Argment 5 an a übergeben. b behält den Vorgabewert 20. D.h. e= 25 und f=100.
* Dritter <code>mathFunc</code>-Aufruf: Es wird nur die Zahl 6 an b übergeben, a behält seinen Vorgabewert 10. Somit ergibt sich g=16 und h=60.
Beispiel (Schlüsselwortargumente vs. Positionsargumente):
def mathFunc(a, b):
r1 = a - b
r2 = a / b
return r1, r2
c, d = mathFunc(b=3, a=5) # Schlüsselwortargumente
e, f = mathFunc(3, 5) # Positionsargumente
print(c)
print(d)
print(e)
print(f)
Ausgabe:
2
1.6666666666666667
-2
0.6
Durch die Verwendung von Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge angegeben werden. Bei den Positionsargumenten ist die Reihenfolge vorgegeben. Daraus resultiert auch der Unterschied bei den obigen Ausgaben. Werden beide Arten in einem Aufruf gemischt, so müssen die Positionsargumente zuerst angegeben werden. Den Unterschied zwischen beiden Argumentarten zu kennen ist wichtig, nicht nur bei selbst erstellten Funktionen. Auch beim Aufruf von Python-Funktionen verfolgt einen die Mischung von Schlüsselwort- und Positionsargumenten auf Schritt und Tritt, z.B. beim etwas später folgenden Abschnitt über "Grafiken zeichnen":
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
Bei dieser <code>plot</code>-Funktion aus dem Modul <code>matplotlib.pyplot</code> sind <code>x</code> und <code>y1</code> Positionsargumente. <code>label, lw</code> und <code>ls</code> sind die Namen der Schlüsselwortargumente. Die Schlüsselwortargumente könnten auch in anderer Reihenfolge angeschrieben werden, nicht jedoch die Positionsargumente!
Siehe zu <code>matplotlib.pyplot.plot</code> auch die Seite [https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html].
== Lambda-Funktionen ==
print((lambda a, b: a*b) (3, 5))
Ausgabe:
15
Eingeleitet wird eine Lambda-Funktion (auch Lambda-Form, Lambda-Operator oder anonyme Funktion genannt) mit dem Schlüsselwort <code>lambda</code>. Es folgen die formalen Argumente, danach ein Doppelpunkt, die Berechnungsvorschrift und ggf. abschliessend in Klammern die aktuellen Parameter.
Man kann einer Lambda-Funktion auch einen Funktionsnamen geben und die Funktion über diesen Namen aufrufen, z.B.
prod = lambda a, b: a*b
print(prod(3, 5))
Als Ausgabe wird wieder die Zahl 15 geliefert.
== Rekursive Funktionen ==
Funktionen können wiederum andere Funktionen aufrufen. Von einem rekursiven Funktionsaufruf spricht man, wenn die aufgerufene Funktion gleich der aufrufenden ist.
def printFunc(i):
if (i >= 5):
return
else:
print("Hallo Welt")
printFunc(i+1)
printFunc(1)
Ausgabe:
Hallo Welt
Hallo Welt
Hallo Welt
Hallo Welt
== Funktionsannotationen ==
Python ist sehr flexibel, was Typen angeht. Im Vorhergehenden haben wir generell keine Typangaben gemacht. Will man Typen angeben, so bietet Python das Konzept der Funktionsannotation.
def calcFunc(a: int, b: int) -> int:
return a+b
r1 = calcFunc(8, 9)
r2 = calcFunc(8.0, 9.0)
r3 = calcFunc("Hallo", "Welt")
print(r1)
print(r2)
print(r3)
Ausgabe:
17
17.0
HalloWelt
Jetzt sieht man auf den ersten Blick, welche Typen der Programmierer im Sinn hatte, als er die Funktion erstellte. Das Problem dabei ist nur, dass es Python ziemlich egal ist, welche Typen man im Endeffekt eingibt. Im obigen Beispiel können statt Integer-Typen u.a. auch Float- oder String-Typen eingegeben werden.
<small>
Siehe zum Thema "Type Checking" aber auch den später folgenden Abschnitt [[Ing_Mathematik:_Python#Type_Checker]].
</small>
== Variadische Funktionen ==
Python-Code:
def test1(a, *b):
print(a);
for c in b:
print(c);
test1("Hallo", "Welt", "Schweizer", "und alle anderen")
Ausgabe:
Hallo
Welt
Schweizer
und alle anderen
Mit dem Stern (auch als Splat-Operator bezeichnet) in der formalen Parameterliste bei der Funktion <code>test1</code> wird angezeigt, dass eine beliebige Anzahl von Argumenten übergeben wird. <small> Dies entspricht in etwa dem, was in anderen Programmiersprachen (PHP etc.) mittels Ellipse (<code>...</code>) angezeigt wird.</small>
= Tupel, Listen und andere =
[[Datei:Python 3. The standard type hierarchy.png|mini|hochkant=1.7|Datentypen und Strukturen]]
== Tupel und Listen ==
Tupel, Listen und einige andere sind Datenstrukturen oder Sequenzen.
Listen (z.B. eine Einkaufsliste) sind veränderbar (mutable). Ein Tupel kann dagegen nicht verändert werden (immutable). Listen werden beim Anlegen in eckige Klammern eingeschlossen, Tupel in runde Klammern. Beim Tupel können die Klammern auch weggelassen werden. Ein Tupel mit nur einem Element muss mit einem Beistrich abgeschlossen werden. Der Grund ist, dass Python sonst nicht entscheiden kann, ob ein Tupel angelegt werden soll, oder nur ein geklammerter Wert.
Als Gedächtnisstütze kann man sich den Unterschied zwischen Tupel und Liste ev. so leichter merken:
: T'''u'''pel ... r'''u'''nde Klammern, '''u'''nveränderlich
: L'''i'''ste ... eck'''i'''ge Klammern, veränderl'''i'''ch.
Nachfolgend werden einige Operationen mit Listen und Tupel dargestellt.
# Liste und Tupel
liste = [1, 2, "Hallo"]
tupel = (1, 2, "Hallo")
# Ausgabe von liste und tupel
print(liste)
print(tupel)
# Ausgabe von Einzelelementen
print(liste[1])
print(tupel[2])
# Element an Liste anhängen und einfügen
liste.append(55)
liste.insert(4, "Welt")
print(liste)
# Element aus Liste entfernen
liste.remove(1)
print(liste)
# einige weitere Beispiele
liste2 = [1,]
tupel2 = 1, 2
tupel3 = (1,)
print(liste2)
print(tupel2)
print(tupel3)
Ausgabe:
[1, 2, 'Hallo']
(1, 2, 'Hallo')
2
Hallo
[1, 2, 'Hallo', 55, 'Welt']
[2, 'Hallo', 55, 'Welt']
[1]
(1, 2)
(1,)
Beispiel (eine Liste von Wörtern zu einem einzigen zusammenhängenden Text verbinden):
woerter = ["Hallo", "Welt"]
satz = " ".join(woerter)
print(satz)
Ausgabe:
Hallo Welt
== Dictionaries und Mengen ==
Zu den Datenstrukturen gehören weiters auch Mengen und Dictionaries. Mengen sind von der Mathematik bekannt, sie sind ungeordnet und es kommen keine mehrfachen Elemente vor. Dictionaries sind durch Schlüssel :Wert-Paare gekennzeichnet. Mengen werden beim Anlegen wie Dictionaries in geschweifte Klammern eingeschlossen.
dict = {"vorname":"Hugo", "nachname":"Meister" }
menge = {1, 1, 3, 4, 4, 4, "Hallo"}
print(dict)
print(menge)
print(dict["vorname"])
Ausgabe:
{'vorname': 'Hugo', 'nachname': 'Meister'}
{1, 3, 4, 'Hallo'}
Hugo
Geschweifte Klammern ohne Inhalt stellen Dictionaries dar und keine Mengen:
di = {}
print(type(di))
Ausgabe:
<class 'dict'>
Leere Mengen lassen sich mit <code>set()</code> erzeugen:
menge = set() # leere Menge
print(menge)
menge.add("Hallo") # Element hinzufügen
print(menge)
Ausgabe:
set()
{'Hallo'}
Beispiel (einige Mengenoperationen):
mengeA = {"Hallo", "Welt"}
mengeB = {1, 2, "Welt", 3}
# Vereinigung
print(mengeA | mengeB)
print(mengeA.union(mengeB))
# Durchschnitt
print(mengeA & mengeB)
print(mengeA.intersection(mengeB))
# Differenz
print(mengeA - mengeB)
print(mengeA.difference(mengeB))
# Symmetrische Differenz
print(mengeA ^ mengeB)
print(mengeA.symmetric_difference(mengeB))
# Teilmenge
print(mengeA.issubset(mengeB))
# Mehrere Elemente hinzu
mengeA.update(["Super", 67, 125])
print(mengeA)
# Element löschen
mengeA.discard("Hallo")
print(mengeA)
Ausgabe:
{1, 2, 3, 'Welt', 'Hallo'}
{1, 2, 3, 'Welt', 'Hallo'}
{'Welt'}
{'Welt'}
{'Hallo'}
{'Hallo'}
{1, 2, 3, 'Hallo'}
{1, 2, 3, 'Hallo'}
False
{67, 'Super', 'Welt', 'Hallo', 125}
{67, 'Super', 'Welt', 125}
Es gibt schon seit "ewigen" Zeiten unveränderbare Mengen, die mittels <code>frozenset</code> eingeleitet werden. Neu ab Python 3.15 ist dagegen das Pendant <code>frozendict</code>, das unveränderbare Dictionaries darstellt.
fdict = frozendict({"vorname":"Hugo", "nachname":"Meister"})
fset = frozenset({"A", 1, "A"})
print(fdict)
print(fdict["vorname"])
print (fset)
try:
fdict["vorname"] = "Max"
print(fdict["vorname"])
except TypeError as e:
print(f"Fehler: {e}")
try:
fset.add("B")
print(fset)
except AttributeError as e:
print(f"Fehler: {e}")
Ausgabe:
frozendict({'vorname': 'Hugo', 'nachname': 'Meister'})
Hugo
frozenset({1, 'A'})
Fehler: 'frozendict' object does not support item assignment
Fehler: 'frozenset' object has no attribute 'add'
== List Comprehensions ==
Aus einer Eingabeliste soll eine Ausgabeliste erzeugt werden. Das kann folgendermaßen geschehen.
Mathematische Schreibweise: <math>lc = \{2x|x\in\ \mathbb{N}, 1\le x < 11\}</math>
Python-Code:
lc = [x*2 for x in range(1,11)]
print(lc)
Ausgabe:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Mathematische Schreibweise: <math>lc = \{2x | x \in \mathbb{N}, 1\le x < 11, x \bmod 2 = 0 \}</math>
Python-Code:
lc = [x*2 for x in range(1,11) if x%2 == 0]
print(lc)
Ausgabe:
[4, 8, 12, 16, 20]
Siehe auch {{W|List Comprehension}}.
== Set Comprehensions ==
Dies ist sehr ähnlich wie im vorigen Abschnitt beschrieben. Es wird aber keine Liste, sondern eine Menge erzeugt.
sc = {x*2 for x in range(1,11)}
print(sc)
Ausgabe:
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
== Listen zusammenführen - zip() ==
li1 = ["A", "B", "C", "D"]
li2 = [1, 2, 3, 4]
li3 = [5.5, 6.6, 7.7, 8.8]
z = zip(li1, li2, li3)
print(z)
li4 = list(z)
print(li4)
Ausgabe:
<zip object at 0x00000283B6C6AC80>
[('A', 1, 5.5), ('B', 2, 6.6), ('C', 3, 7.7), ('D', 4, 8.8)]
== Generatorausdruck ==
g = (i*2 for i in range(1,11))
print(g)
t = tuple(g)
print(t)
print(t[1:3])
Ausgabe:
<generator object <genexpr> at 0x00000241D2A4A5A0>
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
(4, 6)
== Slicing ==
slice ... Scheibe, Teil, in Scheiben schneiden
Beispiel: Zugriff auf Elemente eines geordneten sequentiellen Objekttyps (Liste, Tupel oder String):
str1 = "Hallo"
# Das erste Element wird mit dem Index 0 angesprochen
# [start (inkl.) : stop (exkl.) : step (default=1)]
str2 = str1[0:2]
# Alternativ auch: str2 = str1[:2]
print(str2)
tup1 = (0,1,2,3)
# Das letzte Element hat auch den Index -1, das vorletzte den Index -2 usw.
tup2 = tup1[-3:-1]
print(tup2)
lst1 = [[1, 5, 10, 20],
[30, 40, 50, 60]]
lst2 = lst1[1][1]
print(lst2)
Ausgabe:
Ha
(1, 2)
40
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2])
print(x[-3])
print(x)
print(x[:])
print(x[2:])
print(x[:2])
print(x[::-1])
Ausgabe:
c
c
('a', 'b', 'c', 'd', 'e')
('a', 'b', 'c', 'd', 'e')
('c', 'd', 'e')
('a', 'b')
('e', 'd', 'c', 'b', 'a')
Visualisierung:
'''a''' '''b''' '''c''' '''d''' '''e'''
+-----------------------------+
| 0 | 1 |//'''2'''//| 3 | 4 |
+-----------------------------+
| -5 | -4 |/'''-3'''//| -2 | -1 |
+-----------------------------+
|/////////////////////////////|
+-----------------------------+
|/////////////''':'''///////////////|
+-----------------------------+
| | |///////'''2:'''////////|
+-----------------------------+
|////''':2'''/////| | | |
+-----------------------------+
|\\\\\<--\\\\\'''::-1'''\\\\<--\\\\\|
+-----------------------------+
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2::2])
print(x[2::-1])
print(x[2:0:-1])
Ausgabe:
('c', 'e')
('c', 'b', 'a')
('c', 'b')
Hier sieht man sehr schön, dass beim letzen <code>print</code>-Befehl die 0, die in diesem Fall den Buchstaben "a" repräsentiert, als letzer Wert nicht mehr dazugehört (wie weiter oben angedeutet ist der End- oder Stoppwert exklusiv). Will man den Buchstaben "a" dazunehmen, so ist die vorletzte Zeile die richtige.
Beispiel: Umdrehen von Strings
str1 = "Hallo"
str2 = str1[::-1]
print(str2)
Ausgabe:
ollaH
Mit zweidimensionalen Listen/Tupels wird das Ganze schon bedeutend komplexer.
Beispiel: Verkettetes Slicing
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
print(A[2::][::2])
Ausgabe:
[['20', '21', '22', '23'], ['40', '41', '42', '43']]
Das erste Slicing erstellt folgenden Slice:
[["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
Das zweite Slicing wird dann auf diesen Slice angewendet und ergibt das genannte Endergebnis. Will man Spalten statt Zeilen, so funktioniert dieser direkte Weg nicht. Man verwendet dann List Comprehensions oder die NumPy-Bibliothek. Diese Bibliothek erlaubt zweidimensionales Slicing. Sie wird erst später bei den Grafiken eingeführt. Deshalb wird hier dazu noch kein Beispiel gezeigt.
= Objektorientierte Programmierung =
{{Wikipedia|Objektorientierte Programmierung}}
* {{W|Klasse (Objektorientierung)|Klasse}} ... die Schablone oder der Bauplan, enthält Methoden und Attribute
* {{W|Objekt (Programmierung)|Objekt}} ... eine Klasseninstanz (die konkrete Ausprägung der Klasse)
* {{W|Attribut (Programmierung)|Attribute}} ... die Eigenschaften eines Objekts
* {{W|Methode (Programmierung)|Methoden}} ... die Aktionen (Operationen), die ein Objekt ausführen kann
* {{W|Vererbung (Programmierung)|Vererbung}} ... neue Klassen (Subklassen, Unterklassen, abgeleitete Klassen) aus vorhandenen Klassen (Superklassen, Oberklassen, Basisklassen, Elternklassen) ableiten. Ermöglicht den Aufbau von Klassenhierarchien. Die Subklasse "erbt" Attribute und Methoden von der Superklasse. Python unterstützt (so wie C++, aber im Gegensatz zu Java) Mehrfachvererbung.
== UML ==
* {{W|Unified Modeling Language|UML}} ... '''U'''nified '''M'''odeling '''L'''anguage, eine Modellierungssprache. Die UML enthält zahlreiche Diagrammarten, um Programme zu modellieren. Im Nachfolgenden wird nur das {{W|Klassendiagramm}} verwendet.
[[File:UmlCd Klasse-3.svg|300px]]
* {{W|Sichtbarkeit (Programmierung)|Sichtbarkeit}}:
** + ... public (öffentlich)
** - ... private
** # ... protected
* {{W|Attribut_(UML)#Attribute_für_Instanzen_und_für_Klassen|Klassenattribute}} (statische Attribute): Werden nur einmal pro Klasse angelegt. Im Klassendiagramm werden sie unterstrichen.
[[File:Attribute-3.png|200px]]
* Vererbung:
<gallery>
InheritancePgmUML.svg | Abgeleitete Klasse erbt von Basisklasse (Einfachvererbung)
Diamond inheritance.svg | D erbt von B und C (Mehrfachvererbung). B und C erben von A (Einfachvererbung)
</gallery>
Für weitergehende Betrachtungen zur UML wird auf Spezialliteratur verwiesen, z.B.:
* Seidl et al.: UML@Classroom. dpunkt, 2012, ISBN 978-3-89864-776-2
* Rupp et al.: UML 2 glasklar. Hanser, 4. Aufl., 2012, ISBN 978-3-446-43057-0
== Eine einfache Klasse ==
[[Datei:PythonIng_uml1.svg | 200px]]
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
fahr = Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die Klasse Fahrzeug wird durch das class-Schlüsselwort eingeleitet. raeder ist ein Klassenattribut und public. __init__ wird bei der Objekterzeugung automatisch aufgerufen (ist der sogenannte Konstruktor). Man achte darauf, dass diese Methode immer mit zwei Unterstrichen eingeleitet und abgeschlossen wird. Instanzattributen wird das Wort self vorangestellt. Wir sehen uns z.B. das Attribut self.__geschwind an. Auch hier werden zwei Unterstriche verwendet. Das bedeutet, dass dieses Attribut strikt/stark private ist. Wird nur ein Unterstrich verwendet, so deutet dies auf schwach/weakly private hin. Letzteres wird in Python deutlich häufiger verwendet. Bei den Methoden wird immer self als erster Parameter angegeben. Beim Aufruf der entsprechenden Funktion wird das self aber nicht berücksichtigt.
Besonderheiten bei stark und schwach private:
* '''stark private''':
** zwei führende Unterstriche
** Name Mangling: Name wird zu <code>_Klassenname__variablenname</code>
** Schutz vor Namenskollisionen bei Vererbung
** am Ende des Namens dürfen keine zwei Unterstriche verwendet werden. Das wären dann Magic Methods oder Dunder-Methods (z.B. __init__). Diese sind public.
* '''schwach private''':
** ein führender Unterstrich
** Name bleibt gleich
** ist nur ein Hinweis an die Programmierer, kein starker Schutz
** <code>from modul import *</code>: Objekte mit einem führenden Unterstrich werden standardmäßig nicht importiert
** Standard für die Kapselung bei Python. Schätzung: Weit mehr als 80% der nicht-öffentlichen Attribute/Methoden werden als schwach private deklariert. Weniger als 5-10% als stark private (Quelle: Google KI)
== Klassen importieren ==
Häufig ist es sinnvoll und übersichtlicher Klassen in eigenen Dateien zu speichern. Das sind dann eigene Module. Abgespeichert werden Sie mit der Endung py, wie bisher auch praktiziert. Aufgerufen werden Sie mit der import-Anweisung. Dann ist aber nur der Dateiname ohne Endung py zu verwenden. Klarer wird das mit einem Beispiel.
Datei c:\tmp\fahrzeug.py
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
Datei c:\tmp\test1.py
import fahrzeug
fahr = fahrzeug.Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die üblichen import-Anweisungen lauten wie folgt:
{| {{prettytable}}
! import-Befehl
! Instanz
|-
| import xyz || xyz.Klasse
|-
| import xyz as x || x.Klasse
|-
| from xyz import Klasse || Klasse
|-
| from xyz import * || Klasse
|}
Der Vorteil der ersten beiden import-Anweisungen ist, dass es kaum zu Namenskollisionen kommen kann. Dafür hat man bei den letzten beiden Varianten weniger Tipparbeit.
== Vererbung ==
=== Einfachvererbung ===
[[Datei:PythonIng_uml2.svg | 200px]]
Datei fahrzeug.py:
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
class Luftfahrzeug(Fahrzeug):
def __init__(self, geschwindigkeit, leistung, fluegel):
super().__init__(geschwindigkeit, leistung)
self.__flueg = fluegel
def getFlueg(self):
return self.__flueg
Datei test1.py:
import fahrzeug
fahr = fahrzeug.Luftfahrzeug(150, 90, 4)
print(fahr.getFlueg())
Ausgabe:
4
=== Mehrfachvererbung ===
Mit Python ist auch Mehrfachvererbung möglich, z.B.:
class A:
def _printA(self):
print("Klasse A")
class B:
def _printB(self):
print("Klasse B")
class C(A,B):
def __init__(self):
self._printA()
self._printB()
c = C()
Ausgabe:
Klasse A
Klasse B
Die Klasse C erbt von A und B. In UML sieht das in etwa so aus:
+-----------------------------+ +-------------------------+
| A | | B |
+-----------------------------+ +-------------------------+
| | | |
+-----------------------------+ +-------------------------+
| # printA() | | # printB() |
+-----------------------------+ +-------------------------+
. .
/ \ / \
--- ---
| |
| |
+---------------------+
| C |
+---------------------+
| |
+---------------------+
| |
+---------------------+
<code>printA()</code> und <code>printB()</code> sind schwach private (in UML als <code>protected</code> mit einem # dargestellt). Es ist aber zu beachten, dass schwach private nur Konvention ist. Praktisch könnte man auch von außerhalb auf diese Methoden zugreifen. Das soll man aber nicht tun, und das wird in Python durch einen Unterstrich angedeutet.
= Grafiken zeichnen =
Für das Zeichnen von Grafiken wird hier das Modul <code>matplotlib</code> verwendet. <code>matplotlib</code> ist ein externes Modul und muss vor der ersten Verwendung installiert werden. Das geht so:
# Starten Sie ein Terminal (bei Windows die Eingabeaufforderung).
# Führen Sie darin folgenden Befehl aus <code>c:\devel\Python\Scripts\pip.exe install matplotlib</code>
pip ist übrigens der Paketmanager von Python ({{W|Pip_(Python)}}).
Optimalerweise installieren wir auch gleich das Modul <code>numpy</code> (Numerical Python). Wir werden es im Folgenden oft benötigen (nicht nur bei den Grafiken). Das funktioniert vom Prinzip her genauso, wie für <code>matplotlib</code> gezeigt.
<small>Verwenden Sie Spyder, so sind diese Schritte nicht nötig. Spyder inkludiert diese Pakete standardmäßig. Unter openSUSE Tumbleweed lassen sich diese Pakete mittels YaST oder zypper installieren.</small>
== 2D ==
=== Graph einer Funktion ===
Es soll die cosh-Funktion im Intervall <math>x\in[-3,3]</math> gezeichnet werden. Der Programmcode lautet in der einfachsten Form:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x)
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh1.jpg]]
Der Code ist quasi selbsterklärend. Das Untermodul pyplot des matplotlib-Moduls und das numpy-Modul werden importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plt.plot()" ist der Zeichenbefehl. "plt.show" ist notwendig, um das Fenster mit der Grafik anzuzeigen.
Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen. "plt.grid()" zeichnet ein Gitter in die Grafik (kann auch weggelassen werden).
Die Bezeichnungen plt und np könnten auch anders gewählt werden. Es ist aber Konvention, diese so wie hier gezeigt zu wählen. Die "arange"-Funktion aus der NumPy-Bibliothek wird später ein bisschen genauer behandelt (siehe [[Ing_Mathematik:_Python#Zahlenfolgen|Zahlenfolgen]]).
<small>Mit der im obigen Bild gezeigten Menüleiste kann die dargestellte Grafik nachträglich noch geändert werden (Zoom, Pan, Achsenparameter, Kurvenparameter etc.). Natürlich kann man das alles auch direkt programmieren. Wie das funktioniert wird ansatzweise etwas später gezeigt.</small>
Ein etwas komplexeres Beispiel ist Folgendes:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x) + 2**x
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh4.png]]
Man beachte, dass im Gegensatz zu Octave und Julia der ominöse Punkt (.) bei 2**x mit Python nicht benötigt wird. Das macht das Programmiererleben etwas einfacher.
Die Farbe des Graphen kann man über den <code>color</code>-Schalter einstellen, z.B. auf rot setzen:
plt.plot(x, y, color="red")
Das ist nur eine Möglichkeit, es gibt auch andere, z.B. mittels
* hexadezimaler Zahl, z.B. <code>color="#ff0000"</code>
* Kurzform, z.B. <code>"r"</code>
Statt <code>color</code> kann auch die Kurzform <code>c</code> verwendet werden.
<u>Kleine Aufgabe:</u> Probieren Sie diese "Farbspielereien" am Computer aus.
=== Graphen mehrerer Funktionen und weiteres ===
==== Mehrere Funktionen in einen Plot zeichnen ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x")
plt.plot(x, y2, label = "sin(x) * cos(x)")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh2.png]]
Um die Linienstile etwas individueller zu gestalten, ist folgender Programmcode gedacht:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
plt.plot(x, y2, label = "sin(x) * cos(x)", lw=3, ls="--")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh3.png]]
Einige weitere Bespiele zu <code>ls</code></code>:
* - ... durchgezogene Linie
* -. ... Strichpunkt-Linie
* dashed ... gestrichelte Linie
==== Marker ====
Desweiteren kann man Marker verwenden.
Beispiel:
import matplotlib.pyplot as plt
plt.plot(10, 10, "ob", markersize=30)
plt.plot(20,20, ".r")
plt.plot(30,30, "Dg", ms=15)
plt.plot(40, 40, "ok", ms=20, mec="#FF5733", mew=3)
plt.plot(50, 50, "vk", ms=20, mec="yellow", mew=3)
plt.grid()
plt.show()
Das erste Zeichen im String nach den Koordinaten im plot-Befehl symbolisiert die Form (z.B. o für einen Kreis). Das zweite Zeichen steht für die Farbe (z.B. b für blue). <code>markersize</code> oder <code>ms</code> setzt die Größe des Markers.
Ausgabe:
[[Bild:PythonIng_formatpara1.svg|200px]]
Einige weitere Marker:
* * ... Stern
* + ... Plus
* h oder H ... Sechseck
Man kann mit den Parametern
* <code>markeredgecolor</code> oder kurz <code>mec</code> die Farbe des Markerrandes
* <code>markeredgewidth</code> oder kurz <code>mew</code> die Dicke des Randes
* <code>markerfacecolor</code> oder kurz <code>mfc</code> die Innenfarbe des Markers
bestimmen.
=== Funktion in Parameterdarstellung ===
Es soll die archimedische Spirale <math>x = t \cos(t), y = t \sin(t)</math> im Intervall <math>[0, 6\pi[</math> gezeichnet werden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.show()
[[Datei:PythonIng_spirale1.png]]
Diese Darstellung erscheint verzerrt. Will man gleiche Achsenskalierungen, so kann man den plt.axis()-Befehl verwenden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.axis("equal")
plt.show()
[[Datei:PythonIng_spirale2.png]]
=== Funktion in Polardarstellung ===
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
r = np.arange(0, 1, 0.01)
theta = r**3
line = ax.plot(theta, r)
plt.show()
[[Datei:PythonIng_polar1.png]]
=== Logarithmische Achsenskalierung ===
==== Semilog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.semilogy()
plt.show()
Ausgabe:
[[Datei:PythonIng_semilog1.png]]
==== LogLog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.loglog()
plt.show()
[[Datei:PythonIng_loglog1.png]]
=== Gefüllte Fläche ===
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 3, 0.1)
y1 = 3*x - 1
y2 = x**2
plt.plot(x, y1, x, y2, color='black')
plt.fill_between(x, y1, y2, where=y1>=y2)
plt.show()
[[Datei:PythonIng_gefuellt.png]]
=== Linien, Pfeile, Rechtecke, Kreise und Texte ===
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
r = mpl.patches.Rectangle((0, 0), 3, 3, angle=30, fill=False)
c = mpl.patches.Circle((4, 4), 2, fill=False)
ax.add_patch(r)
ax.add_patch(c)
ax.plot([-2, 7], [-2, 0], color="black")
ax.arrow(0, 7, 5, 0, length_includes_head=True, head_width=0.5, head_length=1.5,
color="black")
ax.set_aspect("equal")
plt.axis([-3, 8, -3, 8])
plt.show()
[[Datei:PythonIng_linien_pfeile_etc.png]]
Text kann mit <code>ax.text(x, y, "Text")</code> hinzugefügt werden, bspw.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
ax.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
Oder einfacher auch ohne <code>subplots</code>
import matplotlib.pyplot as plt
plt.text(0.1, 0.1, "Hallo")
plt.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text1.png]]
Auch Sonderzeichen (griechische Buchstaben etc.) können verwendet werden (siehe dazu auch [https://matplotlib.org/stable/users/explain/text/mathtext.html]).
import matplotlib.pyplot as plt
plt.text(.3, .5,
r'$\Omega\ \psi\ \oint\ \nabla\ \dot a\ \frac{a}{b}\ a_b$',
size="20")
plt.show()
[[Datei:PythonIng_text20.svg]]
Jetzt wird noch gezeigt, wofür <code>subplots</code> sinnvoll eingesetzt werden können.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(0.1, 0.1, "Hallo")
ax[1].text(0.1, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text2.png]]
=== Anmerkungen hinzufügen ===
Anmerkungen (engl. annotations) lassen sich mit matplotlib einfach hinzufügen. Unter Anmerkung wird hier ein Pfeil mit Text verstanden.
Beispiel:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1,10], [1,10])
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0))
plt.show()
Ausgabe:
[[Datei: PythonIng_ann1.svg|400px]]
<code>shrink</code> verkürzt den Pfeil. Sinnvoll sind beim obigen Beispiel Werte irgendwo zwischen 0.0 und 0.3.
<u>Kleine Aufgabe:</u> Probieren Sie verschiedene Pfeillängen aus.
Die Schriftgröße verändern können Sie übrigens mit <code>fontsize</code> oder <code>size</code>, z.B.
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0), fontsize=25)
Eine andere Schreibweise für Dictionaries, die wir weiter oben schon kennengelernt haben, die wir aber nochmals explizit aufschreiben wollen, ist
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops={"facecolor":"red", "shrink":0.0})
=== Figure, Axes etc.===
[[Bild:PythonIng_figure33.svg|350px]]
* fig (figure) ... das übergeordnete Fenster
* ax (axes) ... "Plot", das eigentliche Zeichenfenster
* axis ... die Koordinatenachsen
* spine ... Begrenzungslinien des Zeichenfensters
* tick ... Markierung an den Achsen des Zeichenfensters
Beispiel (eine figure mit 6 axes, ax-Titel, y-axis-Titel):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=3, ncols=2)
ax[0][0].text(0.1, 0.5, "11")
ax[0][1].text(0.1, 0.5, "12")
ax[1][0].text(0.1, 0.5, "21")
ax[1][1].text(0.1, 0.5, "22")
ax[2][0].text(0.1, 0.5, "31")
ax[2][1].text(0.1, 0.5, "32")
ax[0][0].set(ylabel="y-label", title="axes 1")
plt.show()
[[Bild:PythonIng_figure34.png|350px]]
Beispiel (Achsenbereiche setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-1, 10, 1, 12))
plt.show()
[[Bild:PythonIng_figure35.svg|350px]]
Beispiel (Gitter einschalten):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-5, 10, 1, 12))
ax[0].minorticks_on()
ax[0].grid(which='minor')
ax[1].grid(which='major')
plt.show()
[[Bild:PythonIng_figure36.svg|350px]]
Beispiel (ticks setzen)
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
pos = [0, .2, .5]
lab = ["a", "b", "c"]
ax.xaxis.set_major_locator(tick.FixedLocator(pos))
ax.xaxis.set_major_formatter(tick.FixedFormatter(lab))
plt.show()
[[Bild:PythonIng_figure37.svg|350px]]
Beispiel (Achsenkreuz beliebig setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position(('data', 0.3))
ax.spines['left'].set_position(('data', 0.5))
plt.show()
[[Bild:PythonIng_figure38.svg|350px]]
Beispiel (Inset):
import matplotlib.pyplot as plt
# Hauptplot erstellen
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
# Inset hinzu:
axin = ax.inset_axes([0.4, 0.4, 0.3, 0.3])
axin.text(0, 0, "Servus")
axin.plot()
plt.show()
[[Bild:PythonIng_figure40.svg|350px]]
Beispiel (Hintergrundfarben setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_facecolor("green")
fig.set_facecolor("yellow")
plt.plot([1, 3], [6, 8])
plt.show()
[[Bild:PythonIng_figure39.svg|300px]]
=== GridSpec ===
Mit figures und axes lassen sich schon jede Menge an Grafikdetails einstellen. GridSpec ist dann der Turbo oder Raketenantrieb den matplotlib eingebaut hat. Naja, vielleicht ist das etwas übertrieben, aber GridSpec ist sozusagen ein flexibler Layout-Manager. Bisher haben wir immer gleich große axes gezeichnet. Mit GridSpec können wir Subplots über mehrere Zeilen und Spalten ziehen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(3, 3)
ax1 = fig.add_subplot(gs[0, :])
ax1.set_title("Bereich 1: gs[0, :]")
ax2 = fig.add_subplot(gs[1:, 0])
ax2.set_title("Bereich 2: gs[1:, 0]")
ax3 = fig.add_subplot(gs[1, 1:])
ax3.set_title("Bereich 3: gs[1, 1:]")
ax4 = fig.add_subplot(gs[2, 1:])
ax4.set_title("Bereich 4: gs[2, 1:]")
plt.show()
[[Bild:PythonIng_gridspec1.svg|350px]]
Erklärung zu <code>(gs[zeile, spalte])</code>: Slicing; damit legen Sie fest, welche Zellen ein Subplot belegt. Achtung! Die Indizes beginnen bei 0 und nicht bei 1 (d.h., die erste Zeile/Spalte hat den Index 0)
* : ... alle
* 1: ... 1 bis Ende
* etc.
<code>constrained_layout=True</code> sorgt dafür, dass sich die Subplots nicht überlappen.
Aber auch die Spaltenbreiten und Zeilenhöhen lassen sich anpassen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
# Verhältnis erste zu zweite Zeile = 1.5:1
# Verhältnis erste zu zweite Spalte = 1:4
gs = fig.add_gridspec(2, 2, figure=fig, height_ratios=[1.5, 1], width_ratios=[1, 4])
ax1 = fig.add_subplot(gs[0, 0])
ax1.set_title("Bereich 1: gs[0, 0]")
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_title("Bereich 2: gs[0, 0]")
ax3 = fig.add_subplot(gs[1, 0])
ax3.set_title("Bereich 3: gs[1, 0]")
ax4 = fig.add_subplot(gs[1, 1:])
ax4.set_title("Bereich 4: gs[1, 1]")
plt.show()
[[Bild:PythonIng_gridspec2.svg|350px]]
Auch die Ränder lassen sich einstellen.
Beispiel 1:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.1, right=0.9, bottom=0.1,
top=0.9, wspace=0.2, hspace=0.2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec3.svg|300px]]
* hspace ... height space, vertikaler Abstand zwischen den Zeilen
* wspace ... width space, horizontaler Abstand zwischen den Spalten
Und im Vergleich dazu Beispiel 2:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.3, right=0.7, bottom=0.3,
top=0.7, wspace=0.3, hspace=0.3)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec4.svg|300px]]
Es gibt noch einige weitere Details, die sich mit GridSpec variieren lassen (z.B. SubGridSpec ... verschachtelte Grid-Layouts). Aber wir belassen es vorerst dabei. Das bisher Gezeigte sollte für die meisten Probleme ausreichend sein.
=== Aufgaben ===
* Zeichnen Sie die Strophoide <math>x = \frac{a(t^2-1)}{t^2+1}, y = \frac{at(t^2-1)}{t^2+1}, a = 2, -3 \leq t \leq 3</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_strophoide.jpg|300px|center]]
* Zeichnen Sie die verschlungene Hypozykloide <math>x = (R-r)\cos t + c\cos\frac{R-r}{r}t, y = (R-r)\sin t - c\sin\frac{R-r}{r}t, c = 3, r = 2, R = 6, -15 \leq t \leq 15</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_hypozykloide.jpg|300px|center]]
* Testen Sie bei den obigen Übungsaufgaben verschiedene Linienstile und Farben. Farben können mit dem plt.plot()-Parameter color gewählt werden.
* Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.
* Zeichnen Sie folgendes Bild (die Achsenbeschriftungen positionieren Sie z.B. mit den Befehlen <code>ax.set_xlabel("x", loc="right"); ax.set_ylabel("y", loc="top")</code>):
[[Bild:PythonIng_aufgabe24.svg|400px|center]]
* Zeichnen Sie mit Python, matplotlib und NumPy folgendes Bild:
[[Bild:PythonIng_figure41.svg|400px|center]]
* Zeichnen Sie mit GridSpec ein Layout, das in etwa wie folgendes aussieht (<code>height_ratios=[1, 2], width_ratios=[2, 1]</code>):
[[Bild:PythonIng_aufgabe23.svg|300px|center]]
== 3D ==
=== Räumliche Kurven ===
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0, 6*np.pi, 0.1)
x = t * np.cos(t)
y = t * np.sin(t)
z = t
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot(x, y, z)
plt.show()
[[Datei:PythonIng_raumkurve1.png]]
=== Flächen ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z)
plt.show()
[[Datei:PythonIng_fläche1.png]]
Das Ganze in Netzdarstellung läßt sich so programmieren:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = np.arange(0, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_wireframe(x, y, z)
plt.show()
[[Datei:PythonIng_fläche2.png]]
Ein etwas komplexeres Beispiel:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.1, 10, 0.1)
y = np.arange(0.1, 10, 0.1)
x, y = np.meshgrid(x, y)
z1 = np.sin(x) + 3 * np.cos(y)
z2 = np.sin(x) + np.log(y)
z3 = x + np.cos(y)
z4 = x**2 - y
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, nrows=2, ncols=2)
ax[0][0].plot_surface(x, y, z1)
ax[0][1].plot_surface(x, y, z2)
ax[1][0].plot_surface(x, y, z3)
ax[1][1].plot_surface(x, y, z4)
plt.show()
[[Datei:PythonIng_subplot1.png]]
Man beachte, dass man die Unterbilder im Bild nach dem Ausführen des Scripts z.B. mit der mittleren Maustaste einzeln drehen, oder über die Einträge in der Menüzeile einzeln bearbeiten kann. Mit ein paar Zeilen Programmtext lässt sich also eine Menge an Funktionalität generieren.
Die Farbgebung lässt sich über <code>colormaps</code> variieren.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm)
plt.show()
[[Datei:PythonIng_colormap1.png]]
Es gibt eine Menge an Colormaps, z.B. <code>plasma, Greys, Dark2, ocean</code>. Zwecks detaillierterer Infos siehe die matplotlib-Dokumentation. <small>Verwendet man die IDE namens IDLE, so gibt es dort auch die automatische Codevervollständigung. D.h. es werden alle Möglichkeiten (in unserem Fall nach dem Eintippen von <code>cm.</code> alle verfügbaren Colormaps) angezeigt.</small>
Die "edgecolor" und Linienbreite können auch frei gewählt werden:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm, edgecolor="black", linewidth=1.0)
plt.show()
[[Datei:PythonIng_colormap2.png]]
=== Höhenlinien ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
ax.contour(x, y, z)
plt.show()
[[Datei:PythonIng_höhenlinien1.png|400px]]
Etwas abgewandelt sieht das so aus:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contour(x, y, z)
ax.clabel(hl, inline = True)
plt.show()
[[Datei:PythonIng_höhenlinien2.png|400px]]
Und noch eine Variante (mit einem Farbbalken) sei gezeigt.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contourf(x, y, z)
fig.colorbar(hl)
plt.show()
[[Datei:PythonIng_höhenlinien5.svg|400px]]
=== Aufgaben ===
* Zeichnen Sie die räumliche Kurve <math>x = 2 \cdot \cosh(t)</math>, <math>y = 5 \cdot \sin(t)</math>, <math> z = t^{2} - t</math>, <math>0 \leq t \leq 3\pi</math>.
* Zeichnen Sie die Fläche <math>z = \log(x) + \cos(y)</math>.
== Animationen und fortgeschrittenes 3D ==
=== Mit matplotlib ===
Auch mit matplotlib sind Animationen möglich. Das ist ein bisschen komplizierter und wird deshalb hier nur mit einem sehr einfachen Beispiel dargestellt (bei Interesse siehe z.B. auch das [https://matplotlib.org/stable/users/explain/animations/animations.html#animations Animations using Matplotlib-Tutorial]).
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib
import numpy as np
def update(frame):
line.set_xdata(x[:frame])
line.set_ydata(y[:frame])
return (line)
fig, ax = plt.subplots()
x = np.arange(0, 10, .1)
y = np.sin(x)
line, = ax.plot(x[0], y[0])
ax.set(xlim=[0, 10], ylim=[-1, 1])
a = ani.FuncAnimation(fig=fig, func=update, frames=100, interval=20)
plt.show()
# Speichere die Animation in einem animierten GIF (optional)
a.save(filename="c:/tmp/PythonIng_anim5.gif", writer="pillow")
[[Datei:PythonIng_anim5.gif]]
Es wird eine Sinuskurve auf den Bildschirm gezeichnet. In der letzten Zeile wird diese Animation in ein animiertes GIF gespeichert. Das ist natürlich optional und kann auch weggelassen werden.
=== Mit VPython ===
Aber auch mit dem Modul VPython lassen sich einfache 3D-Animationen erstellen. VPython ist ein externes Modul, das vorab installiert werden muss. Unter openSUSE Tumbleweed gibt es dzt. kein entsprechendes rpm-Paket. Die übliche Methode der Installation mittels YaST oder zypper ist somit nicht möglich. Auch eine direkte Verwendung von pip führt nur zu einer Fehlermeldung (<code>error: externally-managed-environment</code>). Es empfiehlt sich dort folgende Vorgehensweise:
# Erstelle zuerst eine virtuelle Umgebung, z.B.: <code>python3.11 -m venv ~/tmp/venv1</code>
# Wechsle das Verzeichnis: <code>cd ~/tmp/venv1/bin</code>
# Installiere das entsprechende Paket: <code>./pip install vpython</code>
# Führe das entsprechende Skript aus: <code>./python ~/tmp/test1.py</code>
Aktuell (März 2026) ist dieses Programmpaket lt. der [https://vpython.org/presentation2018/install.html VPython-Homepage] nur für die Python-Versionen 3.8 bis 3.12 verfügbar.
Ein Beispiel zu einer einfachen Animation wird nachfolgend geliefert.
from vpython import *
scene.width = 1200
scene.height = 600
scene.center = vector(20,0,0)
scene.background = color.white
cylinder(pos=vector(0,0,0), axis=vector(20,0,0), radius=5,
color=color.blue)
cone(pos=vector(0,0,0), axis=vector(-10,0,0), radius=5,
color=color.blue)
helix(pos=vector(20,0,0), axis=vector(40,0,0), radius=2,
coils=10, thickness=0.5, color=color.blue)
ball = sphere(pos=vector(20,0,0), color = color.green, radius = 1)
ball.p = vector(0.15, 0, 0)
toc = True
while True:
rate(200)
if(ball.pos.x <= 60 and toc == True):
ball.pos += ball.p
else:
toc = False
ball.pos -= ball.p
if(ball.pos.x <= 20 and toc == False):
toc = True
[[Datei:PythonIng_vpython_anim.JPG]]
Idealerweise öffnet sich beim Ausführen des Scripts ein Browserfenster. Darin wird die programmierte Animation gezeigt (siehe auch den obigen Screenshot). Eine Größenänderung können Sie mit der mittleren Maustaste initiieren. Die Szenerie drehen können Sie mit der rechten Maustaste.
=== Mit build123d ===
Hiermit lassen sich einfach 3D-Modelle für CAD-Systeme erstellen. [https://build123d.readthedocs.io/en/latest/ build123d] ist ein externes Modul und muss vorab, wie schon für mehrere andere Module gezeigt, installiert werden (pip, venv etc.).
Beispielcode:
from build123d import *
# Bauteil
with BuildPart() as bauteil:
# Zylinder erstellen
Cylinder(100, 60)
# Bohrung
with BuildSketch(bauteil.faces().sort_by(Axis.Z)[-1]) as loch:
Circle(radius=10)
# negativ extrudieren
extrude(amount=-60, mode=Mode.SUBTRACT)
# Dem Bauteil z.B. die Farbe rot zuweisen
# bauteil.part.color = Color("red", alpha=1.0)
# Fertiges Modell exportieren
export_step(bauteil.part, "bauteil.step")
Ausgabe ({{W|Standard for the exchange of product model data | STEP}}-Datei, z.B. in {{W|FreeCAD}} importiert, Screenshot):
[[Datei:PythonIng_build123d.jpg | 300px]]
FreeCAD ist ein freies 3D-CAD-System. Die [[Ing_Mathematik:_Python#FreeCAD | Makroprogrammierung]] in diesem System wird später noch gezeigt. STEP steht für "'''St'''andard for the '''e'''xchange of '''p'''roduct model data" und ist ein Datenaustauschformat.
=== Mit VTK ===
Komplexer, aber auch mächtiger als VPython ist die Verwendung von VTK ('''V'''isualization '''T'''ool'''k'''it). Genauer gesagt des Python-Wrappers von VTK. Dieses externe Python-Modul muss vorab installiert werden (z.B. mittels YaST, pip oder in eine virtuelle Umgebung). VTK ist eine Softwarebibliothek zur 3D-Visualisierung und wurde ursprünglich in C++ geschrieben. Verbreitet eingesetzt wird diese Bibliothek in der Wissenschaft und Forschung, z.B.
* in der medizinischen Bildgebung
* für Strömungssimulationen
* für Klimadaten
VTK funktioniert nach dem {{W|Grafikpipeline|Pipeline-Prinzip}}:
Source (Quellen) -> Filter -> Mapper (Senken) -> Actor/Renderer
Daten fließen von den Quellen zu den Senken.
Als einfaches Beispiel wird die Darstellung eines Zylinders gezeigt, der mit den Maustasten gedreht oder in der Größe geändert werden kann:
import vtk
# Zylinder erzeugen
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
# Geometrie in darstellbare Daten umwandeln
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
# Objekt in der Szene
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Szene verwalten
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# Render-Fenster
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
# Maus/Tastatur-Steuerung
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Starten
render_window.Render()
interactor.Start()
Ausgabe:
[[Datei:PythonIng_VTK_1.png]]
Gleiches Beispiel wie oben, aber mit einer Animationssequenz:
import vtk
import time
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
render_window.Render()
time.sleep(0.01)
Das Grafikfenster schließt sich nach Ablauf der Schleife. Das Fenster bleibt geöffnet, wenn Sie am Programmende folgenden Befehl hinschreiben
interactor.Start()
Um den animierten Zylinder grün einzufärben, müssen Sie Folgendes im obigen Programm ergänzen (Farbnamen):
colors = vtk.vtkNamedColors()
actor.GetProperty().SetColor(colors.GetColor3d("Green"))
Als Namen können Sie u.a. die CSS3 Web-Farben verwenden (siehe z.B. [https://wiki.selfhtml.org/wiki/Farbe/Farbangaben] und {{W|Webfarbe#CSS_3}}).
Alternativ funktioniert auch das ({{W|RGB-Farbraum|RGB}}):
actor.GetProperty().SetColor(0.0, 0.6, 0.0)
Wie der Zylinder mit einer Textur versehen wird, zeigt folgendes Programm:
import vtk
import time
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(30)
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.CappingOn()
texture_coords = vtk.vtkTextureMapToCylinder()
texture_coords.SetInputConnection(cylinder.GetOutputPort())
texture_coords.PreventSeamOn()
reader = vtk.vtkJPEGReader()
reader.SetFileName("PythonIng_textur.jpg")
texture = vtk.vtkTexture()
texture.SetInputConnection(reader.GetOutputPort())
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(texture_coords.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.SetTexture(texture)
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
renderWindow.Render()
time.sleep(0.01)
interactor.Start()
<gallery>
PythonIng_textur.jpg | Textur-Datei
PythonIng_VTK_2.png | Ausgabe (Screenshot)
</gallery>
== Sonstige Grafikbibliotheken ==
=== Py5 ===
Im Buch ''Iacono et al.: Programmieren trainieren, mit über 150 Workouts in Java und Python; 3. Aufl., Hanser, 2023'' werden zahlreiche Aufgaben gestellt, die u.a. mit Processing zu lösen sind. Processing ist eine einfache Programmiersprache und Entwicklungsumgebung. Warum ich das erwähne? Weil in älteren Processing-Versionen auch die Programmiersprache Python 2 abgedeckt war. Bei neueren Versionen gibt es keine Python-Anbindung mehr (getestet nur mit openSUSE Tumbleweed und Python 3). Somit funktioniert der Python-Teil im genannten Buch zum Teil nicht mehr. Ist das tragisch, oder kann das Buch weggeschmissen werden? Nein! Es gibt Alternativen zu Processing. Zum einen die im Buch selbst genannten Bibliotheken tkinter oder pygame. Pygame wird dort auch kurz anhand eines Beispiels thematisiert. Aber noch besser ist es, die py5-Bibliothek zu verwenden (lt. Google KI vom 30. Sept. 2026: ''Der echte, moderne „spirituelle Nachfolger“''). Damit ist die Funktionalität von Processing gewährleistet. Man kann aber beliebige Editoren oder IDEs zur Programmerstellung verwenden, ohne an Processing als IDE gebunden zu sein. Nachfolgend werden ein paar Beispiele zu dieser externen Bibliothek gegeben. Der erste Schritt ist wieder, die py5-Bibliothek zu installieren (z.B. mittels pip in eine virtuelle Umgebung; Python>=3.10 und ein JDK>=17 müssen auch installiert sein (Stand Okt. 2026)). Dann kann es schon mit dem Programmieren losgehen.
Beispiel (angelehnt an die ''Aufgabe W.2.3 Haus'' des genannten Buchs, jedoch etwas erweitert):
import py5
def setup():
py5.size(600, 600) # Fenstergröße 600px x 600px
py5.background(255, 255, 255) # Hintergrundfarbe ... weiss
def draw():
# Haus zeichnen
py5.fill(255, 255, 255) # Hintergrundfarbe ... weiss
py5.stroke(255, 0, 0) # Linienfarbe ... rot
py5.stroke_weight(3) # Linienbreite ... 3px
py5.rect(150, 200, 300, 300) # Rechteck zeichnen (x, y, b, h)
py5.triangle(150, 200, 300, 100, 450, 200) # Dreieck zeichnen
py5.circle(250, 300, 70) # Kreis zeichnen (x, y, d)
# Bemassung zeichnen
py5.stroke(0, 255, 0)
py5.stroke_weight(1)
py5.line(300, 100, 550, 100) # Linie zeichnen
py5.line(450, 200, 550, 200)
py5.line(450, 500, 550, 500)
py5.line(150, 500, 150, 550)
py5.line(450, 500, 450, 550)
py5.text_size(20) # Textgroesse
py5.fill(0, 255, 0) # Textfarbe
py5.text("300", 280, 550) # Text zeichnen
py5.text("100", 500, 150)
py5.text("300", 500, 350)
# Gedrehtes Rechteck zeichnen
py5.stroke(255, 255, 0)
py5.stroke_weight(3)
py5.fill(200, 200, 200)
py5.translate(320, 260)
py5.rotate(0.3) # Drehung (in Radiant)
py5.rect(0, 0, 100, 50)
# Startet den Sketch
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_1.png|300px]]
Das skizzierte Haus ist mit einer rudimentären Bemaßung versehen und hat zwei Fenster, ein rundes und ein gedrehtes, trübes rechteckiges.
Beispiel (Mausoperationen):
import py5
def setup():
py5.size(600, 600)
py5.background(255, 255, 255)
def draw():
pass
def mouse_pressed():
py5.text_size(15)
py5.fill(0, 0, 255)
x = py5.mouse_x
y = py5.mouse_y
py5.text("(%d, %d)" %(x, y), x, y) # Positionsdaten bei Maus-Klick schreiben
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_2.png|300px]]
Obiges Bild zeigt das Resultat nach einigen Mausklicks. Man erkennt, dass links-oben der Koordinatennullpunkt ist. Die x-Achse zeigt nach rechts, die y-Achse nach unten.
Beispiel (Fünfeck):
import py5
import random
def setup():
py5.size(400, 400)
py5.no_loop() # statisches Bild (schont die Ressourcen)
def draw():
py5.translate(py5.width / 2, py5.height / 2) # KS setzen
radius = 150
eck_anzahl = 5
py5.fill(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255)) # Füllfarbe auf Zufallswert setzen
py5.stroke(155, 0, 0)
py5.stroke_weight(5)
# Fünfeck als Polygon zeichnen
py5.begin_shape()
for i in range(eck_anzahl):
winkel = i * py5.TWO_PI / eck_anzahl - py5.HALF_PI
x = py5.cos(winkel) * radius
y = py5.sin(winkel) * radius
py5.vertex(x, y)
py5.end_shape(py5.CLOSE)
py5.run_sketch()
Ausgabe, bspw.:
[[Datei:PythonIng_py5_5.png|200px]]
<u>Kleine Aufgaben:</u>
* Um die Funktionsweise von <code>py5.no_loop()</code> zu verstehen, kommentieren Sie die Anweisung im Beispiel einfach aus, und starten Sie das Programm erneut.
* Zeichnen Sie ein Siebeneck.
* Was passiert, wenn man <code>py5.CLOSE</code> im <code>py5.end_shape()</code>-Befehl weglässt?
Beispiel (Grafik laden und zeichnen):
import py5
image1 = None
def setup():
global image1
py5.size(600, 600)
py5.no_loop()
image1 = py5.load_image("PythonIng_py5_1.png")
def draw():
py5.image(image1, 0, 0)
py5.run_sketch()
Hier wird einfach das Bild vom Haus-Beispiel (Screenshot von weiter oben) geladen und gezeichnet.
Beispiel (angelehnt an ''W.5.10 Wurfparabel'' des genannten Buches; mit OOP erstellt):
import py5
class Wurfparabel(py5.Sketch):
def __init__(self, v0, angle):
super().__init__()
self.v0 = v0
self.angle = self.radians(angle)
self.g = 9.81
self.t = 0.0
self.scale = 1.5
def settings(self):
self.size(800, 600)
def setup(self):
self.background(0, 0, 0)
def draw(self):
self.t += 0.1
self.translate(50, 500)
# KS Zeichnen
self.fill(255, 255, 0)
self.stroke(255, 255, 0)
self.stroke_weight(1)
self.line(0, 0, 0, -300)
self.line(0, 0, 700, 0)
# Punkt zeichnen
cx = self.v0 * self.cos(self.angle) * self.t * self.scale
cy = -(self.v0 * self.sin(self.angle) * self.t - \
self.g/2 * self.t**2) * self.scale
self.fill(255, 0, 0)
self.stroke(255, 0, 0)
self.circle(cx, cy, 3)
# Stoppen bei Bodenkontakt
if cy >= -5:
self.no_loop()
def wurfparabel(v0=50, angle=45):
sketch = Wurfparabel(v0, angle)
sketch.run_sketch()
v0 = float(input("v0 = "))
winkel = float(input("winkel = "))
wurfparabel(v0=v0, angle=winkel)
Eingabe auf der Konsole:
v0 = 60
winkel = 45
Ausgabe:
[[Datei:PythonIng_py5_13.png|200px]]
Die benötigten Formeln der Bewegungsgleichung kann man leicht herleiten, bzw. man benutzt folgende Grafik als Hilfestellung:
[[Datei:Wurfparabel_Zusammenfassung_aktualisierung.png|700px]]
Hiermit belassen wir es mit der py5-Bibliothek und wenden uns wieder "mathematischeren" Themen zu.
= Vektoren und Matrizen =
== Zahlenfolgen ==
Für das Erstellen von Zahlenfolgen bieten sich die Funktionen <code>arange</code> und <code>linspace</code> aus dem <code>numpy</code>-Modul an.
from numpy import *
start = 0
stop = 10
step = 2
num = 10
r = arange(start, stop, step) # step ... Schrittweite
l = linspace(start, stop, num) # num ... Anzahl der Werte
print("r = ", r)
print("l = ", l)
Ausgabe:
r = [0 2 4 6 8]
l = [ 0. 1.11111111 2.22222222 3.33333333 4.44444444 5.55555556
6.66666667 7.77777778 8.88888889 10. ]
Bei <code>arange</code> ist der <code>stop</code>-Wert nicht im Ergebnis enthalten, bei <code>linspace</code> standardmäßig aber sehr wohl. Jedoch kann man das bei <code>linspace</code> auch ändern. Dann ist der Stoppwert nicht mehr enthalten:
linspace(start, stop, num, endpoint=False)
== Vektoren ==
Vektoren sollten jedem aus der Linearen Algebra bekannt sein.
=== Arrays ===
In Python mit NumPy kann man Vektoren durch die Funktion array erzeugen.
import numpy as np
l1 = (-5, 3, 2)
l2 = (1, 1, 4)
a1 = np.array(l1)
a2 = np.array(l2)
a3 = a1 + a2
a4 = 2 * a2
print(a1)
print(a2)
print(a3)
print(a3[2])
print(a4)
Ausgabe:
[-5 3 2]
[1 1 4]
[-4 4 6]
6
[2 2 8]
=== Zeilen- und Spaltenvektoren ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
print(z)
print(s)
Ausgabe:
[ [-5 3 2] ]
[[1]
[1]
[4]]
=== Skalarprodukt ===
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
skalarprodukt = np.dot(a1, a2)
print(skalarprodukt)
Ausgabe:
6
=== Vektorprodukt ===
<math>a\ast b=\left(\begin{array}{c}
a_{1}\\
a_{2}\\
a_{3}
\end{array}\right)\ast\left(\begin{array}{c}
b_{1}\\
b_{2}\\
b_{3}
\end{array}\right)=\left(\begin{array}{c}
a_{2}b_{3}-a_{3}b_{2}\\
a_{3}b_{1}-a_{1}b_{3}\\
a_{1}b_{2}-a_{2}b_{1}
\end{array}\right)
</math>
Python-Code:
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
vektorprodukt = np.cross(a1, a2)
print(vektorprodukt)
Ausgabe:
[10 22 -8]
=== Transponierter Vektor ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
# transponierter Vektor
z_tp = np.transpose(z)
# transponierter Vektor
s_tp = np.transpose(s)
print(z_tp)
print(s_tp)
Ausgabe:
[[-5]
[ 3]
[ 2]]
[ [1 1 4] ]
=== Vektorfelder visualisieren ===
import matplotlib.pyplot as plt
import numpy as np
# Daten generieren
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
X, Y = np.meshgrid(x, y)
U = X * Y
V = Y + X
# Plotten
fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='xy')
plt.show()
Ausgabe:
[[Datei:PythonIng_quiver1.png]]
== Matrizen==
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
print(m1)
Ausgabe:
[[1 2 3]
[4 5 6]]
=== Zugriff auf Matrizenelemente ===
Beispiel:
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
# Element aus Zeile 2 und Spalte 3 (Achtung! Index startet bei Null)
print(m1[1,2])
Ausgabe:
6
Visualisierung:
0 1 2
+-----------+
0 | 1 | 2 | 3 |
+-----------+
1 | 4 | 5 | '''6''' |
+-----------+
Beispiel:
import numpy as np
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
B = np.matrix(A)
print(B[2::, ::2])
Ausgabe:
[['20' '22']
['30' '32']
['40' '42']]
Mit der NumPy-Bibliothek funktioniert das zweidimensionale Slicing. Mit normalen Listen/Tupels geht das nicht, was wir schon früher thematisiert haben.
=== Addition und Subtraktion von Matrizen ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
m2 = np.matrix([[0, 0, 2], [1, 3, 2]])
print(m1 + m2)
print(m1 - m2)
Ausgabe:
[[1 2 5]
[5 8 8]]
[[1 2 1]
[3 2 4]]
=== Transponierte Matrix ===
import numpy as np
m = np.matrix([[1, 2, 3], [4, 5, 6]])
mt = np.transpose(m)
print(m)
print(mt)
Ausgabe:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]
=== Rang einer Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
rg = np.linalg.matrix_rank(m)
print(rg)
Ausgabe:
2
=== Inverse Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
mi = np.linalg.inv(m)
print(mi)
Ausgabe:
[[ 1. 0.6]
[-0. -0.2]]
=== Multiplikation von Matrizen (falksches Schema) ===
import numpy as np
m1 = np.matrix([[1, 3, 4], [0, -5, 1]])
m2 = np.matrix([[1, 2], [2, 3], [0, 2]])
print(m1 @ m2)
Ausgabe:
[[ 7 19]
[-10 -13]]
=== Eigenwerte und Eigenvektoren ===
import numpy as np
m = np.matrix([[5, 8], [1, 3]])
D,V = np.linalg.eig(m)
# Eigenwerte
print(D)
# Eigenvektoren
print(V)
Ausgabe:
[7. 1.]
[[ 0.9701425 -0.89442719]
[ 0.24253563 0.4472136 ]]
=== Teilmatrizen ===
import numpy as np
m = np.matrix([[1, 3, 4], [0, -5, 1]])
print("m = ", m)
# Erste Zeile extrahieren
m1 = m[0,:]
print("m1 = ", m1)
# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
m2 = m[0,1]
print("m2 = ", m2)
# Zweite Spalte extrahieren
m3 = m[:, 1]
print("m3 = ", m3)
Ausgabe:
m = [[ 1 3 4]
[ 0 -5 1]]
m1 = [ [1 3 4] ]
m2 = 3
m3 = [[ 3]
[-5]]
=== Spezielle Matrizen ===
==== Nullmatrix ====
import numpy as np
z = np.zeros((3, 2))
print(z)
Ausgabe:
[[0. 0.]
[0. 0.]
[0. 0.]]
==== Einheitsmatrix ====
import numpy as np
z = np.eye(3)
print(z)
Ausgabe:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
==== Matrix mit lauter Einsen ====
import numpy as np
z = np.ones((3, 2))
print(z)
Ausgabe:
[[1. 1.]
[1. 1.]
[1. 1.]]
=== Spärlich besetzte Matrizen ===
Das Thema spärlich besetzter Matrizen wird hier nur kurz angerissen. Nähere Details siehe unter dem Weblink [https://docs.scipy.org/doc/scipy/reference/sparse.html#module-scipy.sparse].
Beispiel:
import numpy as np
import scipy
A = scipy.sparse.csr_array(np.eye(5))
print(A)
Ausgabe:
<Compressed Sparse Row sparse array of dtype 'float64'
with 5 stored elements and shape (5, 5)>
Coords Values
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
(4, 4) 1.0
csr steht für '''c'''ompressed '''s'''parse '''r'''ow.
Andere Möglichkeiten:
* coo-Format ('''coo'''rdinate Format): <code>scipy.sparse.coo_array()</code>
* lil-Format ('''li'''st of '''l'''ists): <code>scipy.sparse.lil_array()</code>
* csc-Format ('''c'''ompressed '''s'''parse '''c'''olumn): <code>scipy.sparse.csc_array()</code>
Es gibt auch <code>scipy.sparse.csr_matrix()</code> etc. Diese Befehle sind aber veraltet und es wird empfohlen, statt dessen die <code>..._array()</code>-Funktionen zu verwenden.
<u>Aufgaben:</u>
Recherchieren Sie im Internet
* generell zum Thema "spärlich besetzte Matrizen mit Python".
* Was sind die Vor-/Nachteile von csr-arrays gegenüber coo- und lil-arrays?
* Wann verwendet man sinnvollerweise csr- und wann csc-arrays?
* Wie wandelt man coo-arrays in csr-arrays um?
= Lineare Gleichungssysteme =
Sei <math>Ax = b</math> ein lineares Gleichungssystem. <math>A</math> sei die Koeffizientenmatrix, <math>x</math> der Lösungsvektor und <math>b</math> ein bekannter Vektor.
Beispiel:
import numpy as np
A = np.array([[5, 1], [0, 2]])
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)
Ausgabe:
[0. 1.]
Siehe dazu auch das Kapitel [[Ing Mathematik: Numerisches Lösen von linearen Gleichungssystemen]]. Dort wird dieses Themengebiet u.a. mit weitergehenden Python-Skripten vertieft.
== Aufgabe ==
* Lösen Sie folgendes Gleichungssystem mittels Python (und zur Kontrolle auch händisch):
5x + 6y - 2z = 12
3x - y - 3z = 6
2x + 2y + 4z = 5
= Polynome =
== Ein erstes einfaches Beispiel ==
Gegeben sei das Polynom <math>7x^3+5x^2+1</math>. In Python:
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p)
Ausgabe:
3 2
7 x + 5 x + 1
== Einzelne Polynomwerte berechnen ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p(1.5))
Ausgabe:
35.875
== Polynome integrieren und differenzieren ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
# 1. Ableitung
p1 = p.deriv()
p2 = p.deriv(1)
# 2. Ableitung
p3 = p.deriv(2)
# Integral
p4 = p.integ()
print(p1)
print(p2)
print(p3)
print(p4)
Ausgabe:
2
21 x + 10 x
2
21 x + 10 x
42 x + 10
4 3
1.75 x + 1.667 x + 1 x
== Nullstellen bestimmen ==
import numpy as np
p = np.poly1d([2, 5, 0, 4])
r = np.roots(p)
print(r)
Ausgabe:
[-2.7621427 +0.j 0.13107135+0.84077099j 0.13107135-0.84077099j]
== Aufgaben ==
* Berechnen Sie den Wert für x = 3 des Polynoms <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Differenzieren und integrieren Sie das Polynom <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Berechnen Sie die Nullstellen von <math>y = 7x^5 - 3x^2 + 12</math>.
= Nichtlineare Gleichungen und Gleichungssysteme =
== Nullstellenbestimmung ==
Löse eine beliebige Gleichung f(x) = 0, z.B. <math> f(x) = x^2 - 5\cos(x) - 10 = 0 </math>:
import scipy
import numpy as np
def f(x):
return x**2 - 5*np.cos(x) - 10
xstart = [-1, 1] # Startwerte
xn = scipy.optimize.root(f, xstart)
print(xn.x)
Ausgabe:
[-2.46813009 2.46813009]
Funktionsgraph:
[[Datei:octave_nichtlin2.jpg]]
== Gleichungssysteme ==
SymPy ist ein externes Modul, das symbolisches Rechnen ('''Sym'''bolic '''Py'''thon) ermöglicht.
Folgende Aufgabe ist dem Buch "Knorrenschild: Numerische Mathematik, Hanser, 2017, Seite 72" entnommen. Zu lösen ist das nichtlineare Gleichungssystem
<math>f_1 = 2x_1 + 4x_2 = 0 </math>
<math>f_2 = 4x_1 + 8x_2^3 = 0</math>
Mit Python ist das so möglich:
import sympy
x1, x2 = sympy.symbols("x1 x2")
f1 = 2*x1 + 4*x2
f2 = 4*x1 + 8*x2**3
s = sympy.solve((f1, f2), x1, x2)
print(s)
Ausgabe:
[(-2, 1), (0, 0), (2, -1)]
Plot:
[[Datei:IngPython_nl_gleichung1.svg|500px]]
= Komplexe Zahlen =
Die imaginäre Einheit wird in Python durch den Buchstaben <code>j</code> symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:
* Kartesische Darstellung <math>z = \Re(z) + j \cdot \Im(z)</math>
* Polardarstellungen <math>z = r \cdot (\cos(\phi) + j \cdot \sin(\phi)) = r \cdot e^{j\cdot \phi}</math>
Die konjugiert komplexe Zahl ist <math>z^* = \Re(z) - j \cdot \Im(z)</math>
Nachfolgend einige mathematische Operationen mit Python und NumPy.
import numpy as np
z1 = 2 + 5j # kartesische Darstellung
z2 = 3 * np.exp(3j) # Polardarstellung
# Addition
res = z1 + z2
print("z1 + z2 = ", res)
# Multiplikation
res = z1 * z2
print("z1 * z2 = ", res)
# Realteil
res = np.real(z2)
print("Realteil von z2 = ", res)
# Imaginärteil
res = np.imag(z2)
print("Imaginaerteil von z2 = ", res)
# Betrag
res = np.abs(z1)
print("Betrag von z1 = ", res)
# Argument
res = np.angle(z1)
print("Argument von z1 = ", res)
# Konjugiert komplexe Zahl
res = np.conj(z1)
print("Konjugiert komplexe Zahl von z1 = ", res)
Ausgabe:
z1 + z2 = (-0.9699774898013365+5.423360024179601j)
z1 * z2 = (-8.05675510050068-14.003167400647481j)
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = (2-5j)
= Interpolation =
import numpy as np
import scipy
import matplotlib.pyplot as plt
# Stützpunkte
xp = np.arange(1, 6)
yp = (0, -5, 2, 7, 6)
ti = np.arange(1, 5, 0.01)
i1 = scipy.interpolate.interp1d(xp, yp, kind = "linear")
i2 = scipy.interpolate.interp1d(xp, yp, kind = "cubic")
plt.plot(xp, yp, "rx")
plt.plot(xp, i1(xp))
plt.plot(ti, i2(ti))
plt.show()
Ausgabe:
[[Datei:PythonIng_interpol1.png]]
= Differenzialrechnung =
== Numerisches Differenzieren ==
Als Beispiel differenzieren wir <math>y = 5x\sin{x}</math> und stellen das Ganze grafisch dar.
from findiff import Diff
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
f = 5 * x * np.sin(x)
dx = x[1] - x[0]
# Ableitung
d_dx = Diff(0, dx)
df_dx = d_dx(f)
# Grafik
plt.plot(x, f, label = "y")
plt.plot(x, df_dx, label = "y'")
plt.grid()
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:octave_diff1.jpg]]
<small>findiff ist ein externes Modul. Dieses muss installiert werden (z.B. so: ...\Python\Scripts\pip.exe install --upgrade findiff). Für die Vorgehensweise unter openSUSE Tumbleweed siehe das Kapitel [[Ing_Mathematik:_Python#Mit_VPython | VPython]], nur dass das Ganze mit einer aktuelleren Python-Version exekutiert wird, z.B. mit Python 3.13. Das im Buch "Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler, Rheinwerk" verwendete Modul "scipy.misc" ist veraltet (deprecated ... missbilligt). Lt. [https://docs.scipy.org/doc/scipy-1.17.0/dev/roadmap-detailed.html#misc SciPy-Dokumentation für die Version 1.17.0] wurden alle entsprechenden Features schon entfernt.</small>
== Symbolisches Differenzieren ==
Differenzieren Sie die Funktionen <math>f_1(x) = x^2</math> und <math>f_2(x) = \sin(x)\cos\left(\frac{x}{2}\right)</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2;
f2 = sympy.sin(x) * sympy.cos(x/2.)
d1 = sympy.diff(f1, x)
d2 = sympy.diff(f2, x)
print(d1)
print(d2)
Ausgabe:
2*x
-0.5*sin(0.5*x)*sin(x) + cos(0.5*x)*cos(x)
== Aufgaben ==
* Differenzieren Sie die Funktion <math>y = \log(x) + 10x</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
* Differenzieren Sie die Funktion <math>y = \frac{\sinh(x)}{(1+x)}</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
= Integralrechnung =
== Numerisches Integrieren ==
Berechnen Sie das Integral <math>\int_{0}^{3}x^2 dx</math>.
import scipy
def f(x):
return x**2
i = scipy.integrate.quad(f, 0, 3)
print(i)
Ausgabe:
(9.000000000000002, 9.992007221626411e-14)
Das trifft den exakten Wert 9.0 ziemlich genau.
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} dx</math>.
import scipy
import numpy as np
def f(x):
return 2**(-x)
i = scipy.integrate.quad(f, 0, np.inf)
print(i)
Ausgabe:
(1.4426950408889556, 4.486558477977586e-09)
== Symbolisches Integrieren ==
Berechnen Sie <math>\int x^2 \text{d}x</math> und <math>\int \sin{x}\cos{\frac{x}{2}} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2
f2 = sympy.sin(x) * sympy.cos(x/2.)
i1 = sympy.integrate(f1, x)
i2 = sympy.integrate(f2, x)
print(i1)
print(i2)
Ausgabe:
x**3/3
-0.666666666666667*sin(0.5*x)*sin(x) - 1.33333333333333*cos(0.5*x)*cos(x)
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f = 2**(-x)
i = sympy.integrate(f, (x, 0, sympy.oo))
print(i)
Ausgabe:
1/log(2)
<code>sympy.oo</code> steht für das {{W|Unendlichzeichen}} <math>\infty</math> (die liegende Acht oder das Möbiusband). Mit <code>sympy.pprint(i)</code> ließe sich letzere Ausgabe etwas schöner schreiben:
1
──────
log(2)
Man beachtete, <code>log</code> steht hier für den natürlichen Logarithmus <code>ln</code>.
== Aufgaben ==
* Integrieren Sie die Funktion <math>y = \log(x) + 10x</math> von 1 bis 5.
* Integrieren Sie die Funktion <math>y = x^3</math> von 0 bis 4.
* Integrieren Sie <math>\int x^x(\log (x) + 1)\mathrm dx</math> symbolisch.
= Gewöhnliche Differenzialgleichungen =
== DGL numerisch lösen ==
Für die Lösung von Differenzialgleichungen steht u.a. die Funktion scipy.integrate.solve_ivp() zur Verfügung. Diese Funktion implementiert auch das Runge-Kutta-Verfahren (RK45).
{{Wikipedia | Runge-Kutta-Verfahren}}
Beispiel <math>y' = x^2 + y^3</math>:
import scipy
import numpy as np
import matplotlib.pyplot as plt
def dy_dx(x, y):
return x**2 + y**3
y0 = [1]
xi = [0, 1]
x = np.arange(0, 1, 0.01)
z = scipy.integrate.solve_ivp(dy_dx, xi, y0, method="RK45", dense_output=True)
y = z.sol(x)
plt.plot(x, y.T)
plt.grid()
plt.show()
[[Datei:PythonIng_dgl1.png]]
== DGL symbolisch lösen ==
Beispiel <math>y' = x^2 + y^3</math>:
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
print(lsg)
Ausgabe:
[Eq(f(x), (-x**2)**(1/3)), Eq(f(x), (-x**2)**(1/3)*(-1 - sqrt(3)*I)/2), Eq(f(x), (-x**2)**(1/3)*(-1 + sqrt(3)*I)/2)]
Mit <code>sympy.pprint</code> (pretty print) lässt sich die Ausgabe etwas übersichtlicher darstellen.
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
sympy.pprint(lsg)
Ausgabe:
⎡ _____ _____ ⎤
⎢ _____ 3 ╱ 2 3 ╱ 2 ⎥
⎢ 3 ╱ 2 ╲╱ -x ⋅(-1 - √3⋅ⅈ) ╲╱ -x ⋅(-1 + √3⋅ⅈ)⎥
⎢f(x) = ╲╱ -x , f(x) = ────────────────────, f(x) = ────────────────────⎥
⎣ 2 2 ⎦
== Aufgaben ==
* Lösen Sie die Differenzialgleichung <math>y' = \frac{1}{x\cdot y}</math> mit Python. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>m' = -k\cdot m</math>. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>y' = \sqrt{|y|}</math>.
=Laplace-Transformation=
Laplace-Transformation:
<math>F(s) =\mathcal{L} \left\{f\right\}(s) = \int_{0}^{\infty} f(t) \mathrm e^{-st} \,\mathrm{d}t, \qquad s\in\mathbb{C}
</math>
Inverse Laplace-Transformation:
<math>\mathcal{L}^{-1} \left\{F\right\}(t)
= \frac{1}{2 \pi \mathrm j} \int_{ \gamma - \mathrm j \infty}^{ \gamma + \mathrm j \infty} \mathrm e^{st} F(s)\,\mathrm ds
= \begin{cases}
f(t) & \text{für } t \geq 0 \\
0 & \text{für } t < 0
\end{cases}
</math>
Siehe auch [[Ing_Mathematik:_Laplace-Transformation]]
Code:
import sympy
from sympy.abc import t, s
# Laplace-Transformation der Funktion f(t) = 1 (Heaviside-Fkt.)
f = 1
# alternativ: f = sympy.Heaviside(t)
F = sympy.laplace_transform(f, t, s, noconds=True)
print("Laplace-Transformierte F(s):", F)
# Inverse Laplace-Transformation zurück in den Zeitbereich
f_inv = sympy.inverse_laplace_transform(F, s, t)
print("Inverse Transformation f(t):", f_inv)
Ausgabe:
Laplace-Transformierte F(s): 1/s
Inverse Transformation f(t): Heaviside(t)
Die Zeile
from sympy.abc import t, s
steht alternativ für
t = sympy.symbols("t")
s = sympy.symbols("s")
<u>Aufgaben</u>: Ermitteln Sie mittels SymPy die <math>\mathcal{L}</math>-Transformierten und dann wieder die <math>\mathcal{L}^{-1}</math>-Transformationen (ähnlich wie beim obigen Beispiel):
* <math>\sin(t) \circ\! -\! \bullet \ ?</math>
* <math>t^3 \circ\! -\! \bullet \ ?</math>
* <math>\text{e}^{\omega t} \circ\! -\! \bullet \ ?</math>
=Fourier-Reihen=
<math>
f(x)\approx \frac{a_{0}}{2}+\sum_{k=1}^{\infty}\left(a_{k}\cos\left(kx\right)+b_{k}\sin\left(kx\right)\right)
</math>
<math>
a_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\cos\left(kx\right)\mathrm dx\quad\text{für }k\geq0
</math>
<math>
b_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\sin\left(kx\right)\mathrm dx\quad\text{für }k\geq1
</math>
Für die Sägezahnfunktion <math>y=x;\, 0 < x < 2\pi</math> sei die Fourierreihe mit einem Python-Programm (unter Mithilfe von sympy) hergeleitet.
Code:
from sympy import fourier_series, pi, symbols, pprint
x = symbols('x')
f = x
s = fourier_series(f, (x, 0, 2*pi))
pprint(s.truncate(n=4))
Ausgabe:
2⋅sin(3⋅x)
-2⋅sin(x) - sin(2⋅x) - ────────── + π
3
Siehe auch [[Ing Mathematik: Fourierreihen]].
Ein komplizierteres Beispiel:
[[Datei:IngMath fourier bsp13.svg | 300px]]
<math>0\le t < T/2\text{:}\quad f(t) = H</math>
<math>T/2 \le t \le T\text{:}\quad f(t) = \frac{2H}{T}\left( t-\frac{T}{2}\right)</math>
Code:
import sympy as sp
H = sp.Symbol('H', positive=True)
T = sp.Symbol('T', positive=True)
t = sp.Symbol('t')
f = sp.Piecewise(
(H, (t > 0) & (t < T/2)),
(2*H/T*(t-T/2), (t > T/2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Ausgabe:
⎛2⋅π⋅t⎞ ⎛4⋅π⋅t⎞ ⎛6⋅π⋅t⎞ ⎛2⋅π⋅t⎞ ⎛6⋅π⋅t⎞
H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ 2⋅H⋅cos⎜─────⎟ 2⋅H⋅cos⎜─────⎟
⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ 3⋅H
──────────── - ──────────── + ──────────── + ────────────── + ────────────── + ───
π 2⋅π 3⋅π 2 2 4
π 9⋅π
=Rechnen mit wirklich großen Zahlen=
Bekannt ist, dass Python kaum Einschränkungen beim Wertebereich von Ganzzahlen hat, z.B.
print(10**300)
Ausgabe (gekürzt):
100000000000000000000...00000000000000000000000000000000000000000000000000000000000000000000000
Ähnliches geht auch mit Gleitpunktzahlen, z.B. durch die Verwendung des Moduls [https://mpmath.org/ mpmath]:
import mpmath
print(mpmath.mpf(1500.4)**mpmath.mpf(300))
Ausgabe:
7.27975299218612e+952
Anderes Beispiel:
from mpmath import mp, pi
mp.dps = 100
print(pi)
Ausgabe:
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
mpmath kann noch einiges mehr, dazu sei aber auf die entsprechende Dokumentation auf der mpmath-Homepage verwiesen. mpmath ist Bestandteil von SymPy, kann aber auch separat installiert werden.
Aber auch Python selbst besitzt eine Möglichkeit, um mit großen bzw. exakten Gleitpunktzahlen zu rechnen, nämlich das interne Modul decimal. Dieses hat einige Vorteile gegenüber mpmath, aber auch gravierende Nachteile. Diese seien hier nicht detailliert aufgezählt. Grob gesagt hat decimal im Finanzwesen seine Berechtigung. Für wissenschaftliche Anwendungen wird aber mpmath vorzuziehen sein, da es u.a. vielfältige mathematische Funktionen bereit stellt. Nachfolgend ein einfaches Beispiel mit decimal:
import decimal
print("Potenzierung:", decimal.Decimal(1500.4) ** decimal.Decimal(300.0))
print("Einfache Addition:", 0.1 + 0.2)
decimal.getcontext().prec = 50
print("Addition mit decimal:", decimal.Decimal("0.1") + decimal.Decimal("0.2"))
Ausgabe:
Potenzierung: 7.279752992186121551039839134E+952
Einfache Addition: 0.30000000000000004
Addition mit decimal: 0.3
<u>Aufgabe:</u> Recherchieren Sie im Internet die genauen Vor- und Nachteile von decimal und mpmath. Verwenden Sie dazu auch KI (z.B. von Google, chatgpt).
= pint - mit physikalischen Größen rechnen =
[[File:Pint-Glas_UK.jpg|right|100px]]
pint ist ein externes Python-Paket zur Manipulation von physikalischen Einheiten. Es muss vor der ersten Benutzung installiert werden (Vorgehensweise wie immer: pip, YaST, via venv etc.).
Beispiel:
import pint
import numpy as np
ureg = pint.UnitRegistry()
# Einfache Berechnung
print(3 * ureg.meter + 4 * ureg.cm)
# Mit NumPy
npeinzel = [3, 4] * ureg.meter + [2, 5] * ureg.cm
print(npeinzel)
npsum = np.sum(npeinzel)
print(npsum)
# Konvertierung von Einheiten
npsum_inch = npsum.to(ureg.inch)
print(npsum_inch)
print(npeinzel.magnitude)
print(npeinzel.units)
print(npeinzel.dimensionality)
Ausgabe:
3.04 meter
[3.02 4.05] meter
7.07 meter
278.3464566929134 inch
[3.02 4.05]
meter
[length]
Die Dokumentation zu pint findet sich auf [https://pint.readthedocs.io/en/stable/].
=Regelungstechnische Aufgabenstellungen=
Für regelungstechnische Aufgaben gibt es u.a. das externe Paket <code>control</code>. Hier soll nicht detailliert darauf eingegangen werden. Anhand eines Beispiels soll anschließend nur die Visualisierung in Form eines Bode-Diagramms und der Sprungantwort gezeigt werden. Gegeben sei ein P-Regler mit <math>R = \frac{5}{2}</math> und eine Strecke <math>S= \frac{1}{30s^3+20s^2+10s+1,5}</math>. Gesucht sei vorerst ein Bode-Diagramm für den offenen Regelkreis und das Führungsverhalten.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke # oder: G0 = ct.series(regler, strecke)
Gw = ct.feedback(G0)
ct.bode_plot(G0, label='G0')
ct.bode_plot(Gw, label='Gw')
plt.show()
[[Datei:PythonIng_bode1.svg]]
Nun noch für obiges Beispiel die Sprungantwort. Diese zeigt einige große Überschwinger, d.h. der Regler kann sicher noch optimiert werden.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke
Gw = ct.feedback(G0)
t, y = ct.step_response(Gw)
plt.plot(t,y)
plt.title('Sprungantwort')
plt.xlabel('t')
plt.ylabel('h(t)')
plt.grid()
plt.show()
[[Datei:PythonIng_bode3.svg]]
Einige weitere wichtige Daten (Phasenreserve, Amplitudenreserve, Durchtrittsfrequenz) lassen sich mittels der <code>control</code>-Funktion <code>margin()</code> ermitteln. Die Ortskurve lässt sich mit der Funktion <code>nyquist_plot()</code> zeichnen. Dies sei hier aber nicht weiter ausgeführt.
==Aufgaben==
* Zeichen Sie mit Python die Ortskurve für obiges Beispiel.
* Was passiert, wenn man die Reglerverstärkung weiter aufdreht (z.B. auf <math>R = \frac{25}{2}</math>)?
* Wie sehen das Bode-Diagramm und die Sprungantwort aus, wenn ein PI-Regler verwendet wird?
= Stereostatik etc. =
Das Modul SymPy bietet einige Möglichkeiten einfache Bauwerke zu berechnen, z.B. Balken oder Fachwerke. Nachfolgend wird ein einfaches Fachwerk berechnet und gezeichnet.
Python-Code:
from sympy.physics.continuum_mechanics.truss import Truss
t = Truss()
# Knoten
t.add_node(("A", -3, 0), ("B", 0, 0), ("C", 4, 0), ("D", 7, 0),
("E", 6, 1.5), ("F", 2, 3), ("G", -2, 1.5))
# Stäbe
t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D"))
t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F"))
t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E"))
t.add_member(("FE","F","E"), ("DE","D","E"))
# Auflager; roller ... Loslager, pinned ... Festlager
t.apply_support(("A","roller"), ("D","pinned"))
# Einwirkende Kräfte
t.apply_load(("G", 5, 270), ("E", 3, 90))
# Berechnung
t.solve()
print("Reaction Forces: ", t.reaction_loads)
print("Internal Forces: ", t.internal_forces)
# Fachwerk zeichnen
p = t.draw()
p.show()
Ausgabe auf der Konsole:
Reaction Forces: {'R_A_y': 4.20000000000000, 'R_D_x': 0, 'R_D_y': -2.20000000000000}
Internal Forces: {'AB': 2.80000000000000, 'BC': 0.333333333333333, 'CD': -1.46666666666667,
'AG': -5.04777178564958, 'GB': -2.05555555555556, 'GF': -1.23413387432364,
'BF': 0.411111111111111*sqrt(13), 'FC': -0.3*sqrt(13), 'CE': 1.50000000000000,
'FE': 0.284800124843917, 'DE': 2.64407093534026}
Zeichnung:
[[File:PythonIng_fachwerk1.svg|300px]]
Details zu diesem Thema siehe z.B. [https://docs.sympy.org/latest/modules/physics/continuum_mechanics/index.html Continuum Mechanics] oder [https://docs.sympy.org/latest/tutorials/physics/continuum_mechanics/index.html Continuum Mechanics Tutorials]. Auch andere mechanische Probleme werden von SymPy abgehandelt ([https://docs.sympy.org/latest/tutorials/physics/index.html Physics Tutorials]).
== Aufgabe ==
Gegeben sei ein einseitig eingespannter Kragträger. Belastet wird er durch eine Einzellast am Trägerende. Für die Daten siehe folgende ASCII-Skizze:
| 20 kN
//|---> x |
//| V
//|----------------------
//| 10 m |
Elastizitätsmodul E = 2,1*10⁵ N/mm²
Flächenträgheitsmoment I = 0.001 m⁴
Berechnen Sie die Auflagerreaktionen, den Querkraft- und Biegemomentenverlauf, sowie die Verformungen.
Stellen Sie dies mit Hilfe von SymPy graphisch und auch mittels Formeln dar. Verwenden Sie dazu auch pprint (pretty print) aus dem SymPy-Modul. Zwecks Lösungsansatz siehe die oben aufgeführte Seite "Continuum Mechanics Tutorials". Achten Sie auch auf die Einheiten! Kontrollieren Sie das Ganze mittels händischer Rechnung. In dem genannten Tutorial ist von "Singularity Functions" die Rede. Gemeint ist damit in diesem Kontext die {{W|Föppl-Klammer}}.
Einige Python-Programme, vorrangig zu Maschinenelementen, finden sich auf [https://baymp.de/download_python.html BayMP für Python] (Balken, Zahnräder, Stabknickung usw.).
=Thermodynamik=
== PYroMat ==
Für thermodynamische Aufgabenstellungen gibt es verschiedene externe Module. Eines davon ist PYroMat (siehe auch [http://pyromat.org]). Damit lassen sich thermodynamische Stoffdaten für viele Substanzen berechnen.
Beispiel (einige Stoffdaten für Wasser bei 400°C und 20 bar berechnen):
import pyromat as pm
# Wasserdaten laden:
H2O = pm.get('mp.H2O')
# Stoffdaten berechnen:
T = 673.15 # Temperatur in Kelvin
p = 20 # Druck in bar
v = H2O.v(T, p)
h = H2O.h(T, p)
s = H2O.s(T, p)
print(f"Spezifisches Volumen: {v} m³/kg")
print(f"Spezifische Enthalpie: {h} kJ/kg")
print(f"Spezifische Entropie: {s} kJ/(kg K)")
Ausgabe:
Spezifisches Volumen: [0.1512163] m³/kg
Spezifische Enthalpie: [3248.3789473] kJ/kg
Spezifische Entropie: [7.12924142] kJ/(kg K)
<small>
PYroMat muss vorab installiert werden (z.B. mittels pip, in eine virtuelle Umgebung)
</small>
<code>mp</code> steht für "multi phase". Für ein ideales Gas wäre <code>ig</code> zuständig, z.B. <code>'ig.O2'</code>.
Beispiel (T-s-Diagramm für Wasser zeichnen):
import numpy as np
import matplotlib.pyplot as plt
import pyromat as pm
# Konfigurieren
pm.config["unit_pressure"] = "bar"
pm.config["unit_temperature"] = "K"
fluid = pm.get("mp.H2O")
# Temperaturbereich für das Nassdampfgebiet
T_tripel = 273.16
T_crit = 647.096
T = np.linspace(T_tripel, T_crit - 0.1, 200)
# Sättigungslinien berechnen und zeichnen
for x in np.linspace(0.0, 1.0, 5):
s = fluid.s(T=T, x=x)
if(x<=0.0):
plt.plot(s, T, label="Siedelinie x=%3.1f" % x, linewidth=2.0)
elif(x>=1.0):
plt.plot(s, T, label="Taulinie x=%3.1f" % x, linewidth=2.0)
else:
plt.plot(s, T, label="x=%3.1f" % x, linewidth=1.0)
# Isobaren zeichnen
p_values = [0.1, 1, 10, 50, 100]
T_isobar = np.linspace(T_tripel, 1000, 200)
t = 0.7
for p in p_values:
s_iso = fluid.s(T=T_isobar, p=p)
plt.plot(s_iso, T_isobar, 'k-', alpha=0.8, linewidth=0.8)
t += .05
idx = int(len(s_iso) * t)
plt.text(s_iso[idx], T_isobar[idx], f"{p} bar", fontsize=9, alpha=0.8)
# Diagramm zeichnen
plt.title("T-s-Diagramm für Wasser")
plt.xlabel("Spezifische Entropie s in kJ/kg K", fontsize=10)
plt.ylabel("Temperatur T in K", fontsize=10)
plt.legend(loc="best")
plt.grid(True)
plt.show()
Ausgabe (in etwa so):
[[Datei:T-s-Diagramm fuer Wasser.svg|400px]]
== CoolProp ==
Auch mit CoolProp können Stoffdaten berechnet werden. Siehe auch [https://coolprop.org/coolprop/wrappers/Python/index.html]
Beispiel (Wasser bei 20bar und 400°C):
import CoolProp.CoolProp as CP
fluid = 'Water'
T = 673.15 # Temperatur in Kelvin
P = 20e5 # Druck in Pascal
dichte = CP.PropsSI('D', 'T', T, 'P', P, fluid)
enthalpie = CP.PropsSI('H', 'T', T, 'P', P, fluid)
entropie = CP.PropsSI('S', 'T', T, 'P', P, fluid)
print(f"Spez. Volumen: {1/dichte:.6f} m³/kg")
print(f"Spez. Enthalpie: {enthalpie:.2f} J/kg")
print(f"Spez. Entropie: {entropie:.2f} J/kgK")
Ausgabe:
Spez. Volumen: 0.151215 m³/kg
Spez. Enthalpie: 3248344.02 J/kg
Spez. Entropie: 7129.16 J/kgK
== iapws ==
Um Werte für Wasser(dampf) zu erhalten (IAPWS; '''I'''nternational '''A'''ssociation for the '''P'''roperties of '''W'''ater and '''S'''team) gibt es die Bibliothek iapws. Siehe auch [https://iapws.org/] und [https://pypi.org/project/iapws/]
Beispiel (Wasser für 20bar und 400°C):
from iapws import IAPWS97
dampf = IAPWS97(P=2.0, T=673.15)
print(f"Spezifisches Volumen: {dampf.v:.6f} m³/kg")
print(f"Spezifische Enthalpie: {dampf.h:.2f} kJ/kg")
print(f"Spezifische Entropie: {dampf.s:.4f} kJ/(kgK)")
print(f"Phase: {dampf.phase}")
Ausgabe:
Spezifisches Volumen: 0.151208 m³/kg
Spezifische Enthalpie: 3248.23 kJ/kg
Spezifische Entropie: 7.1290 kJ/(kgK)
Phase: Gas
== TESPy ==
Ein anderes Modul für einen anderen Aufgabenzweck ist TESPy ('''T'''hermal '''E'''ngineering '''S'''ystems in '''Py'''thon). Dieses Modul ist für die Anlagensimulation zuständig. Für nähere Informationen siehe [https://tespy.readthedocs.io/en/main/getting_started/introduction.html]. Als Beipiel sei hier vorerst Code, der von der Google KI generiert wurde, angeführt. Der Code wurde überarbeitet, damit keine Warnungen auftreten. Bitte aber den Code trotzdem mit Vorsicht genießen, auch KI-generierter Code kann Fehler aufweisen. Eine Pumpe wird berechnet:
from tespy.components import Sink, Source, Pump
from tespy.connections import Connection
from tespy.networks import Network
# 1. Netzwerk definieren (Zentrales Steuerungselement)
# Wir wählen Wasser als Fluid und bar/Celsius als Einheiten
nw = Network(fluids=["water"])
nw.units.set_defaults(pressure="bar", pressure_difference="bar",
temperature="°C", enthalpy="kJ / kg")
# 2. Komponenten erstellen
eingang = Source("Wasserquelle")
ausgang = Sink("Wasserspeicher")
pumpe = Pump("Speisewasserpumpe")
# 3. Verbindungen definieren (Komponenten miteinander verknüpfen)
c1 = Connection(eingang, "out1", pumpe, "in1")
c2 = Connection(pumpe, "out1", ausgang, "in1")
# Verbindungen dem Netzwerk hinzufügen
nw.add_conns(c1, c2)
# 4. Randbedingungen und Parameter festlegen
# Zustand am Eingang (Druck, Temperatur, Massenstrom, Fluid-Zusammensetzung)
c1.set_attr(
v=1, # Massenstrom: 1 kg/s
T=20, # Temperatur: 20 °C
p=1, # Druck: 1 bar
fluid={"water": 1}, # 100% Wasser
)
# Zustand am Ausgang / Zielwerte der Pumpe
c2.set_attr(p=10) # Ziel-Druck nach der Pumpe: 10 bar
# Pumpeneigenschaften festlegen
pumpe.set_attr(eta_s=0.8) # Isentroper Wirkungsgrad von 80%
# 5. Simulation ausführen
nw.solve(mode="design")
# 6. Ergebnisse ausgeben
nw.print_results()
# Spezifische Werte direkt auslesen
print("\n--- Auswertung ---")
print(f"Erforderliche Pumpenleistung: {pumpe.P.val / 1000:.2f} kW")
print(f"Temperatur nach der Pumpe: {c2.T.val:.2f} °C")
Ausgabe (gekürzt):
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 7.04e+04 | 12 % | 9.96e+02 | 0.00e+00 | 8.81e+04 | 0.00e+00 | 0.00e+00
2 | 5.91e-12 | 100 % | 1.11e-13 | 0.00e+00 | 7.39e-12 | 0.00e+00 | 0.00e+00
3 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
4 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.01 s, Iterations per second: 480.85
##### RESULTS (Pump) #####
+-------------------+----------+----------+-----------+----------+----------+----------+
| | P | pr | dp | eta | eta_s | head |
|-------------------+----------+----------+-----------+----------+----------+----------|
| Speisewasserpumpe | 1.12e+06 | 1.00e+01 | -9.00e+00 | 8.00e-01 | 8.00e-01 | 9.19e+01 |
+-------------------+----------+----------+-----------+----------+----------+----------+
...
...
--- Auswertung ---
Erforderliche Pumpenleistung: 1124.77 kW
Temperatur nach der Pumpe: 20.07 °C
= Stochastik =
Die {{W|Stochastik}} ist ein sehr weites Feld. Hier werden etliche wichtige Themen kurz angerissen. Python stellt mit den Moduln math und statistics Software zu diesem Zwecke bereit. math und statistics sind bereits im Lieferumfang von Python enthalten. Aber auch mit den externen Modulen NumPy, SciPy, stochastic und pandas kann man Stochastik in Python betreiben. Die Theorie der Wahrscheinlichkeitsrechnung und Statistik soll etwas später in Band 5 dieser Buchreihe behandelt werden.
== Lageparameter ==
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
m1 = statistics.mean(werte)
m2 = statistics.mode(werte)
m3 = statistics.median(werte)
print("Arithmetischer Mittelwert = ", m1)
print("Modalwert = ", m2)
print("Median = ", m3)
Ausgabe:
Arithmetischer Mittelwert = 3.5
Modalwert = 1
Median = 3.0
== Streuungsparameter ==
Beispiel (Berechnung der Standardabweichung):
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
s = statistics.stdev(werte)
print("Standardabweichung = ", s)
Ausgabe:
Standardabweichung = 2.6770630673681683
Beispiel (Berechnung des Variationskoeffizienten V = Standardabweichung/Mittelwert)
import numpy as np
from scipy import stats
import statistics
k = 50
dat1 = [14, 21, 18, 25, 30, 17, 20]
dat = np.array(dat1)
# Mit SciPy
v = stats.variation(dat)
vddof = stats.variation(dat, ddof=1)
print("V SciPy: ", v)
print("V DDOF SciPy: ", vddof)
print(k*"-")
# mit NumPy
mittelwert1 = np.mean(dat)
std_abw1 = np.std(dat)
std_abw1ddof = np.std(dat, ddof=1)
v1= std_abw1 / mittelwert1
v1ddof = std_abw1ddof / mittelwert1
print("Mittelwert NumPy: ", mittelwert1)
print("Std.abw. NumPy: ", std_abw1)
print("Std.abw. DDOF NumPy: ", std_abw1ddof)
print("V NumPy: ", v1)
print("V DDOF NumPy: ", v1ddof)
print(k*"-")
# nur mit reinem Python
mittelwert2 = statistics.mean(dat1)
std_abw2 = statistics.stdev(dat1)
v2 = std_abw2 / mittelwert2
print("Mittelwert Python: ", mittelwert2)
print("Std.abw. Python: ", std_abw2)
print("V Python:", v2)
print(k*"-")
Ausgabe:
V SciPy: 0.23890355966467272
V DDOF SciPy: 0.25804533701889254
--------------------------------------------------
Mittelwert NumPy: 20.714285714285715
Std.abw. NumPy: 4.948716593053935
Std.abw. DDOF NumPy: 5.3452248382484875
V NumPy: 0.23890355966467272
V DDOF NumPy: 0.2580453370188925
--------------------------------------------------
Mittelwert Python: 20.714285714285715
Std.abw. Python: 5.3452248382484875
V Python: 0.2580453370188925
--------------------------------------------------
Der Unterschied bei der Standardabweichung zwischen reinem Python und den externen Bibliotheken SciPy und NumPy entsteht dadurch, dass einmal durch (n-1) und das andere Mal nur durch n dividiert wird. Dies kann bei NumPy und SciPy dadurch entschärft werden, indem <code>ddof=1</code> gesetzt wird. ddof steht für '''D'''elta '''D'''egrees '''o'''f '''F'''reedom. <small>Je größer die Anzahl der Datensätze n wird, umso weniger spielt das eine Rolle.</small>
== Kombinatorik ==
Beispiel:
import math
n = 7
k = 5
print("n! = ", math.factorial(n))
print("Kombinationen (n über k) = ", math.comb(n, k))
Ausgabe:
n! = 5040
Kombinationen (n über k) = 21
Siehe zu diesem Thema auch [[Ing Mathematik: Permutationen, Kombinationen, binomischer Lehrsatz]]. Die Anzahlen lassen sich einfach aus den dortigen Formeln ermitteln, z.B. bei Permutationen mit <math>n!</math> oder Variationen mit Wiederholungen als <math>n^k</math>. Will man die Kombinationen oder Variationen aber auch als Liste ausgeben, so kann das Modul <code>itertools</code> nützlich sein.
Beispiel (Variationen ohne Wiederholung):
from itertools import permutations
menge = ["A", "B", "C", "D"] # n = 4
k = 3
variationen = list(permutations(menge, k))
for v in variationen:
print("".join(v))
print(50*"-")
print(len(variationen))
Ausgabe (gekürzt):
ABC
ABD
ACB
...
DCA
DCB
--------------------------------------------------
24
Siehe zum Modul <code>itertools</code> auch die Website [https://docs.python.org/3/library/itertools.html].
* Variationen mit Wiederholung: <code>itertools.product()</code>
* Kombinationen ohne Wiederholung: <code>itertools.combinations()</code>
* Kombinationen mit Wiederholung: <code>itertools.combinations_with_replacement()</code>
== Zufallszahlen ==
Beispiel:
import random
# Ganzzahlige Zufallszahl von 1 bis 10
zufallszahl1 = random.randint(1, 10)
# Gleitpunktzahlen
# zwischen 0.0 und 1.0
zufallszahl2 = random.random()
# Zahl zwischen 1.5 und 9.5
zufallszahl3 = random.uniform(1.5, 9.5)
# aus Liste auswählen
farbe = ["Rot", "Grün", "Blau"]
zufallswert = random.choice(farbe)
print(zufallszahl1)
print(zufallszahl2)
print(zufallszahl3)
print(zufallswert)
Ausgabe, z.B.:
5
0.14147945849015753
6.894003397570905
Rot
Benötigt man mehrere Zufallszahlen, so ist das Modul <code>numpy</code> zu bevorzugen, z.B.:
* Normalverteilung: <code>np.random.normal(...)</code>
* Gleichverteilung: <code>np.random.uniform(...)</code>
== Histogramm ==
Zum Thema Histogramm siehe {{W|Histogramm}}.
Beispiel (mit Matplotlib):
import matplotlib.pyplot as plt
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
plt.hist(daten, bins=25, edgecolor='darkgray')
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm.svg|300px]]
Beispiel (mit Seaborn):
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
sns.set_theme(style="darkgrid")
sns.histplot(data=daten)
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm2.svg|300px]]
Das Kürzel <code>sns</code> ist Konvention und steht für die fiktive Figur '''S'''amuel '''N'''orman '''S'''eaborn aus der US-Fernsehserie {{W|The West Wing – Im Zentrum der Macht | The West Wing}}.
== Box-Plot ==
[[File:Elements of a boxplot.svg|400px]]
Siehe auch {{W|Box-Plot}}.
Beispiel (mit Seaborn erstellt):
import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("tips")
sns.boxplot(data=df, x="day", y="tip", hue="day", legend=False)
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot.svg|400px]]
Beispiel (mit Matplotlib erstellt):
import matplotlib.pyplot as plt
daten = [12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25]
plt.boxplot(daten, patch_artist=True)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot2.svg|300px]]
Um mehrere Box-Plots unterschiedlicher Farbe mit Matplotlib in einem Diagramm zu zeichnen, können Sie folgendermaßen vorgehen:
import matplotlib.pyplot as plt
daten = [[12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25],
[10, 19, 20, 21, 20, 30, 19, 40, 11, 17, 19, 21]]
farben = ["green", "blue"]
boxplot = plt.boxplot(daten, patch_artist=True)
for patch, farbe in zip(boxplot['boxes'], farben):
patch.set_facecolor(farbe)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
== Regressionsrechnung ==
Beispiel:
import numpy as np
import matplotlib.pyplot as plt
# Messpunkte
x = np.array([1, 3, 5, 6, 8, 10, 20])
y = np.array([3, 4, 5, 5, 7, 9, 11])
# Regressionskurve (Grad 1 = lineare Regression, 2 = Polynom-Regression 2. Gr.)
# y = kx + d
k, d = np.polyfit(x, y, deg=1)
# y = ax**2 + bx + c
a, b, c = np.polyfit(x, y, deg=2)
x_l = np.linspace(1, 20, 100)
y_p = a * x_l**2 + b * x_l + c
# Zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.plot(x, k*x + d, color='blue', label='Regressionsgerade')
plt.plot(x_l, y_p, color='red', label='Regressionspolynom 2. Gr.')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:IngMath_regression.svg|400px]]
== Korrelationsrechnung ==
Beispiel:
import pandas as pd
import matplotlib.pyplot as plt
# Messdaten
x = [1, 3, 4, 5, 6]
y = [2, 4, 6, 8, 5]
daten = {'X': x, 'Y': y}
df = pd.DataFrame(daten)
# Korrelation
korr = df['X'].corr(df['Y'])
print(f"Korrelationskoeff.: {korr}")
# Messpunkte zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
Korrelationskoeff.: 0.7556096518348252
[[Datei:IngMath_korrelation.svg|300px]]
== Mengen und Venn-Diagramme ==
Beispiel:
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
menge_a = {1, 2, 3, 4, 5, 6}
menge_b = {4, 5, 6, 7, 8}
vereinigung = menge_a | menge_b
schnitt = menge_a & menge_b
print("Vereinigungsmenge = ", vereinigung)
print("Schnittmenge = ", schnitt)
venn2([menge_a, menge_b], set_labels=('Menge A', 'Menge B'))
plt.show()
Ausgabe:
Vereinigungsmenge = {1, 2, 3, 4, 5, 6, 7, 8}
Schnittmenge = {4, 5, 6}
[[Datei:IngMath_venn.svg|300px]]
Siehe auch {{W|Mengendiagramm#Venn-Diagramme}}.
== Verteilungs- und Dichtefunktion ==
* CDF ... '''C'''umulative '''D'''istribution '''F'''unction, Verteilungsfunktion
* PDF ... '''P'''robability '''D'''ensity '''F'''unction, Dichtefunktion
Beispiel (Normalverteilung):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
my, sigma = 0, 1
x = np.linspace(-4, 4, 50)
pdf = norm.pdf(x, my, sigma)
cdf = norm.cdf(x, my, sigma)
plt.plot(x, pdf, lw=2, label="Dichtefunktion")
plt.plot(x, cdf, lw=2, label="Verteilungsfunktion")
plt.legend()
plt.grid()
plt.show()
Ausgabe:
[[Datei:IngMath_cdf_pdf.svg|300px]]
Beispiel (<math>\chi^2</math>-Verteilung):
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
x = np.linspace(0, 20, 500)
# df ... degree of freedom, Freiheitsgrad
pdf = (stats.chi2.pdf(x, df=2), stats.chi2.pdf(x, df=5), stats.chi2.pdf(x, df=10))
for i in range(0,3):
if(i==0):
lab = "Freiheitsgrad 2"
elif(i==1):
lab = "Freiheitsgrad 5"
else:
lab = "Freiheitsgrad 10"
plt.plot(x, pdf[i], label=lab, lw=2)
plt.grid()
plt.legend()
plt.show()
Ausgabe:
[[Datei:IngMath_chi2.svg | 300px]]
== Schätzen und Testen ==
=== Intervallschätzung ===
Als Beispiel seien Daten gegeben, die von ''Dürr, Mayer: Wahrscheinlichkeitsrechnung und Schließende Statistik; 7. Aufl., Hanser, 2014, Seite 137'' stammen. Und zwar soll das 95%-Vertrauensintervall für den Mittelwert des Kaloriengehalts (kcal/100g) von Hähnchen ermittelt werden. Wir wollen das mit Python inkl. NumPy und SciPy durchführen. Die Stichprobe ist groß (50 Hähnchen):
Python-Code:
import numpy as np
import scipy.stats as stats
# Stichprobe
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203]
# Parameter definieren
konfidenzniveau = 0.95
mean = np.mean(daten)
std = np.std(daten, ddof=1)
stdfehler = stats.sem(daten)
intervall = stats.norm.interval(confidence=konfidenzniveau, loc=mean, scale=stdfehler)
print(f"Mittelwert: {mean}")
print(f"Standardabweichung: {std}")
print(f"Konfidenzintervall: {intervall}")
Ausgabe:
Mittelwert: 215.48
Standardabweichung: 33.14238915925757
Konfidenzintervall: (np.float64(206.29356722321992), np.float64(224.66643277678006))
Diese Werte stimmen gerundet mit denen im genannten Buch überein. Zum Code selbst:
* sem steht für '''s'''tandard '''e'''rror of the '''m'''ean.
* <code>scipy.stats.norm</code> ... Modul für die Normalverteilung.
=== Punktschätzung ===
Gleiche Daten wie oben bei der Intervallschätzung.
Python-Code:
import numpy as np
from scipy import stats
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203
]
mu_hat, sigma_hat = stats.norm.fit(daten)
print(f"Schätzer für den Erwartungswert (μ): {mu_hat:.4f}")
print(f"Schätzer für die Standardabweichung (σ): {sigma_hat:.4f}")
Ausgabe:
Schätzer für den Erwartungswert (μ): 215.4800
Schätzer für die Standardabweichung (σ): 32.8093
=== Hypothesentests ===
Beispiel:
import numpy as np
import scipy.stats as stats
x_quer = 12.075 # Stichproben-Mittelwert
var = 0.069 # Stichproben-Varianz
n = 90 # Stichprobengröße
my_0 = 12.0 # Nullhypothese
alpha = 0.05 # Signifikanzniveau
z_stat = (x_quer - my_0) / np.sqrt(var / n)
p_val = 2 * (1 - stats.norm.cdf(np.abs(z_stat)))
print(f"Z-Statistik: {z_stat:.4f}")
if p_val < alpha:
print(f"p-Wert: {p_val:.6f} < alpha:", alpha)
print("Die Nullhypothese wird verworfen.")
else:
print(f"p-Wert: {p_val:.6f} > alpha:", alpha)
print("Die Nullhypothese wird nicht verworfen.")
Ausgabe:
Z-Statistik: 2.7087
p-Wert: 0.006755 < alpha: 0.05
Die Nullhypothese wird verworfen.
== Statistische Qualitätskontrolle ==
Beispiel (Mittelwertkarte):
import numpy as np
import matplotlib.pyplot as plt
# Gegeben
sollwert = 50.0
varianz = 4.0
stichproben_umfang = 1
daten = [49.5, 50.2, 53.0, 48.1, 52.6, 53.4, 49.8]
# Berechnung
standardabweichung = np.sqrt(varianz)
streuung = standardabweichung / np.sqrt(stichproben_umfang)
cl = sollwert
ucl = cl + 3 * streuung
lcl = cl - 3 * streuung
# Darstellung
plt.plot(daten, marker='o', linestyle='-', color='b', label='Messdaten')
plt.axhline(cl, color='green', linestyle='-', label=f'CL: {cl}')
plt.axhline(ucl, color='red', linestyle='--', label=f'UCL: {ucl:.2f}')
plt.axhline(lcl, color='red', linestyle='--', label=f'LCL: {lcl:.2f}')
plt.title('Mittelwertkarte')
plt.xlabel('Stichprobe')
plt.ylabel('Wert')
plt.legend(loc='lower left')
plt.grid(True)
plt.show()
Ausgabe:
[[Datei:IngMath_mittelwertkarte.svg|300px]]
Siehe auch {{W|Shewhart-Regelkarte}} und {{W|Qualitätsregelkarte}}.
* UCL ... '''U'''pper '''C'''ontrol '''Limit''', Obere Eingriffsgrenze
* LCL ... '''L'''ower '''C'''ontrol '''Limit''', Untere Eingriffsgrenze
* CL ... '''C'''enter '''L'''ine, Mittellinie
= Ein- und Ausgabe =
== print ==
Die Anweisung print haben wir schon oft verwendet. Hier soll anhand von Beispielen kurz beschrieben werden, was der Befehl print leisten kann.
print("Hallo", "Welt", 1, sep="-")
print("Hallo", end=" ")
print("Welt")
Ausgabe:
Hallo-Welt-1
Hallo Welt
== input ==
a = int(input("Zahl 1: "))
b = int(input("Zahl 2: "))
print("a + b = ", a+b)
Ausgabe (nach Eingabe der beiden Ganzzahlen):
Zahl 1: 4
Zahl 2: 5
a + b = 9
== Aus Dateien lesen ==
Es seinen die datei.txt
Hallo Welt.
Wie geht es dir?
...
und test1.py
dat = open("datei.txt", mode = "r")
print(dat.read())
dat.close()
Ausgabe
Hallo Welt.
Wie geht es dir?
...
Mit dem open()-Befehl wird die Datei datei.txt im Lesemodus geöffnet (r ... read). Mit dem read()-Befehl wird die Datei eingelesen und mittels print ausgegeben.
== In Dateien schreiben ==
dat = open("datei.txt", mode = "a", encoding = "utf-8")
dat.write("Hänge Zeile an\n")
dat.close()
Die Datei datei.txt sieht nach Abarbeitung des obigen Skripts nun so aus
Hallo Welt.
Wie geht es dir?
...
Hänge Zeile an
Es wird die Datei im Schreibmodus geöffnet (a ... append (anhängend), w ... write (überschreibend)).
write() fügt hier also eine Zeile Text am Dateiende ein. close() schließt die Datei wieder.
Das close() kann man sich mit der with-Anweisung auch sparen.
with open("datei.txt", mode="a", encoding="utf-8") as dat:
dat.write("Hänge Zeile an\n")
= Benutzeroberflächen erstellen =
== tkinter ==
{{Wikipedia | Tkinter}}
Python bietet standardmäßig das Modul tkinter zur Programmierung von Benutzeroberflächen. Es müssen also bei der Verwendung von tkinter keine externen Module installiert werden. Hier wird eine (sehr) kurze Einführung in das Erstellen von grafischen Oberflächen mittels tkinter gegeben.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
win.minsize(300, 50)
but = tk.Button(win, text = "Push the button")
but.pack()
win.mainloop()
Ausgabe:
[[Datei:PythonIng_gui1.jpg]]
Ein etwas komplizierteres Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
def on_button_clicked():
str = ent1.get() + ent2.get()
lab2["text"] = str
ent1 = tk.Entry(win)
ent2 = tk.Entry(win)
lab1 = tk.Label(win, text="verknuepfen mit")
lab2 = tk.Label(win, text="")
but = tk.Button(win, text = "=", command=on_button_clicked)
ent1.pack(side="left")
lab1.pack(side="left")
ent2.pack(side="left")
but.pack(side="left")
ent2.pack(side="left")
lab2.pack(side="left")
win.mainloop()
Ausgabe (vor der Eingabe der Teilstrings):
[[Datei:PythonIng_gui2.jpg]]
Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):
[[Datei:PythonIng_gui3.jpg]]
== curses ==
{{Wikipedia | curses}}
Mit dem curses-Modul lassen sich u.a. TUIs ('''T'''ext '''U'''ser '''I'''nterfaces) erstellen. Ein sehr einfaches Beispiel zur allgemeinen Funktionsweise wird nachstehend geliefert.
import curses
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
stdscr.clear()
stdscr.addstr("Hallo Welt", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.endwin()
Als Ausgabe sollte <span style="color:#FF0000;">Hallo Welt</span> (rote Schrift auf weißem Hintergrund) auf dem Terminal/der Konsole erscheinen. Getestet wurde dies mit openSUSE Tumbleweed, Python-Version 3.13.12. Das entsprechende Python-curses-Package muss installiert sein.
Allgemeine Informationen zur Terminal-/Konsolengröße und Cursorposition liefert folgendes Programm:
import curses
stdscr = curses.initscr()
stdscr.addstr(3, 5, "LINES: %d" % curses.LINES)
stdscr.addstr(4, 5, "COLS: %d" % curses.COLS)
(y,x) = stdscr.getyx()
stdscr.addstr(5, 5, "Momentane Cursorposition: [%d, %d]" % (y, x))
(y,x) = stdscr.getbegyx()
stdscr.addstr(6, 5, "Koordinatenursprung: [%d, %d]" % (y, x))
(y,x) = stdscr.getmaxyx()
stdscr.addstr(7, 5, "Fenstergröße: [%d, %d]" % (y, x))
stdscr.addstr(11, 2, "Taste drücken -> Ende")
stdscr.refresh()
stdscr.getch()
curses.endwin()
Es sollte sich in etwa folgende Ausgabe ergeben:
LINES: 44
COLS: 110
Momentane Cursorposition: [4, 15]
Koordinatenursprung: [0, 0]
Fenstergröße: [44, 110]
Taste drücken -> Ende
Zur Funktionsweise von curses siehe auch das Wikibook [[ncurses]]. Zum Verständnis sind dort allerdings elementare Kenntnisse in der Programmiersprache C erforderlich.
== Qt ==
{{Wikipedia | Qt (Bibliothek)}}
Auch für das Qt-Framework gibt es eine Anbindung an Python. Nachfolgend ein einfaches Beispiel.
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hallo Welt!")
label.show()
sys.exit(app.exec())
Ausgabe:
[[Datei:PythonIng_gui10.png]]
== Gtk ==
{{Wikipedia | GTK (Programmbibliothek)}}
Eine idente Ausgabe, wie oben für Qt gezeigt, erzeugt z.B. folgendes Gtk-Programm:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
lab = Gtk.Label(label="Hallo Welt!")
win.set_child(lab)
win.present()
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
Auch für die Benutzung von Qt und Gtk müssen die jeweiligen Packages installiert sein. Getestet wurden die entsprechenden Python-Programme nur unter openSUSE Tumbleweed. Wie das GTK-Paket unter MS Windows 11 installiert wird, siehe z.B. [https://www.gtk.org/docs/installations/windows Setting up GTK for Windows].
Damit sei aber das Thema "Benutzeroberflächen erstellen" hier abgeschlossen, da dies schon ein sehr spezielles Aufgabengebiet ist, das eher Informatiker und nicht so sehr Ingenieure anspricht. Bei Bedarf siehe aber ggf. die entsprechenden Links unten in diesem Tutorial. Dort sind weiterführende Informationen zu finden.
= Pandas kurz erklärt =
Hier wird kurz auf das externe Modul Pandas eingegangen. Pandas steht für '''Pan'''el '''Da'''ta und ist ein Modul für die Datenanalyse und -manipulation.
== Series ==
Vorstellbar ist eine "Series" wie eine einzelne Spalte in einem Tabellenkalkulationsprogramm.
Beispiel (Index implizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5]) # Temperaturwerte
print(temp)
Ausgabe:
0 8.5
1 11.0
2 12.5
3 10.0
4 13.0
5 11.0
6 14.5
dtype: float64
Das Kürzel <code>pd</code> ist Konvention. Es seien Temperaturwerte gegeben. Die erste Spalte bei der Ausgabe ist der Index. Die zweite Spalte enthält die Werte.
Beispiel (separater Zugriff auf den Index und auf die Werte):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5])
print(temp.index)
print(temp.values)
Ausgabe:
RangeIndex(start=0, stop=7, step=1)
[ 8.5 11. 12.5 10. 13. 11. 14.5]
Beispiel (Index explizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
print("*** Die gesamte Series ***")
print(temp)
print("*** Temperatur am Donnerstag ***")
print(temp["Do"])
print("*** Tage wärmer als 12 Grad ***")
temp_gr_12 = temp[temp > 12]
print(temp_gr_12)
Ausgabe:
*** Die gesamte Series ***
Mo 8.5
Di 11.0
Mi 12.5
Do 10.0
Fr 13.0
Sa 11.0
So 14.5
dtype: float64
*** Temperatur am Donnerstag ***
10.0
*** Tage wärmer als 12 Grad ***
Mi 12.5
Fr 13.0
So 14.5
dtype: float64
== DataFrame ==
Ein DataFrame entspricht einer Tabelle.
Beispiel (Erzeugen eines DataFrames):
import pandas as pd
tag = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
v1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=tag)
v2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=tag)
v3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=tag)
tab = pd.concat([v1, v2, v3], axis=1)
tab.columns = stadt
print(tab)
print(type(tab))
Ausgabe:
Linz Salzburg Innsbruck
Mo 1 8 Hallo
Di 2 9 16
Mi 3 10 17
Do 4 11 18
Fr 5 12 19
Sa 6 13 20
So 7 14 21
<class 'pandas.core.frame.DataFrame'>
Wir haben hier drei Datenspalten (v1, v2, v3) mit den Spaltennamen "Linz", "Salzburg" und "Innsbruck", sowie sieben Zeilen "Mo" bis "So".
Beispiel (Zugriff auf eine Spalte):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab["Salzburg"])
Ausgabe:
Mo 8
Di 9
Mi 10
Do 11
Fr 12
Sa 13
So 14
Name: Salzburg, dtype: int64
Beispiel (Zugriff auf eine Zeile):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab.loc["Di"])
Ausgabe:
Linz 2
Salzburg 9
Innsbruck 16
Name: Di, dtype: object
== Grafiken erstellen ==
Hier sei nur ein Torten- oder Kreisdiagramm gezeichnet:
import pandas as pd
import matplotlib.pyplot as plt
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
expl = [0, 0.2, 0, 0, 0, 0, 0]
temp.plot.pie(figsize=(5,5), explode=expl)
plt.show()
Ausgabe:
[[Datei:IngPython_pandas1.svg|350px]]
Die <code>figsize</code> hat nichts mit der Spaltenanzahl zu tun, sondern setzt die Fenster- oder Diagrammgröße in Inches (Breite * Höhe).
Mit Pandas kann man auch noch andere Diagrammarten erstellen, z.B. Linien- oder Balkendiagramme. Dies wird hier aber nicht vorgeführt.
== Arbeiten mit CSV- und LibreOffice-Dateien ==
Gegeben sei eine CSV-Datei test1.csv:
Mai;Juni;Juli
12;17;45
15;65;65
16;32;23
4;14;7
23;17;Keine Daten verfügbar
67;Keine Daten verfügbar;45
15;24;12
Lesen von dieser CSV-Datei:
import pandas as pd
tab = pd.read_csv("test1.csv", sep=";")
print(tab)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Schreiben in eine CSV-Datei test2.csv:
import pandas as pd
val = pd.read_csv("test1.csv", sep=";")
val.to_csv("test2.csv", index=False)
Ausgabedatei:
Mai,Juni,Juli
12,17,45
15,65,65
16,32,23
4,14,7
23,17,Keine Daten verfügbar
67,Keine Daten verfügbar,45
15,24,12
Die Ausgabedatei ist beinahe gleich wie die Eingabedatei. Es werden aber Kommas statt Strichpunkten verwendet. Daher kommt auch der Name CSV ('''C'''omma '''S'''eparated '''V'''alue). Will man wieder Strichpunkte, so kann man dies über den Parameter <code>sep=";"</code> in der <code>to_csv</code>-Funktion machen.
Um direkt von einer ODS-Datei (LibreOffice Calc, '''O'''pen '''D'''ocument '''S'''preadsheet) zu lesen muss das Modul odfpy extra installiert sein (per YaST, pip etc.). Gelesen wird dann folgendermaßen:
import pandas as pd
df = pd.read_excel('test1.ods', engine='odf')
print(df)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Die Datei "test1.ods" sei die Datei, aus der das obige "test1.csv" generiert wurde. Schreiben kann man ebenfalls in eine ODS-Datei:
import pandas as pd
daten = {
"Name": ["Hugo", "Richie", "Wilhelmine"],
"Alter": [38, 30, 29],
"Ort": ["Linz", "Innsbruck", "Salzburg"]
}
tab = pd.DataFrame(daten)
with pd.ExcelWriter("test2.ods", engine="odf") as writer:
tab.to_excel(writer, sheet_name="Daten", index=False)
Es ergibt sich eine "test2.ods"-Datei (Screenshot):
[[Datei:IngPython_pandas2.png|250px]]
== Sonstiges ==
Hier seien stichpunktartig einige weitere Features von Pandas angeführt:
* {{W|Pivot-Tabelle|Pivot-Tabellen}} (pivot ... Dreh-, Angelpunkt): Zweck - große Datenmengen schnell zusammenfassen, filtern und analysieren.
* NaN ('''n'''ot '''a''' '''n'''umber): In einem Datensatz fehlt ein Wert oder ist nicht definiert.
* groupby-Funktion: Daten strukturieren, aggregieren oder Zwischensummen bilden.
* {{W|Binning#Datenverarbeitung_und_-analyse|Binning}}: Klassenbildung.
* Mehrstufige Indizierung (Hierarchical Indexing oder MultiIndex)
* Zeitreihen (Time Series)
Für tiefergehende und weiterführende Informationen wird auf das Buch von ''Klein: Numerisches Python; Hanser, 2023'' und [https://pandas.pydata.org/ pandas] verwiesen.
= Style Guide, flake8, pylint, Black etc. =
== Style Guide ==
Wie man schönen und richtigen Python-Code schreibt, erfahren Sie in
* [https://peps.python.org/pep-0008/ PEP 8 – Style Guide for Python Code]
== Formatter und Linter ==
Ein Modul, das prüft, ob die Richtlinien im Style Guide eingehalten wurden, ist ''flake8'':
* [https://flake8.pycqa.org/en/latest/ Flake8: Your Tool For Style Guide Enforcement]
Code formatieren kann man auch mit [https://pypi.org/project/black/ Black]. Z.B. übersetzt <code>black test1.py</code> die Datei <code>test1.py</code>
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)),
(2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
in
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)), (2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Die Programmausgabe ist
reformatted test1.py
All done! ✨ 🍰 ✨
1 file reformatted.
Der Unterschied zwischen Black und Flake8:
* Black ist ein Code-Formatter. Er formatiert Ihren Code um, sodass er im Einklang mit PEP 8 steht.
* Flake8 ist ein {{W|Lint (Programmierwerkzeug) | Code-Linter}}. Flake8 verändert Ihren Code nicht, sondern durchsucht ihn nach potenziellen Fehlern etc.
Am obigen Beispiel sieht man auch, dass flake8 und Black nicht immer einer Meinung sind. Flake8 (<code>flake8 test1.py</code>) würde standardmäßig den mit Black formatierten Code bemängeln:
test1.py:8:80: E501 line too long (80 > 79 characters)
Diese Diskrepanz kann beseitigt werden. Da 79 Zeichen auf modernen Bildschirmen meist als zu kurz empfunden werden, ist ein Limit von 88 Zeichen (Black-Standard) oder mehr empfehlenswert. Um dies zu implementieren, erstellen Sie in Ihrem Projektverzeichnis eine <code>.flake8</code>-Datei mit dem Inhalt
[flake8]
max-line-length = 88
Und schon ignoriert Flake8 dieses Problem.
Ein anderer Linter ist pylint. Der würde beim Abarbeiten des obigen Beispiels, z.B. mit <code>pylint test1.py</code> noch eine Kleinigkeit bemängeln:
************* Module test1
/home/hr/tmp/test1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)
Auch pylint muss vor der ersten Verwendung installiert werden (z.B. mittels pip, virtuelle Umgebung, YaST). Die Dokumentation zu pylint findet sich auf [https://pylint.readthedocs.io/en/latest/].
<u>Aufgabe:</u> Fügen Sie einen "module docstring" in die <code>test1.py</code>-Datei ein und testen Sie erneut mit flake8, Black und pylint. <small>Sehen Sie zum Thema docstrings auch [https://peps.python.org/pep-0257/#what-is-a-docstring PEP 257 – Docstring Conventions].</small>
Es gibt noch weitere Formatierungswerkzeuge für Python-Code. Z.B. [https://docs.astral.sh/ruff/ Ruff], ein moderner Code-Formatter und -Linter. Mittels <code>ruff check test1.py</code> würde obiger Code geprüft (Linter). <code>ruff format test1.py</code> formatiert den Code (Formatter).
== Type Checker ==
"Type Checker" sind z.B.
* mypy
* pyright
* ty
Diese prüfen die Datentypen, z.B. in folgendem Code
def greetings(name: str) -> str:
return "Hello, %s" % name
print(greetings(42))
Python selbst, flake8, ruff oder black würden diesen Code ohne zu murren akzeptieren. "Type Checker" würden aber sehr wohl Alarm schlagen, z.B. liefert <code>mypy</code> folgende Ausgabe
test1.py:5: error: Argument 1 to "greetings" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Das funktioniert übrigens nicht nur bei Funktionsannotationen, sondern auch mit Variablen etc.
from typing import Final
# "Konstante", ab Python 3.8
NUMBER: Final = 123
print(NUMBER)
NUMBER = 125
print(NUMBER)
# Variable
a: int = 345
print(a)
a = "Irgendwas"
print(a)
# Variable (Pipe-Symbol), ab Python 3.10
b : int|str = 567
print(b)
b = "sonstiges"
print(b)
Ausgabe mit python:
123
125
345
Irgendwas
567
sonstiges
Ausgabe mit mypy:
test3.py:6: error: Cannot assign to final name "NUMBER" [misc]
test3.py:12: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
Found 2 errors in 1 file (checked 1 source file)
Python kennt übrigens keine Konstanten. Man kann diese mittels Großbuchstaben andeuten. Das ist aber nur Konvention, hat aber keine sonstigen Auswirkungen. Oder man verwendet wie oben gezeigt <code>Final</code>. Dann werfen Typchecker Errors aus.
==pydoc==
pydoc ist ein Werkzeug, um Python-Module, -Funktionen und -Klassen zu dokumentieren.
Beispiel <code>test1.py</code>:
"""Rechen-Modul.
Funktionen die von pydoc gelesen werden.
"""
def multiply(a, b):
"""Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a * b
def add(a, b):
"""Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a + b
if __name__ == '__main__':
print(multiply(3, 5))
print(add(4, 6))
Ausgabe mit <code>python3.13 -m pydoc test1</code> auf der Konsole:
Help on module test1:
NAME
test1 - Rechen-Modul.
DESCRIPTION
Funktionen die von pydoc gelesen werden.
FUNCTIONS
add(a, b)
Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
multiply(a, b)
Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
FILE
/home/xyz/tmp/test1.py
Siehe zu diesem Thema z.B. auch [https://docs.python.org/3/library/pydoc.html]. Mittels <code>python3.13 -m pydoc -w test1</code> kann man auch eine HTML-Dokumentation erstellen.
Wofür <code>if __name__ == '__main__':</code> steht, siehe z.B. etwas später im Abschnitt [[Ing_Mathematik:_Python#Doctests]].
== Sonstige Tools ==
Andere Tools für die {{W|Statische Code-Analyse|statische Codeanalyse}}, die aber für Ingenieure weniger interessant sein dürften, sind z.B.
* Radon: Liefert verschiedene {{W|Softwaremetrik|Codemetriken}} (Komplexität, Wartbarkeitsindex ...)
* Bandit: Findet Sicherheitslücken
Tools für die {{W|Dynamisches Software-Testverfahren|dynamische Codeanalyse}}, z.B.:
* DynaPyt (Framework zur dynamischen Programmanalyse)
* cProfile (Profiler)
* Memory Profiler (Speicheranalyse)
* Memray (Speicheranalyse)
* tracemalloc (Speicheranalyse)
Paket- und Projektmanagement (pip-Ersatz etc.):
* uv
* Poetry
* Conda
* pipx
Packaging-Tools (Freezer) und {{W|Compiler#Sonderformen|Transpiler}} :
* pyinstaller
** erstellt eigenständige, ausführbare Binärdatei
** kein Cross-Compiler
** kein Schutz vor Reverse-Engineering
** langsam
** packt alles in eine Datei
** sehr große Datei
** Befehl, z.B.: <code>pyinstaller --onefile test1.py</code>
** GUI: <code>auto-py-to-exe</code>
* cx_Freeze
* nuitka
** Übersetzt Python-Code in C/C++-Code und weiter in eine ausführbare Datei
** kein Cross-Compiler
** Schutz vor Reverse-Engineering
** Befehl, z.B.: <code>nuitka --standalone --onefile test1.py</code>
* cython
= Einige Integrierte Entwicklungsumgebungen (IDEs)=
Werden Programmtexte größer und umfangreicher, so ist das Arbeiten mit der interaktiven Programmierumgebung bzw. das direkte Ausführen von Python-Skripten mühsam. Man wünscht sich z.B. Hilfen zum Debuggen oder die automatische Code-Vervollständigung. Zu diesem Zweck wurden IDEs (Integrated Development Environments) geschaffen. Von diesen seinen nachfolgend auszugsweise einige kurz beschrieben. Testen Sie einfach aus, welche davon für Sie bzw. für Ihr Python-Projekt geeignet sind.
== IDLE ==
IDLE ist die mit dem Python-Programmpaket mitgelieferte IDE. Der Name leitet sich einerseits ab vom Monty-Python-Mitglied Eric Idle, andererseits steht es als Abkürzung für "'''I'''ntegrated '''D'''evelopment and '''L'''earning '''E'''nvironment. IDLE ist einfach zu bedienen, bietet aber schon einen beachtlichen Leistungsumfang. Nachfolgend wird ein Screenshot zu IDLE geliefert. Rechts ist das Editor-Fenster zu sehen, links die interaktive Programmierumgebung. Um das Beispiel selbst nachvollziehen zu können, starten Sie IDLE. Das geht ähnlich, wie Sie die interaktive Programmierumgebung von Python starten (nur, dass Sie eben das IDLE-Icon doppelklicken und nicht das Python-Icon. Unter Linux geben Sie einfach in einem Terminal <code>idle3.13</code> o. Ä. ein). Weiter geht es mit "File - Open - ...". Die auszuführende Datei auswählen (im konkreten Fall ein "Hallo-Welt"-Programm). Es erscheint das rechte Fenster. Dort "Run - Run Module" auswählen. Und schon wird im linken Fenster "Hallo Welt!" ausgegeben.
[[Datei:PythonIng_idle1.jpg | 600px]]
Siehe auch {{W|IDLE}}.
== PyCharm ==
PyCharm ist ein kommerzielles Produkt. Es gab aber auch eine kostenlose Community Edition. Seit 2025 sind beide Varianten vereint. Für die ersten 30 Tage sind die Pro-Funktionen frei verfügbar, danach nur noch die Kernfunktionalitäten (oder man bezieht kostenpflichtig die Pro-Version). Zu beziehen ist PyCharm unter dem Weblink [https://www.jetbrains.com/pycharm/]. Nachfolgend ein etwas abgewandeltes "Hallo Welt"-Programm, editiert und ausgeführt mit PyCharm.
[[Datei:PyCharm_IDE_2023_screenshot.png | 600px]]
Siehe auch {{W|PyCharm}}.
== Eric ==
Auch eric ist Open Source und steht unter der GNU General Public License Version 3 oder später. Zu beziehen ist diese Software unter [https://eric-ide.python-projects.org/].
[[Datei:Screenshot_Eric_4.png | 600px]]
Siehe auch {{W|eric (Software)}}.
<small>
Unter openSUSE Tumbleweed sollte sich eric auch mit YaST installieren lassen. Bei mir gibt es aber dann beim Ausführen des eric-Programms eine Fehlermeldung (Stand März 2026):
...
ModuleNotFoundError: No module named 'PyQt6.QtPdfWidgets'
Umgehen kann man dieses Problem aber wieder mit dem Erstellen einer virtuellen Umgebung, in etwa so
python3.13 -m venv ~/tmp/venv1
cd ~/tmp/venv1/bin
./python3.13 -m pip install --upgrade --prefer-binary eric-ide
./eric7_ide
</small>
== PyScripter ==
Vom Funktionsumfang vergleichbar mit den vorherigen IDEs ist PyScripter. Auch PyScripter ist Open Source. Die Projekt-Homepage findet sich auf [https://sourceforge.net/projects/pyscripter/]. PyScripter ist nur für MS Windows verfügbar.
[[Datei:PythonIng_pyscripter1.jpg | 600px]]
== Spyder IDE ==
Spyder enthält bereits eine stabile Python-Version und etliche Module (z.B. matplotlib, numpy, control). Ansonsten kann dieses Softwarepaket vom Funktionsumfang her mit den anderen genannten IDEs locker mithalten. Spyder wurde unter der MIT-Lizenz veröffentlicht. Diese Software findet sich auf [https://www.spyder-ide.org].
[[Datei:Spyder-windows-screenshot.png | 600px]]
Siehe auch {{W|Spyder (Software)}}
== Eclipse IDE==
Die {{W|Eclipse_(IDE)|Eclipse-IDE}} kann für Python aufgerüstet werden. Dazu gibt es das PyDev-Plugin. Installiert wird es über
* Help > Eclipse Marketplace...
* Find - PyDev - Install
Danach muss noch der Pfad zum Python-Interpreter festgelegt werden
* Window > Preferences > PyDev > Interpreters > Python Interpreter > New ...
Das Ergebnis ist ähnlich wie im folgenden Bild, nur dass statt C/C++ Python Verwendung findet.
[[Datei:Setting Up Eclipse CDT helloout.png | 600px]]
== Sonstige ==
Die genannten IDEs sind nicht die Einzigen. Es gibt, um dem Image Pythons als beliebteste Programmiersprache gerecht zu werden, noch einige andere. Sowohl Open Source-Programme als auch kommerzielle Programme sind im Web zu finden, z.B. Thonny oder {{W|Visual Studio Code}}. Unter Linux kann man auch {{W|KDevelop}}, ausgestattet mit dem Python3-Plugin, einsetzen. Braucht man den Umfang von ausgewachsenen IDEs nicht, so kann man auch normale Texteditoren verwenden (z.B. {{W|Geany}} oder {{W|Kate_(Texteditor)|Kate}}).
= Debuggen und Testen =
Das Debuggen und Testen von Programmen sind wichtige Bestandteile der Programmierung. Syntaxfehler lassen sich i.A. leicht beheben. Schwieriger ist das Eingrenzen von logischen Fehlern, die ev. nur in bestimmten Situationen auftreten und keine explizite Fehlermeldung hervorrufen. Das Programm liefert falsche Ergebnisse oder es stürzt aus heiterem Himmel ab. Um das zu verhindern gibt es verschiedene Werkzeuge, die bei der Fehlersuche behilflich sein können. Vorerst siehe aber zwecks Begriffsklärung noch folgende Links:
* {{W|Debuggen}}
* {{W|Debugger}}
* {{W|Softwaretest}}
<gallery>
First Computer Bug, 1947.jpg
Test ganzheitlich.png
V-Modell.svg
</gallery>
== Das Modul pdb ==
Python bringt schon ein Modul zum Debuggen mit. Siehe z.B. [https://docs.python.org/3/library/pdb.html pdb — The Python Debugger].
Komfortabler lässt sich das aber mittels Integrierter Entwicklungsumgebungen (IDEs) angehen.
== Debuggen mit IDEs ==
Für die IDEs IDLE und Spyder sei kurz auf die entsprechenden Webseiten verwiesen:
* [https://www.cs.uky.edu/~keen/help/debug-tutorial/debug.html Debugging under IDLE].
* [https://docs.spyder-ide.org/current/panes/debugging.html Spyder Debugger]
Dort wird die Vorgehensweise auch mittels Screenshots erläutert.
== assert ==
assert ... behaupten, zusichern ({{W|Assertion (Informatik)}})
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10., 0.)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10., 0.)
File "/home/hr/Develop/test1.py", line 4, in print1
assert y != 0.0
^^^^^^^^
AssertionError
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1("10.", "5.")
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Aber auch bei nachfolgendem Code gibt es eine Fehlermeldung:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10, 5)
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Damit letzteres funktioniert, kann man den Programmcode so umschreiben:
def print1(x, y):
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
2.0
Und jetzt fangen wir den <code>AssertionError</code> auf:
def print1(x, y):
try:
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
except(AssertionError):
print("Hallo")
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Hallo
Ich hoffe, es ist wenigstens im Ansatz klar geworden, wofür <code>assert</code> gut sein kann. Ausschalten kann man die <code>assert</code>-Überprüfung übrigens mit dem Python-Schalter <code>-O</code>.
== Doctests ==
Innerhalb eines Docstrings kann die Arbeit im interaktiven Modus simuliert werden. Nach den Promptzeichen (>>>) erfolgen dann bei unserem Beispiel innerhalb des Docstrings simulierte Aufrufe der Funktion <code>print1()</code>. Danach folgen jeweils die Sollresultate. Wird das Modul oder die Datei als Hauptprogramm aufgerufen, so wird die Funktion <code>doctest.testmode()</code> aufgerufen und ein Bericht auf der Konsole ausgegeben. Wird das Modul nicht als Hauptprogramm aufgerufen, sondern importiert, dann wird diese <code>testmod</code>-Funktion nicht aufgerufen. D.h. dieser Code kann sowohl für Testzwecke als auch für den produktiven Einsatz verwendet werden. Das ist auch sinnvoll, weil wenn man Teile der Datei immer löschen bzw. einfügen müsste, so würden sich Fehlerquellen auftun. Das würde den Sinn und Zweck von Doctests konterkarieren.
def print1(x=0., y=1.):
""" Dividiere zwei Zahlen
Autor: Intruder
Datum: 12.08.2025
>>> print1(2., 1.)
2.0
>>> print1(5., 2.)
2.5
>>> print1(5.)
5.0
"""
print(x/y)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Ausgabe:
Trying:
print1(2., 1.)
Expecting:
2.0
ok
Trying:
print1(5., 2)
Expecting:
2.5
ok
Trying:
print1(5.)
Expecting:
5.0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.print1
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Das gezeigte Beispiel ist so ziemlich das einfachste, das es gibt. Für weiterführende Details siehe z.B.:
* [https://peps.python.org/pep-0257/ PEP 257 – Docstring Conventions]
* [https://docs.python.org/3/library/doctest.html doctest — Test interactive Python examples]
''Einschub:'' Ganz ähnlich kann man auch Klassen testen, z.B. in folgendem Code-Fragment
class Fahrzeug:
# siehe Abschnitt "Objektorientierte Programmierung"
# ...
if __name__ == "__main__":
vauweh = Fahrzeug(170, 90)
beemweh = Fahrzeug(200, 120)
print(vauweh.convertGeschw())
print(beemweh.convertGeschw())
Wird das Script als Hauptprogramm ausgeführt (z.B. zu Testzwecken), so erfolgt die Ausgabe der zwei, via <code>convertGeschw()</code>, umgerechneten Geschwindigkeiten. Wird es aber als Modul eingebunden, so wird der letzte Programmabschnitt nicht ausgeführt (<code>__name__ == "__main__"</code> ergibt <code>False</code>).
== pytest ==
Siehe zu diesem Thema auch {{W|Modultest}}.
pytest ist ein externes Modul und muss vorab installiert werden, z.B. mittels
pip install -U pytest
pip install -U pytest-html
Python-Code, Datei test1.py:
def add(x, y):
return x + y
def test_answer():
assert add(1, 1) == 3
Starten von pytest in der Konsole:
pytest test1.py
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py F [100%]
========================================================= FAILURES ==========================================================
________________________________________________________ test_answer ________________________________________________________
def test_answer():
> assert add(1, 1) == 3
E assert 2 == 3
E + where 2 = add(1, 1)
test1.py:6: AssertionError
================================================== short test summary info ==================================================
FAILED test1.py::test_answer - assert 2 == 3
===================================================== 1 failed in 0.09s =====================================================
Hier erhalten wir einen Fehler, da 1+1 eindeutig ungleich 3 ist. Aber aus irgendeinem Grund wollte der Programmierer oder Tester in diesem Fall, dass dies so ist. Testfälle werden übrigens mit dem Präfix <code>test_</code> eingeleitet.
Python-Code:
def add(x, y):
return x + y + 1
def test_answer():
assert add(1, 1) == 3
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py . [100%]
===================================================== 1 passed in 0.01s =====================================================
Jetzt ist alles in Ordnung. Weiterführendes siehe z.B.
* [https://docs.pytest.org/en/stable/ pytest: helps you write better programs]
== unittest ==
Auch unittest dient zur Durchführung von Testreihen, ist aber Bestandteil von Python. Hier wird vorerst nicht näher darauf eingegangen. Siehe z.B.
* [https://docs.python.org/3/library/unittest.html unittest — Unit testing framework]
Lt. ''Inden: Python Challenge; dpunkt, 2021, Seite 481'' soll unittest weniger komfortabel als pytest sein.
Einen Vergleich von unittest mit pytest findet man in
* [https://knapsackpro.com/testing_frameworks/difference_between/pytest/vs/unittest pytest vs unittest]
= Python und Anwendungsprogramme =
Bisher stand immer alleine die Programmiersprache Python (ev. unter Einbeziehung von Modulen) im Mittelpunkt der Betrachtungen. Aber Python kann auch als Makrosprache für Anwendungsprogramme auftreten. Als Beispiele seien {{W|FreeCAD}} und {{W|LibreOffice}} genannt.
== FreeCAD ==
FreeCAD ist ein freies 3D-CAD-Programm. Hier soll nicht auf die Bedienung dieses CAD-Pakets eingegangen werden, sondern nur auf die Möglichkeit, mittels Python Makros zu schreiben. Als einfacher Einstieg soll ein Makro erstellt werden, welches eine Kugel (rot) und einen Quader (blau) zeichnet. Folgende Vorbereitungsschritte sind erforderlich (es sei vorausgesetzt, dass FreeCAD schon am Rechner installiert ist. Downloaden können Sie das Programm von der Website [https://www.freecad.org/downloads.php?lang=en]):
* FreeCAD starten
* Leere Datei erstellen
* Makro > Makros > Erstellen ...
Es öffnet sich ein leeres Editorfenster, in das Sie folgenden Code eingeben können:
import FreeCAD
import Part
doc = FreeCAD.newDocument()
# Kugel
kugel = Part.makeSphere(10)
form_element = doc.addObject("Part::Feature", "Kugel")
form_element.Shape = kugel
kug = FreeCAD.ActiveDocument.getObject("Kugel")
kug.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
neuePosition = App.Vector(5, 2.5, 2.5)
kug.Placement = App.Placement(neuePosition, kug.Placement.Rotation)
# Quader
quader = Part.makeBox(5, 5, 50)
form_element = doc.addObject("Part::Feature", "Quader")
form_element.Shape = quader
quad = FreeCAD.ActiveDocument.getObject("Quader")
quad.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
doc.recompute()
Diesen Code können Sie nun ausführen:
* Makro > Makro ausführen
Es ergibt sich folgende Ausgabe (gedreht und gezoomt):
[[Datei: PythonIng_freecad1.png|500px]]
Siehe auch [https://wiki.freecad.org/Python_scripting_tutorial/de# Anleitung Skripterstellung mit Python]. Getestet wurde obiges Beispiel mit FreeCAD 1.1.3 unter Linux und 1.1.1 unter MS Windows.
== LibreOffice ==
LibreOffice ist ein freies Officepaket ([https://de.libreoffice.org/]). Hier soll nur das Tabellenkalkulationsprogramm Calc kurz betrachtet werden. Es seinen in den ersten 3 Zellen (A1 bis A3) Zahlen gegeben. Diese sollen mit einem Python-Makro addiert und das Resultat in der Zelle A5 ausgegeben werden. Auch hier sind Vorbereitungsarbeiten nötig:
* zuerst muss unter Linux das Verzeichnis <code>~/.config/libreoffice/4/user/Scripts/python</code> erstellt werden
* für MS Windows ist es das Verzeichnis <code>%APPDATA%\LibreOffice\4\user\Scripts\python</code>
** drücken Sie zuerst Win + R (es öffnet sich das Ausführen-Fenster)
** geben Sie <code>%appdata%</code> ein, danach drücken Sie Enter (es öffnet sich der Explorer)
** navigieren Sie zu dem genannten Verzeichnis bzw. erstellen Sie das Verzeichnis
* in diesem Verzeichnis wird dann mit einem beliebigen Texteditor das Python-Makro erstellt, in unserem Fall die Datei <code>summiere_zellen.py</code>:
import uno
def summiere_zellen(*args):
# Zugriff auf das aktuelle Dokument und das aktive Tabellenblatt
ctx = uno.getComponentContext()
smgr = ctx.getServiceManager()
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.getCurrentController().getActiveSheet()
# Werte aus den Zellen A1 bis A3 auslesen
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
# Addition der drei Werte
summe = w1 + w2 + w3
# Ergebnis in die Zelle A5 schreiben
sheet.getCellRangeByName("A5").Value = summe
* siehe dazu ggf. auch [https://help.libreoffice.org/latest/de/text/sbasic/python/python_locations.html?DbPAR=BASIC].
Weiter geht es in LibreOffice Calc mit dem Menü ''Extras > Makros > Makros verwalten > Python''. Dort wird das Makro <code>summiere_zellen</code> ausgeführt. Es ergibt sich z.B. folgendes Resultat
[[Datei:PythonIng_libreoffice1.png]]
Das Kürzel <code>uno</code> steht für '''U'''niversal '''N'''etwork '''O'''bjects. Etwas einfacher geht's auch so:
def summiere_zellen():
desktop = XSCRIPTCONTEXT.getDesktop()
model = desktop.getCurrentComponent()
sheets = model.getSheets()
sheet = sheets.getByIndex(0)
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
cell = sheet.getCellRangeByName("A5")
cell.setValue(w1 + w2 + w3)
Empfohlen wird auch, das Erweiterungspaket APSO ('''A'''lternative '''P'''ython '''S'''cript '''O'''rganizer, apso.oxt) zu installieren. Die Vorgehensweise wird hier nicht gezeigt, sondern nur darauf hingewiesen, dass man das einfach "googeln" kann. Siehe zur Python-Programmierung für LibreOffice auch [https://wiki.documentfoundation.org/Macros/Python_Guide/de Makros/Python-Handbuch]. Getestet wurden obige Beispiele mit LibreOffice 26.2.5.1 unter Linux und 26.2.1.2 unter MS Windows.
= Ausblick =
Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Python. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks, Bücher und die Python-Hilfefunktion verwiesen. Python kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Module fast beliebig erweiterbar.
= Weblinks=
== Python allgemein ==
* [https://www.python.org/ Python Homepage]
== Externe mathematische Module ==
* [https://numpy.org/ NumPy]
* [https://numpy.org/doc/stable/user/numpy-for-matlab-users.html NumPy for MATLAB users]
* [https://scipy.org/ SciPy]
* [https://www.sympy.org/en/index.html SymPy]
* [https://pandas.pydata.org/ pandas]
* [https://github.com/maroba/findiff findiff]
* [https://mpmath.org/ mpmath]
== Externe Module für Grafiken ==
* [https://matplotlib.org/ Matplotlib]
* [https://vpython.org/ VPython]
* [https://build123d.readthedocs.io/en/latest/ build123d]
* [https://docs.vtk.org/en/latest/api/python.html VTK]
* [https://docs.bokeh.org/en/latest/docs/first_steps.html bokeh]
* [https://py5coding.org/ py5]
== Erstellung von User Interfaces ==
* [https://docs.python.org/3/library/tkinter.html tkinter - Python interface to Tcl/Tk]
* [https://docs.python.org/3/library/curses.html curses - Terminal handling for character-cell displays]
* [https://wiki.qt.io/Qt_for_Python Qt for Python]
* [https://www.gtk.org/docs/language-bindings/python GTK and Python]
== Erstellen virtueller Umgebungen ==
* [https://docs.python.org/3/library/venv.html venv - Creation of virtual environments]
== Sonstige ==
* [https://python-control.readthedocs.io/en/stable/ Python Control Systems Library]
* [https://pypi.org/project/regex/ regex - Regular Expressions]
* [http://pyromat.org/ PYroMat]
* [https://coolprop.org/coolprop/wrappers/Python/index.html CoolProp]
* [https://pypi.org/project/iapws/ iapws]
* [https://tespy.readthedocs.io/en/main/getting_started/introduction.html TESPy - Thermal Engineering Systems in Python]
* [https://pint.readthedocs.io/en/stable/ pint]
= Bücher =
== Gedruckte Bücher, OpenBooks, Magazine ==
* Diverse: c't Python Lernen, Verstehen, Anwenden; Heise, 2022
* Ernesti, Kaiser: Python3 - das umfassende Handbuch; 5. Aufl., Rheinwerk, [https://openbook.rheinwerk-verlag.de/python/ OpenBook]
* Iacono et al.: Programmieren trainieren; 3. Aufl., Hanser, 2023, ISBN 978-3-446-47766-7
* Inden: Python Challenge; dpunkt, 2021, ISBN 978-3-86490-809-5
* Klein: Numerisches Python; 2. Aufl., Hanser, 2023, ISBN 978-3-446-47170-2
* Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler; Rheinwerk, 2021, ISBN 978-3-8362-7316-9
* Weigend: Python 3 - Das umfassende Praxisbuch; 9. Aufl., mitp, 2022, ISBN 978-3-7475-0544-1
* Woyand: Python für Ingenieure und Naturwissenschaftler; 4. Aufl., Hanser, 2021, ISBN 978-3-446-46483-4
== Andere Wikibooks ==
* [[:en:Subject:Python_programming_language | Englische Wikibooks zum Thema Python]]
* [[Python|Deutschsprachiges Python-Wikibook]] [[Bild:2von10.png|20%]]
* [[Python unter Linux|Python 2.7 unter Linux]] [[Bild:10von10.png|100%]]
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
nytshhidtttzvokil5vyjvh6r4ki387
1091906
1091905
2026-10-04T09:45:03Z
Intruder
1513
/* Py5 */ Aufgabe hinzu
1091906
wikitext
text/x-wiki
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
= Hallo Welt und allgemeine Hinweise =
== Was ist Python ==
* Python ist eine universelle höhere Programmiersprache.
* Python ist objektorientiert.
* Python ist Open-Source (Python Software Foundation License).
* Python ist für viele Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
* Python ist ein Interpreter.
* Python ist durch Module fast beliebig erweiterbar.
* Python als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
* Python ist in etlichen Anwendungsprogrammen (z.B. {{W|FreeCAD}}, {{W|LibreOffice}}, {{W|GIMP}}, {{W|Blender (Software) | Blender}}) als Makrosprache verwendbar.
{{Wikipedia | Python (Programmiersprache)}}
== Python installieren ==
=== MS Windows ===
Laden Sie das aktuelle Python-Paket von der Webseite [https://www.python.org/] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.
=== Linux ===
Entweder ist Python bereits standardmäßig installiert, ansonsten ist die Installation mittels Paketmanagementsystem einfach möglich. Aber auch die Spyder-Entwicklungsumgebung ([https://www.spyder-ide.org]) bietet einen guten Einstieg mit Python (das gilt auch für MS Windows). Spyder bringt auch schon etliche wichtige Module standardmäßig mit.
== Python starten ==
=== MS Windows ===
Das Icon für das Python-Programm doppelklicken. Und schon startet das Programm.
[[Datei:PythonIng_start1.jpg]]
Python im interaktiven Modus präsentiert sich dann so:
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Alternativ kann das Programm auch über die Eingabeaufforderung oder die PowerShell gestartet werden:
c:\devel\Python>python.exe
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
=== Linux ===
Tippen Sie einfach das Wort „python“ (oder unter openSUSE Tumbleweed z.B. auch „python3.11“ oder „python3.13“) in einem Linux-Terminal ein, schließen den Befehl mit der RETURN-Taste ab, und schon startet Python im interaktiven Modus:
Python 3.13.12 (main, Feb 09 2026, 22:37:44) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Es gibt auch noch andere Möglichkeiten Python zwecks Programmausführung zu starten, z. B. den {{W|Shebang}} (<code>#!</code>) am Beginn eines Python-Scripts. Das Script sei als Script.py gespeichert. Dann kann das Script mit ./Script.py ausgeführt werden. Für openSUSE Tumbleweed sei nachfolgend ein lauffähiges "Hallo Welt!"-Script angegeben. Es wird in diesem Script der Python-Interpreter in der Version 3.13 verwendet :
#!/usr/bin/python3.13
print("Hallo Welt!")
Die Berechtigungen zum Ausführen der Datei müssen natürlich noch richtig gesetzt werden, z.B. mittels <code>chmod 777 Script.py</code>. <small><code>chmod</code> ist die Abkürzung für"'''ch'''ange file '''mod'''e bits".</small>
<small>Die "Maske" <code>777</code> ist nur für Testzwecke sinnvoll, weil sie leicht zu merken ist und für alle Benutzer alle Zugriffsberechtigungen ('''r'''ead/'''w'''rite/e'''x'''ecute für owner/group/others) setzt. Im richtigen Einsatz wird man das aus Sicherheitsgründen nicht so handhaben, sondern nur die Berechtigungen setzen, die unbedingt erforderlich sind. Welche Zugriffsberechtigungen gesetzt sind, kann man z.B. mit dem Befehl <code>ls -l</code> oder <code>ll</code> ('''l'''i'''s'''t directory contents) erfragen. Aber dazu im Moment genug. Erfahrene Linux-Nutzer kennen das ohnehin und Anfänger sollen jetzt nicht mit Linux-Interna überfordert werden. Bei Bedarf siehe die Linux-Man-Pages oder dezidierte Bücher zu Linux.</code></small>
<small>Oder das Script wird in einen Pfad verschoben, in dem sich ausführbare Programme generell befinden (welche Verzeichnisse im PATH liegen, kann bspw. mit <code>echo $PATH</code> abgefragt werden). Das Script kann dann wie ein normales Programm ohne weitere Angaben mit Script.py gestartet werden. Alternativ wird nicht das Script an sich verschoben, sondern nur ein symbolischer Link angelegt, z.B. mit <code>ln -s ~/tmp/Script.py ~/.local/bin/Script.py</code>. <code>~/.local/bin</code> sei ein im PATH gelegenes Verzeichnis. Dies sind aber schon Features für fortgeschrittene Linux-Benutzer und werden am Anfang eher selten benötigt.</small>
== Ein paar Worte zur Erklärung ==
=== Tests ===
Getestet wurden die Beispiele unter den Betriebssystemen
* MS Windows 10 mit der Python-Version 3.12.0 (teilweise auch mit 3.12.2 und 3.13.1; nur die Inhalte die bis spätestens Juli 2025 erstellt wurden)
* MS Windows 11 ab der Python-Version 3.13.4 (nur zum Teil; ab Juli 2025)
* openSUSE Leap 15.6 mit der Python-Version 3.11.12 (Spyder, nur vereinzelt) und zum Teil mit 3.12.11 (ab Juli 2025 bis November 2025).
* openSUSE Tumbleweed ab der Python-Version 3.13.9 (nur vereinzelt, ab November 2025)
=== Popularität ===
* An Beliebtheit rangiert Python mit Stand September 2026 mit einem Rating von 17,76% an 1. Stelle vor C und C++ (lt. [https://www.tiobe.com/tiobe-index/ TPCI - TIOBE Programming Community Index]).
* Lt. [https://innovationgraph.github.com/global-metrics/programming-languages GitHub Top 50 Programming Languages Globally] lag Python im Q1/2026 auf Rang 2, vor TypeScript und hinter JavaScript.
* [https://pypl.github.io/PYPL.html PYPL] (Popularity of Programming Language Index) ist ein anderer Popularitätsindex für Programmiersprachen. Auch hier liegt Python mit großem Vorsprung auf dem ersten Platz (52,08%), gefolgt von Java (13,34%) und C/C++ (7,99%) (Stand September 2026).
=== Namensgebung ===
Der Name "Python" rührt von der Komikertruppe {{W|Monty Python}} her. Die Icons für Python (z.B. Python selbst, Eric IDE, IDLE) sind aber durch die Python-Schlangenart symbolisiert.
<gallery>
Python-logo-notext.svg|Python-Logo
Guido van Rossum in PyConUS24.jpg|{{W|Guido van Rossum}} (geb. 1956), der Erfinder von Python
</gallery>
== Ein erstes Programm ==
Kommentare werden in Python mit der Raute (#) eingeleitet. Sie werden vom Python-Interpreter ignoriert. Text kann mit der print-Funktion ausgegeben werden. Starten Sie Python und geben sie folgende Anweisungen zeilenweise ein
>>> # Das ist ein Kommentar
>>> print("Hallo Welt!")
Als Ergebnis erhalten Sie
Hallo Welt!
Der Prompt (>>>) ist selbstverständlich nicht einzutippen, sondern wird vom Python-System geliefert.
Strings können in Python entweder in Anführungszeichen (") gesetzt werden oder in Hochkommatas('). In diesem Text wird die erste Variante bevorzugt eingesetzt.
Im Gegensatz zu Julia ist es hier egal, ob zwischen <code>print</code> und der öffnenden Klammer Leerzeichen stehen.
= Python als Taschenrechner =
== Allgemeines ==
Wir wollen 3 * 5 berechnen. Dazu starten wir Python im interaktiven Modus. Geben Sie dann die Formel
>>> 3 * 5
ein, drücken die Taste ENTER/RETURN ({{Taste|↵}}) und erhalten als Ergebnis
15
Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck <math>\sin\sqrt{15}</math> berechnen :
>>> import math
>>> math.sin(math.sqrt(15))
-0.6679052983383519
Als erstes wird das math-Modul importiert. Dann wird der mathematische Ausdruck berechnet.
Eine andere Variante, die dasselbe Ergebnis liefert, ist
>>> from math import *
>>> sin(sqrt(15))
-0.6679052983383519
Es wird also aus dem Modul <code>math</code> alles importiert (erkennbar am <code>*</code>). Will man nicht alles importieren, so kann man das auch einschränken:
>>> from math import sin, sqrt
Beenden lässt sich das Python-Programm durch Eingabe von <code>exit()</code> (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken).
== Die Hilfefunktion von Python ==
Bei Eingabe der Anweisung <code>help</code> oder <code>help()</code> springt Python in den Hilfemodus.
Eingabe:
>>> help()
Eingabe:
help> math.sin
Ausgabe:
Help on built-in function sin in math:
math.sin = sin(x, /)
Return the sine of x (measured in radians).
Für die komplette Python-Dokumentation siehe [https://docs.python.org/3/]. Verlassen kann man den Hilfemodus durch das Drücken von STRG-C, bzw. der Eingabe von q, quit oder exit mit anschließendem Drücken der RETURN-Taste.
== Aufgaben ==
* Erkunden Sie die Tangensfunktion "tan" mittels Python-Hilfe (vergessen Sie nicht das math-Modul zu importieren und das <code>math.</code> vor <code>tan</code>)
* Berechnen Sie mit Python den Ausdruck <math>\frac{1}{2}\cdot \text{e}^2 \cdot \tan(\pi/3)</math>. Siehe für die Exponentialfunktion im Python-Hilfesystem auch den Befehl <code>math.exp</code>. Alternativ kann auch die Konstante <code>math.e</code> eingesetzt werden. Potenzieren kann man bei Python mit dem **-Operator (z.B. 2**3 = 8). Für <math>\pi</math> gibt es <code>math.pi</code>.
= Python als Scriptsprache =
Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.py
# Das ist ein Kommentar
print("Hallo Welt!")
Python-Dateien werden mit der Dateiendung .py versehen. Achten Sie darauf, dass vor dem print keine Leerzeichen vorhanden sind. Das ist eine Python-Eigenheit. Wie wir später sehen werden, nutzt Python Einrückungen als syntaktisches Mittel, z.B. um bei Schleifen den Schleifenkörper zu kennzeichnen.
Danach bringen Sie die Skriptdatei test1.py (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:
1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ auch die Windows PowerShell). Das sieht dann etwa so aus:
Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\xyz>
: <small>Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol ([[Image:Windows_logo_-_2021_(Black).svg|10px]]) mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell unter Windows 10 den Eintrag "Windows PowerShell", unter Windows 11 den Eintrag "Terminal"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort <code>cmd</code> ein und mit "OK" wird das Ganze bestätigt.</small>
2) Wechseln Sie mittels <code>cd c:\tmp</code> in das Verzeichnis c:\tmp
3) Angenommen, Sie haben Python unter dem Pfad <code>c:\devel\Python\</code> installiert. Starten Sie das Programm so (der Prompt <code>c:\tmp></code>ist natürlich nicht mit einzutippen):
c:\tmp>c:\devel\Python\python.exe test1.py
4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm
Hallo Welt!
Die Vorgehensweise unter Linux ist prinzipiell gleich. Die kleinen Unterschiede, wie z.B. der Slash statt dem Backslash in Pfadangaben, sollten für Linux-Benutzer keine Hürde darstellen.
== Variablen ==
Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9) und Underscores (_) bestehen, dürfen aber nicht mit einer Zahl beginnen. Führende Underscores haben u.a. im Kontext mit der Objektorientierten Programmierung eine spezielle Bedeutung und sollten nicht für "normale" Variablenbezeichner verwendet werden.
Gültige Variablenbezeichner wären also:
xyz
x1
_wert
name_anzahl
Theoretisch kann man auch Umlaute, griechische Buchstaben u.ä. in Variablenbezeichnern nutzen, z.B.
ößÜ = 16
α = 134
print(ößÜ)
print(α)
Ausgabe:
16
134
Davon wird aber aus offensichtlichen Gründen ({{W|Englisch als Lingua franca}}) abgeraten. Das Eurozeichen (€) etc. darf man ohnehin nicht in Variablenbezeichnern verwenden, dies ergäbe einen Syntaxfehler. Siehe dazu auch [https://peps.python.org/pep-3131/].
Es gibt in Python etliche Schlüsselwörter (z.B. for, if oder return). Diese dürfen nicht als eigene Variablenbezeichner verwendet werden. Eine Liste aller Schlüsselwörter liefert das Script
import keyword
print(keyword.kwlist)
<small>Übung: Speichern Sie dieses Script in eine Datei, z.B. in c:\tmp\test1.py. Führen Sie diese Datei aus, um die Liste der Schlüsselwörter auszugeben.</small>
Da Python case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:
xyz
XYZ
xYz
Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.py gespeichert.
x = 5
y = 10
z = x*y
print(z)
Bringen Sie die Datei test1.py zur Ausführung, so erhalten Sie folgende Bildschirmausgabe
50
Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben. Dies führt aber zu unübersichtlichem Code.
x = 5; y = 10; z = x*y; print(z)
Ausgabe:
50
Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.
x = 5
# x = x - 2
x -= 2
print(x)
Bildschirmausgabe:
3
Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Den Inkrement-/Dekrementoperator (z.B. x++ oder x--) aus C/C++ oder Java kennt Python aber nicht.
Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Python problemlos möglich:
import math
wert = 10
print(wert)
wert = 35.5
print(wert)
wert = "Hallo"
print(wert)
wert = math.pi
print(wert)
Ausgabe:
10
35.5
Hallo
3.141592653589793
== Physische und logische Zeilen ==
In Python muss eine Anweisung in einer logischen Zeile Platz finden. Wird eine Anweisung aber zu lang für eine Zeile, dann kann sie in mehrere physische Zeilen unterteilt werden. Dies kann einerseits durch einen Backslash am Ende einer Zeile geschehen, z.B.
a = 2 + \
5
Dies stellt eine logische Zeile dar, die in zwei physische Zeilen unterbrochen ist.
Geklammerte Ausdrücke werden automatisch zu einer logischen Zeile verbunden, z.B.
a = (2 +
5)
Achtung: Im ersten Beispiel darf nach dem Backslash nichts mehr stehen, auch kein Kommentar. Dies trifft im zweiten Bespiel nicht zu, hier könnte noch ein Kommentar folgen, z.B.
a = (2 + # Kommentar
5)
Auch für Strings gibt es Möglichkeiten, diese auf mehrere Zeilen aufzuspalten.
# Kurzer String
str1 = "ABC"
# Langer String
str2 = """Hallo Welt,
Grüetzi Schwyzer,
Servus an alle"""
# Backslash
str3 = "UVW\
XYZ"
# Mit Klammern
str4 = ("Sehr langer Text, der automatisch .............. "
"in einer einzigen Variable zusammengefügt wird."
)
print(str1)
print(str2)
print(str3)
print(str4)
Ausgabe:
ABC
Hallo Welt,
Grüetzi Schwyzer,
Servus an alle
UVWXYZ
Sehr langer Text, der automatisch .............. in einer einzigen Variable zusammengefügt wird.
==Hexadezimale, oktale, binäre und andere Zahlen==
d = 1050 # Dezimalzahl
h = 0xAA2 # Hexadezimalzahl
o = 0o12 # Oktalzahl
b = 0b100001101 # Binärzahl
print(d)
print(h)
print(o)
print(b)
Ausgabe:
1050
2722
10
269
Groß- und Kleinbuchstaben sind in obigen Literalen übrigens egal. So kann man z.B. statt <code>0b1001</code> auch <code>0B1001</code> schreiben (siehe dazu [https://docs.python.org/3/reference/lexical_analysis.html#integer-literals]).
Sie können auch dezimale in hexadezimale Zahlen umwandeln, usw.:
h = hex(1050) # Dezimalzahl -> Hexadezimalzahl
b = bin(1050) # Dezimalzahl -> Binärzahl
o = oct(1050) # Dezimalzahl -> Oktalzahl
print(h)
print(b)
print(o)
Ausgabe:
0x41a
0b10000011010
0o2032
Gegeben sei die Zahl 121 zur Basis 3. Diese soll in eine Dezimalzahl umgewandelt werden. Das kann so geschehen:
z = int("121", 3)
print(z)
Ausgabe:
16
Dass dies richtig ist, davon kann man sich folgendermaßen überzeugen:
<math> 1 \cdot 3^2 + 2 \cdot 3^1 + 1 \cdot 3^0 = 9 + 6+ 1 = 16 </math>
Zahlen übersichtlicher schreiben kann man auch mittels Underscore, z.B.:
print("Eine Million (Variante 1) =", 1000000)
print("Eine Million (Variante 2) =", 1_000_000)
print("Eine Rechnung:", 2_000 * 400_000);
Es ergibt sich bei beiden Varianten die gleiche Ausgabe. Variante 2 ist aber im Sourcecode leichter lesbar, detto die Zahlen in der Rechnung:
Eine Million (Variante 1) = 1000000
Eine Million (Variante 2) = 1000000
Eine Rechnung: 800000000
== Strings und Platzhalter==
Ein paar einfache Beispiele:
print("Hallo {}" . format("Hugo"))
print("Hallo {:s}" . format("Hugo"))
print("Hallo %s" % "Hugo")
Ausgabe:
Hallo Hugo
Hallo Hugo
Hallo Hugo
Python-Code (formatted string literals, Beispiel 1):
str1 = "Hallo"
str2 = "Hugo"
print(f"{str1} {str2}")
Ausgabe:
Hallo Hugo
Python-Code (formatted string literals, Beispiel 2):
wert = 11.567
print(f"Ausgabe: {wert:.5f}")
Ausgabe:
Ausgabe: 11.56700
Komplexere Beispiele:
print("Hallo {} und {}" . format("Hugo", "Mike"))
print("Hallo {name1} und {name2}" . format(name2="Hugo", name1="Mike"))
# Füllzeichen: *
# Bündigkeit: > (=rechts), < (=links), ^ (=zentriert)
# Feldweite: 10
# Typ: s (=String), f (=Gleitkommazahl), d (=Dezimalzahl) etc.
print("Hallo {:*>10s}" . format("Hugo"))
print("Hallo {:*<10s}" . format("Hugo"))
Ausgabe:
Hallo Hugo und Mike
Hallo Mike und Hugo
Hallo ******Hugo
Hallo Hugo******
Python-Code:
str = "Hallo\t%s\t%7.2f\t%10.2e\t%i" % ("Hugo", 12.34567, 34.567, 264)
print(str)
Ausgabe:
Hallo Hugo 12.35 3.46e+01 264
== Unicode ==
Neben den bekannten ASCII-Zeichen lassen sich Zeichen auch mittels Unicode beschreiben. Griechische Buchstaben oder komplexere mathematische Operatoren - all das sollte kein Problem sein. Siehe auch {{W|Unicode}}, {{W|Liste der Unicodeblöcke}} und {{W|Unicodeblock Mathematische Operatoren}}. Im Folgenden werden ein paar Zeichen (Allquantor, Nabla-Operator, Existenzquantor), die man aus der Mathematik kennt, erzeugt.
ch1 = "\N{FOR ALL}"
ch2 = "\N{NABLA}"
ch3 = "\u2203"
print(ch1, ch2, ch3)
Ausgabe:
∀ ∇ ∃
<small>Diese Ausgabe ergibt sich z.B. mit der IDLE-Shell oder mit Cygwin. Beim Ausführen über die Windows-Eingabeaufforderung oder Windows PowerShell unter MS Windows 10 erfolgt keine korrekte Darstellung. IDLE ist die mit Python mitgelieferte IDE ('''I'''ntegrated '''D'''evelopment '''E'''nvironment, Integrierte Entwicklungsumgebung). Gegen Ende dieses Textes wird IDLE kurz beschrieben.
Das Problem mit der Windows Eingabeaufforderung lässt sich aber umgehen. Man muss nur eine Schriftart auswählen, die die Zeichen kennt, z.B. "DejaVu Sans Mono". Dazu klicken Sie einfach bei der Eingabeaufforderung mit der rechten Maustaste oben auf die weiße Leiste und wählen im aufpoppenden Fenster den Menüpunkt "Eigenschaften". Es öffnet sich ein Dialogfenster. Über den Reiter "Schriftart" lässt sich nun die Schriftart einstellen. Unter MS Windows 11 oder openSUSE Leap 15.6 (bash-Konsole) gibt es dieses Problem ohnehin nicht.</small>
== Reguläre Ausdrücke ==
Python kennt auch {{W|Regulärer Ausdruck|reguläre Ausdrücke}}. Dazu gibt es in Python das Modul <code>re</code>. Beipielsweise sollen alle Zahlen (<math>\text{zahl}\in\mathbb{N}_0</math>) in einem String gesucht und ausgegeben werden. Als String sei gegeben: <code>3x Grüße und 100 Kekse.</code> Das Muster (Pattern) ist <code>\d+</code>. <code>\d</code> steht für eine Dezimalziffer 0-9. Das Plus-Zeichen (+) steht symbolisch für ein oder mehrere Zeichen des vorherigen Ausdrucks. Hier also ein oder mehrere Dezimalziffern. Es wird die Funktion <code>findall</code> aus dem Modul <code>re</code>verwendet.
Python-Code:
from re import findall
str = "3x Grüße und 100 Kekse."
pat = "\\d+" # Doppel-Backslashes müssen verwendet werden, sonst gibt Python eine Warnung aus!
# alternativ: pat = r"\d+"
# oder: pat = "[0-9]+"
numb = findall(pat, str)
print(numb)
Ausgabe:
['3', '100']
Python kennt noch viele weitere Möglichkeiten mittels regulärer Ausdrücke zu hantieren. Dies soll hier aber nicht vertieft werden, da das Thema schon ziemlich speziell und komplex ist. Bei Bedarf siehe aber z.B. die Bücher ''Weigend, Seite 380ff'' und ''Ernesti, Kaiser'' [https://openbook.rheinwerk-verlag.de/python/28_001.html] oder die Python-Dokumentation [https://docs.python.org/3/library/re.html]. Auch [[Python unter Linux: Reguläre Ausdrücke]] liefert ein umfangreiches und brauchbares Python-2-Kapitel zu den regulären Ausdrücken. Die dort gelisteten Beispiele müssten ggf. vor Verwendung auf Python-3 umgeschrieben werden. <small>Wie macht man das? Dazu siehe z.B. [https://openbook.rheinwerk-verlag.de/python/43_001.html], [https://portingguide.readthedocs.io/en/latest/] oder [https://www.digitalocean.com/community/tutorials/how-to-port-python-2-code-to-python-3]</small>
<small>Es gibt auch ein externes Modul ''regex'', das bei Bedarf extra installiert werden muss ([https://pypi.org/project/regex/]). Es bietet zusätzliche Funktionalität und gründlicheren Unicode-Support. Dies sei hier aber nur der Vollständigkeit halber erwähnt.</small>
== Verzweigungen ==
=== if ===
Die IF-Verzweigung sei aus anderen Programmiersprachen bereits bekannt. In {{W|Pseudocode}} lässt sie sich folgendermaßen darstellen:
WENN bedingung TRUE
führe block1 aus
SONST
führe block2 aus
ENDE
Als {{W|Aktivitätsdiagramm|UML-Aktivitätsdiagramm}} sieht das in etwa so aus:
[[File:If-Then-Else-diagram.svg|200px]]
Und als {{W|Nassi-Shneiderman-Diagramm|Nassi-Shneiderman-Struktogramm}} so:
[[File:Zweiseitige Auswahl.png|250px]]
In Python gibt es keinen expliziten ENDE-Kennzeichner. Stattdessen wird der Code durch Einrückungen strukturiert. Alles mit der gleichen Einrückungstiefe gehört zum selben Block. Dies zeichnet Python vor anderen Programmiersprachen aus.
Die test1.py-Datei laute also wie folgt:
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4
Man achte auch auf die Doppelpunkte in der if- und else-Zeile. Darauf vergisst man gerne, wenn man von anderen Programmiersprachen kommt.
Folgendes wäre in Python ein Fehler (genauer gesagt ein IndentationError).
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Auch Nachstehendes würde nicht zum gewünschten Ergebnis führen (löst aber keine Fehlermeldung aus). Der letzte print-Befehl ist schon außerhalb der IF-ELSE-Verzweigung.
x = 3
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
x ist kleiner als 4
x ist groesser oder gleich 4
Python kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:
<, <= ... kleiner (gleich)
>, >= ... größer (gleich)
== ... gleich
!= ... ungleich
is ... identisch
is not ... nicht identisch
and ... AND
or ... OR
not ... NOT
Beispielsweise:
a = 5
b = 9
if a<=10 and b!=7:
print("OK")
else
print("Nicht OK")
Ausgabe:
OK
Der else-Block kann übrigens auch ersatzlos entfallen. Als Pseudocode sieht das so aus
WENN bedingung TRUE
führe block aus
ENDE
Mehrfache Verzweigungen werden durch das elif-Konstrukt erstellt. In Pseudocode:
WENN bedingung1 TRUE
führe block1 aus
SONST WENN bedingung2 TRUE
führe block2 aus
SONST WENN bedingung3 TRUE
führe block3 aus
SONST
führe block4 aus
ENDE
Ein Python-Beispiel:
a = 14
if a<=10:
print("<=5")
elif a>11 and a<15:
print("11 bis 15")
elif a>16 and a<20:
print("16 bis 20")
else:
print(">=20")
Ausgabe:
11 bis 15
In Python gibt es auch die Schlüsselwörter <code>True</code> (für wahr) und <code>False</code> (für falsch). Man beachte, dass sie mit Großbuchstaben beginnen. Andere Schreibweisen wären ein Fehler. Sie gehören zum Datentyp <code>bool</code>. Ihnen sind auch die Zahlen <code>1</code> und <code>0</code> zugewiesen.
Man beachte, dass {{W|Rundungsfehler}} auftreten können. D.h. man sollte bei der Verwendung von {{W|Gleitkommazahl|Gleitpunktzahlen}} niemals auf absolute Genauigkeit prüfen, sondern eine Toleranz (einen <math>\varepsilon</math>-Wert) vorgeben.
Ein klassisches Beispiel, das ein falsches Ergebnis liefert, ist:
i = 0.1 + 0.2
print(i)
if i == 0.3:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
NOK
Und das, obwohl man schon in der Volksschule lernt, dass 0.1 + 0.2 gleich 0.3 ist.
Korrekt muss das obige Beispiel z.B. so umgeschrieben werden:
ist = 0.1 + 0.2
soll = 0.3
epsilon = 0.000001
print(ist)
if abs(ist-soll) < epsilon:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
OK
Alternativ kann auch die <code>math.isclose()</code>-Funktion verwendet werden. Das sei aber hier nur erwähnt und nicht konkret ausgeführt.
<u>Aufgabe:</u> Recherchieren Sie im Internet zum Thema <code>math.isclose()</code>-Funktion.
=== match ===
Ab Python 3.10 gibt es auch die match-Anweisung. Dies ist das Python-Pendant für die switch-Anweisung in anderen Programmiersprachen, geht aber bei näherer Betrachtung weit darüber hinaus. Hier nur ein einfaches Beispiel:
x = "Hello"
match x:
case "Servus" | "Ciao": # or
print("Servus an alle")
case "Grüetzi":
print("Grüetzi Schwyzer")
case _: # other, default, sonstiges ...
print("Hallo Welt")
Ausgabe:
Hallo Welt
Als Struktogramm sieht das in etwa so aus:
[[File:Mehrseitige Auswahl.png|250px]]
Für nähere Details siehe z.B. [https://www.geeksforgeeks.org/python-match-case-statement/], [https://learnpython.com/blog/python-match-case-statement/], [https://docs.python.org/3/tutorial/controlflow.html#match-statements] und das Python Enhancement Proposal (PEP) 636 – Structural Pattern Matching: Tutorial [https://peps.python.org/pep-0636] und dort insbesondere den Anhang A - Quick Intro.
<small><code>match, case, _</code> etc. sind sogenannte ''soft keywords''. Im Gegensatz zu den normalen Schlüsselwörtern dürfen ihnen auch Werte zugewiesen werden. Eine Liste der weichen Schlüsselwörter lässt sich durch <code>keyword.softkwlist</code> erstellen (die Anweisung gibt es seit Python 3.9). Siehe dazu auch [https://stackoverflow.com/questions/65800344/what-are-soft-keywords] und [https://docs.python.org/3/library/keyword.html#keyword.softkwlist].</small>
== Schleifen ==
Kopfgesteuerte Schleife, Endlosschleife und fußgesteuerte Schleife:
[[File:Programmingloops.svg|450px]]
=== while ===
Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert wie aus anderen Programmiersprachen bekannt.
In Pseudocode:
SOLANGE bedingung TRUE
führe block aus
ENDE
In Python:
x = 0
while x <= 10:
print(x)
x += 1
Ausgabe:
0
1
2
3
4
5
6
7
8
9
10
Eine Endlosschleife ergibt sich z.B. so:
i = 5
while True:
print(i)
i-=1
Beendet werden kann sie mit der Tastenkombination STRG-C.
Eine fußgesteuerte Schleife kann so simuliert werden:
i = 5
while True:
print(i)
i-=1
if i<=0:
print("Fire")
break
Ausgabe:
5
4
3
2
1
Fire
Der <code>break</code>-Befehl wird etwas später noch einmal kurz thematisiert.
=== for ===
Struktogramm einer for-Schleife:
[[File:Zählschleife.png|200px]]
In Python bspw. so:
for x in range(6):
print(x*2)
Ausgabe:
0
2
4
6
8
10
Die Schleife läuft von 0 bis 5. Ausgegeben wird jeweils der Wert x*2. Aquivalent kann diese Schleife auch so geschrieben werden:
for x in range(0, 11, 2):
print(x)
Die Ausgabe ist wie oben. Der Startwert sei 0, der Endwert ist 11-1 und die Schrittweite ist 2.
Ein anderes Beispiel sei
for x in "text":
print(x)
Ausgabe:
t
e
x
t
== Schleifen abbrechen ==
=== break ===
<code>break</code> bricht die Schleife ab und setzt mit dem nächsten Befehl außerhalb der Schleife fort.
for var in range(100):
print(var)
if var == 5:
break
Ausgabe:
0
1
2
3
4
5
=== continue ===
<code>continue</code> bricht den aktuellen Schleifendurchlauf ab und setzt mit dem nächsten Schleifendurchlauf fort.
for var in range (11):
if var == 5:
continue
print(var)
Ausgabe:
0
1
2
3
4
6
7
8
9
10
== try - except ==
try:
z1 = 12 / 0
print(z1)
except ZeroDivisionError:
print("Das Ergebnis ist unendlich")
except:
print("Kann nicht berechnet werden!")
print("Bitte die Formel korrigieren!")
print("Setze Programm fort!")
Ausgabe:
Das Ergebnis ist unendlich
Setze Programm fort!
Es wird versucht, eine Zahl durch Null zu dividieren. Das ist nicht möglich, es wird eine Ausnahme ausgelöst. Das Programm springt daher in den except-ZeroDivisionError-Block und führt die dort gelisteten Anweisungen aus (in unserem Fall eine print-Anweisung). Danach wird das Programm fortgesetzt. Würden wir dieses Programm ohne try-except ausführen, so ergibt sich aus
z1 = 12 / 0
print(z1)
folgende Fehlermeldung und ein unmittelbarer Programmabbruch
Traceback (most recent call last):
File "C:\tmp\test1.py", line 1, in <module>
z1 = 12 / 0
ZeroDivisionError: division by zero
Mit dem try-except-Mechanismus können also Ausnahmen oder Fehler aufgefangen und behandelt werden. In unserem Beispiel ist das eher trivial, aber bei größeren Programmen kann das durchaus Sinn machen.
Neu in Python 3.14 ist, dass mehrere Ausnahmen auch ohne Klammern angegeben werden können, z.B.:
bis inkl. Python 3.13 nur:
except (ZeroDivisionError, ValueError):
ab Python 3.14 auch:
except ZeroDivisionError, ValueError:
== pass ==
Ein leerer Block muss in Python mittels dem Schlüsselwort <code>pass</code> dargestellt werden. Z.B.
x = 2
if x == 1:
print("Wert ist ", x)
else:
pass
Würde man das <code>pass</code> im else-Block weglassen, so würde man eine Fehlermeldung erhalten:
IndentationError: expected an indented block after 'else' statement on line 5
= Funktionen =
== Aufrufen von Funktionen ==
Funktionen sind uns im Rahmen dieses Kurses schon zuhauf begegnet. Sei es die print()-, die math.sin()- oder die hex()-Funktion. All diese Funktionen werden von Python zur Verfügung gestellt, ohne dass man sie explizit programmieren müsste. Aufgerufen werden diese Funktionen, indem man ihren Namen eintippt, gefolgt von runden Klammern. In diesen Klammern können noch Argumente übergeben werden. Auch Rückgabewerte sind möglich.
== Funktionen selber schreiben ==
Funktionen werden mit dem def-Schlüsselwort (man definiert die Funktion) eingeleitet, danach folgt der Funktionsname, danach wiederum runde Klammern, in denen formale Argumente stehen können. Abgeschlossen wird die def-Zeile mit einem Doppelpunkt. Danach folgt der Funktionskörper. Dieser Funktionskörper muss wiederum eingerückt werden (wie von den Verzweigungen und Schleifen bekannt). Aufgerufen wird diese Funktion, indem man ihren Funktionsnamen eingibt, gefolgt von runden Klammern (ggf. mit den aktuellen Parametern). Z.B.
# Funktion definieren
def halloWelt(i):
# i ... beliebige Ganzzahl
print("Hallo " * i, end="")
print("Welt!")
# Funktion aufrufen
halloWelt(3)
Ausgabe:
Hallo Hallo Hallo Welt!
Unterschied zwischen formalen und aktuellen Parametern:
[[Datei:PythonIng_func1.jpg]]
<small>Aktuelle Parameter werden auch Argumente genannt.</small>
Rückgabe von Funktionswerten:
# Funktion definieren
def mathFunc(a, b):
r1 = a + b
r2 = a * b
return r1, r2
# Funktion aufrufen
c, d = mathFunc(3, 5)
# Ausgabe der zurückgegebenen Werte
print(c)
print(d)
Ausgabe:
8
15
Es werden r1 und r2 zurückgegeben und den Variablen c und d zugewiesen. (r1, r2) und (c, d) sind Tupel. Was Tupel konkret sind, siehe etwas später in diesem Kapitel. 3 und 5 sind die aktuellen Parameter (die Argumente). a und b sind die formalen Parameter. Die Zuweisung der aktuellen zu den formalen Parametern erfolgt in der gegebenen Reihenfolge, also die Zahl 3 wird an a übergeben und die Zahl 5 an b.
Vorgabeparameter, z.B.:
def mathFunc(a=10, b=20):
r1 = a + b
r2 = a * b
return r1, r2
c, d = mathFunc(3, 5)
print(c)
print(d)
e, f = mathFunc(5)
print(e)
print(f)
g, h = mathFunc(b=6)
print(g)
print(h)
Ausgabe:
8
15
25
100
16
60
Erklärung:
* Erster <code>mathFunc</code>-Aufruf: Es werden, wie weiter oben, die Argumente 3 und 5 an die formalen Parameter a und b übergeben. Die Rückgabewerte r1 und r2 werden an c und d übergeben. Somit ist c=8 und d=15.
* Zweiter <code>mathFunc</code>-Aufruf: Es wird nur das Argment 5 an a übergeben. b behält den Vorgabewert 20. D.h. e= 25 und f=100.
* Dritter <code>mathFunc</code>-Aufruf: Es wird nur die Zahl 6 an b übergeben, a behält seinen Vorgabewert 10. Somit ergibt sich g=16 und h=60.
Beispiel (Schlüsselwortargumente vs. Positionsargumente):
def mathFunc(a, b):
r1 = a - b
r2 = a / b
return r1, r2
c, d = mathFunc(b=3, a=5) # Schlüsselwortargumente
e, f = mathFunc(3, 5) # Positionsargumente
print(c)
print(d)
print(e)
print(f)
Ausgabe:
2
1.6666666666666667
-2
0.6
Durch die Verwendung von Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge angegeben werden. Bei den Positionsargumenten ist die Reihenfolge vorgegeben. Daraus resultiert auch der Unterschied bei den obigen Ausgaben. Werden beide Arten in einem Aufruf gemischt, so müssen die Positionsargumente zuerst angegeben werden. Den Unterschied zwischen beiden Argumentarten zu kennen ist wichtig, nicht nur bei selbst erstellten Funktionen. Auch beim Aufruf von Python-Funktionen verfolgt einen die Mischung von Schlüsselwort- und Positionsargumenten auf Schritt und Tritt, z.B. beim etwas später folgenden Abschnitt über "Grafiken zeichnen":
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
Bei dieser <code>plot</code>-Funktion aus dem Modul <code>matplotlib.pyplot</code> sind <code>x</code> und <code>y1</code> Positionsargumente. <code>label, lw</code> und <code>ls</code> sind die Namen der Schlüsselwortargumente. Die Schlüsselwortargumente könnten auch in anderer Reihenfolge angeschrieben werden, nicht jedoch die Positionsargumente!
Siehe zu <code>matplotlib.pyplot.plot</code> auch die Seite [https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html].
== Lambda-Funktionen ==
print((lambda a, b: a*b) (3, 5))
Ausgabe:
15
Eingeleitet wird eine Lambda-Funktion (auch Lambda-Form, Lambda-Operator oder anonyme Funktion genannt) mit dem Schlüsselwort <code>lambda</code>. Es folgen die formalen Argumente, danach ein Doppelpunkt, die Berechnungsvorschrift und ggf. abschliessend in Klammern die aktuellen Parameter.
Man kann einer Lambda-Funktion auch einen Funktionsnamen geben und die Funktion über diesen Namen aufrufen, z.B.
prod = lambda a, b: a*b
print(prod(3, 5))
Als Ausgabe wird wieder die Zahl 15 geliefert.
== Rekursive Funktionen ==
Funktionen können wiederum andere Funktionen aufrufen. Von einem rekursiven Funktionsaufruf spricht man, wenn die aufgerufene Funktion gleich der aufrufenden ist.
def printFunc(i):
if (i >= 5):
return
else:
print("Hallo Welt")
printFunc(i+1)
printFunc(1)
Ausgabe:
Hallo Welt
Hallo Welt
Hallo Welt
Hallo Welt
== Funktionsannotationen ==
Python ist sehr flexibel, was Typen angeht. Im Vorhergehenden haben wir generell keine Typangaben gemacht. Will man Typen angeben, so bietet Python das Konzept der Funktionsannotation.
def calcFunc(a: int, b: int) -> int:
return a+b
r1 = calcFunc(8, 9)
r2 = calcFunc(8.0, 9.0)
r3 = calcFunc("Hallo", "Welt")
print(r1)
print(r2)
print(r3)
Ausgabe:
17
17.0
HalloWelt
Jetzt sieht man auf den ersten Blick, welche Typen der Programmierer im Sinn hatte, als er die Funktion erstellte. Das Problem dabei ist nur, dass es Python ziemlich egal ist, welche Typen man im Endeffekt eingibt. Im obigen Beispiel können statt Integer-Typen u.a. auch Float- oder String-Typen eingegeben werden.
<small>
Siehe zum Thema "Type Checking" aber auch den später folgenden Abschnitt [[Ing_Mathematik:_Python#Type_Checker]].
</small>
== Variadische Funktionen ==
Python-Code:
def test1(a, *b):
print(a);
for c in b:
print(c);
test1("Hallo", "Welt", "Schweizer", "und alle anderen")
Ausgabe:
Hallo
Welt
Schweizer
und alle anderen
Mit dem Stern (auch als Splat-Operator bezeichnet) in der formalen Parameterliste bei der Funktion <code>test1</code> wird angezeigt, dass eine beliebige Anzahl von Argumenten übergeben wird. <small> Dies entspricht in etwa dem, was in anderen Programmiersprachen (PHP etc.) mittels Ellipse (<code>...</code>) angezeigt wird.</small>
= Tupel, Listen und andere =
[[Datei:Python 3. The standard type hierarchy.png|mini|hochkant=1.7|Datentypen und Strukturen]]
== Tupel und Listen ==
Tupel, Listen und einige andere sind Datenstrukturen oder Sequenzen.
Listen (z.B. eine Einkaufsliste) sind veränderbar (mutable). Ein Tupel kann dagegen nicht verändert werden (immutable). Listen werden beim Anlegen in eckige Klammern eingeschlossen, Tupel in runde Klammern. Beim Tupel können die Klammern auch weggelassen werden. Ein Tupel mit nur einem Element muss mit einem Beistrich abgeschlossen werden. Der Grund ist, dass Python sonst nicht entscheiden kann, ob ein Tupel angelegt werden soll, oder nur ein geklammerter Wert.
Als Gedächtnisstütze kann man sich den Unterschied zwischen Tupel und Liste ev. so leichter merken:
: T'''u'''pel ... r'''u'''nde Klammern, '''u'''nveränderlich
: L'''i'''ste ... eck'''i'''ge Klammern, veränderl'''i'''ch.
Nachfolgend werden einige Operationen mit Listen und Tupel dargestellt.
# Liste und Tupel
liste = [1, 2, "Hallo"]
tupel = (1, 2, "Hallo")
# Ausgabe von liste und tupel
print(liste)
print(tupel)
# Ausgabe von Einzelelementen
print(liste[1])
print(tupel[2])
# Element an Liste anhängen und einfügen
liste.append(55)
liste.insert(4, "Welt")
print(liste)
# Element aus Liste entfernen
liste.remove(1)
print(liste)
# einige weitere Beispiele
liste2 = [1,]
tupel2 = 1, 2
tupel3 = (1,)
print(liste2)
print(tupel2)
print(tupel3)
Ausgabe:
[1, 2, 'Hallo']
(1, 2, 'Hallo')
2
Hallo
[1, 2, 'Hallo', 55, 'Welt']
[2, 'Hallo', 55, 'Welt']
[1]
(1, 2)
(1,)
Beispiel (eine Liste von Wörtern zu einem einzigen zusammenhängenden Text verbinden):
woerter = ["Hallo", "Welt"]
satz = " ".join(woerter)
print(satz)
Ausgabe:
Hallo Welt
== Dictionaries und Mengen ==
Zu den Datenstrukturen gehören weiters auch Mengen und Dictionaries. Mengen sind von der Mathematik bekannt, sie sind ungeordnet und es kommen keine mehrfachen Elemente vor. Dictionaries sind durch Schlüssel :Wert-Paare gekennzeichnet. Mengen werden beim Anlegen wie Dictionaries in geschweifte Klammern eingeschlossen.
dict = {"vorname":"Hugo", "nachname":"Meister" }
menge = {1, 1, 3, 4, 4, 4, "Hallo"}
print(dict)
print(menge)
print(dict["vorname"])
Ausgabe:
{'vorname': 'Hugo', 'nachname': 'Meister'}
{1, 3, 4, 'Hallo'}
Hugo
Geschweifte Klammern ohne Inhalt stellen Dictionaries dar und keine Mengen:
di = {}
print(type(di))
Ausgabe:
<class 'dict'>
Leere Mengen lassen sich mit <code>set()</code> erzeugen:
menge = set() # leere Menge
print(menge)
menge.add("Hallo") # Element hinzufügen
print(menge)
Ausgabe:
set()
{'Hallo'}
Beispiel (einige Mengenoperationen):
mengeA = {"Hallo", "Welt"}
mengeB = {1, 2, "Welt", 3}
# Vereinigung
print(mengeA | mengeB)
print(mengeA.union(mengeB))
# Durchschnitt
print(mengeA & mengeB)
print(mengeA.intersection(mengeB))
# Differenz
print(mengeA - mengeB)
print(mengeA.difference(mengeB))
# Symmetrische Differenz
print(mengeA ^ mengeB)
print(mengeA.symmetric_difference(mengeB))
# Teilmenge
print(mengeA.issubset(mengeB))
# Mehrere Elemente hinzu
mengeA.update(["Super", 67, 125])
print(mengeA)
# Element löschen
mengeA.discard("Hallo")
print(mengeA)
Ausgabe:
{1, 2, 3, 'Welt', 'Hallo'}
{1, 2, 3, 'Welt', 'Hallo'}
{'Welt'}
{'Welt'}
{'Hallo'}
{'Hallo'}
{1, 2, 3, 'Hallo'}
{1, 2, 3, 'Hallo'}
False
{67, 'Super', 'Welt', 'Hallo', 125}
{67, 'Super', 'Welt', 125}
Es gibt schon seit "ewigen" Zeiten unveränderbare Mengen, die mittels <code>frozenset</code> eingeleitet werden. Neu ab Python 3.15 ist dagegen das Pendant <code>frozendict</code>, das unveränderbare Dictionaries darstellt.
fdict = frozendict({"vorname":"Hugo", "nachname":"Meister"})
fset = frozenset({"A", 1, "A"})
print(fdict)
print(fdict["vorname"])
print (fset)
try:
fdict["vorname"] = "Max"
print(fdict["vorname"])
except TypeError as e:
print(f"Fehler: {e}")
try:
fset.add("B")
print(fset)
except AttributeError as e:
print(f"Fehler: {e}")
Ausgabe:
frozendict({'vorname': 'Hugo', 'nachname': 'Meister'})
Hugo
frozenset({1, 'A'})
Fehler: 'frozendict' object does not support item assignment
Fehler: 'frozenset' object has no attribute 'add'
== List Comprehensions ==
Aus einer Eingabeliste soll eine Ausgabeliste erzeugt werden. Das kann folgendermaßen geschehen.
Mathematische Schreibweise: <math>lc = \{2x|x\in\ \mathbb{N}, 1\le x < 11\}</math>
Python-Code:
lc = [x*2 for x in range(1,11)]
print(lc)
Ausgabe:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Mathematische Schreibweise: <math>lc = \{2x | x \in \mathbb{N}, 1\le x < 11, x \bmod 2 = 0 \}</math>
Python-Code:
lc = [x*2 for x in range(1,11) if x%2 == 0]
print(lc)
Ausgabe:
[4, 8, 12, 16, 20]
Siehe auch {{W|List Comprehension}}.
== Set Comprehensions ==
Dies ist sehr ähnlich wie im vorigen Abschnitt beschrieben. Es wird aber keine Liste, sondern eine Menge erzeugt.
sc = {x*2 for x in range(1,11)}
print(sc)
Ausgabe:
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
== Listen zusammenführen - zip() ==
li1 = ["A", "B", "C", "D"]
li2 = [1, 2, 3, 4]
li3 = [5.5, 6.6, 7.7, 8.8]
z = zip(li1, li2, li3)
print(z)
li4 = list(z)
print(li4)
Ausgabe:
<zip object at 0x00000283B6C6AC80>
[('A', 1, 5.5), ('B', 2, 6.6), ('C', 3, 7.7), ('D', 4, 8.8)]
== Generatorausdruck ==
g = (i*2 for i in range(1,11))
print(g)
t = tuple(g)
print(t)
print(t[1:3])
Ausgabe:
<generator object <genexpr> at 0x00000241D2A4A5A0>
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
(4, 6)
== Slicing ==
slice ... Scheibe, Teil, in Scheiben schneiden
Beispiel: Zugriff auf Elemente eines geordneten sequentiellen Objekttyps (Liste, Tupel oder String):
str1 = "Hallo"
# Das erste Element wird mit dem Index 0 angesprochen
# [start (inkl.) : stop (exkl.) : step (default=1)]
str2 = str1[0:2]
# Alternativ auch: str2 = str1[:2]
print(str2)
tup1 = (0,1,2,3)
# Das letzte Element hat auch den Index -1, das vorletzte den Index -2 usw.
tup2 = tup1[-3:-1]
print(tup2)
lst1 = [[1, 5, 10, 20],
[30, 40, 50, 60]]
lst2 = lst1[1][1]
print(lst2)
Ausgabe:
Ha
(1, 2)
40
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2])
print(x[-3])
print(x)
print(x[:])
print(x[2:])
print(x[:2])
print(x[::-1])
Ausgabe:
c
c
('a', 'b', 'c', 'd', 'e')
('a', 'b', 'c', 'd', 'e')
('c', 'd', 'e')
('a', 'b')
('e', 'd', 'c', 'b', 'a')
Visualisierung:
'''a''' '''b''' '''c''' '''d''' '''e'''
+-----------------------------+
| 0 | 1 |//'''2'''//| 3 | 4 |
+-----------------------------+
| -5 | -4 |/'''-3'''//| -2 | -1 |
+-----------------------------+
|/////////////////////////////|
+-----------------------------+
|/////////////''':'''///////////////|
+-----------------------------+
| | |///////'''2:'''////////|
+-----------------------------+
|////''':2'''/////| | | |
+-----------------------------+
|\\\\\<--\\\\\'''::-1'''\\\\<--\\\\\|
+-----------------------------+
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2::2])
print(x[2::-1])
print(x[2:0:-1])
Ausgabe:
('c', 'e')
('c', 'b', 'a')
('c', 'b')
Hier sieht man sehr schön, dass beim letzen <code>print</code>-Befehl die 0, die in diesem Fall den Buchstaben "a" repräsentiert, als letzer Wert nicht mehr dazugehört (wie weiter oben angedeutet ist der End- oder Stoppwert exklusiv). Will man den Buchstaben "a" dazunehmen, so ist die vorletzte Zeile die richtige.
Beispiel: Umdrehen von Strings
str1 = "Hallo"
str2 = str1[::-1]
print(str2)
Ausgabe:
ollaH
Mit zweidimensionalen Listen/Tupels wird das Ganze schon bedeutend komplexer.
Beispiel: Verkettetes Slicing
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
print(A[2::][::2])
Ausgabe:
[['20', '21', '22', '23'], ['40', '41', '42', '43']]
Das erste Slicing erstellt folgenden Slice:
[["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
Das zweite Slicing wird dann auf diesen Slice angewendet und ergibt das genannte Endergebnis. Will man Spalten statt Zeilen, so funktioniert dieser direkte Weg nicht. Man verwendet dann List Comprehensions oder die NumPy-Bibliothek. Diese Bibliothek erlaubt zweidimensionales Slicing. Sie wird erst später bei den Grafiken eingeführt. Deshalb wird hier dazu noch kein Beispiel gezeigt.
= Objektorientierte Programmierung =
{{Wikipedia|Objektorientierte Programmierung}}
* {{W|Klasse (Objektorientierung)|Klasse}} ... die Schablone oder der Bauplan, enthält Methoden und Attribute
* {{W|Objekt (Programmierung)|Objekt}} ... eine Klasseninstanz (die konkrete Ausprägung der Klasse)
* {{W|Attribut (Programmierung)|Attribute}} ... die Eigenschaften eines Objekts
* {{W|Methode (Programmierung)|Methoden}} ... die Aktionen (Operationen), die ein Objekt ausführen kann
* {{W|Vererbung (Programmierung)|Vererbung}} ... neue Klassen (Subklassen, Unterklassen, abgeleitete Klassen) aus vorhandenen Klassen (Superklassen, Oberklassen, Basisklassen, Elternklassen) ableiten. Ermöglicht den Aufbau von Klassenhierarchien. Die Subklasse "erbt" Attribute und Methoden von der Superklasse. Python unterstützt (so wie C++, aber im Gegensatz zu Java) Mehrfachvererbung.
== UML ==
* {{W|Unified Modeling Language|UML}} ... '''U'''nified '''M'''odeling '''L'''anguage, eine Modellierungssprache. Die UML enthält zahlreiche Diagrammarten, um Programme zu modellieren. Im Nachfolgenden wird nur das {{W|Klassendiagramm}} verwendet.
[[File:UmlCd Klasse-3.svg|300px]]
* {{W|Sichtbarkeit (Programmierung)|Sichtbarkeit}}:
** + ... public (öffentlich)
** - ... private
** # ... protected
* {{W|Attribut_(UML)#Attribute_für_Instanzen_und_für_Klassen|Klassenattribute}} (statische Attribute): Werden nur einmal pro Klasse angelegt. Im Klassendiagramm werden sie unterstrichen.
[[File:Attribute-3.png|200px]]
* Vererbung:
<gallery>
InheritancePgmUML.svg | Abgeleitete Klasse erbt von Basisklasse (Einfachvererbung)
Diamond inheritance.svg | D erbt von B und C (Mehrfachvererbung). B und C erben von A (Einfachvererbung)
</gallery>
Für weitergehende Betrachtungen zur UML wird auf Spezialliteratur verwiesen, z.B.:
* Seidl et al.: UML@Classroom. dpunkt, 2012, ISBN 978-3-89864-776-2
* Rupp et al.: UML 2 glasklar. Hanser, 4. Aufl., 2012, ISBN 978-3-446-43057-0
== Eine einfache Klasse ==
[[Datei:PythonIng_uml1.svg | 200px]]
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
fahr = Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die Klasse Fahrzeug wird durch das class-Schlüsselwort eingeleitet. raeder ist ein Klassenattribut und public. __init__ wird bei der Objekterzeugung automatisch aufgerufen (ist der sogenannte Konstruktor). Man achte darauf, dass diese Methode immer mit zwei Unterstrichen eingeleitet und abgeschlossen wird. Instanzattributen wird das Wort self vorangestellt. Wir sehen uns z.B. das Attribut self.__geschwind an. Auch hier werden zwei Unterstriche verwendet. Das bedeutet, dass dieses Attribut strikt/stark private ist. Wird nur ein Unterstrich verwendet, so deutet dies auf schwach/weakly private hin. Letzteres wird in Python deutlich häufiger verwendet. Bei den Methoden wird immer self als erster Parameter angegeben. Beim Aufruf der entsprechenden Funktion wird das self aber nicht berücksichtigt.
Besonderheiten bei stark und schwach private:
* '''stark private''':
** zwei führende Unterstriche
** Name Mangling: Name wird zu <code>_Klassenname__variablenname</code>
** Schutz vor Namenskollisionen bei Vererbung
** am Ende des Namens dürfen keine zwei Unterstriche verwendet werden. Das wären dann Magic Methods oder Dunder-Methods (z.B. __init__). Diese sind public.
* '''schwach private''':
** ein führender Unterstrich
** Name bleibt gleich
** ist nur ein Hinweis an die Programmierer, kein starker Schutz
** <code>from modul import *</code>: Objekte mit einem führenden Unterstrich werden standardmäßig nicht importiert
** Standard für die Kapselung bei Python. Schätzung: Weit mehr als 80% der nicht-öffentlichen Attribute/Methoden werden als schwach private deklariert. Weniger als 5-10% als stark private (Quelle: Google KI)
== Klassen importieren ==
Häufig ist es sinnvoll und übersichtlicher Klassen in eigenen Dateien zu speichern. Das sind dann eigene Module. Abgespeichert werden Sie mit der Endung py, wie bisher auch praktiziert. Aufgerufen werden Sie mit der import-Anweisung. Dann ist aber nur der Dateiname ohne Endung py zu verwenden. Klarer wird das mit einem Beispiel.
Datei c:\tmp\fahrzeug.py
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
Datei c:\tmp\test1.py
import fahrzeug
fahr = fahrzeug.Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die üblichen import-Anweisungen lauten wie folgt:
{| {{prettytable}}
! import-Befehl
! Instanz
|-
| import xyz || xyz.Klasse
|-
| import xyz as x || x.Klasse
|-
| from xyz import Klasse || Klasse
|-
| from xyz import * || Klasse
|}
Der Vorteil der ersten beiden import-Anweisungen ist, dass es kaum zu Namenskollisionen kommen kann. Dafür hat man bei den letzten beiden Varianten weniger Tipparbeit.
== Vererbung ==
=== Einfachvererbung ===
[[Datei:PythonIng_uml2.svg | 200px]]
Datei fahrzeug.py:
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
class Luftfahrzeug(Fahrzeug):
def __init__(self, geschwindigkeit, leistung, fluegel):
super().__init__(geschwindigkeit, leistung)
self.__flueg = fluegel
def getFlueg(self):
return self.__flueg
Datei test1.py:
import fahrzeug
fahr = fahrzeug.Luftfahrzeug(150, 90, 4)
print(fahr.getFlueg())
Ausgabe:
4
=== Mehrfachvererbung ===
Mit Python ist auch Mehrfachvererbung möglich, z.B.:
class A:
def _printA(self):
print("Klasse A")
class B:
def _printB(self):
print("Klasse B")
class C(A,B):
def __init__(self):
self._printA()
self._printB()
c = C()
Ausgabe:
Klasse A
Klasse B
Die Klasse C erbt von A und B. In UML sieht das in etwa so aus:
+-----------------------------+ +-------------------------+
| A | | B |
+-----------------------------+ +-------------------------+
| | | |
+-----------------------------+ +-------------------------+
| # printA() | | # printB() |
+-----------------------------+ +-------------------------+
. .
/ \ / \
--- ---
| |
| |
+---------------------+
| C |
+---------------------+
| |
+---------------------+
| |
+---------------------+
<code>printA()</code> und <code>printB()</code> sind schwach private (in UML als <code>protected</code> mit einem # dargestellt). Es ist aber zu beachten, dass schwach private nur Konvention ist. Praktisch könnte man auch von außerhalb auf diese Methoden zugreifen. Das soll man aber nicht tun, und das wird in Python durch einen Unterstrich angedeutet.
= Grafiken zeichnen =
Für das Zeichnen von Grafiken wird hier das Modul <code>matplotlib</code> verwendet. <code>matplotlib</code> ist ein externes Modul und muss vor der ersten Verwendung installiert werden. Das geht so:
# Starten Sie ein Terminal (bei Windows die Eingabeaufforderung).
# Führen Sie darin folgenden Befehl aus <code>c:\devel\Python\Scripts\pip.exe install matplotlib</code>
pip ist übrigens der Paketmanager von Python ({{W|Pip_(Python)}}).
Optimalerweise installieren wir auch gleich das Modul <code>numpy</code> (Numerical Python). Wir werden es im Folgenden oft benötigen (nicht nur bei den Grafiken). Das funktioniert vom Prinzip her genauso, wie für <code>matplotlib</code> gezeigt.
<small>Verwenden Sie Spyder, so sind diese Schritte nicht nötig. Spyder inkludiert diese Pakete standardmäßig. Unter openSUSE Tumbleweed lassen sich diese Pakete mittels YaST oder zypper installieren.</small>
== 2D ==
=== Graph einer Funktion ===
Es soll die cosh-Funktion im Intervall <math>x\in[-3,3]</math> gezeichnet werden. Der Programmcode lautet in der einfachsten Form:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x)
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh1.jpg]]
Der Code ist quasi selbsterklärend. Das Untermodul pyplot des matplotlib-Moduls und das numpy-Modul werden importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plt.plot()" ist der Zeichenbefehl. "plt.show" ist notwendig, um das Fenster mit der Grafik anzuzeigen.
Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen. "plt.grid()" zeichnet ein Gitter in die Grafik (kann auch weggelassen werden).
Die Bezeichnungen plt und np könnten auch anders gewählt werden. Es ist aber Konvention, diese so wie hier gezeigt zu wählen. Die "arange"-Funktion aus der NumPy-Bibliothek wird später ein bisschen genauer behandelt (siehe [[Ing_Mathematik:_Python#Zahlenfolgen|Zahlenfolgen]]).
<small>Mit der im obigen Bild gezeigten Menüleiste kann die dargestellte Grafik nachträglich noch geändert werden (Zoom, Pan, Achsenparameter, Kurvenparameter etc.). Natürlich kann man das alles auch direkt programmieren. Wie das funktioniert wird ansatzweise etwas später gezeigt.</small>
Ein etwas komplexeres Beispiel ist Folgendes:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x) + 2**x
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh4.png]]
Man beachte, dass im Gegensatz zu Octave und Julia der ominöse Punkt (.) bei 2**x mit Python nicht benötigt wird. Das macht das Programmiererleben etwas einfacher.
Die Farbe des Graphen kann man über den <code>color</code>-Schalter einstellen, z.B. auf rot setzen:
plt.plot(x, y, color="red")
Das ist nur eine Möglichkeit, es gibt auch andere, z.B. mittels
* hexadezimaler Zahl, z.B. <code>color="#ff0000"</code>
* Kurzform, z.B. <code>"r"</code>
Statt <code>color</code> kann auch die Kurzform <code>c</code> verwendet werden.
<u>Kleine Aufgabe:</u> Probieren Sie diese "Farbspielereien" am Computer aus.
=== Graphen mehrerer Funktionen und weiteres ===
==== Mehrere Funktionen in einen Plot zeichnen ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x")
plt.plot(x, y2, label = "sin(x) * cos(x)")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh2.png]]
Um die Linienstile etwas individueller zu gestalten, ist folgender Programmcode gedacht:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
plt.plot(x, y2, label = "sin(x) * cos(x)", lw=3, ls="--")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh3.png]]
Einige weitere Bespiele zu <code>ls</code></code>:
* - ... durchgezogene Linie
* -. ... Strichpunkt-Linie
* dashed ... gestrichelte Linie
==== Marker ====
Desweiteren kann man Marker verwenden.
Beispiel:
import matplotlib.pyplot as plt
plt.plot(10, 10, "ob", markersize=30)
plt.plot(20,20, ".r")
plt.plot(30,30, "Dg", ms=15)
plt.plot(40, 40, "ok", ms=20, mec="#FF5733", mew=3)
plt.plot(50, 50, "vk", ms=20, mec="yellow", mew=3)
plt.grid()
plt.show()
Das erste Zeichen im String nach den Koordinaten im plot-Befehl symbolisiert die Form (z.B. o für einen Kreis). Das zweite Zeichen steht für die Farbe (z.B. b für blue). <code>markersize</code> oder <code>ms</code> setzt die Größe des Markers.
Ausgabe:
[[Bild:PythonIng_formatpara1.svg|200px]]
Einige weitere Marker:
* * ... Stern
* + ... Plus
* h oder H ... Sechseck
Man kann mit den Parametern
* <code>markeredgecolor</code> oder kurz <code>mec</code> die Farbe des Markerrandes
* <code>markeredgewidth</code> oder kurz <code>mew</code> die Dicke des Randes
* <code>markerfacecolor</code> oder kurz <code>mfc</code> die Innenfarbe des Markers
bestimmen.
=== Funktion in Parameterdarstellung ===
Es soll die archimedische Spirale <math>x = t \cos(t), y = t \sin(t)</math> im Intervall <math>[0, 6\pi[</math> gezeichnet werden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.show()
[[Datei:PythonIng_spirale1.png]]
Diese Darstellung erscheint verzerrt. Will man gleiche Achsenskalierungen, so kann man den plt.axis()-Befehl verwenden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.axis("equal")
plt.show()
[[Datei:PythonIng_spirale2.png]]
=== Funktion in Polardarstellung ===
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
r = np.arange(0, 1, 0.01)
theta = r**3
line = ax.plot(theta, r)
plt.show()
[[Datei:PythonIng_polar1.png]]
=== Logarithmische Achsenskalierung ===
==== Semilog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.semilogy()
plt.show()
Ausgabe:
[[Datei:PythonIng_semilog1.png]]
==== LogLog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.loglog()
plt.show()
[[Datei:PythonIng_loglog1.png]]
=== Gefüllte Fläche ===
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 3, 0.1)
y1 = 3*x - 1
y2 = x**2
plt.plot(x, y1, x, y2, color='black')
plt.fill_between(x, y1, y2, where=y1>=y2)
plt.show()
[[Datei:PythonIng_gefuellt.png]]
=== Linien, Pfeile, Rechtecke, Kreise und Texte ===
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
r = mpl.patches.Rectangle((0, 0), 3, 3, angle=30, fill=False)
c = mpl.patches.Circle((4, 4), 2, fill=False)
ax.add_patch(r)
ax.add_patch(c)
ax.plot([-2, 7], [-2, 0], color="black")
ax.arrow(0, 7, 5, 0, length_includes_head=True, head_width=0.5, head_length=1.5,
color="black")
ax.set_aspect("equal")
plt.axis([-3, 8, -3, 8])
plt.show()
[[Datei:PythonIng_linien_pfeile_etc.png]]
Text kann mit <code>ax.text(x, y, "Text")</code> hinzugefügt werden, bspw.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
ax.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
Oder einfacher auch ohne <code>subplots</code>
import matplotlib.pyplot as plt
plt.text(0.1, 0.1, "Hallo")
plt.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text1.png]]
Auch Sonderzeichen (griechische Buchstaben etc.) können verwendet werden (siehe dazu auch [https://matplotlib.org/stable/users/explain/text/mathtext.html]).
import matplotlib.pyplot as plt
plt.text(.3, .5,
r'$\Omega\ \psi\ \oint\ \nabla\ \dot a\ \frac{a}{b}\ a_b$',
size="20")
plt.show()
[[Datei:PythonIng_text20.svg]]
Jetzt wird noch gezeigt, wofür <code>subplots</code> sinnvoll eingesetzt werden können.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(0.1, 0.1, "Hallo")
ax[1].text(0.1, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text2.png]]
=== Anmerkungen hinzufügen ===
Anmerkungen (engl. annotations) lassen sich mit matplotlib einfach hinzufügen. Unter Anmerkung wird hier ein Pfeil mit Text verstanden.
Beispiel:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1,10], [1,10])
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0))
plt.show()
Ausgabe:
[[Datei: PythonIng_ann1.svg|400px]]
<code>shrink</code> verkürzt den Pfeil. Sinnvoll sind beim obigen Beispiel Werte irgendwo zwischen 0.0 und 0.3.
<u>Kleine Aufgabe:</u> Probieren Sie verschiedene Pfeillängen aus.
Die Schriftgröße verändern können Sie übrigens mit <code>fontsize</code> oder <code>size</code>, z.B.
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0), fontsize=25)
Eine andere Schreibweise für Dictionaries, die wir weiter oben schon kennengelernt haben, die wir aber nochmals explizit aufschreiben wollen, ist
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops={"facecolor":"red", "shrink":0.0})
=== Figure, Axes etc.===
[[Bild:PythonIng_figure33.svg|350px]]
* fig (figure) ... das übergeordnete Fenster
* ax (axes) ... "Plot", das eigentliche Zeichenfenster
* axis ... die Koordinatenachsen
* spine ... Begrenzungslinien des Zeichenfensters
* tick ... Markierung an den Achsen des Zeichenfensters
Beispiel (eine figure mit 6 axes, ax-Titel, y-axis-Titel):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=3, ncols=2)
ax[0][0].text(0.1, 0.5, "11")
ax[0][1].text(0.1, 0.5, "12")
ax[1][0].text(0.1, 0.5, "21")
ax[1][1].text(0.1, 0.5, "22")
ax[2][0].text(0.1, 0.5, "31")
ax[2][1].text(0.1, 0.5, "32")
ax[0][0].set(ylabel="y-label", title="axes 1")
plt.show()
[[Bild:PythonIng_figure34.png|350px]]
Beispiel (Achsenbereiche setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-1, 10, 1, 12))
plt.show()
[[Bild:PythonIng_figure35.svg|350px]]
Beispiel (Gitter einschalten):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-5, 10, 1, 12))
ax[0].minorticks_on()
ax[0].grid(which='minor')
ax[1].grid(which='major')
plt.show()
[[Bild:PythonIng_figure36.svg|350px]]
Beispiel (ticks setzen)
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
pos = [0, .2, .5]
lab = ["a", "b", "c"]
ax.xaxis.set_major_locator(tick.FixedLocator(pos))
ax.xaxis.set_major_formatter(tick.FixedFormatter(lab))
plt.show()
[[Bild:PythonIng_figure37.svg|350px]]
Beispiel (Achsenkreuz beliebig setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position(('data', 0.3))
ax.spines['left'].set_position(('data', 0.5))
plt.show()
[[Bild:PythonIng_figure38.svg|350px]]
Beispiel (Inset):
import matplotlib.pyplot as plt
# Hauptplot erstellen
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
# Inset hinzu:
axin = ax.inset_axes([0.4, 0.4, 0.3, 0.3])
axin.text(0, 0, "Servus")
axin.plot()
plt.show()
[[Bild:PythonIng_figure40.svg|350px]]
Beispiel (Hintergrundfarben setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_facecolor("green")
fig.set_facecolor("yellow")
plt.plot([1, 3], [6, 8])
plt.show()
[[Bild:PythonIng_figure39.svg|300px]]
=== GridSpec ===
Mit figures und axes lassen sich schon jede Menge an Grafikdetails einstellen. GridSpec ist dann der Turbo oder Raketenantrieb den matplotlib eingebaut hat. Naja, vielleicht ist das etwas übertrieben, aber GridSpec ist sozusagen ein flexibler Layout-Manager. Bisher haben wir immer gleich große axes gezeichnet. Mit GridSpec können wir Subplots über mehrere Zeilen und Spalten ziehen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(3, 3)
ax1 = fig.add_subplot(gs[0, :])
ax1.set_title("Bereich 1: gs[0, :]")
ax2 = fig.add_subplot(gs[1:, 0])
ax2.set_title("Bereich 2: gs[1:, 0]")
ax3 = fig.add_subplot(gs[1, 1:])
ax3.set_title("Bereich 3: gs[1, 1:]")
ax4 = fig.add_subplot(gs[2, 1:])
ax4.set_title("Bereich 4: gs[2, 1:]")
plt.show()
[[Bild:PythonIng_gridspec1.svg|350px]]
Erklärung zu <code>(gs[zeile, spalte])</code>: Slicing; damit legen Sie fest, welche Zellen ein Subplot belegt. Achtung! Die Indizes beginnen bei 0 und nicht bei 1 (d.h., die erste Zeile/Spalte hat den Index 0)
* : ... alle
* 1: ... 1 bis Ende
* etc.
<code>constrained_layout=True</code> sorgt dafür, dass sich die Subplots nicht überlappen.
Aber auch die Spaltenbreiten und Zeilenhöhen lassen sich anpassen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
# Verhältnis erste zu zweite Zeile = 1.5:1
# Verhältnis erste zu zweite Spalte = 1:4
gs = fig.add_gridspec(2, 2, figure=fig, height_ratios=[1.5, 1], width_ratios=[1, 4])
ax1 = fig.add_subplot(gs[0, 0])
ax1.set_title("Bereich 1: gs[0, 0]")
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_title("Bereich 2: gs[0, 0]")
ax3 = fig.add_subplot(gs[1, 0])
ax3.set_title("Bereich 3: gs[1, 0]")
ax4 = fig.add_subplot(gs[1, 1:])
ax4.set_title("Bereich 4: gs[1, 1]")
plt.show()
[[Bild:PythonIng_gridspec2.svg|350px]]
Auch die Ränder lassen sich einstellen.
Beispiel 1:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.1, right=0.9, bottom=0.1,
top=0.9, wspace=0.2, hspace=0.2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec3.svg|300px]]
* hspace ... height space, vertikaler Abstand zwischen den Zeilen
* wspace ... width space, horizontaler Abstand zwischen den Spalten
Und im Vergleich dazu Beispiel 2:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.3, right=0.7, bottom=0.3,
top=0.7, wspace=0.3, hspace=0.3)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec4.svg|300px]]
Es gibt noch einige weitere Details, die sich mit GridSpec variieren lassen (z.B. SubGridSpec ... verschachtelte Grid-Layouts). Aber wir belassen es vorerst dabei. Das bisher Gezeigte sollte für die meisten Probleme ausreichend sein.
=== Aufgaben ===
* Zeichnen Sie die Strophoide <math>x = \frac{a(t^2-1)}{t^2+1}, y = \frac{at(t^2-1)}{t^2+1}, a = 2, -3 \leq t \leq 3</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_strophoide.jpg|300px|center]]
* Zeichnen Sie die verschlungene Hypozykloide <math>x = (R-r)\cos t + c\cos\frac{R-r}{r}t, y = (R-r)\sin t - c\sin\frac{R-r}{r}t, c = 3, r = 2, R = 6, -15 \leq t \leq 15</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_hypozykloide.jpg|300px|center]]
* Testen Sie bei den obigen Übungsaufgaben verschiedene Linienstile und Farben. Farben können mit dem plt.plot()-Parameter color gewählt werden.
* Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.
* Zeichnen Sie folgendes Bild (die Achsenbeschriftungen positionieren Sie z.B. mit den Befehlen <code>ax.set_xlabel("x", loc="right"); ax.set_ylabel("y", loc="top")</code>):
[[Bild:PythonIng_aufgabe24.svg|400px|center]]
* Zeichnen Sie mit Python, matplotlib und NumPy folgendes Bild:
[[Bild:PythonIng_figure41.svg|400px|center]]
* Zeichnen Sie mit GridSpec ein Layout, das in etwa wie folgendes aussieht (<code>height_ratios=[1, 2], width_ratios=[2, 1]</code>):
[[Bild:PythonIng_aufgabe23.svg|300px|center]]
== 3D ==
=== Räumliche Kurven ===
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0, 6*np.pi, 0.1)
x = t * np.cos(t)
y = t * np.sin(t)
z = t
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot(x, y, z)
plt.show()
[[Datei:PythonIng_raumkurve1.png]]
=== Flächen ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z)
plt.show()
[[Datei:PythonIng_fläche1.png]]
Das Ganze in Netzdarstellung läßt sich so programmieren:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = np.arange(0, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_wireframe(x, y, z)
plt.show()
[[Datei:PythonIng_fläche2.png]]
Ein etwas komplexeres Beispiel:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.1, 10, 0.1)
y = np.arange(0.1, 10, 0.1)
x, y = np.meshgrid(x, y)
z1 = np.sin(x) + 3 * np.cos(y)
z2 = np.sin(x) + np.log(y)
z3 = x + np.cos(y)
z4 = x**2 - y
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, nrows=2, ncols=2)
ax[0][0].plot_surface(x, y, z1)
ax[0][1].plot_surface(x, y, z2)
ax[1][0].plot_surface(x, y, z3)
ax[1][1].plot_surface(x, y, z4)
plt.show()
[[Datei:PythonIng_subplot1.png]]
Man beachte, dass man die Unterbilder im Bild nach dem Ausführen des Scripts z.B. mit der mittleren Maustaste einzeln drehen, oder über die Einträge in der Menüzeile einzeln bearbeiten kann. Mit ein paar Zeilen Programmtext lässt sich also eine Menge an Funktionalität generieren.
Die Farbgebung lässt sich über <code>colormaps</code> variieren.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm)
plt.show()
[[Datei:PythonIng_colormap1.png]]
Es gibt eine Menge an Colormaps, z.B. <code>plasma, Greys, Dark2, ocean</code>. Zwecks detaillierterer Infos siehe die matplotlib-Dokumentation. <small>Verwendet man die IDE namens IDLE, so gibt es dort auch die automatische Codevervollständigung. D.h. es werden alle Möglichkeiten (in unserem Fall nach dem Eintippen von <code>cm.</code> alle verfügbaren Colormaps) angezeigt.</small>
Die "edgecolor" und Linienbreite können auch frei gewählt werden:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm, edgecolor="black", linewidth=1.0)
plt.show()
[[Datei:PythonIng_colormap2.png]]
=== Höhenlinien ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
ax.contour(x, y, z)
plt.show()
[[Datei:PythonIng_höhenlinien1.png|400px]]
Etwas abgewandelt sieht das so aus:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contour(x, y, z)
ax.clabel(hl, inline = True)
plt.show()
[[Datei:PythonIng_höhenlinien2.png|400px]]
Und noch eine Variante (mit einem Farbbalken) sei gezeigt.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contourf(x, y, z)
fig.colorbar(hl)
plt.show()
[[Datei:PythonIng_höhenlinien5.svg|400px]]
=== Aufgaben ===
* Zeichnen Sie die räumliche Kurve <math>x = 2 \cdot \cosh(t)</math>, <math>y = 5 \cdot \sin(t)</math>, <math> z = t^{2} - t</math>, <math>0 \leq t \leq 3\pi</math>.
* Zeichnen Sie die Fläche <math>z = \log(x) + \cos(y)</math>.
== Animationen und fortgeschrittenes 3D ==
=== Mit matplotlib ===
Auch mit matplotlib sind Animationen möglich. Das ist ein bisschen komplizierter und wird deshalb hier nur mit einem sehr einfachen Beispiel dargestellt (bei Interesse siehe z.B. auch das [https://matplotlib.org/stable/users/explain/animations/animations.html#animations Animations using Matplotlib-Tutorial]).
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib
import numpy as np
def update(frame):
line.set_xdata(x[:frame])
line.set_ydata(y[:frame])
return (line)
fig, ax = plt.subplots()
x = np.arange(0, 10, .1)
y = np.sin(x)
line, = ax.plot(x[0], y[0])
ax.set(xlim=[0, 10], ylim=[-1, 1])
a = ani.FuncAnimation(fig=fig, func=update, frames=100, interval=20)
plt.show()
# Speichere die Animation in einem animierten GIF (optional)
a.save(filename="c:/tmp/PythonIng_anim5.gif", writer="pillow")
[[Datei:PythonIng_anim5.gif]]
Es wird eine Sinuskurve auf den Bildschirm gezeichnet. In der letzten Zeile wird diese Animation in ein animiertes GIF gespeichert. Das ist natürlich optional und kann auch weggelassen werden.
=== Mit VPython ===
Aber auch mit dem Modul VPython lassen sich einfache 3D-Animationen erstellen. VPython ist ein externes Modul, das vorab installiert werden muss. Unter openSUSE Tumbleweed gibt es dzt. kein entsprechendes rpm-Paket. Die übliche Methode der Installation mittels YaST oder zypper ist somit nicht möglich. Auch eine direkte Verwendung von pip führt nur zu einer Fehlermeldung (<code>error: externally-managed-environment</code>). Es empfiehlt sich dort folgende Vorgehensweise:
# Erstelle zuerst eine virtuelle Umgebung, z.B.: <code>python3.11 -m venv ~/tmp/venv1</code>
# Wechsle das Verzeichnis: <code>cd ~/tmp/venv1/bin</code>
# Installiere das entsprechende Paket: <code>./pip install vpython</code>
# Führe das entsprechende Skript aus: <code>./python ~/tmp/test1.py</code>
Aktuell (März 2026) ist dieses Programmpaket lt. der [https://vpython.org/presentation2018/install.html VPython-Homepage] nur für die Python-Versionen 3.8 bis 3.12 verfügbar.
Ein Beispiel zu einer einfachen Animation wird nachfolgend geliefert.
from vpython import *
scene.width = 1200
scene.height = 600
scene.center = vector(20,0,0)
scene.background = color.white
cylinder(pos=vector(0,0,0), axis=vector(20,0,0), radius=5,
color=color.blue)
cone(pos=vector(0,0,0), axis=vector(-10,0,0), radius=5,
color=color.blue)
helix(pos=vector(20,0,0), axis=vector(40,0,0), radius=2,
coils=10, thickness=0.5, color=color.blue)
ball = sphere(pos=vector(20,0,0), color = color.green, radius = 1)
ball.p = vector(0.15, 0, 0)
toc = True
while True:
rate(200)
if(ball.pos.x <= 60 and toc == True):
ball.pos += ball.p
else:
toc = False
ball.pos -= ball.p
if(ball.pos.x <= 20 and toc == False):
toc = True
[[Datei:PythonIng_vpython_anim.JPG]]
Idealerweise öffnet sich beim Ausführen des Scripts ein Browserfenster. Darin wird die programmierte Animation gezeigt (siehe auch den obigen Screenshot). Eine Größenänderung können Sie mit der mittleren Maustaste initiieren. Die Szenerie drehen können Sie mit der rechten Maustaste.
=== Mit build123d ===
Hiermit lassen sich einfach 3D-Modelle für CAD-Systeme erstellen. [https://build123d.readthedocs.io/en/latest/ build123d] ist ein externes Modul und muss vorab, wie schon für mehrere andere Module gezeigt, installiert werden (pip, venv etc.).
Beispielcode:
from build123d import *
# Bauteil
with BuildPart() as bauteil:
# Zylinder erstellen
Cylinder(100, 60)
# Bohrung
with BuildSketch(bauteil.faces().sort_by(Axis.Z)[-1]) as loch:
Circle(radius=10)
# negativ extrudieren
extrude(amount=-60, mode=Mode.SUBTRACT)
# Dem Bauteil z.B. die Farbe rot zuweisen
# bauteil.part.color = Color("red", alpha=1.0)
# Fertiges Modell exportieren
export_step(bauteil.part, "bauteil.step")
Ausgabe ({{W|Standard for the exchange of product model data | STEP}}-Datei, z.B. in {{W|FreeCAD}} importiert, Screenshot):
[[Datei:PythonIng_build123d.jpg | 300px]]
FreeCAD ist ein freies 3D-CAD-System. Die [[Ing_Mathematik:_Python#FreeCAD | Makroprogrammierung]] in diesem System wird später noch gezeigt. STEP steht für "'''St'''andard for the '''e'''xchange of '''p'''roduct model data" und ist ein Datenaustauschformat.
=== Mit VTK ===
Komplexer, aber auch mächtiger als VPython ist die Verwendung von VTK ('''V'''isualization '''T'''ool'''k'''it). Genauer gesagt des Python-Wrappers von VTK. Dieses externe Python-Modul muss vorab installiert werden (z.B. mittels YaST, pip oder in eine virtuelle Umgebung). VTK ist eine Softwarebibliothek zur 3D-Visualisierung und wurde ursprünglich in C++ geschrieben. Verbreitet eingesetzt wird diese Bibliothek in der Wissenschaft und Forschung, z.B.
* in der medizinischen Bildgebung
* für Strömungssimulationen
* für Klimadaten
VTK funktioniert nach dem {{W|Grafikpipeline|Pipeline-Prinzip}}:
Source (Quellen) -> Filter -> Mapper (Senken) -> Actor/Renderer
Daten fließen von den Quellen zu den Senken.
Als einfaches Beispiel wird die Darstellung eines Zylinders gezeigt, der mit den Maustasten gedreht oder in der Größe geändert werden kann:
import vtk
# Zylinder erzeugen
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
# Geometrie in darstellbare Daten umwandeln
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
# Objekt in der Szene
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Szene verwalten
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# Render-Fenster
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
# Maus/Tastatur-Steuerung
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Starten
render_window.Render()
interactor.Start()
Ausgabe:
[[Datei:PythonIng_VTK_1.png]]
Gleiches Beispiel wie oben, aber mit einer Animationssequenz:
import vtk
import time
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
render_window.Render()
time.sleep(0.01)
Das Grafikfenster schließt sich nach Ablauf der Schleife. Das Fenster bleibt geöffnet, wenn Sie am Programmende folgenden Befehl hinschreiben
interactor.Start()
Um den animierten Zylinder grün einzufärben, müssen Sie Folgendes im obigen Programm ergänzen (Farbnamen):
colors = vtk.vtkNamedColors()
actor.GetProperty().SetColor(colors.GetColor3d("Green"))
Als Namen können Sie u.a. die CSS3 Web-Farben verwenden (siehe z.B. [https://wiki.selfhtml.org/wiki/Farbe/Farbangaben] und {{W|Webfarbe#CSS_3}}).
Alternativ funktioniert auch das ({{W|RGB-Farbraum|RGB}}):
actor.GetProperty().SetColor(0.0, 0.6, 0.0)
Wie der Zylinder mit einer Textur versehen wird, zeigt folgendes Programm:
import vtk
import time
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(30)
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.CappingOn()
texture_coords = vtk.vtkTextureMapToCylinder()
texture_coords.SetInputConnection(cylinder.GetOutputPort())
texture_coords.PreventSeamOn()
reader = vtk.vtkJPEGReader()
reader.SetFileName("PythonIng_textur.jpg")
texture = vtk.vtkTexture()
texture.SetInputConnection(reader.GetOutputPort())
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(texture_coords.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.SetTexture(texture)
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
renderWindow.Render()
time.sleep(0.01)
interactor.Start()
<gallery>
PythonIng_textur.jpg | Textur-Datei
PythonIng_VTK_2.png | Ausgabe (Screenshot)
</gallery>
== Sonstige Grafikbibliotheken ==
=== Py5 ===
Im Buch ''Iacono et al.: Programmieren trainieren, mit über 150 Workouts in Java und Python; 3. Aufl., Hanser, 2023'' werden zahlreiche Aufgaben gestellt, die u.a. mit Processing zu lösen sind. Processing ist eine einfache Programmiersprache und Entwicklungsumgebung. Warum ich das erwähne? Weil in älteren Processing-Versionen auch die Programmiersprache Python 2 abgedeckt war. Bei neueren Versionen gibt es keine Python-Anbindung mehr (getestet nur mit openSUSE Tumbleweed und Python 3). Somit funktioniert der Python-Teil im genannten Buch zum Teil nicht mehr. Ist das tragisch, oder kann das Buch weggeschmissen werden? Nein! Es gibt Alternativen zu Processing. Zum einen die im Buch selbst genannten Bibliotheken tkinter oder pygame. Pygame wird dort auch kurz anhand eines Beispiels thematisiert. Aber noch besser ist es, die py5-Bibliothek zu verwenden (lt. Google KI vom 30. Sept. 2026: ''Der echte, moderne „spirituelle Nachfolger“''). Damit ist die Funktionalität von Processing gewährleistet. Man kann aber beliebige Editoren oder IDEs zur Programmerstellung verwenden, ohne an Processing als IDE gebunden zu sein. Nachfolgend werden ein paar Beispiele zu dieser externen Bibliothek gegeben. Der erste Schritt ist wieder, die py5-Bibliothek zu installieren (z.B. mittels pip in eine virtuelle Umgebung; Python>=3.10 und ein JDK>=17 müssen auch installiert sein (Stand Okt. 2026)). Dann kann es schon mit dem Programmieren losgehen.
Beispiel (angelehnt an die ''Aufgabe W.2.3 Haus'' des genannten Buchs, jedoch etwas erweitert):
import py5
def setup():
py5.size(600, 600) # Fenstergröße 600px x 600px
py5.background(255, 255, 255) # Hintergrundfarbe ... weiss
def draw():
# Haus zeichnen
py5.fill(255, 255, 255) # Hintergrundfarbe ... weiss
py5.stroke(255, 0, 0) # Linienfarbe ... rot
py5.stroke_weight(3) # Linienbreite ... 3px
py5.rect(150, 200, 300, 300) # Rechteck zeichnen (x, y, b, h)
py5.triangle(150, 200, 300, 100, 450, 200) # Dreieck zeichnen
py5.circle(250, 300, 70) # Kreis zeichnen (x, y, d)
# Bemassung zeichnen
py5.stroke(0, 255, 0)
py5.stroke_weight(1)
py5.line(300, 100, 550, 100) # Linie zeichnen
py5.line(450, 200, 550, 200)
py5.line(450, 500, 550, 500)
py5.line(150, 500, 150, 550)
py5.line(450, 500, 450, 550)
py5.text_size(20) # Textgroesse
py5.fill(0, 255, 0) # Textfarbe
py5.text("300", 280, 550) # Text zeichnen
py5.text("100", 500, 150)
py5.text("300", 500, 350)
# Gedrehtes Rechteck zeichnen
py5.stroke(255, 255, 0)
py5.stroke_weight(3)
py5.fill(200, 200, 200)
py5.translate(320, 260)
py5.rotate(0.3) # Drehung (in Radiant)
py5.rect(0, 0, 100, 50)
# Startet den Sketch
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_1.png|300px]]
Das skizzierte Haus ist mit einer rudimentären Bemaßung versehen und hat zwei Fenster, ein rundes und ein gedrehtes, trübes rechteckiges.
Beispiel (Mausoperationen):
import py5
def setup():
py5.size(600, 600)
py5.background(255, 255, 255)
def draw():
pass
def mouse_pressed():
py5.text_size(15)
py5.fill(0, 0, 255)
x = py5.mouse_x
y = py5.mouse_y
py5.text("(%d, %d)" %(x, y), x, y) # Positionsdaten bei Maus-Klick schreiben
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_2.png|300px]]
Obiges Bild zeigt das Resultat nach einigen Mausklicks. Man erkennt, dass links-oben der Koordinatennullpunkt ist. Die x-Achse zeigt nach rechts, die y-Achse nach unten.
Beispiel (Fünfeck):
import py5
import random
def setup():
py5.size(400, 400)
py5.no_loop() # statisches Bild (schont die Ressourcen)
def draw():
py5.translate(py5.width / 2, py5.height / 2) # KS setzen
radius = 150
eck_anzahl = 5
py5.fill(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255)) # Füllfarbe auf Zufallswert setzen
py5.stroke(155, 0, 0)
py5.stroke_weight(5)
# Fünfeck als Polygon zeichnen
py5.begin_shape()
for i in range(eck_anzahl):
winkel = i * py5.TWO_PI / eck_anzahl - py5.HALF_PI
x = py5.cos(winkel) * radius
y = py5.sin(winkel) * radius
py5.vertex(x, y)
py5.end_shape(py5.CLOSE)
py5.run_sketch()
Ausgabe, bspw.:
[[Datei:PythonIng_py5_5.png|200px]]
<u>Kleine Aufgaben:</u>
* Um die Funktionsweise von <code>py5.no_loop()</code> zu verstehen, kommentieren Sie die Anweisung im Beispiel einfach aus, und starten Sie das Programm erneut.
* Zeichnen Sie ein Siebeneck.
* Was passiert, wenn man <code>py5.CLOSE</code> im <code>py5.end_shape()</code>-Befehl weglässt?
Beispiel (Grafik laden und zeichnen):
import py5
image1 = None
def setup():
global image1
py5.size(600, 600)
py5.no_loop()
image1 = py5.load_image("PythonIng_py5_1.png")
def draw():
py5.image(image1, 0, 0)
py5.run_sketch()
Hier wird einfach das Bild vom Haus-Beispiel (Screenshot von weiter oben) geladen und gezeichnet.
Beispiel (angelehnt an ''W.5.10 Wurfparabel'' des genannten Buches; mit OOP erstellt):
import py5
class Wurfparabel(py5.Sketch):
def __init__(self, v0, angle):
super().__init__()
self.v0 = v0
self.angle = self.radians(angle)
self.g = 9.81
self.t = 0.0
self.scale = 1.5
def settings(self):
self.size(800, 600)
def setup(self):
self.background(0, 0, 0)
def draw(self):
self.t += 0.1
self.translate(50, 500)
# KS Zeichnen
self.fill(255, 255, 0)
self.stroke(255, 255, 0)
self.stroke_weight(1)
self.line(0, 0, 0, -300)
self.line(0, 0, 700, 0)
# Punkt zeichnen
cx = self.v0 * self.cos(self.angle) * self.t * self.scale
cy = -(self.v0 * self.sin(self.angle) * self.t - \
self.g/2 * self.t**2) * self.scale
self.fill(255, 0, 0)
self.stroke(255, 0, 0)
self.circle(cx, cy, 3)
# Stoppen bei Bodenkontakt
if cy >= -5:
self.no_loop()
def wurfparabel(v0=50, angle=45):
sketch = Wurfparabel(v0, angle)
sketch.run_sketch()
v0 = float(input("v0 = "))
winkel = float(input("winkel = "))
wurfparabel(v0=v0, angle=winkel)
Eingabe auf der Konsole:
v0 = 60
winkel = 45
Ausgabe:
[[Datei:PythonIng_py5_13.png|200px]]
Die benötigten Formeln der Bewegungsgleichung kann man leicht herleiten, bzw. man benutzt folgende Grafik als Hilfestellung:
[[Datei:Wurfparabel_Zusammenfassung_aktualisierung.png|700px]]
<u>Aufgabe:</u> Berechnen Sie den Scheitelpunkt und die Wurfweite bei gegebener Anfangsgeschwindigkeit und gegebenem Abwurfwinkel. Die Abwurfhöhe <math>y_0</math> sei 0. Der Wurf soll auf der Erde stattfinden (g = 9.81 m/s²). Die dazu benötigten Formeln können aus obiger Grafik entnommen werden (oder Sie leiten sie selbst her). Geben Sie die Ergebnisse auf der Konsole aus.
Hiermit belassen wir es mit der py5-Bibliothek und wenden uns wieder "mathematischeren" Themen zu.
= Vektoren und Matrizen =
== Zahlenfolgen ==
Für das Erstellen von Zahlenfolgen bieten sich die Funktionen <code>arange</code> und <code>linspace</code> aus dem <code>numpy</code>-Modul an.
from numpy import *
start = 0
stop = 10
step = 2
num = 10
r = arange(start, stop, step) # step ... Schrittweite
l = linspace(start, stop, num) # num ... Anzahl der Werte
print("r = ", r)
print("l = ", l)
Ausgabe:
r = [0 2 4 6 8]
l = [ 0. 1.11111111 2.22222222 3.33333333 4.44444444 5.55555556
6.66666667 7.77777778 8.88888889 10. ]
Bei <code>arange</code> ist der <code>stop</code>-Wert nicht im Ergebnis enthalten, bei <code>linspace</code> standardmäßig aber sehr wohl. Jedoch kann man das bei <code>linspace</code> auch ändern. Dann ist der Stoppwert nicht mehr enthalten:
linspace(start, stop, num, endpoint=False)
== Vektoren ==
Vektoren sollten jedem aus der Linearen Algebra bekannt sein.
=== Arrays ===
In Python mit NumPy kann man Vektoren durch die Funktion array erzeugen.
import numpy as np
l1 = (-5, 3, 2)
l2 = (1, 1, 4)
a1 = np.array(l1)
a2 = np.array(l2)
a3 = a1 + a2
a4 = 2 * a2
print(a1)
print(a2)
print(a3)
print(a3[2])
print(a4)
Ausgabe:
[-5 3 2]
[1 1 4]
[-4 4 6]
6
[2 2 8]
=== Zeilen- und Spaltenvektoren ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
print(z)
print(s)
Ausgabe:
[ [-5 3 2] ]
[[1]
[1]
[4]]
=== Skalarprodukt ===
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
skalarprodukt = np.dot(a1, a2)
print(skalarprodukt)
Ausgabe:
6
=== Vektorprodukt ===
<math>a\ast b=\left(\begin{array}{c}
a_{1}\\
a_{2}\\
a_{3}
\end{array}\right)\ast\left(\begin{array}{c}
b_{1}\\
b_{2}\\
b_{3}
\end{array}\right)=\left(\begin{array}{c}
a_{2}b_{3}-a_{3}b_{2}\\
a_{3}b_{1}-a_{1}b_{3}\\
a_{1}b_{2}-a_{2}b_{1}
\end{array}\right)
</math>
Python-Code:
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
vektorprodukt = np.cross(a1, a2)
print(vektorprodukt)
Ausgabe:
[10 22 -8]
=== Transponierter Vektor ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
# transponierter Vektor
z_tp = np.transpose(z)
# transponierter Vektor
s_tp = np.transpose(s)
print(z_tp)
print(s_tp)
Ausgabe:
[[-5]
[ 3]
[ 2]]
[ [1 1 4] ]
=== Vektorfelder visualisieren ===
import matplotlib.pyplot as plt
import numpy as np
# Daten generieren
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
X, Y = np.meshgrid(x, y)
U = X * Y
V = Y + X
# Plotten
fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='xy')
plt.show()
Ausgabe:
[[Datei:PythonIng_quiver1.png]]
== Matrizen==
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
print(m1)
Ausgabe:
[[1 2 3]
[4 5 6]]
=== Zugriff auf Matrizenelemente ===
Beispiel:
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
# Element aus Zeile 2 und Spalte 3 (Achtung! Index startet bei Null)
print(m1[1,2])
Ausgabe:
6
Visualisierung:
0 1 2
+-----------+
0 | 1 | 2 | 3 |
+-----------+
1 | 4 | 5 | '''6''' |
+-----------+
Beispiel:
import numpy as np
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
B = np.matrix(A)
print(B[2::, ::2])
Ausgabe:
[['20' '22']
['30' '32']
['40' '42']]
Mit der NumPy-Bibliothek funktioniert das zweidimensionale Slicing. Mit normalen Listen/Tupels geht das nicht, was wir schon früher thematisiert haben.
=== Addition und Subtraktion von Matrizen ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
m2 = np.matrix([[0, 0, 2], [1, 3, 2]])
print(m1 + m2)
print(m1 - m2)
Ausgabe:
[[1 2 5]
[5 8 8]]
[[1 2 1]
[3 2 4]]
=== Transponierte Matrix ===
import numpy as np
m = np.matrix([[1, 2, 3], [4, 5, 6]])
mt = np.transpose(m)
print(m)
print(mt)
Ausgabe:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]
=== Rang einer Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
rg = np.linalg.matrix_rank(m)
print(rg)
Ausgabe:
2
=== Inverse Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
mi = np.linalg.inv(m)
print(mi)
Ausgabe:
[[ 1. 0.6]
[-0. -0.2]]
=== Multiplikation von Matrizen (falksches Schema) ===
import numpy as np
m1 = np.matrix([[1, 3, 4], [0, -5, 1]])
m2 = np.matrix([[1, 2], [2, 3], [0, 2]])
print(m1 @ m2)
Ausgabe:
[[ 7 19]
[-10 -13]]
=== Eigenwerte und Eigenvektoren ===
import numpy as np
m = np.matrix([[5, 8], [1, 3]])
D,V = np.linalg.eig(m)
# Eigenwerte
print(D)
# Eigenvektoren
print(V)
Ausgabe:
[7. 1.]
[[ 0.9701425 -0.89442719]
[ 0.24253563 0.4472136 ]]
=== Teilmatrizen ===
import numpy as np
m = np.matrix([[1, 3, 4], [0, -5, 1]])
print("m = ", m)
# Erste Zeile extrahieren
m1 = m[0,:]
print("m1 = ", m1)
# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
m2 = m[0,1]
print("m2 = ", m2)
# Zweite Spalte extrahieren
m3 = m[:, 1]
print("m3 = ", m3)
Ausgabe:
m = [[ 1 3 4]
[ 0 -5 1]]
m1 = [ [1 3 4] ]
m2 = 3
m3 = [[ 3]
[-5]]
=== Spezielle Matrizen ===
==== Nullmatrix ====
import numpy as np
z = np.zeros((3, 2))
print(z)
Ausgabe:
[[0. 0.]
[0. 0.]
[0. 0.]]
==== Einheitsmatrix ====
import numpy as np
z = np.eye(3)
print(z)
Ausgabe:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
==== Matrix mit lauter Einsen ====
import numpy as np
z = np.ones((3, 2))
print(z)
Ausgabe:
[[1. 1.]
[1. 1.]
[1. 1.]]
=== Spärlich besetzte Matrizen ===
Das Thema spärlich besetzter Matrizen wird hier nur kurz angerissen. Nähere Details siehe unter dem Weblink [https://docs.scipy.org/doc/scipy/reference/sparse.html#module-scipy.sparse].
Beispiel:
import numpy as np
import scipy
A = scipy.sparse.csr_array(np.eye(5))
print(A)
Ausgabe:
<Compressed Sparse Row sparse array of dtype 'float64'
with 5 stored elements and shape (5, 5)>
Coords Values
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
(4, 4) 1.0
csr steht für '''c'''ompressed '''s'''parse '''r'''ow.
Andere Möglichkeiten:
* coo-Format ('''coo'''rdinate Format): <code>scipy.sparse.coo_array()</code>
* lil-Format ('''li'''st of '''l'''ists): <code>scipy.sparse.lil_array()</code>
* csc-Format ('''c'''ompressed '''s'''parse '''c'''olumn): <code>scipy.sparse.csc_array()</code>
Es gibt auch <code>scipy.sparse.csr_matrix()</code> etc. Diese Befehle sind aber veraltet und es wird empfohlen, statt dessen die <code>..._array()</code>-Funktionen zu verwenden.
<u>Aufgaben:</u>
Recherchieren Sie im Internet
* generell zum Thema "spärlich besetzte Matrizen mit Python".
* Was sind die Vor-/Nachteile von csr-arrays gegenüber coo- und lil-arrays?
* Wann verwendet man sinnvollerweise csr- und wann csc-arrays?
* Wie wandelt man coo-arrays in csr-arrays um?
= Lineare Gleichungssysteme =
Sei <math>Ax = b</math> ein lineares Gleichungssystem. <math>A</math> sei die Koeffizientenmatrix, <math>x</math> der Lösungsvektor und <math>b</math> ein bekannter Vektor.
Beispiel:
import numpy as np
A = np.array([[5, 1], [0, 2]])
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)
Ausgabe:
[0. 1.]
Siehe dazu auch das Kapitel [[Ing Mathematik: Numerisches Lösen von linearen Gleichungssystemen]]. Dort wird dieses Themengebiet u.a. mit weitergehenden Python-Skripten vertieft.
== Aufgabe ==
* Lösen Sie folgendes Gleichungssystem mittels Python (und zur Kontrolle auch händisch):
5x + 6y - 2z = 12
3x - y - 3z = 6
2x + 2y + 4z = 5
= Polynome =
== Ein erstes einfaches Beispiel ==
Gegeben sei das Polynom <math>7x^3+5x^2+1</math>. In Python:
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p)
Ausgabe:
3 2
7 x + 5 x + 1
== Einzelne Polynomwerte berechnen ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p(1.5))
Ausgabe:
35.875
== Polynome integrieren und differenzieren ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
# 1. Ableitung
p1 = p.deriv()
p2 = p.deriv(1)
# 2. Ableitung
p3 = p.deriv(2)
# Integral
p4 = p.integ()
print(p1)
print(p2)
print(p3)
print(p4)
Ausgabe:
2
21 x + 10 x
2
21 x + 10 x
42 x + 10
4 3
1.75 x + 1.667 x + 1 x
== Nullstellen bestimmen ==
import numpy as np
p = np.poly1d([2, 5, 0, 4])
r = np.roots(p)
print(r)
Ausgabe:
[-2.7621427 +0.j 0.13107135+0.84077099j 0.13107135-0.84077099j]
== Aufgaben ==
* Berechnen Sie den Wert für x = 3 des Polynoms <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Differenzieren und integrieren Sie das Polynom <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Berechnen Sie die Nullstellen von <math>y = 7x^5 - 3x^2 + 12</math>.
= Nichtlineare Gleichungen und Gleichungssysteme =
== Nullstellenbestimmung ==
Löse eine beliebige Gleichung f(x) = 0, z.B. <math> f(x) = x^2 - 5\cos(x) - 10 = 0 </math>:
import scipy
import numpy as np
def f(x):
return x**2 - 5*np.cos(x) - 10
xstart = [-1, 1] # Startwerte
xn = scipy.optimize.root(f, xstart)
print(xn.x)
Ausgabe:
[-2.46813009 2.46813009]
Funktionsgraph:
[[Datei:octave_nichtlin2.jpg]]
== Gleichungssysteme ==
SymPy ist ein externes Modul, das symbolisches Rechnen ('''Sym'''bolic '''Py'''thon) ermöglicht.
Folgende Aufgabe ist dem Buch "Knorrenschild: Numerische Mathematik, Hanser, 2017, Seite 72" entnommen. Zu lösen ist das nichtlineare Gleichungssystem
<math>f_1 = 2x_1 + 4x_2 = 0 </math>
<math>f_2 = 4x_1 + 8x_2^3 = 0</math>
Mit Python ist das so möglich:
import sympy
x1, x2 = sympy.symbols("x1 x2")
f1 = 2*x1 + 4*x2
f2 = 4*x1 + 8*x2**3
s = sympy.solve((f1, f2), x1, x2)
print(s)
Ausgabe:
[(-2, 1), (0, 0), (2, -1)]
Plot:
[[Datei:IngPython_nl_gleichung1.svg|500px]]
= Komplexe Zahlen =
Die imaginäre Einheit wird in Python durch den Buchstaben <code>j</code> symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:
* Kartesische Darstellung <math>z = \Re(z) + j \cdot \Im(z)</math>
* Polardarstellungen <math>z = r \cdot (\cos(\phi) + j \cdot \sin(\phi)) = r \cdot e^{j\cdot \phi}</math>
Die konjugiert komplexe Zahl ist <math>z^* = \Re(z) - j \cdot \Im(z)</math>
Nachfolgend einige mathematische Operationen mit Python und NumPy.
import numpy as np
z1 = 2 + 5j # kartesische Darstellung
z2 = 3 * np.exp(3j) # Polardarstellung
# Addition
res = z1 + z2
print("z1 + z2 = ", res)
# Multiplikation
res = z1 * z2
print("z1 * z2 = ", res)
# Realteil
res = np.real(z2)
print("Realteil von z2 = ", res)
# Imaginärteil
res = np.imag(z2)
print("Imaginaerteil von z2 = ", res)
# Betrag
res = np.abs(z1)
print("Betrag von z1 = ", res)
# Argument
res = np.angle(z1)
print("Argument von z1 = ", res)
# Konjugiert komplexe Zahl
res = np.conj(z1)
print("Konjugiert komplexe Zahl von z1 = ", res)
Ausgabe:
z1 + z2 = (-0.9699774898013365+5.423360024179601j)
z1 * z2 = (-8.05675510050068-14.003167400647481j)
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = (2-5j)
= Interpolation =
import numpy as np
import scipy
import matplotlib.pyplot as plt
# Stützpunkte
xp = np.arange(1, 6)
yp = (0, -5, 2, 7, 6)
ti = np.arange(1, 5, 0.01)
i1 = scipy.interpolate.interp1d(xp, yp, kind = "linear")
i2 = scipy.interpolate.interp1d(xp, yp, kind = "cubic")
plt.plot(xp, yp, "rx")
plt.plot(xp, i1(xp))
plt.plot(ti, i2(ti))
plt.show()
Ausgabe:
[[Datei:PythonIng_interpol1.png]]
= Differenzialrechnung =
== Numerisches Differenzieren ==
Als Beispiel differenzieren wir <math>y = 5x\sin{x}</math> und stellen das Ganze grafisch dar.
from findiff import Diff
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
f = 5 * x * np.sin(x)
dx = x[1] - x[0]
# Ableitung
d_dx = Diff(0, dx)
df_dx = d_dx(f)
# Grafik
plt.plot(x, f, label = "y")
plt.plot(x, df_dx, label = "y'")
plt.grid()
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:octave_diff1.jpg]]
<small>findiff ist ein externes Modul. Dieses muss installiert werden (z.B. so: ...\Python\Scripts\pip.exe install --upgrade findiff). Für die Vorgehensweise unter openSUSE Tumbleweed siehe das Kapitel [[Ing_Mathematik:_Python#Mit_VPython | VPython]], nur dass das Ganze mit einer aktuelleren Python-Version exekutiert wird, z.B. mit Python 3.13. Das im Buch "Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler, Rheinwerk" verwendete Modul "scipy.misc" ist veraltet (deprecated ... missbilligt). Lt. [https://docs.scipy.org/doc/scipy-1.17.0/dev/roadmap-detailed.html#misc SciPy-Dokumentation für die Version 1.17.0] wurden alle entsprechenden Features schon entfernt.</small>
== Symbolisches Differenzieren ==
Differenzieren Sie die Funktionen <math>f_1(x) = x^2</math> und <math>f_2(x) = \sin(x)\cos\left(\frac{x}{2}\right)</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2;
f2 = sympy.sin(x) * sympy.cos(x/2.)
d1 = sympy.diff(f1, x)
d2 = sympy.diff(f2, x)
print(d1)
print(d2)
Ausgabe:
2*x
-0.5*sin(0.5*x)*sin(x) + cos(0.5*x)*cos(x)
== Aufgaben ==
* Differenzieren Sie die Funktion <math>y = \log(x) + 10x</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
* Differenzieren Sie die Funktion <math>y = \frac{\sinh(x)}{(1+x)}</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
= Integralrechnung =
== Numerisches Integrieren ==
Berechnen Sie das Integral <math>\int_{0}^{3}x^2 dx</math>.
import scipy
def f(x):
return x**2
i = scipy.integrate.quad(f, 0, 3)
print(i)
Ausgabe:
(9.000000000000002, 9.992007221626411e-14)
Das trifft den exakten Wert 9.0 ziemlich genau.
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} dx</math>.
import scipy
import numpy as np
def f(x):
return 2**(-x)
i = scipy.integrate.quad(f, 0, np.inf)
print(i)
Ausgabe:
(1.4426950408889556, 4.486558477977586e-09)
== Symbolisches Integrieren ==
Berechnen Sie <math>\int x^2 \text{d}x</math> und <math>\int \sin{x}\cos{\frac{x}{2}} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2
f2 = sympy.sin(x) * sympy.cos(x/2.)
i1 = sympy.integrate(f1, x)
i2 = sympy.integrate(f2, x)
print(i1)
print(i2)
Ausgabe:
x**3/3
-0.666666666666667*sin(0.5*x)*sin(x) - 1.33333333333333*cos(0.5*x)*cos(x)
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f = 2**(-x)
i = sympy.integrate(f, (x, 0, sympy.oo))
print(i)
Ausgabe:
1/log(2)
<code>sympy.oo</code> steht für das {{W|Unendlichzeichen}} <math>\infty</math> (die liegende Acht oder das Möbiusband). Mit <code>sympy.pprint(i)</code> ließe sich letzere Ausgabe etwas schöner schreiben:
1
──────
log(2)
Man beachtete, <code>log</code> steht hier für den natürlichen Logarithmus <code>ln</code>.
== Aufgaben ==
* Integrieren Sie die Funktion <math>y = \log(x) + 10x</math> von 1 bis 5.
* Integrieren Sie die Funktion <math>y = x^3</math> von 0 bis 4.
* Integrieren Sie <math>\int x^x(\log (x) + 1)\mathrm dx</math> symbolisch.
= Gewöhnliche Differenzialgleichungen =
== DGL numerisch lösen ==
Für die Lösung von Differenzialgleichungen steht u.a. die Funktion scipy.integrate.solve_ivp() zur Verfügung. Diese Funktion implementiert auch das Runge-Kutta-Verfahren (RK45).
{{Wikipedia | Runge-Kutta-Verfahren}}
Beispiel <math>y' = x^2 + y^3</math>:
import scipy
import numpy as np
import matplotlib.pyplot as plt
def dy_dx(x, y):
return x**2 + y**3
y0 = [1]
xi = [0, 1]
x = np.arange(0, 1, 0.01)
z = scipy.integrate.solve_ivp(dy_dx, xi, y0, method="RK45", dense_output=True)
y = z.sol(x)
plt.plot(x, y.T)
plt.grid()
plt.show()
[[Datei:PythonIng_dgl1.png]]
== DGL symbolisch lösen ==
Beispiel <math>y' = x^2 + y^3</math>:
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
print(lsg)
Ausgabe:
[Eq(f(x), (-x**2)**(1/3)), Eq(f(x), (-x**2)**(1/3)*(-1 - sqrt(3)*I)/2), Eq(f(x), (-x**2)**(1/3)*(-1 + sqrt(3)*I)/2)]
Mit <code>sympy.pprint</code> (pretty print) lässt sich die Ausgabe etwas übersichtlicher darstellen.
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
sympy.pprint(lsg)
Ausgabe:
⎡ _____ _____ ⎤
⎢ _____ 3 ╱ 2 3 ╱ 2 ⎥
⎢ 3 ╱ 2 ╲╱ -x ⋅(-1 - √3⋅ⅈ) ╲╱ -x ⋅(-1 + √3⋅ⅈ)⎥
⎢f(x) = ╲╱ -x , f(x) = ────────────────────, f(x) = ────────────────────⎥
⎣ 2 2 ⎦
== Aufgaben ==
* Lösen Sie die Differenzialgleichung <math>y' = \frac{1}{x\cdot y}</math> mit Python. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>m' = -k\cdot m</math>. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>y' = \sqrt{|y|}</math>.
=Laplace-Transformation=
Laplace-Transformation:
<math>F(s) =\mathcal{L} \left\{f\right\}(s) = \int_{0}^{\infty} f(t) \mathrm e^{-st} \,\mathrm{d}t, \qquad s\in\mathbb{C}
</math>
Inverse Laplace-Transformation:
<math>\mathcal{L}^{-1} \left\{F\right\}(t)
= \frac{1}{2 \pi \mathrm j} \int_{ \gamma - \mathrm j \infty}^{ \gamma + \mathrm j \infty} \mathrm e^{st} F(s)\,\mathrm ds
= \begin{cases}
f(t) & \text{für } t \geq 0 \\
0 & \text{für } t < 0
\end{cases}
</math>
Siehe auch [[Ing_Mathematik:_Laplace-Transformation]]
Code:
import sympy
from sympy.abc import t, s
# Laplace-Transformation der Funktion f(t) = 1 (Heaviside-Fkt.)
f = 1
# alternativ: f = sympy.Heaviside(t)
F = sympy.laplace_transform(f, t, s, noconds=True)
print("Laplace-Transformierte F(s):", F)
# Inverse Laplace-Transformation zurück in den Zeitbereich
f_inv = sympy.inverse_laplace_transform(F, s, t)
print("Inverse Transformation f(t):", f_inv)
Ausgabe:
Laplace-Transformierte F(s): 1/s
Inverse Transformation f(t): Heaviside(t)
Die Zeile
from sympy.abc import t, s
steht alternativ für
t = sympy.symbols("t")
s = sympy.symbols("s")
<u>Aufgaben</u>: Ermitteln Sie mittels SymPy die <math>\mathcal{L}</math>-Transformierten und dann wieder die <math>\mathcal{L}^{-1}</math>-Transformationen (ähnlich wie beim obigen Beispiel):
* <math>\sin(t) \circ\! -\! \bullet \ ?</math>
* <math>t^3 \circ\! -\! \bullet \ ?</math>
* <math>\text{e}^{\omega t} \circ\! -\! \bullet \ ?</math>
=Fourier-Reihen=
<math>
f(x)\approx \frac{a_{0}}{2}+\sum_{k=1}^{\infty}\left(a_{k}\cos\left(kx\right)+b_{k}\sin\left(kx\right)\right)
</math>
<math>
a_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\cos\left(kx\right)\mathrm dx\quad\text{für }k\geq0
</math>
<math>
b_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\sin\left(kx\right)\mathrm dx\quad\text{für }k\geq1
</math>
Für die Sägezahnfunktion <math>y=x;\, 0 < x < 2\pi</math> sei die Fourierreihe mit einem Python-Programm (unter Mithilfe von sympy) hergeleitet.
Code:
from sympy import fourier_series, pi, symbols, pprint
x = symbols('x')
f = x
s = fourier_series(f, (x, 0, 2*pi))
pprint(s.truncate(n=4))
Ausgabe:
2⋅sin(3⋅x)
-2⋅sin(x) - sin(2⋅x) - ────────── + π
3
Siehe auch [[Ing Mathematik: Fourierreihen]].
Ein komplizierteres Beispiel:
[[Datei:IngMath fourier bsp13.svg | 300px]]
<math>0\le t < T/2\text{:}\quad f(t) = H</math>
<math>T/2 \le t \le T\text{:}\quad f(t) = \frac{2H}{T}\left( t-\frac{T}{2}\right)</math>
Code:
import sympy as sp
H = sp.Symbol('H', positive=True)
T = sp.Symbol('T', positive=True)
t = sp.Symbol('t')
f = sp.Piecewise(
(H, (t > 0) & (t < T/2)),
(2*H/T*(t-T/2), (t > T/2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Ausgabe:
⎛2⋅π⋅t⎞ ⎛4⋅π⋅t⎞ ⎛6⋅π⋅t⎞ ⎛2⋅π⋅t⎞ ⎛6⋅π⋅t⎞
H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ 2⋅H⋅cos⎜─────⎟ 2⋅H⋅cos⎜─────⎟
⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ 3⋅H
──────────── - ──────────── + ──────────── + ────────────── + ────────────── + ───
π 2⋅π 3⋅π 2 2 4
π 9⋅π
=Rechnen mit wirklich großen Zahlen=
Bekannt ist, dass Python kaum Einschränkungen beim Wertebereich von Ganzzahlen hat, z.B.
print(10**300)
Ausgabe (gekürzt):
100000000000000000000...00000000000000000000000000000000000000000000000000000000000000000000000
Ähnliches geht auch mit Gleitpunktzahlen, z.B. durch die Verwendung des Moduls [https://mpmath.org/ mpmath]:
import mpmath
print(mpmath.mpf(1500.4)**mpmath.mpf(300))
Ausgabe:
7.27975299218612e+952
Anderes Beispiel:
from mpmath import mp, pi
mp.dps = 100
print(pi)
Ausgabe:
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
mpmath kann noch einiges mehr, dazu sei aber auf die entsprechende Dokumentation auf der mpmath-Homepage verwiesen. mpmath ist Bestandteil von SymPy, kann aber auch separat installiert werden.
Aber auch Python selbst besitzt eine Möglichkeit, um mit großen bzw. exakten Gleitpunktzahlen zu rechnen, nämlich das interne Modul decimal. Dieses hat einige Vorteile gegenüber mpmath, aber auch gravierende Nachteile. Diese seien hier nicht detailliert aufgezählt. Grob gesagt hat decimal im Finanzwesen seine Berechtigung. Für wissenschaftliche Anwendungen wird aber mpmath vorzuziehen sein, da es u.a. vielfältige mathematische Funktionen bereit stellt. Nachfolgend ein einfaches Beispiel mit decimal:
import decimal
print("Potenzierung:", decimal.Decimal(1500.4) ** decimal.Decimal(300.0))
print("Einfache Addition:", 0.1 + 0.2)
decimal.getcontext().prec = 50
print("Addition mit decimal:", decimal.Decimal("0.1") + decimal.Decimal("0.2"))
Ausgabe:
Potenzierung: 7.279752992186121551039839134E+952
Einfache Addition: 0.30000000000000004
Addition mit decimal: 0.3
<u>Aufgabe:</u> Recherchieren Sie im Internet die genauen Vor- und Nachteile von decimal und mpmath. Verwenden Sie dazu auch KI (z.B. von Google, chatgpt).
= pint - mit physikalischen Größen rechnen =
[[File:Pint-Glas_UK.jpg|right|100px]]
pint ist ein externes Python-Paket zur Manipulation von physikalischen Einheiten. Es muss vor der ersten Benutzung installiert werden (Vorgehensweise wie immer: pip, YaST, via venv etc.).
Beispiel:
import pint
import numpy as np
ureg = pint.UnitRegistry()
# Einfache Berechnung
print(3 * ureg.meter + 4 * ureg.cm)
# Mit NumPy
npeinzel = [3, 4] * ureg.meter + [2, 5] * ureg.cm
print(npeinzel)
npsum = np.sum(npeinzel)
print(npsum)
# Konvertierung von Einheiten
npsum_inch = npsum.to(ureg.inch)
print(npsum_inch)
print(npeinzel.magnitude)
print(npeinzel.units)
print(npeinzel.dimensionality)
Ausgabe:
3.04 meter
[3.02 4.05] meter
7.07 meter
278.3464566929134 inch
[3.02 4.05]
meter
[length]
Die Dokumentation zu pint findet sich auf [https://pint.readthedocs.io/en/stable/].
=Regelungstechnische Aufgabenstellungen=
Für regelungstechnische Aufgaben gibt es u.a. das externe Paket <code>control</code>. Hier soll nicht detailliert darauf eingegangen werden. Anhand eines Beispiels soll anschließend nur die Visualisierung in Form eines Bode-Diagramms und der Sprungantwort gezeigt werden. Gegeben sei ein P-Regler mit <math>R = \frac{5}{2}</math> und eine Strecke <math>S= \frac{1}{30s^3+20s^2+10s+1,5}</math>. Gesucht sei vorerst ein Bode-Diagramm für den offenen Regelkreis und das Führungsverhalten.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke # oder: G0 = ct.series(regler, strecke)
Gw = ct.feedback(G0)
ct.bode_plot(G0, label='G0')
ct.bode_plot(Gw, label='Gw')
plt.show()
[[Datei:PythonIng_bode1.svg]]
Nun noch für obiges Beispiel die Sprungantwort. Diese zeigt einige große Überschwinger, d.h. der Regler kann sicher noch optimiert werden.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke
Gw = ct.feedback(G0)
t, y = ct.step_response(Gw)
plt.plot(t,y)
plt.title('Sprungantwort')
plt.xlabel('t')
plt.ylabel('h(t)')
plt.grid()
plt.show()
[[Datei:PythonIng_bode3.svg]]
Einige weitere wichtige Daten (Phasenreserve, Amplitudenreserve, Durchtrittsfrequenz) lassen sich mittels der <code>control</code>-Funktion <code>margin()</code> ermitteln. Die Ortskurve lässt sich mit der Funktion <code>nyquist_plot()</code> zeichnen. Dies sei hier aber nicht weiter ausgeführt.
==Aufgaben==
* Zeichen Sie mit Python die Ortskurve für obiges Beispiel.
* Was passiert, wenn man die Reglerverstärkung weiter aufdreht (z.B. auf <math>R = \frac{25}{2}</math>)?
* Wie sehen das Bode-Diagramm und die Sprungantwort aus, wenn ein PI-Regler verwendet wird?
= Stereostatik etc. =
Das Modul SymPy bietet einige Möglichkeiten einfache Bauwerke zu berechnen, z.B. Balken oder Fachwerke. Nachfolgend wird ein einfaches Fachwerk berechnet und gezeichnet.
Python-Code:
from sympy.physics.continuum_mechanics.truss import Truss
t = Truss()
# Knoten
t.add_node(("A", -3, 0), ("B", 0, 0), ("C", 4, 0), ("D", 7, 0),
("E", 6, 1.5), ("F", 2, 3), ("G", -2, 1.5))
# Stäbe
t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D"))
t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F"))
t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E"))
t.add_member(("FE","F","E"), ("DE","D","E"))
# Auflager; roller ... Loslager, pinned ... Festlager
t.apply_support(("A","roller"), ("D","pinned"))
# Einwirkende Kräfte
t.apply_load(("G", 5, 270), ("E", 3, 90))
# Berechnung
t.solve()
print("Reaction Forces: ", t.reaction_loads)
print("Internal Forces: ", t.internal_forces)
# Fachwerk zeichnen
p = t.draw()
p.show()
Ausgabe auf der Konsole:
Reaction Forces: {'R_A_y': 4.20000000000000, 'R_D_x': 0, 'R_D_y': -2.20000000000000}
Internal Forces: {'AB': 2.80000000000000, 'BC': 0.333333333333333, 'CD': -1.46666666666667,
'AG': -5.04777178564958, 'GB': -2.05555555555556, 'GF': -1.23413387432364,
'BF': 0.411111111111111*sqrt(13), 'FC': -0.3*sqrt(13), 'CE': 1.50000000000000,
'FE': 0.284800124843917, 'DE': 2.64407093534026}
Zeichnung:
[[File:PythonIng_fachwerk1.svg|300px]]
Details zu diesem Thema siehe z.B. [https://docs.sympy.org/latest/modules/physics/continuum_mechanics/index.html Continuum Mechanics] oder [https://docs.sympy.org/latest/tutorials/physics/continuum_mechanics/index.html Continuum Mechanics Tutorials]. Auch andere mechanische Probleme werden von SymPy abgehandelt ([https://docs.sympy.org/latest/tutorials/physics/index.html Physics Tutorials]).
== Aufgabe ==
Gegeben sei ein einseitig eingespannter Kragträger. Belastet wird er durch eine Einzellast am Trägerende. Für die Daten siehe folgende ASCII-Skizze:
| 20 kN
//|---> x |
//| V
//|----------------------
//| 10 m |
Elastizitätsmodul E = 2,1*10⁵ N/mm²
Flächenträgheitsmoment I = 0.001 m⁴
Berechnen Sie die Auflagerreaktionen, den Querkraft- und Biegemomentenverlauf, sowie die Verformungen.
Stellen Sie dies mit Hilfe von SymPy graphisch und auch mittels Formeln dar. Verwenden Sie dazu auch pprint (pretty print) aus dem SymPy-Modul. Zwecks Lösungsansatz siehe die oben aufgeführte Seite "Continuum Mechanics Tutorials". Achten Sie auch auf die Einheiten! Kontrollieren Sie das Ganze mittels händischer Rechnung. In dem genannten Tutorial ist von "Singularity Functions" die Rede. Gemeint ist damit in diesem Kontext die {{W|Föppl-Klammer}}.
Einige Python-Programme, vorrangig zu Maschinenelementen, finden sich auf [https://baymp.de/download_python.html BayMP für Python] (Balken, Zahnräder, Stabknickung usw.).
=Thermodynamik=
== PYroMat ==
Für thermodynamische Aufgabenstellungen gibt es verschiedene externe Module. Eines davon ist PYroMat (siehe auch [http://pyromat.org]). Damit lassen sich thermodynamische Stoffdaten für viele Substanzen berechnen.
Beispiel (einige Stoffdaten für Wasser bei 400°C und 20 bar berechnen):
import pyromat as pm
# Wasserdaten laden:
H2O = pm.get('mp.H2O')
# Stoffdaten berechnen:
T = 673.15 # Temperatur in Kelvin
p = 20 # Druck in bar
v = H2O.v(T, p)
h = H2O.h(T, p)
s = H2O.s(T, p)
print(f"Spezifisches Volumen: {v} m³/kg")
print(f"Spezifische Enthalpie: {h} kJ/kg")
print(f"Spezifische Entropie: {s} kJ/(kg K)")
Ausgabe:
Spezifisches Volumen: [0.1512163] m³/kg
Spezifische Enthalpie: [3248.3789473] kJ/kg
Spezifische Entropie: [7.12924142] kJ/(kg K)
<small>
PYroMat muss vorab installiert werden (z.B. mittels pip, in eine virtuelle Umgebung)
</small>
<code>mp</code> steht für "multi phase". Für ein ideales Gas wäre <code>ig</code> zuständig, z.B. <code>'ig.O2'</code>.
Beispiel (T-s-Diagramm für Wasser zeichnen):
import numpy as np
import matplotlib.pyplot as plt
import pyromat as pm
# Konfigurieren
pm.config["unit_pressure"] = "bar"
pm.config["unit_temperature"] = "K"
fluid = pm.get("mp.H2O")
# Temperaturbereich für das Nassdampfgebiet
T_tripel = 273.16
T_crit = 647.096
T = np.linspace(T_tripel, T_crit - 0.1, 200)
# Sättigungslinien berechnen und zeichnen
for x in np.linspace(0.0, 1.0, 5):
s = fluid.s(T=T, x=x)
if(x<=0.0):
plt.plot(s, T, label="Siedelinie x=%3.1f" % x, linewidth=2.0)
elif(x>=1.0):
plt.plot(s, T, label="Taulinie x=%3.1f" % x, linewidth=2.0)
else:
plt.plot(s, T, label="x=%3.1f" % x, linewidth=1.0)
# Isobaren zeichnen
p_values = [0.1, 1, 10, 50, 100]
T_isobar = np.linspace(T_tripel, 1000, 200)
t = 0.7
for p in p_values:
s_iso = fluid.s(T=T_isobar, p=p)
plt.plot(s_iso, T_isobar, 'k-', alpha=0.8, linewidth=0.8)
t += .05
idx = int(len(s_iso) * t)
plt.text(s_iso[idx], T_isobar[idx], f"{p} bar", fontsize=9, alpha=0.8)
# Diagramm zeichnen
plt.title("T-s-Diagramm für Wasser")
plt.xlabel("Spezifische Entropie s in kJ/kg K", fontsize=10)
plt.ylabel("Temperatur T in K", fontsize=10)
plt.legend(loc="best")
plt.grid(True)
plt.show()
Ausgabe (in etwa so):
[[Datei:T-s-Diagramm fuer Wasser.svg|400px]]
== CoolProp ==
Auch mit CoolProp können Stoffdaten berechnet werden. Siehe auch [https://coolprop.org/coolprop/wrappers/Python/index.html]
Beispiel (Wasser bei 20bar und 400°C):
import CoolProp.CoolProp as CP
fluid = 'Water'
T = 673.15 # Temperatur in Kelvin
P = 20e5 # Druck in Pascal
dichte = CP.PropsSI('D', 'T', T, 'P', P, fluid)
enthalpie = CP.PropsSI('H', 'T', T, 'P', P, fluid)
entropie = CP.PropsSI('S', 'T', T, 'P', P, fluid)
print(f"Spez. Volumen: {1/dichte:.6f} m³/kg")
print(f"Spez. Enthalpie: {enthalpie:.2f} J/kg")
print(f"Spez. Entropie: {entropie:.2f} J/kgK")
Ausgabe:
Spez. Volumen: 0.151215 m³/kg
Spez. Enthalpie: 3248344.02 J/kg
Spez. Entropie: 7129.16 J/kgK
== iapws ==
Um Werte für Wasser(dampf) zu erhalten (IAPWS; '''I'''nternational '''A'''ssociation for the '''P'''roperties of '''W'''ater and '''S'''team) gibt es die Bibliothek iapws. Siehe auch [https://iapws.org/] und [https://pypi.org/project/iapws/]
Beispiel (Wasser für 20bar und 400°C):
from iapws import IAPWS97
dampf = IAPWS97(P=2.0, T=673.15)
print(f"Spezifisches Volumen: {dampf.v:.6f} m³/kg")
print(f"Spezifische Enthalpie: {dampf.h:.2f} kJ/kg")
print(f"Spezifische Entropie: {dampf.s:.4f} kJ/(kgK)")
print(f"Phase: {dampf.phase}")
Ausgabe:
Spezifisches Volumen: 0.151208 m³/kg
Spezifische Enthalpie: 3248.23 kJ/kg
Spezifische Entropie: 7.1290 kJ/(kgK)
Phase: Gas
== TESPy ==
Ein anderes Modul für einen anderen Aufgabenzweck ist TESPy ('''T'''hermal '''E'''ngineering '''S'''ystems in '''Py'''thon). Dieses Modul ist für die Anlagensimulation zuständig. Für nähere Informationen siehe [https://tespy.readthedocs.io/en/main/getting_started/introduction.html]. Als Beipiel sei hier vorerst Code, der von der Google KI generiert wurde, angeführt. Der Code wurde überarbeitet, damit keine Warnungen auftreten. Bitte aber den Code trotzdem mit Vorsicht genießen, auch KI-generierter Code kann Fehler aufweisen. Eine Pumpe wird berechnet:
from tespy.components import Sink, Source, Pump
from tespy.connections import Connection
from tespy.networks import Network
# 1. Netzwerk definieren (Zentrales Steuerungselement)
# Wir wählen Wasser als Fluid und bar/Celsius als Einheiten
nw = Network(fluids=["water"])
nw.units.set_defaults(pressure="bar", pressure_difference="bar",
temperature="°C", enthalpy="kJ / kg")
# 2. Komponenten erstellen
eingang = Source("Wasserquelle")
ausgang = Sink("Wasserspeicher")
pumpe = Pump("Speisewasserpumpe")
# 3. Verbindungen definieren (Komponenten miteinander verknüpfen)
c1 = Connection(eingang, "out1", pumpe, "in1")
c2 = Connection(pumpe, "out1", ausgang, "in1")
# Verbindungen dem Netzwerk hinzufügen
nw.add_conns(c1, c2)
# 4. Randbedingungen und Parameter festlegen
# Zustand am Eingang (Druck, Temperatur, Massenstrom, Fluid-Zusammensetzung)
c1.set_attr(
v=1, # Massenstrom: 1 kg/s
T=20, # Temperatur: 20 °C
p=1, # Druck: 1 bar
fluid={"water": 1}, # 100% Wasser
)
# Zustand am Ausgang / Zielwerte der Pumpe
c2.set_attr(p=10) # Ziel-Druck nach der Pumpe: 10 bar
# Pumpeneigenschaften festlegen
pumpe.set_attr(eta_s=0.8) # Isentroper Wirkungsgrad von 80%
# 5. Simulation ausführen
nw.solve(mode="design")
# 6. Ergebnisse ausgeben
nw.print_results()
# Spezifische Werte direkt auslesen
print("\n--- Auswertung ---")
print(f"Erforderliche Pumpenleistung: {pumpe.P.val / 1000:.2f} kW")
print(f"Temperatur nach der Pumpe: {c2.T.val:.2f} °C")
Ausgabe (gekürzt):
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 7.04e+04 | 12 % | 9.96e+02 | 0.00e+00 | 8.81e+04 | 0.00e+00 | 0.00e+00
2 | 5.91e-12 | 100 % | 1.11e-13 | 0.00e+00 | 7.39e-12 | 0.00e+00 | 0.00e+00
3 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
4 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.01 s, Iterations per second: 480.85
##### RESULTS (Pump) #####
+-------------------+----------+----------+-----------+----------+----------+----------+
| | P | pr | dp | eta | eta_s | head |
|-------------------+----------+----------+-----------+----------+----------+----------|
| Speisewasserpumpe | 1.12e+06 | 1.00e+01 | -9.00e+00 | 8.00e-01 | 8.00e-01 | 9.19e+01 |
+-------------------+----------+----------+-----------+----------+----------+----------+
...
...
--- Auswertung ---
Erforderliche Pumpenleistung: 1124.77 kW
Temperatur nach der Pumpe: 20.07 °C
= Stochastik =
Die {{W|Stochastik}} ist ein sehr weites Feld. Hier werden etliche wichtige Themen kurz angerissen. Python stellt mit den Moduln math und statistics Software zu diesem Zwecke bereit. math und statistics sind bereits im Lieferumfang von Python enthalten. Aber auch mit den externen Modulen NumPy, SciPy, stochastic und pandas kann man Stochastik in Python betreiben. Die Theorie der Wahrscheinlichkeitsrechnung und Statistik soll etwas später in Band 5 dieser Buchreihe behandelt werden.
== Lageparameter ==
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
m1 = statistics.mean(werte)
m2 = statistics.mode(werte)
m3 = statistics.median(werte)
print("Arithmetischer Mittelwert = ", m1)
print("Modalwert = ", m2)
print("Median = ", m3)
Ausgabe:
Arithmetischer Mittelwert = 3.5
Modalwert = 1
Median = 3.0
== Streuungsparameter ==
Beispiel (Berechnung der Standardabweichung):
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
s = statistics.stdev(werte)
print("Standardabweichung = ", s)
Ausgabe:
Standardabweichung = 2.6770630673681683
Beispiel (Berechnung des Variationskoeffizienten V = Standardabweichung/Mittelwert)
import numpy as np
from scipy import stats
import statistics
k = 50
dat1 = [14, 21, 18, 25, 30, 17, 20]
dat = np.array(dat1)
# Mit SciPy
v = stats.variation(dat)
vddof = stats.variation(dat, ddof=1)
print("V SciPy: ", v)
print("V DDOF SciPy: ", vddof)
print(k*"-")
# mit NumPy
mittelwert1 = np.mean(dat)
std_abw1 = np.std(dat)
std_abw1ddof = np.std(dat, ddof=1)
v1= std_abw1 / mittelwert1
v1ddof = std_abw1ddof / mittelwert1
print("Mittelwert NumPy: ", mittelwert1)
print("Std.abw. NumPy: ", std_abw1)
print("Std.abw. DDOF NumPy: ", std_abw1ddof)
print("V NumPy: ", v1)
print("V DDOF NumPy: ", v1ddof)
print(k*"-")
# nur mit reinem Python
mittelwert2 = statistics.mean(dat1)
std_abw2 = statistics.stdev(dat1)
v2 = std_abw2 / mittelwert2
print("Mittelwert Python: ", mittelwert2)
print("Std.abw. Python: ", std_abw2)
print("V Python:", v2)
print(k*"-")
Ausgabe:
V SciPy: 0.23890355966467272
V DDOF SciPy: 0.25804533701889254
--------------------------------------------------
Mittelwert NumPy: 20.714285714285715
Std.abw. NumPy: 4.948716593053935
Std.abw. DDOF NumPy: 5.3452248382484875
V NumPy: 0.23890355966467272
V DDOF NumPy: 0.2580453370188925
--------------------------------------------------
Mittelwert Python: 20.714285714285715
Std.abw. Python: 5.3452248382484875
V Python: 0.2580453370188925
--------------------------------------------------
Der Unterschied bei der Standardabweichung zwischen reinem Python und den externen Bibliotheken SciPy und NumPy entsteht dadurch, dass einmal durch (n-1) und das andere Mal nur durch n dividiert wird. Dies kann bei NumPy und SciPy dadurch entschärft werden, indem <code>ddof=1</code> gesetzt wird. ddof steht für '''D'''elta '''D'''egrees '''o'''f '''F'''reedom. <small>Je größer die Anzahl der Datensätze n wird, umso weniger spielt das eine Rolle.</small>
== Kombinatorik ==
Beispiel:
import math
n = 7
k = 5
print("n! = ", math.factorial(n))
print("Kombinationen (n über k) = ", math.comb(n, k))
Ausgabe:
n! = 5040
Kombinationen (n über k) = 21
Siehe zu diesem Thema auch [[Ing Mathematik: Permutationen, Kombinationen, binomischer Lehrsatz]]. Die Anzahlen lassen sich einfach aus den dortigen Formeln ermitteln, z.B. bei Permutationen mit <math>n!</math> oder Variationen mit Wiederholungen als <math>n^k</math>. Will man die Kombinationen oder Variationen aber auch als Liste ausgeben, so kann das Modul <code>itertools</code> nützlich sein.
Beispiel (Variationen ohne Wiederholung):
from itertools import permutations
menge = ["A", "B", "C", "D"] # n = 4
k = 3
variationen = list(permutations(menge, k))
for v in variationen:
print("".join(v))
print(50*"-")
print(len(variationen))
Ausgabe (gekürzt):
ABC
ABD
ACB
...
DCA
DCB
--------------------------------------------------
24
Siehe zum Modul <code>itertools</code> auch die Website [https://docs.python.org/3/library/itertools.html].
* Variationen mit Wiederholung: <code>itertools.product()</code>
* Kombinationen ohne Wiederholung: <code>itertools.combinations()</code>
* Kombinationen mit Wiederholung: <code>itertools.combinations_with_replacement()</code>
== Zufallszahlen ==
Beispiel:
import random
# Ganzzahlige Zufallszahl von 1 bis 10
zufallszahl1 = random.randint(1, 10)
# Gleitpunktzahlen
# zwischen 0.0 und 1.0
zufallszahl2 = random.random()
# Zahl zwischen 1.5 und 9.5
zufallszahl3 = random.uniform(1.5, 9.5)
# aus Liste auswählen
farbe = ["Rot", "Grün", "Blau"]
zufallswert = random.choice(farbe)
print(zufallszahl1)
print(zufallszahl2)
print(zufallszahl3)
print(zufallswert)
Ausgabe, z.B.:
5
0.14147945849015753
6.894003397570905
Rot
Benötigt man mehrere Zufallszahlen, so ist das Modul <code>numpy</code> zu bevorzugen, z.B.:
* Normalverteilung: <code>np.random.normal(...)</code>
* Gleichverteilung: <code>np.random.uniform(...)</code>
== Histogramm ==
Zum Thema Histogramm siehe {{W|Histogramm}}.
Beispiel (mit Matplotlib):
import matplotlib.pyplot as plt
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
plt.hist(daten, bins=25, edgecolor='darkgray')
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm.svg|300px]]
Beispiel (mit Seaborn):
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
sns.set_theme(style="darkgrid")
sns.histplot(data=daten)
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm2.svg|300px]]
Das Kürzel <code>sns</code> ist Konvention und steht für die fiktive Figur '''S'''amuel '''N'''orman '''S'''eaborn aus der US-Fernsehserie {{W|The West Wing – Im Zentrum der Macht | The West Wing}}.
== Box-Plot ==
[[File:Elements of a boxplot.svg|400px]]
Siehe auch {{W|Box-Plot}}.
Beispiel (mit Seaborn erstellt):
import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("tips")
sns.boxplot(data=df, x="day", y="tip", hue="day", legend=False)
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot.svg|400px]]
Beispiel (mit Matplotlib erstellt):
import matplotlib.pyplot as plt
daten = [12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25]
plt.boxplot(daten, patch_artist=True)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot2.svg|300px]]
Um mehrere Box-Plots unterschiedlicher Farbe mit Matplotlib in einem Diagramm zu zeichnen, können Sie folgendermaßen vorgehen:
import matplotlib.pyplot as plt
daten = [[12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25],
[10, 19, 20, 21, 20, 30, 19, 40, 11, 17, 19, 21]]
farben = ["green", "blue"]
boxplot = plt.boxplot(daten, patch_artist=True)
for patch, farbe in zip(boxplot['boxes'], farben):
patch.set_facecolor(farbe)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
== Regressionsrechnung ==
Beispiel:
import numpy as np
import matplotlib.pyplot as plt
# Messpunkte
x = np.array([1, 3, 5, 6, 8, 10, 20])
y = np.array([3, 4, 5, 5, 7, 9, 11])
# Regressionskurve (Grad 1 = lineare Regression, 2 = Polynom-Regression 2. Gr.)
# y = kx + d
k, d = np.polyfit(x, y, deg=1)
# y = ax**2 + bx + c
a, b, c = np.polyfit(x, y, deg=2)
x_l = np.linspace(1, 20, 100)
y_p = a * x_l**2 + b * x_l + c
# Zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.plot(x, k*x + d, color='blue', label='Regressionsgerade')
plt.plot(x_l, y_p, color='red', label='Regressionspolynom 2. Gr.')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:IngMath_regression.svg|400px]]
== Korrelationsrechnung ==
Beispiel:
import pandas as pd
import matplotlib.pyplot as plt
# Messdaten
x = [1, 3, 4, 5, 6]
y = [2, 4, 6, 8, 5]
daten = {'X': x, 'Y': y}
df = pd.DataFrame(daten)
# Korrelation
korr = df['X'].corr(df['Y'])
print(f"Korrelationskoeff.: {korr}")
# Messpunkte zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
Korrelationskoeff.: 0.7556096518348252
[[Datei:IngMath_korrelation.svg|300px]]
== Mengen und Venn-Diagramme ==
Beispiel:
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
menge_a = {1, 2, 3, 4, 5, 6}
menge_b = {4, 5, 6, 7, 8}
vereinigung = menge_a | menge_b
schnitt = menge_a & menge_b
print("Vereinigungsmenge = ", vereinigung)
print("Schnittmenge = ", schnitt)
venn2([menge_a, menge_b], set_labels=('Menge A', 'Menge B'))
plt.show()
Ausgabe:
Vereinigungsmenge = {1, 2, 3, 4, 5, 6, 7, 8}
Schnittmenge = {4, 5, 6}
[[Datei:IngMath_venn.svg|300px]]
Siehe auch {{W|Mengendiagramm#Venn-Diagramme}}.
== Verteilungs- und Dichtefunktion ==
* CDF ... '''C'''umulative '''D'''istribution '''F'''unction, Verteilungsfunktion
* PDF ... '''P'''robability '''D'''ensity '''F'''unction, Dichtefunktion
Beispiel (Normalverteilung):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
my, sigma = 0, 1
x = np.linspace(-4, 4, 50)
pdf = norm.pdf(x, my, sigma)
cdf = norm.cdf(x, my, sigma)
plt.plot(x, pdf, lw=2, label="Dichtefunktion")
plt.plot(x, cdf, lw=2, label="Verteilungsfunktion")
plt.legend()
plt.grid()
plt.show()
Ausgabe:
[[Datei:IngMath_cdf_pdf.svg|300px]]
Beispiel (<math>\chi^2</math>-Verteilung):
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
x = np.linspace(0, 20, 500)
# df ... degree of freedom, Freiheitsgrad
pdf = (stats.chi2.pdf(x, df=2), stats.chi2.pdf(x, df=5), stats.chi2.pdf(x, df=10))
for i in range(0,3):
if(i==0):
lab = "Freiheitsgrad 2"
elif(i==1):
lab = "Freiheitsgrad 5"
else:
lab = "Freiheitsgrad 10"
plt.plot(x, pdf[i], label=lab, lw=2)
plt.grid()
plt.legend()
plt.show()
Ausgabe:
[[Datei:IngMath_chi2.svg | 300px]]
== Schätzen und Testen ==
=== Intervallschätzung ===
Als Beispiel seien Daten gegeben, die von ''Dürr, Mayer: Wahrscheinlichkeitsrechnung und Schließende Statistik; 7. Aufl., Hanser, 2014, Seite 137'' stammen. Und zwar soll das 95%-Vertrauensintervall für den Mittelwert des Kaloriengehalts (kcal/100g) von Hähnchen ermittelt werden. Wir wollen das mit Python inkl. NumPy und SciPy durchführen. Die Stichprobe ist groß (50 Hähnchen):
Python-Code:
import numpy as np
import scipy.stats as stats
# Stichprobe
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203]
# Parameter definieren
konfidenzniveau = 0.95
mean = np.mean(daten)
std = np.std(daten, ddof=1)
stdfehler = stats.sem(daten)
intervall = stats.norm.interval(confidence=konfidenzniveau, loc=mean, scale=stdfehler)
print(f"Mittelwert: {mean}")
print(f"Standardabweichung: {std}")
print(f"Konfidenzintervall: {intervall}")
Ausgabe:
Mittelwert: 215.48
Standardabweichung: 33.14238915925757
Konfidenzintervall: (np.float64(206.29356722321992), np.float64(224.66643277678006))
Diese Werte stimmen gerundet mit denen im genannten Buch überein. Zum Code selbst:
* sem steht für '''s'''tandard '''e'''rror of the '''m'''ean.
* <code>scipy.stats.norm</code> ... Modul für die Normalverteilung.
=== Punktschätzung ===
Gleiche Daten wie oben bei der Intervallschätzung.
Python-Code:
import numpy as np
from scipy import stats
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203
]
mu_hat, sigma_hat = stats.norm.fit(daten)
print(f"Schätzer für den Erwartungswert (μ): {mu_hat:.4f}")
print(f"Schätzer für die Standardabweichung (σ): {sigma_hat:.4f}")
Ausgabe:
Schätzer für den Erwartungswert (μ): 215.4800
Schätzer für die Standardabweichung (σ): 32.8093
=== Hypothesentests ===
Beispiel:
import numpy as np
import scipy.stats as stats
x_quer = 12.075 # Stichproben-Mittelwert
var = 0.069 # Stichproben-Varianz
n = 90 # Stichprobengröße
my_0 = 12.0 # Nullhypothese
alpha = 0.05 # Signifikanzniveau
z_stat = (x_quer - my_0) / np.sqrt(var / n)
p_val = 2 * (1 - stats.norm.cdf(np.abs(z_stat)))
print(f"Z-Statistik: {z_stat:.4f}")
if p_val < alpha:
print(f"p-Wert: {p_val:.6f} < alpha:", alpha)
print("Die Nullhypothese wird verworfen.")
else:
print(f"p-Wert: {p_val:.6f} > alpha:", alpha)
print("Die Nullhypothese wird nicht verworfen.")
Ausgabe:
Z-Statistik: 2.7087
p-Wert: 0.006755 < alpha: 0.05
Die Nullhypothese wird verworfen.
== Statistische Qualitätskontrolle ==
Beispiel (Mittelwertkarte):
import numpy as np
import matplotlib.pyplot as plt
# Gegeben
sollwert = 50.0
varianz = 4.0
stichproben_umfang = 1
daten = [49.5, 50.2, 53.0, 48.1, 52.6, 53.4, 49.8]
# Berechnung
standardabweichung = np.sqrt(varianz)
streuung = standardabweichung / np.sqrt(stichproben_umfang)
cl = sollwert
ucl = cl + 3 * streuung
lcl = cl - 3 * streuung
# Darstellung
plt.plot(daten, marker='o', linestyle='-', color='b', label='Messdaten')
plt.axhline(cl, color='green', linestyle='-', label=f'CL: {cl}')
plt.axhline(ucl, color='red', linestyle='--', label=f'UCL: {ucl:.2f}')
plt.axhline(lcl, color='red', linestyle='--', label=f'LCL: {lcl:.2f}')
plt.title('Mittelwertkarte')
plt.xlabel('Stichprobe')
plt.ylabel('Wert')
plt.legend(loc='lower left')
plt.grid(True)
plt.show()
Ausgabe:
[[Datei:IngMath_mittelwertkarte.svg|300px]]
Siehe auch {{W|Shewhart-Regelkarte}} und {{W|Qualitätsregelkarte}}.
* UCL ... '''U'''pper '''C'''ontrol '''Limit''', Obere Eingriffsgrenze
* LCL ... '''L'''ower '''C'''ontrol '''Limit''', Untere Eingriffsgrenze
* CL ... '''C'''enter '''L'''ine, Mittellinie
= Ein- und Ausgabe =
== print ==
Die Anweisung print haben wir schon oft verwendet. Hier soll anhand von Beispielen kurz beschrieben werden, was der Befehl print leisten kann.
print("Hallo", "Welt", 1, sep="-")
print("Hallo", end=" ")
print("Welt")
Ausgabe:
Hallo-Welt-1
Hallo Welt
== input ==
a = int(input("Zahl 1: "))
b = int(input("Zahl 2: "))
print("a + b = ", a+b)
Ausgabe (nach Eingabe der beiden Ganzzahlen):
Zahl 1: 4
Zahl 2: 5
a + b = 9
== Aus Dateien lesen ==
Es seinen die datei.txt
Hallo Welt.
Wie geht es dir?
...
und test1.py
dat = open("datei.txt", mode = "r")
print(dat.read())
dat.close()
Ausgabe
Hallo Welt.
Wie geht es dir?
...
Mit dem open()-Befehl wird die Datei datei.txt im Lesemodus geöffnet (r ... read). Mit dem read()-Befehl wird die Datei eingelesen und mittels print ausgegeben.
== In Dateien schreiben ==
dat = open("datei.txt", mode = "a", encoding = "utf-8")
dat.write("Hänge Zeile an\n")
dat.close()
Die Datei datei.txt sieht nach Abarbeitung des obigen Skripts nun so aus
Hallo Welt.
Wie geht es dir?
...
Hänge Zeile an
Es wird die Datei im Schreibmodus geöffnet (a ... append (anhängend), w ... write (überschreibend)).
write() fügt hier also eine Zeile Text am Dateiende ein. close() schließt die Datei wieder.
Das close() kann man sich mit der with-Anweisung auch sparen.
with open("datei.txt", mode="a", encoding="utf-8") as dat:
dat.write("Hänge Zeile an\n")
= Benutzeroberflächen erstellen =
== tkinter ==
{{Wikipedia | Tkinter}}
Python bietet standardmäßig das Modul tkinter zur Programmierung von Benutzeroberflächen. Es müssen also bei der Verwendung von tkinter keine externen Module installiert werden. Hier wird eine (sehr) kurze Einführung in das Erstellen von grafischen Oberflächen mittels tkinter gegeben.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
win.minsize(300, 50)
but = tk.Button(win, text = "Push the button")
but.pack()
win.mainloop()
Ausgabe:
[[Datei:PythonIng_gui1.jpg]]
Ein etwas komplizierteres Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
def on_button_clicked():
str = ent1.get() + ent2.get()
lab2["text"] = str
ent1 = tk.Entry(win)
ent2 = tk.Entry(win)
lab1 = tk.Label(win, text="verknuepfen mit")
lab2 = tk.Label(win, text="")
but = tk.Button(win, text = "=", command=on_button_clicked)
ent1.pack(side="left")
lab1.pack(side="left")
ent2.pack(side="left")
but.pack(side="left")
ent2.pack(side="left")
lab2.pack(side="left")
win.mainloop()
Ausgabe (vor der Eingabe der Teilstrings):
[[Datei:PythonIng_gui2.jpg]]
Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):
[[Datei:PythonIng_gui3.jpg]]
== curses ==
{{Wikipedia | curses}}
Mit dem curses-Modul lassen sich u.a. TUIs ('''T'''ext '''U'''ser '''I'''nterfaces) erstellen. Ein sehr einfaches Beispiel zur allgemeinen Funktionsweise wird nachstehend geliefert.
import curses
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
stdscr.clear()
stdscr.addstr("Hallo Welt", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.endwin()
Als Ausgabe sollte <span style="color:#FF0000;">Hallo Welt</span> (rote Schrift auf weißem Hintergrund) auf dem Terminal/der Konsole erscheinen. Getestet wurde dies mit openSUSE Tumbleweed, Python-Version 3.13.12. Das entsprechende Python-curses-Package muss installiert sein.
Allgemeine Informationen zur Terminal-/Konsolengröße und Cursorposition liefert folgendes Programm:
import curses
stdscr = curses.initscr()
stdscr.addstr(3, 5, "LINES: %d" % curses.LINES)
stdscr.addstr(4, 5, "COLS: %d" % curses.COLS)
(y,x) = stdscr.getyx()
stdscr.addstr(5, 5, "Momentane Cursorposition: [%d, %d]" % (y, x))
(y,x) = stdscr.getbegyx()
stdscr.addstr(6, 5, "Koordinatenursprung: [%d, %d]" % (y, x))
(y,x) = stdscr.getmaxyx()
stdscr.addstr(7, 5, "Fenstergröße: [%d, %d]" % (y, x))
stdscr.addstr(11, 2, "Taste drücken -> Ende")
stdscr.refresh()
stdscr.getch()
curses.endwin()
Es sollte sich in etwa folgende Ausgabe ergeben:
LINES: 44
COLS: 110
Momentane Cursorposition: [4, 15]
Koordinatenursprung: [0, 0]
Fenstergröße: [44, 110]
Taste drücken -> Ende
Zur Funktionsweise von curses siehe auch das Wikibook [[ncurses]]. Zum Verständnis sind dort allerdings elementare Kenntnisse in der Programmiersprache C erforderlich.
== Qt ==
{{Wikipedia | Qt (Bibliothek)}}
Auch für das Qt-Framework gibt es eine Anbindung an Python. Nachfolgend ein einfaches Beispiel.
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hallo Welt!")
label.show()
sys.exit(app.exec())
Ausgabe:
[[Datei:PythonIng_gui10.png]]
== Gtk ==
{{Wikipedia | GTK (Programmbibliothek)}}
Eine idente Ausgabe, wie oben für Qt gezeigt, erzeugt z.B. folgendes Gtk-Programm:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
lab = Gtk.Label(label="Hallo Welt!")
win.set_child(lab)
win.present()
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
Auch für die Benutzung von Qt und Gtk müssen die jeweiligen Packages installiert sein. Getestet wurden die entsprechenden Python-Programme nur unter openSUSE Tumbleweed. Wie das GTK-Paket unter MS Windows 11 installiert wird, siehe z.B. [https://www.gtk.org/docs/installations/windows Setting up GTK for Windows].
Damit sei aber das Thema "Benutzeroberflächen erstellen" hier abgeschlossen, da dies schon ein sehr spezielles Aufgabengebiet ist, das eher Informatiker und nicht so sehr Ingenieure anspricht. Bei Bedarf siehe aber ggf. die entsprechenden Links unten in diesem Tutorial. Dort sind weiterführende Informationen zu finden.
= Pandas kurz erklärt =
Hier wird kurz auf das externe Modul Pandas eingegangen. Pandas steht für '''Pan'''el '''Da'''ta und ist ein Modul für die Datenanalyse und -manipulation.
== Series ==
Vorstellbar ist eine "Series" wie eine einzelne Spalte in einem Tabellenkalkulationsprogramm.
Beispiel (Index implizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5]) # Temperaturwerte
print(temp)
Ausgabe:
0 8.5
1 11.0
2 12.5
3 10.0
4 13.0
5 11.0
6 14.5
dtype: float64
Das Kürzel <code>pd</code> ist Konvention. Es seien Temperaturwerte gegeben. Die erste Spalte bei der Ausgabe ist der Index. Die zweite Spalte enthält die Werte.
Beispiel (separater Zugriff auf den Index und auf die Werte):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5])
print(temp.index)
print(temp.values)
Ausgabe:
RangeIndex(start=0, stop=7, step=1)
[ 8.5 11. 12.5 10. 13. 11. 14.5]
Beispiel (Index explizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
print("*** Die gesamte Series ***")
print(temp)
print("*** Temperatur am Donnerstag ***")
print(temp["Do"])
print("*** Tage wärmer als 12 Grad ***")
temp_gr_12 = temp[temp > 12]
print(temp_gr_12)
Ausgabe:
*** Die gesamte Series ***
Mo 8.5
Di 11.0
Mi 12.5
Do 10.0
Fr 13.0
Sa 11.0
So 14.5
dtype: float64
*** Temperatur am Donnerstag ***
10.0
*** Tage wärmer als 12 Grad ***
Mi 12.5
Fr 13.0
So 14.5
dtype: float64
== DataFrame ==
Ein DataFrame entspricht einer Tabelle.
Beispiel (Erzeugen eines DataFrames):
import pandas as pd
tag = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
v1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=tag)
v2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=tag)
v3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=tag)
tab = pd.concat([v1, v2, v3], axis=1)
tab.columns = stadt
print(tab)
print(type(tab))
Ausgabe:
Linz Salzburg Innsbruck
Mo 1 8 Hallo
Di 2 9 16
Mi 3 10 17
Do 4 11 18
Fr 5 12 19
Sa 6 13 20
So 7 14 21
<class 'pandas.core.frame.DataFrame'>
Wir haben hier drei Datenspalten (v1, v2, v3) mit den Spaltennamen "Linz", "Salzburg" und "Innsbruck", sowie sieben Zeilen "Mo" bis "So".
Beispiel (Zugriff auf eine Spalte):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab["Salzburg"])
Ausgabe:
Mo 8
Di 9
Mi 10
Do 11
Fr 12
Sa 13
So 14
Name: Salzburg, dtype: int64
Beispiel (Zugriff auf eine Zeile):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab.loc["Di"])
Ausgabe:
Linz 2
Salzburg 9
Innsbruck 16
Name: Di, dtype: object
== Grafiken erstellen ==
Hier sei nur ein Torten- oder Kreisdiagramm gezeichnet:
import pandas as pd
import matplotlib.pyplot as plt
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
expl = [0, 0.2, 0, 0, 0, 0, 0]
temp.plot.pie(figsize=(5,5), explode=expl)
plt.show()
Ausgabe:
[[Datei:IngPython_pandas1.svg|350px]]
Die <code>figsize</code> hat nichts mit der Spaltenanzahl zu tun, sondern setzt die Fenster- oder Diagrammgröße in Inches (Breite * Höhe).
Mit Pandas kann man auch noch andere Diagrammarten erstellen, z.B. Linien- oder Balkendiagramme. Dies wird hier aber nicht vorgeführt.
== Arbeiten mit CSV- und LibreOffice-Dateien ==
Gegeben sei eine CSV-Datei test1.csv:
Mai;Juni;Juli
12;17;45
15;65;65
16;32;23
4;14;7
23;17;Keine Daten verfügbar
67;Keine Daten verfügbar;45
15;24;12
Lesen von dieser CSV-Datei:
import pandas as pd
tab = pd.read_csv("test1.csv", sep=";")
print(tab)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Schreiben in eine CSV-Datei test2.csv:
import pandas as pd
val = pd.read_csv("test1.csv", sep=";")
val.to_csv("test2.csv", index=False)
Ausgabedatei:
Mai,Juni,Juli
12,17,45
15,65,65
16,32,23
4,14,7
23,17,Keine Daten verfügbar
67,Keine Daten verfügbar,45
15,24,12
Die Ausgabedatei ist beinahe gleich wie die Eingabedatei. Es werden aber Kommas statt Strichpunkten verwendet. Daher kommt auch der Name CSV ('''C'''omma '''S'''eparated '''V'''alue). Will man wieder Strichpunkte, so kann man dies über den Parameter <code>sep=";"</code> in der <code>to_csv</code>-Funktion machen.
Um direkt von einer ODS-Datei (LibreOffice Calc, '''O'''pen '''D'''ocument '''S'''preadsheet) zu lesen muss das Modul odfpy extra installiert sein (per YaST, pip etc.). Gelesen wird dann folgendermaßen:
import pandas as pd
df = pd.read_excel('test1.ods', engine='odf')
print(df)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Die Datei "test1.ods" sei die Datei, aus der das obige "test1.csv" generiert wurde. Schreiben kann man ebenfalls in eine ODS-Datei:
import pandas as pd
daten = {
"Name": ["Hugo", "Richie", "Wilhelmine"],
"Alter": [38, 30, 29],
"Ort": ["Linz", "Innsbruck", "Salzburg"]
}
tab = pd.DataFrame(daten)
with pd.ExcelWriter("test2.ods", engine="odf") as writer:
tab.to_excel(writer, sheet_name="Daten", index=False)
Es ergibt sich eine "test2.ods"-Datei (Screenshot):
[[Datei:IngPython_pandas2.png|250px]]
== Sonstiges ==
Hier seien stichpunktartig einige weitere Features von Pandas angeführt:
* {{W|Pivot-Tabelle|Pivot-Tabellen}} (pivot ... Dreh-, Angelpunkt): Zweck - große Datenmengen schnell zusammenfassen, filtern und analysieren.
* NaN ('''n'''ot '''a''' '''n'''umber): In einem Datensatz fehlt ein Wert oder ist nicht definiert.
* groupby-Funktion: Daten strukturieren, aggregieren oder Zwischensummen bilden.
* {{W|Binning#Datenverarbeitung_und_-analyse|Binning}}: Klassenbildung.
* Mehrstufige Indizierung (Hierarchical Indexing oder MultiIndex)
* Zeitreihen (Time Series)
Für tiefergehende und weiterführende Informationen wird auf das Buch von ''Klein: Numerisches Python; Hanser, 2023'' und [https://pandas.pydata.org/ pandas] verwiesen.
= Style Guide, flake8, pylint, Black etc. =
== Style Guide ==
Wie man schönen und richtigen Python-Code schreibt, erfahren Sie in
* [https://peps.python.org/pep-0008/ PEP 8 – Style Guide for Python Code]
== Formatter und Linter ==
Ein Modul, das prüft, ob die Richtlinien im Style Guide eingehalten wurden, ist ''flake8'':
* [https://flake8.pycqa.org/en/latest/ Flake8: Your Tool For Style Guide Enforcement]
Code formatieren kann man auch mit [https://pypi.org/project/black/ Black]. Z.B. übersetzt <code>black test1.py</code> die Datei <code>test1.py</code>
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)),
(2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
in
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)), (2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Die Programmausgabe ist
reformatted test1.py
All done! ✨ 🍰 ✨
1 file reformatted.
Der Unterschied zwischen Black und Flake8:
* Black ist ein Code-Formatter. Er formatiert Ihren Code um, sodass er im Einklang mit PEP 8 steht.
* Flake8 ist ein {{W|Lint (Programmierwerkzeug) | Code-Linter}}. Flake8 verändert Ihren Code nicht, sondern durchsucht ihn nach potenziellen Fehlern etc.
Am obigen Beispiel sieht man auch, dass flake8 und Black nicht immer einer Meinung sind. Flake8 (<code>flake8 test1.py</code>) würde standardmäßig den mit Black formatierten Code bemängeln:
test1.py:8:80: E501 line too long (80 > 79 characters)
Diese Diskrepanz kann beseitigt werden. Da 79 Zeichen auf modernen Bildschirmen meist als zu kurz empfunden werden, ist ein Limit von 88 Zeichen (Black-Standard) oder mehr empfehlenswert. Um dies zu implementieren, erstellen Sie in Ihrem Projektverzeichnis eine <code>.flake8</code>-Datei mit dem Inhalt
[flake8]
max-line-length = 88
Und schon ignoriert Flake8 dieses Problem.
Ein anderer Linter ist pylint. Der würde beim Abarbeiten des obigen Beispiels, z.B. mit <code>pylint test1.py</code> noch eine Kleinigkeit bemängeln:
************* Module test1
/home/hr/tmp/test1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)
Auch pylint muss vor der ersten Verwendung installiert werden (z.B. mittels pip, virtuelle Umgebung, YaST). Die Dokumentation zu pylint findet sich auf [https://pylint.readthedocs.io/en/latest/].
<u>Aufgabe:</u> Fügen Sie einen "module docstring" in die <code>test1.py</code>-Datei ein und testen Sie erneut mit flake8, Black und pylint. <small>Sehen Sie zum Thema docstrings auch [https://peps.python.org/pep-0257/#what-is-a-docstring PEP 257 – Docstring Conventions].</small>
Es gibt noch weitere Formatierungswerkzeuge für Python-Code. Z.B. [https://docs.astral.sh/ruff/ Ruff], ein moderner Code-Formatter und -Linter. Mittels <code>ruff check test1.py</code> würde obiger Code geprüft (Linter). <code>ruff format test1.py</code> formatiert den Code (Formatter).
== Type Checker ==
"Type Checker" sind z.B.
* mypy
* pyright
* ty
Diese prüfen die Datentypen, z.B. in folgendem Code
def greetings(name: str) -> str:
return "Hello, %s" % name
print(greetings(42))
Python selbst, flake8, ruff oder black würden diesen Code ohne zu murren akzeptieren. "Type Checker" würden aber sehr wohl Alarm schlagen, z.B. liefert <code>mypy</code> folgende Ausgabe
test1.py:5: error: Argument 1 to "greetings" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Das funktioniert übrigens nicht nur bei Funktionsannotationen, sondern auch mit Variablen etc.
from typing import Final
# "Konstante", ab Python 3.8
NUMBER: Final = 123
print(NUMBER)
NUMBER = 125
print(NUMBER)
# Variable
a: int = 345
print(a)
a = "Irgendwas"
print(a)
# Variable (Pipe-Symbol), ab Python 3.10
b : int|str = 567
print(b)
b = "sonstiges"
print(b)
Ausgabe mit python:
123
125
345
Irgendwas
567
sonstiges
Ausgabe mit mypy:
test3.py:6: error: Cannot assign to final name "NUMBER" [misc]
test3.py:12: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
Found 2 errors in 1 file (checked 1 source file)
Python kennt übrigens keine Konstanten. Man kann diese mittels Großbuchstaben andeuten. Das ist aber nur Konvention, hat aber keine sonstigen Auswirkungen. Oder man verwendet wie oben gezeigt <code>Final</code>. Dann werfen Typchecker Errors aus.
==pydoc==
pydoc ist ein Werkzeug, um Python-Module, -Funktionen und -Klassen zu dokumentieren.
Beispiel <code>test1.py</code>:
"""Rechen-Modul.
Funktionen die von pydoc gelesen werden.
"""
def multiply(a, b):
"""Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a * b
def add(a, b):
"""Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a + b
if __name__ == '__main__':
print(multiply(3, 5))
print(add(4, 6))
Ausgabe mit <code>python3.13 -m pydoc test1</code> auf der Konsole:
Help on module test1:
NAME
test1 - Rechen-Modul.
DESCRIPTION
Funktionen die von pydoc gelesen werden.
FUNCTIONS
add(a, b)
Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
multiply(a, b)
Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
FILE
/home/xyz/tmp/test1.py
Siehe zu diesem Thema z.B. auch [https://docs.python.org/3/library/pydoc.html]. Mittels <code>python3.13 -m pydoc -w test1</code> kann man auch eine HTML-Dokumentation erstellen.
Wofür <code>if __name__ == '__main__':</code> steht, siehe z.B. etwas später im Abschnitt [[Ing_Mathematik:_Python#Doctests]].
== Sonstige Tools ==
Andere Tools für die {{W|Statische Code-Analyse|statische Codeanalyse}}, die aber für Ingenieure weniger interessant sein dürften, sind z.B.
* Radon: Liefert verschiedene {{W|Softwaremetrik|Codemetriken}} (Komplexität, Wartbarkeitsindex ...)
* Bandit: Findet Sicherheitslücken
Tools für die {{W|Dynamisches Software-Testverfahren|dynamische Codeanalyse}}, z.B.:
* DynaPyt (Framework zur dynamischen Programmanalyse)
* cProfile (Profiler)
* Memory Profiler (Speicheranalyse)
* Memray (Speicheranalyse)
* tracemalloc (Speicheranalyse)
Paket- und Projektmanagement (pip-Ersatz etc.):
* uv
* Poetry
* Conda
* pipx
Packaging-Tools (Freezer) und {{W|Compiler#Sonderformen|Transpiler}} :
* pyinstaller
** erstellt eigenständige, ausführbare Binärdatei
** kein Cross-Compiler
** kein Schutz vor Reverse-Engineering
** langsam
** packt alles in eine Datei
** sehr große Datei
** Befehl, z.B.: <code>pyinstaller --onefile test1.py</code>
** GUI: <code>auto-py-to-exe</code>
* cx_Freeze
* nuitka
** Übersetzt Python-Code in C/C++-Code und weiter in eine ausführbare Datei
** kein Cross-Compiler
** Schutz vor Reverse-Engineering
** Befehl, z.B.: <code>nuitka --standalone --onefile test1.py</code>
* cython
= Einige Integrierte Entwicklungsumgebungen (IDEs)=
Werden Programmtexte größer und umfangreicher, so ist das Arbeiten mit der interaktiven Programmierumgebung bzw. das direkte Ausführen von Python-Skripten mühsam. Man wünscht sich z.B. Hilfen zum Debuggen oder die automatische Code-Vervollständigung. Zu diesem Zweck wurden IDEs (Integrated Development Environments) geschaffen. Von diesen seinen nachfolgend auszugsweise einige kurz beschrieben. Testen Sie einfach aus, welche davon für Sie bzw. für Ihr Python-Projekt geeignet sind.
== IDLE ==
IDLE ist die mit dem Python-Programmpaket mitgelieferte IDE. Der Name leitet sich einerseits ab vom Monty-Python-Mitglied Eric Idle, andererseits steht es als Abkürzung für "'''I'''ntegrated '''D'''evelopment and '''L'''earning '''E'''nvironment. IDLE ist einfach zu bedienen, bietet aber schon einen beachtlichen Leistungsumfang. Nachfolgend wird ein Screenshot zu IDLE geliefert. Rechts ist das Editor-Fenster zu sehen, links die interaktive Programmierumgebung. Um das Beispiel selbst nachvollziehen zu können, starten Sie IDLE. Das geht ähnlich, wie Sie die interaktive Programmierumgebung von Python starten (nur, dass Sie eben das IDLE-Icon doppelklicken und nicht das Python-Icon. Unter Linux geben Sie einfach in einem Terminal <code>idle3.13</code> o. Ä. ein). Weiter geht es mit "File - Open - ...". Die auszuführende Datei auswählen (im konkreten Fall ein "Hallo-Welt"-Programm). Es erscheint das rechte Fenster. Dort "Run - Run Module" auswählen. Und schon wird im linken Fenster "Hallo Welt!" ausgegeben.
[[Datei:PythonIng_idle1.jpg | 600px]]
Siehe auch {{W|IDLE}}.
== PyCharm ==
PyCharm ist ein kommerzielles Produkt. Es gab aber auch eine kostenlose Community Edition. Seit 2025 sind beide Varianten vereint. Für die ersten 30 Tage sind die Pro-Funktionen frei verfügbar, danach nur noch die Kernfunktionalitäten (oder man bezieht kostenpflichtig die Pro-Version). Zu beziehen ist PyCharm unter dem Weblink [https://www.jetbrains.com/pycharm/]. Nachfolgend ein etwas abgewandeltes "Hallo Welt"-Programm, editiert und ausgeführt mit PyCharm.
[[Datei:PyCharm_IDE_2023_screenshot.png | 600px]]
Siehe auch {{W|PyCharm}}.
== Eric ==
Auch eric ist Open Source und steht unter der GNU General Public License Version 3 oder später. Zu beziehen ist diese Software unter [https://eric-ide.python-projects.org/].
[[Datei:Screenshot_Eric_4.png | 600px]]
Siehe auch {{W|eric (Software)}}.
<small>
Unter openSUSE Tumbleweed sollte sich eric auch mit YaST installieren lassen. Bei mir gibt es aber dann beim Ausführen des eric-Programms eine Fehlermeldung (Stand März 2026):
...
ModuleNotFoundError: No module named 'PyQt6.QtPdfWidgets'
Umgehen kann man dieses Problem aber wieder mit dem Erstellen einer virtuellen Umgebung, in etwa so
python3.13 -m venv ~/tmp/venv1
cd ~/tmp/venv1/bin
./python3.13 -m pip install --upgrade --prefer-binary eric-ide
./eric7_ide
</small>
== PyScripter ==
Vom Funktionsumfang vergleichbar mit den vorherigen IDEs ist PyScripter. Auch PyScripter ist Open Source. Die Projekt-Homepage findet sich auf [https://sourceforge.net/projects/pyscripter/]. PyScripter ist nur für MS Windows verfügbar.
[[Datei:PythonIng_pyscripter1.jpg | 600px]]
== Spyder IDE ==
Spyder enthält bereits eine stabile Python-Version und etliche Module (z.B. matplotlib, numpy, control). Ansonsten kann dieses Softwarepaket vom Funktionsumfang her mit den anderen genannten IDEs locker mithalten. Spyder wurde unter der MIT-Lizenz veröffentlicht. Diese Software findet sich auf [https://www.spyder-ide.org].
[[Datei:Spyder-windows-screenshot.png | 600px]]
Siehe auch {{W|Spyder (Software)}}
== Eclipse IDE==
Die {{W|Eclipse_(IDE)|Eclipse-IDE}} kann für Python aufgerüstet werden. Dazu gibt es das PyDev-Plugin. Installiert wird es über
* Help > Eclipse Marketplace...
* Find - PyDev - Install
Danach muss noch der Pfad zum Python-Interpreter festgelegt werden
* Window > Preferences > PyDev > Interpreters > Python Interpreter > New ...
Das Ergebnis ist ähnlich wie im folgenden Bild, nur dass statt C/C++ Python Verwendung findet.
[[Datei:Setting Up Eclipse CDT helloout.png | 600px]]
== Sonstige ==
Die genannten IDEs sind nicht die Einzigen. Es gibt, um dem Image Pythons als beliebteste Programmiersprache gerecht zu werden, noch einige andere. Sowohl Open Source-Programme als auch kommerzielle Programme sind im Web zu finden, z.B. Thonny oder {{W|Visual Studio Code}}. Unter Linux kann man auch {{W|KDevelop}}, ausgestattet mit dem Python3-Plugin, einsetzen. Braucht man den Umfang von ausgewachsenen IDEs nicht, so kann man auch normale Texteditoren verwenden (z.B. {{W|Geany}} oder {{W|Kate_(Texteditor)|Kate}}).
= Debuggen und Testen =
Das Debuggen und Testen von Programmen sind wichtige Bestandteile der Programmierung. Syntaxfehler lassen sich i.A. leicht beheben. Schwieriger ist das Eingrenzen von logischen Fehlern, die ev. nur in bestimmten Situationen auftreten und keine explizite Fehlermeldung hervorrufen. Das Programm liefert falsche Ergebnisse oder es stürzt aus heiterem Himmel ab. Um das zu verhindern gibt es verschiedene Werkzeuge, die bei der Fehlersuche behilflich sein können. Vorerst siehe aber zwecks Begriffsklärung noch folgende Links:
* {{W|Debuggen}}
* {{W|Debugger}}
* {{W|Softwaretest}}
<gallery>
First Computer Bug, 1947.jpg
Test ganzheitlich.png
V-Modell.svg
</gallery>
== Das Modul pdb ==
Python bringt schon ein Modul zum Debuggen mit. Siehe z.B. [https://docs.python.org/3/library/pdb.html pdb — The Python Debugger].
Komfortabler lässt sich das aber mittels Integrierter Entwicklungsumgebungen (IDEs) angehen.
== Debuggen mit IDEs ==
Für die IDEs IDLE und Spyder sei kurz auf die entsprechenden Webseiten verwiesen:
* [https://www.cs.uky.edu/~keen/help/debug-tutorial/debug.html Debugging under IDLE].
* [https://docs.spyder-ide.org/current/panes/debugging.html Spyder Debugger]
Dort wird die Vorgehensweise auch mittels Screenshots erläutert.
== assert ==
assert ... behaupten, zusichern ({{W|Assertion (Informatik)}})
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10., 0.)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10., 0.)
File "/home/hr/Develop/test1.py", line 4, in print1
assert y != 0.0
^^^^^^^^
AssertionError
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1("10.", "5.")
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Aber auch bei nachfolgendem Code gibt es eine Fehlermeldung:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10, 5)
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Damit letzteres funktioniert, kann man den Programmcode so umschreiben:
def print1(x, y):
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
2.0
Und jetzt fangen wir den <code>AssertionError</code> auf:
def print1(x, y):
try:
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
except(AssertionError):
print("Hallo")
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Hallo
Ich hoffe, es ist wenigstens im Ansatz klar geworden, wofür <code>assert</code> gut sein kann. Ausschalten kann man die <code>assert</code>-Überprüfung übrigens mit dem Python-Schalter <code>-O</code>.
== Doctests ==
Innerhalb eines Docstrings kann die Arbeit im interaktiven Modus simuliert werden. Nach den Promptzeichen (>>>) erfolgen dann bei unserem Beispiel innerhalb des Docstrings simulierte Aufrufe der Funktion <code>print1()</code>. Danach folgen jeweils die Sollresultate. Wird das Modul oder die Datei als Hauptprogramm aufgerufen, so wird die Funktion <code>doctest.testmode()</code> aufgerufen und ein Bericht auf der Konsole ausgegeben. Wird das Modul nicht als Hauptprogramm aufgerufen, sondern importiert, dann wird diese <code>testmod</code>-Funktion nicht aufgerufen. D.h. dieser Code kann sowohl für Testzwecke als auch für den produktiven Einsatz verwendet werden. Das ist auch sinnvoll, weil wenn man Teile der Datei immer löschen bzw. einfügen müsste, so würden sich Fehlerquellen auftun. Das würde den Sinn und Zweck von Doctests konterkarieren.
def print1(x=0., y=1.):
""" Dividiere zwei Zahlen
Autor: Intruder
Datum: 12.08.2025
>>> print1(2., 1.)
2.0
>>> print1(5., 2.)
2.5
>>> print1(5.)
5.0
"""
print(x/y)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Ausgabe:
Trying:
print1(2., 1.)
Expecting:
2.0
ok
Trying:
print1(5., 2)
Expecting:
2.5
ok
Trying:
print1(5.)
Expecting:
5.0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.print1
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Das gezeigte Beispiel ist so ziemlich das einfachste, das es gibt. Für weiterführende Details siehe z.B.:
* [https://peps.python.org/pep-0257/ PEP 257 – Docstring Conventions]
* [https://docs.python.org/3/library/doctest.html doctest — Test interactive Python examples]
''Einschub:'' Ganz ähnlich kann man auch Klassen testen, z.B. in folgendem Code-Fragment
class Fahrzeug:
# siehe Abschnitt "Objektorientierte Programmierung"
# ...
if __name__ == "__main__":
vauweh = Fahrzeug(170, 90)
beemweh = Fahrzeug(200, 120)
print(vauweh.convertGeschw())
print(beemweh.convertGeschw())
Wird das Script als Hauptprogramm ausgeführt (z.B. zu Testzwecken), so erfolgt die Ausgabe der zwei, via <code>convertGeschw()</code>, umgerechneten Geschwindigkeiten. Wird es aber als Modul eingebunden, so wird der letzte Programmabschnitt nicht ausgeführt (<code>__name__ == "__main__"</code> ergibt <code>False</code>).
== pytest ==
Siehe zu diesem Thema auch {{W|Modultest}}.
pytest ist ein externes Modul und muss vorab installiert werden, z.B. mittels
pip install -U pytest
pip install -U pytest-html
Python-Code, Datei test1.py:
def add(x, y):
return x + y
def test_answer():
assert add(1, 1) == 3
Starten von pytest in der Konsole:
pytest test1.py
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py F [100%]
========================================================= FAILURES ==========================================================
________________________________________________________ test_answer ________________________________________________________
def test_answer():
> assert add(1, 1) == 3
E assert 2 == 3
E + where 2 = add(1, 1)
test1.py:6: AssertionError
================================================== short test summary info ==================================================
FAILED test1.py::test_answer - assert 2 == 3
===================================================== 1 failed in 0.09s =====================================================
Hier erhalten wir einen Fehler, da 1+1 eindeutig ungleich 3 ist. Aber aus irgendeinem Grund wollte der Programmierer oder Tester in diesem Fall, dass dies so ist. Testfälle werden übrigens mit dem Präfix <code>test_</code> eingeleitet.
Python-Code:
def add(x, y):
return x + y + 1
def test_answer():
assert add(1, 1) == 3
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py . [100%]
===================================================== 1 passed in 0.01s =====================================================
Jetzt ist alles in Ordnung. Weiterführendes siehe z.B.
* [https://docs.pytest.org/en/stable/ pytest: helps you write better programs]
== unittest ==
Auch unittest dient zur Durchführung von Testreihen, ist aber Bestandteil von Python. Hier wird vorerst nicht näher darauf eingegangen. Siehe z.B.
* [https://docs.python.org/3/library/unittest.html unittest — Unit testing framework]
Lt. ''Inden: Python Challenge; dpunkt, 2021, Seite 481'' soll unittest weniger komfortabel als pytest sein.
Einen Vergleich von unittest mit pytest findet man in
* [https://knapsackpro.com/testing_frameworks/difference_between/pytest/vs/unittest pytest vs unittest]
= Python und Anwendungsprogramme =
Bisher stand immer alleine die Programmiersprache Python (ev. unter Einbeziehung von Modulen) im Mittelpunkt der Betrachtungen. Aber Python kann auch als Makrosprache für Anwendungsprogramme auftreten. Als Beispiele seien {{W|FreeCAD}} und {{W|LibreOffice}} genannt.
== FreeCAD ==
FreeCAD ist ein freies 3D-CAD-Programm. Hier soll nicht auf die Bedienung dieses CAD-Pakets eingegangen werden, sondern nur auf die Möglichkeit, mittels Python Makros zu schreiben. Als einfacher Einstieg soll ein Makro erstellt werden, welches eine Kugel (rot) und einen Quader (blau) zeichnet. Folgende Vorbereitungsschritte sind erforderlich (es sei vorausgesetzt, dass FreeCAD schon am Rechner installiert ist. Downloaden können Sie das Programm von der Website [https://www.freecad.org/downloads.php?lang=en]):
* FreeCAD starten
* Leere Datei erstellen
* Makro > Makros > Erstellen ...
Es öffnet sich ein leeres Editorfenster, in das Sie folgenden Code eingeben können:
import FreeCAD
import Part
doc = FreeCAD.newDocument()
# Kugel
kugel = Part.makeSphere(10)
form_element = doc.addObject("Part::Feature", "Kugel")
form_element.Shape = kugel
kug = FreeCAD.ActiveDocument.getObject("Kugel")
kug.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
neuePosition = App.Vector(5, 2.5, 2.5)
kug.Placement = App.Placement(neuePosition, kug.Placement.Rotation)
# Quader
quader = Part.makeBox(5, 5, 50)
form_element = doc.addObject("Part::Feature", "Quader")
form_element.Shape = quader
quad = FreeCAD.ActiveDocument.getObject("Quader")
quad.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
doc.recompute()
Diesen Code können Sie nun ausführen:
* Makro > Makro ausführen
Es ergibt sich folgende Ausgabe (gedreht und gezoomt):
[[Datei: PythonIng_freecad1.png|500px]]
Siehe auch [https://wiki.freecad.org/Python_scripting_tutorial/de# Anleitung Skripterstellung mit Python]. Getestet wurde obiges Beispiel mit FreeCAD 1.1.3 unter Linux und 1.1.1 unter MS Windows.
== LibreOffice ==
LibreOffice ist ein freies Officepaket ([https://de.libreoffice.org/]). Hier soll nur das Tabellenkalkulationsprogramm Calc kurz betrachtet werden. Es seinen in den ersten 3 Zellen (A1 bis A3) Zahlen gegeben. Diese sollen mit einem Python-Makro addiert und das Resultat in der Zelle A5 ausgegeben werden. Auch hier sind Vorbereitungsarbeiten nötig:
* zuerst muss unter Linux das Verzeichnis <code>~/.config/libreoffice/4/user/Scripts/python</code> erstellt werden
* für MS Windows ist es das Verzeichnis <code>%APPDATA%\LibreOffice\4\user\Scripts\python</code>
** drücken Sie zuerst Win + R (es öffnet sich das Ausführen-Fenster)
** geben Sie <code>%appdata%</code> ein, danach drücken Sie Enter (es öffnet sich der Explorer)
** navigieren Sie zu dem genannten Verzeichnis bzw. erstellen Sie das Verzeichnis
* in diesem Verzeichnis wird dann mit einem beliebigen Texteditor das Python-Makro erstellt, in unserem Fall die Datei <code>summiere_zellen.py</code>:
import uno
def summiere_zellen(*args):
# Zugriff auf das aktuelle Dokument und das aktive Tabellenblatt
ctx = uno.getComponentContext()
smgr = ctx.getServiceManager()
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.getCurrentController().getActiveSheet()
# Werte aus den Zellen A1 bis A3 auslesen
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
# Addition der drei Werte
summe = w1 + w2 + w3
# Ergebnis in die Zelle A5 schreiben
sheet.getCellRangeByName("A5").Value = summe
* siehe dazu ggf. auch [https://help.libreoffice.org/latest/de/text/sbasic/python/python_locations.html?DbPAR=BASIC].
Weiter geht es in LibreOffice Calc mit dem Menü ''Extras > Makros > Makros verwalten > Python''. Dort wird das Makro <code>summiere_zellen</code> ausgeführt. Es ergibt sich z.B. folgendes Resultat
[[Datei:PythonIng_libreoffice1.png]]
Das Kürzel <code>uno</code> steht für '''U'''niversal '''N'''etwork '''O'''bjects. Etwas einfacher geht's auch so:
def summiere_zellen():
desktop = XSCRIPTCONTEXT.getDesktop()
model = desktop.getCurrentComponent()
sheets = model.getSheets()
sheet = sheets.getByIndex(0)
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
cell = sheet.getCellRangeByName("A5")
cell.setValue(w1 + w2 + w3)
Empfohlen wird auch, das Erweiterungspaket APSO ('''A'''lternative '''P'''ython '''S'''cript '''O'''rganizer, apso.oxt) zu installieren. Die Vorgehensweise wird hier nicht gezeigt, sondern nur darauf hingewiesen, dass man das einfach "googeln" kann. Siehe zur Python-Programmierung für LibreOffice auch [https://wiki.documentfoundation.org/Macros/Python_Guide/de Makros/Python-Handbuch]. Getestet wurden obige Beispiele mit LibreOffice 26.2.5.1 unter Linux und 26.2.1.2 unter MS Windows.
= Ausblick =
Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Python. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks, Bücher und die Python-Hilfefunktion verwiesen. Python kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Module fast beliebig erweiterbar.
= Weblinks=
== Python allgemein ==
* [https://www.python.org/ Python Homepage]
== Externe mathematische Module ==
* [https://numpy.org/ NumPy]
* [https://numpy.org/doc/stable/user/numpy-for-matlab-users.html NumPy for MATLAB users]
* [https://scipy.org/ SciPy]
* [https://www.sympy.org/en/index.html SymPy]
* [https://pandas.pydata.org/ pandas]
* [https://github.com/maroba/findiff findiff]
* [https://mpmath.org/ mpmath]
== Externe Module für Grafiken ==
* [https://matplotlib.org/ Matplotlib]
* [https://vpython.org/ VPython]
* [https://build123d.readthedocs.io/en/latest/ build123d]
* [https://docs.vtk.org/en/latest/api/python.html VTK]
* [https://docs.bokeh.org/en/latest/docs/first_steps.html bokeh]
* [https://py5coding.org/ py5]
== Erstellung von User Interfaces ==
* [https://docs.python.org/3/library/tkinter.html tkinter - Python interface to Tcl/Tk]
* [https://docs.python.org/3/library/curses.html curses - Terminal handling for character-cell displays]
* [https://wiki.qt.io/Qt_for_Python Qt for Python]
* [https://www.gtk.org/docs/language-bindings/python GTK and Python]
== Erstellen virtueller Umgebungen ==
* [https://docs.python.org/3/library/venv.html venv - Creation of virtual environments]
== Sonstige ==
* [https://python-control.readthedocs.io/en/stable/ Python Control Systems Library]
* [https://pypi.org/project/regex/ regex - Regular Expressions]
* [http://pyromat.org/ PYroMat]
* [https://coolprop.org/coolprop/wrappers/Python/index.html CoolProp]
* [https://pypi.org/project/iapws/ iapws]
* [https://tespy.readthedocs.io/en/main/getting_started/introduction.html TESPy - Thermal Engineering Systems in Python]
* [https://pint.readthedocs.io/en/stable/ pint]
= Bücher =
== Gedruckte Bücher, OpenBooks, Magazine ==
* Diverse: c't Python Lernen, Verstehen, Anwenden; Heise, 2022
* Ernesti, Kaiser: Python3 - das umfassende Handbuch; 5. Aufl., Rheinwerk, [https://openbook.rheinwerk-verlag.de/python/ OpenBook]
* Iacono et al.: Programmieren trainieren; 3. Aufl., Hanser, 2023, ISBN 978-3-446-47766-7
* Inden: Python Challenge; dpunkt, 2021, ISBN 978-3-86490-809-5
* Klein: Numerisches Python; 2. Aufl., Hanser, 2023, ISBN 978-3-446-47170-2
* Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler; Rheinwerk, 2021, ISBN 978-3-8362-7316-9
* Weigend: Python 3 - Das umfassende Praxisbuch; 9. Aufl., mitp, 2022, ISBN 978-3-7475-0544-1
* Woyand: Python für Ingenieure und Naturwissenschaftler; 4. Aufl., Hanser, 2021, ISBN 978-3-446-46483-4
== Andere Wikibooks ==
* [[:en:Subject:Python_programming_language | Englische Wikibooks zum Thema Python]]
* [[Python|Deutschsprachiges Python-Wikibook]] [[Bild:2von10.png|20%]]
* [[Python unter Linux|Python 2.7 unter Linux]] [[Bild:10von10.png|100%]]
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
ixj4b9nnk0aewuj0wbkbi4y5xljaetm
1091907
1091906
2026-10-04T11:50:56Z
Intruder
1513
/* Py5 */
1091907
wikitext
text/x-wiki
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
= Hallo Welt und allgemeine Hinweise =
== Was ist Python ==
* Python ist eine universelle höhere Programmiersprache.
* Python ist objektorientiert.
* Python ist Open-Source (Python Software Foundation License).
* Python ist für viele Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
* Python ist ein Interpreter.
* Python ist durch Module fast beliebig erweiterbar.
* Python als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
* Python ist in etlichen Anwendungsprogrammen (z.B. {{W|FreeCAD}}, {{W|LibreOffice}}, {{W|GIMP}}, {{W|Blender (Software) | Blender}}) als Makrosprache verwendbar.
{{Wikipedia | Python (Programmiersprache)}}
== Python installieren ==
=== MS Windows ===
Laden Sie das aktuelle Python-Paket von der Webseite [https://www.python.org/] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.
=== Linux ===
Entweder ist Python bereits standardmäßig installiert, ansonsten ist die Installation mittels Paketmanagementsystem einfach möglich. Aber auch die Spyder-Entwicklungsumgebung ([https://www.spyder-ide.org]) bietet einen guten Einstieg mit Python (das gilt auch für MS Windows). Spyder bringt auch schon etliche wichtige Module standardmäßig mit.
== Python starten ==
=== MS Windows ===
Das Icon für das Python-Programm doppelklicken. Und schon startet das Programm.
[[Datei:PythonIng_start1.jpg]]
Python im interaktiven Modus präsentiert sich dann so:
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Alternativ kann das Programm auch über die Eingabeaufforderung oder die PowerShell gestartet werden:
c:\devel\Python>python.exe
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
=== Linux ===
Tippen Sie einfach das Wort „python“ (oder unter openSUSE Tumbleweed z.B. auch „python3.11“ oder „python3.13“) in einem Linux-Terminal ein, schließen den Befehl mit der RETURN-Taste ab, und schon startet Python im interaktiven Modus:
Python 3.13.12 (main, Feb 09 2026, 22:37:44) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Es gibt auch noch andere Möglichkeiten Python zwecks Programmausführung zu starten, z. B. den {{W|Shebang}} (<code>#!</code>) am Beginn eines Python-Scripts. Das Script sei als Script.py gespeichert. Dann kann das Script mit ./Script.py ausgeführt werden. Für openSUSE Tumbleweed sei nachfolgend ein lauffähiges "Hallo Welt!"-Script angegeben. Es wird in diesem Script der Python-Interpreter in der Version 3.13 verwendet :
#!/usr/bin/python3.13
print("Hallo Welt!")
Die Berechtigungen zum Ausführen der Datei müssen natürlich noch richtig gesetzt werden, z.B. mittels <code>chmod 777 Script.py</code>. <small><code>chmod</code> ist die Abkürzung für"'''ch'''ange file '''mod'''e bits".</small>
<small>Die "Maske" <code>777</code> ist nur für Testzwecke sinnvoll, weil sie leicht zu merken ist und für alle Benutzer alle Zugriffsberechtigungen ('''r'''ead/'''w'''rite/e'''x'''ecute für owner/group/others) setzt. Im richtigen Einsatz wird man das aus Sicherheitsgründen nicht so handhaben, sondern nur die Berechtigungen setzen, die unbedingt erforderlich sind. Welche Zugriffsberechtigungen gesetzt sind, kann man z.B. mit dem Befehl <code>ls -l</code> oder <code>ll</code> ('''l'''i'''s'''t directory contents) erfragen. Aber dazu im Moment genug. Erfahrene Linux-Nutzer kennen das ohnehin und Anfänger sollen jetzt nicht mit Linux-Interna überfordert werden. Bei Bedarf siehe die Linux-Man-Pages oder dezidierte Bücher zu Linux.</code></small>
<small>Oder das Script wird in einen Pfad verschoben, in dem sich ausführbare Programme generell befinden (welche Verzeichnisse im PATH liegen, kann bspw. mit <code>echo $PATH</code> abgefragt werden). Das Script kann dann wie ein normales Programm ohne weitere Angaben mit Script.py gestartet werden. Alternativ wird nicht das Script an sich verschoben, sondern nur ein symbolischer Link angelegt, z.B. mit <code>ln -s ~/tmp/Script.py ~/.local/bin/Script.py</code>. <code>~/.local/bin</code> sei ein im PATH gelegenes Verzeichnis. Dies sind aber schon Features für fortgeschrittene Linux-Benutzer und werden am Anfang eher selten benötigt.</small>
== Ein paar Worte zur Erklärung ==
=== Tests ===
Getestet wurden die Beispiele unter den Betriebssystemen
* MS Windows 10 mit der Python-Version 3.12.0 (teilweise auch mit 3.12.2 und 3.13.1; nur die Inhalte die bis spätestens Juli 2025 erstellt wurden)
* MS Windows 11 ab der Python-Version 3.13.4 (nur zum Teil; ab Juli 2025)
* openSUSE Leap 15.6 mit der Python-Version 3.11.12 (Spyder, nur vereinzelt) und zum Teil mit 3.12.11 (ab Juli 2025 bis November 2025).
* openSUSE Tumbleweed ab der Python-Version 3.13.9 (nur vereinzelt, ab November 2025)
=== Popularität ===
* An Beliebtheit rangiert Python mit Stand September 2026 mit einem Rating von 17,76% an 1. Stelle vor C und C++ (lt. [https://www.tiobe.com/tiobe-index/ TPCI - TIOBE Programming Community Index]).
* Lt. [https://innovationgraph.github.com/global-metrics/programming-languages GitHub Top 50 Programming Languages Globally] lag Python im Q1/2026 auf Rang 2, vor TypeScript und hinter JavaScript.
* [https://pypl.github.io/PYPL.html PYPL] (Popularity of Programming Language Index) ist ein anderer Popularitätsindex für Programmiersprachen. Auch hier liegt Python mit großem Vorsprung auf dem ersten Platz (52,08%), gefolgt von Java (13,34%) und C/C++ (7,99%) (Stand September 2026).
=== Namensgebung ===
Der Name "Python" rührt von der Komikertruppe {{W|Monty Python}} her. Die Icons für Python (z.B. Python selbst, Eric IDE, IDLE) sind aber durch die Python-Schlangenart symbolisiert.
<gallery>
Python-logo-notext.svg|Python-Logo
Guido van Rossum in PyConUS24.jpg|{{W|Guido van Rossum}} (geb. 1956), der Erfinder von Python
</gallery>
== Ein erstes Programm ==
Kommentare werden in Python mit der Raute (#) eingeleitet. Sie werden vom Python-Interpreter ignoriert. Text kann mit der print-Funktion ausgegeben werden. Starten Sie Python und geben sie folgende Anweisungen zeilenweise ein
>>> # Das ist ein Kommentar
>>> print("Hallo Welt!")
Als Ergebnis erhalten Sie
Hallo Welt!
Der Prompt (>>>) ist selbstverständlich nicht einzutippen, sondern wird vom Python-System geliefert.
Strings können in Python entweder in Anführungszeichen (") gesetzt werden oder in Hochkommatas('). In diesem Text wird die erste Variante bevorzugt eingesetzt.
Im Gegensatz zu Julia ist es hier egal, ob zwischen <code>print</code> und der öffnenden Klammer Leerzeichen stehen.
= Python als Taschenrechner =
== Allgemeines ==
Wir wollen 3 * 5 berechnen. Dazu starten wir Python im interaktiven Modus. Geben Sie dann die Formel
>>> 3 * 5
ein, drücken die Taste ENTER/RETURN ({{Taste|↵}}) und erhalten als Ergebnis
15
Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck <math>\sin\sqrt{15}</math> berechnen :
>>> import math
>>> math.sin(math.sqrt(15))
-0.6679052983383519
Als erstes wird das math-Modul importiert. Dann wird der mathematische Ausdruck berechnet.
Eine andere Variante, die dasselbe Ergebnis liefert, ist
>>> from math import *
>>> sin(sqrt(15))
-0.6679052983383519
Es wird also aus dem Modul <code>math</code> alles importiert (erkennbar am <code>*</code>). Will man nicht alles importieren, so kann man das auch einschränken:
>>> from math import sin, sqrt
Beenden lässt sich das Python-Programm durch Eingabe von <code>exit()</code> (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken).
== Die Hilfefunktion von Python ==
Bei Eingabe der Anweisung <code>help</code> oder <code>help()</code> springt Python in den Hilfemodus.
Eingabe:
>>> help()
Eingabe:
help> math.sin
Ausgabe:
Help on built-in function sin in math:
math.sin = sin(x, /)
Return the sine of x (measured in radians).
Für die komplette Python-Dokumentation siehe [https://docs.python.org/3/]. Verlassen kann man den Hilfemodus durch das Drücken von STRG-C, bzw. der Eingabe von q, quit oder exit mit anschließendem Drücken der RETURN-Taste.
== Aufgaben ==
* Erkunden Sie die Tangensfunktion "tan" mittels Python-Hilfe (vergessen Sie nicht das math-Modul zu importieren und das <code>math.</code> vor <code>tan</code>)
* Berechnen Sie mit Python den Ausdruck <math>\frac{1}{2}\cdot \text{e}^2 \cdot \tan(\pi/3)</math>. Siehe für die Exponentialfunktion im Python-Hilfesystem auch den Befehl <code>math.exp</code>. Alternativ kann auch die Konstante <code>math.e</code> eingesetzt werden. Potenzieren kann man bei Python mit dem **-Operator (z.B. 2**3 = 8). Für <math>\pi</math> gibt es <code>math.pi</code>.
= Python als Scriptsprache =
Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.py
# Das ist ein Kommentar
print("Hallo Welt!")
Python-Dateien werden mit der Dateiendung .py versehen. Achten Sie darauf, dass vor dem print keine Leerzeichen vorhanden sind. Das ist eine Python-Eigenheit. Wie wir später sehen werden, nutzt Python Einrückungen als syntaktisches Mittel, z.B. um bei Schleifen den Schleifenkörper zu kennzeichnen.
Danach bringen Sie die Skriptdatei test1.py (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:
1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ auch die Windows PowerShell). Das sieht dann etwa so aus:
Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\xyz>
: <small>Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol ([[Image:Windows_logo_-_2021_(Black).svg|10px]]) mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell unter Windows 10 den Eintrag "Windows PowerShell", unter Windows 11 den Eintrag "Terminal"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort <code>cmd</code> ein und mit "OK" wird das Ganze bestätigt.</small>
2) Wechseln Sie mittels <code>cd c:\tmp</code> in das Verzeichnis c:\tmp
3) Angenommen, Sie haben Python unter dem Pfad <code>c:\devel\Python\</code> installiert. Starten Sie das Programm so (der Prompt <code>c:\tmp></code>ist natürlich nicht mit einzutippen):
c:\tmp>c:\devel\Python\python.exe test1.py
4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm
Hallo Welt!
Die Vorgehensweise unter Linux ist prinzipiell gleich. Die kleinen Unterschiede, wie z.B. der Slash statt dem Backslash in Pfadangaben, sollten für Linux-Benutzer keine Hürde darstellen.
== Variablen ==
Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9) und Underscores (_) bestehen, dürfen aber nicht mit einer Zahl beginnen. Führende Underscores haben u.a. im Kontext mit der Objektorientierten Programmierung eine spezielle Bedeutung und sollten nicht für "normale" Variablenbezeichner verwendet werden.
Gültige Variablenbezeichner wären also:
xyz
x1
_wert
name_anzahl
Theoretisch kann man auch Umlaute, griechische Buchstaben u.ä. in Variablenbezeichnern nutzen, z.B.
ößÜ = 16
α = 134
print(ößÜ)
print(α)
Ausgabe:
16
134
Davon wird aber aus offensichtlichen Gründen ({{W|Englisch als Lingua franca}}) abgeraten. Das Eurozeichen (€) etc. darf man ohnehin nicht in Variablenbezeichnern verwenden, dies ergäbe einen Syntaxfehler. Siehe dazu auch [https://peps.python.org/pep-3131/].
Es gibt in Python etliche Schlüsselwörter (z.B. for, if oder return). Diese dürfen nicht als eigene Variablenbezeichner verwendet werden. Eine Liste aller Schlüsselwörter liefert das Script
import keyword
print(keyword.kwlist)
<small>Übung: Speichern Sie dieses Script in eine Datei, z.B. in c:\tmp\test1.py. Führen Sie diese Datei aus, um die Liste der Schlüsselwörter auszugeben.</small>
Da Python case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:
xyz
XYZ
xYz
Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.py gespeichert.
x = 5
y = 10
z = x*y
print(z)
Bringen Sie die Datei test1.py zur Ausführung, so erhalten Sie folgende Bildschirmausgabe
50
Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben. Dies führt aber zu unübersichtlichem Code.
x = 5; y = 10; z = x*y; print(z)
Ausgabe:
50
Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.
x = 5
# x = x - 2
x -= 2
print(x)
Bildschirmausgabe:
3
Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Den Inkrement-/Dekrementoperator (z.B. x++ oder x--) aus C/C++ oder Java kennt Python aber nicht.
Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Python problemlos möglich:
import math
wert = 10
print(wert)
wert = 35.5
print(wert)
wert = "Hallo"
print(wert)
wert = math.pi
print(wert)
Ausgabe:
10
35.5
Hallo
3.141592653589793
== Physische und logische Zeilen ==
In Python muss eine Anweisung in einer logischen Zeile Platz finden. Wird eine Anweisung aber zu lang für eine Zeile, dann kann sie in mehrere physische Zeilen unterteilt werden. Dies kann einerseits durch einen Backslash am Ende einer Zeile geschehen, z.B.
a = 2 + \
5
Dies stellt eine logische Zeile dar, die in zwei physische Zeilen unterbrochen ist.
Geklammerte Ausdrücke werden automatisch zu einer logischen Zeile verbunden, z.B.
a = (2 +
5)
Achtung: Im ersten Beispiel darf nach dem Backslash nichts mehr stehen, auch kein Kommentar. Dies trifft im zweiten Bespiel nicht zu, hier könnte noch ein Kommentar folgen, z.B.
a = (2 + # Kommentar
5)
Auch für Strings gibt es Möglichkeiten, diese auf mehrere Zeilen aufzuspalten.
# Kurzer String
str1 = "ABC"
# Langer String
str2 = """Hallo Welt,
Grüetzi Schwyzer,
Servus an alle"""
# Backslash
str3 = "UVW\
XYZ"
# Mit Klammern
str4 = ("Sehr langer Text, der automatisch .............. "
"in einer einzigen Variable zusammengefügt wird."
)
print(str1)
print(str2)
print(str3)
print(str4)
Ausgabe:
ABC
Hallo Welt,
Grüetzi Schwyzer,
Servus an alle
UVWXYZ
Sehr langer Text, der automatisch .............. in einer einzigen Variable zusammengefügt wird.
==Hexadezimale, oktale, binäre und andere Zahlen==
d = 1050 # Dezimalzahl
h = 0xAA2 # Hexadezimalzahl
o = 0o12 # Oktalzahl
b = 0b100001101 # Binärzahl
print(d)
print(h)
print(o)
print(b)
Ausgabe:
1050
2722
10
269
Groß- und Kleinbuchstaben sind in obigen Literalen übrigens egal. So kann man z.B. statt <code>0b1001</code> auch <code>0B1001</code> schreiben (siehe dazu [https://docs.python.org/3/reference/lexical_analysis.html#integer-literals]).
Sie können auch dezimale in hexadezimale Zahlen umwandeln, usw.:
h = hex(1050) # Dezimalzahl -> Hexadezimalzahl
b = bin(1050) # Dezimalzahl -> Binärzahl
o = oct(1050) # Dezimalzahl -> Oktalzahl
print(h)
print(b)
print(o)
Ausgabe:
0x41a
0b10000011010
0o2032
Gegeben sei die Zahl 121 zur Basis 3. Diese soll in eine Dezimalzahl umgewandelt werden. Das kann so geschehen:
z = int("121", 3)
print(z)
Ausgabe:
16
Dass dies richtig ist, davon kann man sich folgendermaßen überzeugen:
<math> 1 \cdot 3^2 + 2 \cdot 3^1 + 1 \cdot 3^0 = 9 + 6+ 1 = 16 </math>
Zahlen übersichtlicher schreiben kann man auch mittels Underscore, z.B.:
print("Eine Million (Variante 1) =", 1000000)
print("Eine Million (Variante 2) =", 1_000_000)
print("Eine Rechnung:", 2_000 * 400_000);
Es ergibt sich bei beiden Varianten die gleiche Ausgabe. Variante 2 ist aber im Sourcecode leichter lesbar, detto die Zahlen in der Rechnung:
Eine Million (Variante 1) = 1000000
Eine Million (Variante 2) = 1000000
Eine Rechnung: 800000000
== Strings und Platzhalter==
Ein paar einfache Beispiele:
print("Hallo {}" . format("Hugo"))
print("Hallo {:s}" . format("Hugo"))
print("Hallo %s" % "Hugo")
Ausgabe:
Hallo Hugo
Hallo Hugo
Hallo Hugo
Python-Code (formatted string literals, Beispiel 1):
str1 = "Hallo"
str2 = "Hugo"
print(f"{str1} {str2}")
Ausgabe:
Hallo Hugo
Python-Code (formatted string literals, Beispiel 2):
wert = 11.567
print(f"Ausgabe: {wert:.5f}")
Ausgabe:
Ausgabe: 11.56700
Komplexere Beispiele:
print("Hallo {} und {}" . format("Hugo", "Mike"))
print("Hallo {name1} und {name2}" . format(name2="Hugo", name1="Mike"))
# Füllzeichen: *
# Bündigkeit: > (=rechts), < (=links), ^ (=zentriert)
# Feldweite: 10
# Typ: s (=String), f (=Gleitkommazahl), d (=Dezimalzahl) etc.
print("Hallo {:*>10s}" . format("Hugo"))
print("Hallo {:*<10s}" . format("Hugo"))
Ausgabe:
Hallo Hugo und Mike
Hallo Mike und Hugo
Hallo ******Hugo
Hallo Hugo******
Python-Code:
str = "Hallo\t%s\t%7.2f\t%10.2e\t%i" % ("Hugo", 12.34567, 34.567, 264)
print(str)
Ausgabe:
Hallo Hugo 12.35 3.46e+01 264
== Unicode ==
Neben den bekannten ASCII-Zeichen lassen sich Zeichen auch mittels Unicode beschreiben. Griechische Buchstaben oder komplexere mathematische Operatoren - all das sollte kein Problem sein. Siehe auch {{W|Unicode}}, {{W|Liste der Unicodeblöcke}} und {{W|Unicodeblock Mathematische Operatoren}}. Im Folgenden werden ein paar Zeichen (Allquantor, Nabla-Operator, Existenzquantor), die man aus der Mathematik kennt, erzeugt.
ch1 = "\N{FOR ALL}"
ch2 = "\N{NABLA}"
ch3 = "\u2203"
print(ch1, ch2, ch3)
Ausgabe:
∀ ∇ ∃
<small>Diese Ausgabe ergibt sich z.B. mit der IDLE-Shell oder mit Cygwin. Beim Ausführen über die Windows-Eingabeaufforderung oder Windows PowerShell unter MS Windows 10 erfolgt keine korrekte Darstellung. IDLE ist die mit Python mitgelieferte IDE ('''I'''ntegrated '''D'''evelopment '''E'''nvironment, Integrierte Entwicklungsumgebung). Gegen Ende dieses Textes wird IDLE kurz beschrieben.
Das Problem mit der Windows Eingabeaufforderung lässt sich aber umgehen. Man muss nur eine Schriftart auswählen, die die Zeichen kennt, z.B. "DejaVu Sans Mono". Dazu klicken Sie einfach bei der Eingabeaufforderung mit der rechten Maustaste oben auf die weiße Leiste und wählen im aufpoppenden Fenster den Menüpunkt "Eigenschaften". Es öffnet sich ein Dialogfenster. Über den Reiter "Schriftart" lässt sich nun die Schriftart einstellen. Unter MS Windows 11 oder openSUSE Leap 15.6 (bash-Konsole) gibt es dieses Problem ohnehin nicht.</small>
== Reguläre Ausdrücke ==
Python kennt auch {{W|Regulärer Ausdruck|reguläre Ausdrücke}}. Dazu gibt es in Python das Modul <code>re</code>. Beipielsweise sollen alle Zahlen (<math>\text{zahl}\in\mathbb{N}_0</math>) in einem String gesucht und ausgegeben werden. Als String sei gegeben: <code>3x Grüße und 100 Kekse.</code> Das Muster (Pattern) ist <code>\d+</code>. <code>\d</code> steht für eine Dezimalziffer 0-9. Das Plus-Zeichen (+) steht symbolisch für ein oder mehrere Zeichen des vorherigen Ausdrucks. Hier also ein oder mehrere Dezimalziffern. Es wird die Funktion <code>findall</code> aus dem Modul <code>re</code>verwendet.
Python-Code:
from re import findall
str = "3x Grüße und 100 Kekse."
pat = "\\d+" # Doppel-Backslashes müssen verwendet werden, sonst gibt Python eine Warnung aus!
# alternativ: pat = r"\d+"
# oder: pat = "[0-9]+"
numb = findall(pat, str)
print(numb)
Ausgabe:
['3', '100']
Python kennt noch viele weitere Möglichkeiten mittels regulärer Ausdrücke zu hantieren. Dies soll hier aber nicht vertieft werden, da das Thema schon ziemlich speziell und komplex ist. Bei Bedarf siehe aber z.B. die Bücher ''Weigend, Seite 380ff'' und ''Ernesti, Kaiser'' [https://openbook.rheinwerk-verlag.de/python/28_001.html] oder die Python-Dokumentation [https://docs.python.org/3/library/re.html]. Auch [[Python unter Linux: Reguläre Ausdrücke]] liefert ein umfangreiches und brauchbares Python-2-Kapitel zu den regulären Ausdrücken. Die dort gelisteten Beispiele müssten ggf. vor Verwendung auf Python-3 umgeschrieben werden. <small>Wie macht man das? Dazu siehe z.B. [https://openbook.rheinwerk-verlag.de/python/43_001.html], [https://portingguide.readthedocs.io/en/latest/] oder [https://www.digitalocean.com/community/tutorials/how-to-port-python-2-code-to-python-3]</small>
<small>Es gibt auch ein externes Modul ''regex'', das bei Bedarf extra installiert werden muss ([https://pypi.org/project/regex/]). Es bietet zusätzliche Funktionalität und gründlicheren Unicode-Support. Dies sei hier aber nur der Vollständigkeit halber erwähnt.</small>
== Verzweigungen ==
=== if ===
Die IF-Verzweigung sei aus anderen Programmiersprachen bereits bekannt. In {{W|Pseudocode}} lässt sie sich folgendermaßen darstellen:
WENN bedingung TRUE
führe block1 aus
SONST
führe block2 aus
ENDE
Als {{W|Aktivitätsdiagramm|UML-Aktivitätsdiagramm}} sieht das in etwa so aus:
[[File:If-Then-Else-diagram.svg|200px]]
Und als {{W|Nassi-Shneiderman-Diagramm|Nassi-Shneiderman-Struktogramm}} so:
[[File:Zweiseitige Auswahl.png|250px]]
In Python gibt es keinen expliziten ENDE-Kennzeichner. Stattdessen wird der Code durch Einrückungen strukturiert. Alles mit der gleichen Einrückungstiefe gehört zum selben Block. Dies zeichnet Python vor anderen Programmiersprachen aus.
Die test1.py-Datei laute also wie folgt:
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4
Man achte auch auf die Doppelpunkte in der if- und else-Zeile. Darauf vergisst man gerne, wenn man von anderen Programmiersprachen kommt.
Folgendes wäre in Python ein Fehler (genauer gesagt ein IndentationError).
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Auch Nachstehendes würde nicht zum gewünschten Ergebnis führen (löst aber keine Fehlermeldung aus). Der letzte print-Befehl ist schon außerhalb der IF-ELSE-Verzweigung.
x = 3
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
x ist kleiner als 4
x ist groesser oder gleich 4
Python kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:
<, <= ... kleiner (gleich)
>, >= ... größer (gleich)
== ... gleich
!= ... ungleich
is ... identisch
is not ... nicht identisch
and ... AND
or ... OR
not ... NOT
Beispielsweise:
a = 5
b = 9
if a<=10 and b!=7:
print("OK")
else
print("Nicht OK")
Ausgabe:
OK
Der else-Block kann übrigens auch ersatzlos entfallen. Als Pseudocode sieht das so aus
WENN bedingung TRUE
führe block aus
ENDE
Mehrfache Verzweigungen werden durch das elif-Konstrukt erstellt. In Pseudocode:
WENN bedingung1 TRUE
führe block1 aus
SONST WENN bedingung2 TRUE
führe block2 aus
SONST WENN bedingung3 TRUE
führe block3 aus
SONST
führe block4 aus
ENDE
Ein Python-Beispiel:
a = 14
if a<=10:
print("<=5")
elif a>11 and a<15:
print("11 bis 15")
elif a>16 and a<20:
print("16 bis 20")
else:
print(">=20")
Ausgabe:
11 bis 15
In Python gibt es auch die Schlüsselwörter <code>True</code> (für wahr) und <code>False</code> (für falsch). Man beachte, dass sie mit Großbuchstaben beginnen. Andere Schreibweisen wären ein Fehler. Sie gehören zum Datentyp <code>bool</code>. Ihnen sind auch die Zahlen <code>1</code> und <code>0</code> zugewiesen.
Man beachte, dass {{W|Rundungsfehler}} auftreten können. D.h. man sollte bei der Verwendung von {{W|Gleitkommazahl|Gleitpunktzahlen}} niemals auf absolute Genauigkeit prüfen, sondern eine Toleranz (einen <math>\varepsilon</math>-Wert) vorgeben.
Ein klassisches Beispiel, das ein falsches Ergebnis liefert, ist:
i = 0.1 + 0.2
print(i)
if i == 0.3:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
NOK
Und das, obwohl man schon in der Volksschule lernt, dass 0.1 + 0.2 gleich 0.3 ist.
Korrekt muss das obige Beispiel z.B. so umgeschrieben werden:
ist = 0.1 + 0.2
soll = 0.3
epsilon = 0.000001
print(ist)
if abs(ist-soll) < epsilon:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
OK
Alternativ kann auch die <code>math.isclose()</code>-Funktion verwendet werden. Das sei aber hier nur erwähnt und nicht konkret ausgeführt.
<u>Aufgabe:</u> Recherchieren Sie im Internet zum Thema <code>math.isclose()</code>-Funktion.
=== match ===
Ab Python 3.10 gibt es auch die match-Anweisung. Dies ist das Python-Pendant für die switch-Anweisung in anderen Programmiersprachen, geht aber bei näherer Betrachtung weit darüber hinaus. Hier nur ein einfaches Beispiel:
x = "Hello"
match x:
case "Servus" | "Ciao": # or
print("Servus an alle")
case "Grüetzi":
print("Grüetzi Schwyzer")
case _: # other, default, sonstiges ...
print("Hallo Welt")
Ausgabe:
Hallo Welt
Als Struktogramm sieht das in etwa so aus:
[[File:Mehrseitige Auswahl.png|250px]]
Für nähere Details siehe z.B. [https://www.geeksforgeeks.org/python-match-case-statement/], [https://learnpython.com/blog/python-match-case-statement/], [https://docs.python.org/3/tutorial/controlflow.html#match-statements] und das Python Enhancement Proposal (PEP) 636 – Structural Pattern Matching: Tutorial [https://peps.python.org/pep-0636] und dort insbesondere den Anhang A - Quick Intro.
<small><code>match, case, _</code> etc. sind sogenannte ''soft keywords''. Im Gegensatz zu den normalen Schlüsselwörtern dürfen ihnen auch Werte zugewiesen werden. Eine Liste der weichen Schlüsselwörter lässt sich durch <code>keyword.softkwlist</code> erstellen (die Anweisung gibt es seit Python 3.9). Siehe dazu auch [https://stackoverflow.com/questions/65800344/what-are-soft-keywords] und [https://docs.python.org/3/library/keyword.html#keyword.softkwlist].</small>
== Schleifen ==
Kopfgesteuerte Schleife, Endlosschleife und fußgesteuerte Schleife:
[[File:Programmingloops.svg|450px]]
=== while ===
Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert wie aus anderen Programmiersprachen bekannt.
In Pseudocode:
SOLANGE bedingung TRUE
führe block aus
ENDE
In Python:
x = 0
while x <= 10:
print(x)
x += 1
Ausgabe:
0
1
2
3
4
5
6
7
8
9
10
Eine Endlosschleife ergibt sich z.B. so:
i = 5
while True:
print(i)
i-=1
Beendet werden kann sie mit der Tastenkombination STRG-C.
Eine fußgesteuerte Schleife kann so simuliert werden:
i = 5
while True:
print(i)
i-=1
if i<=0:
print("Fire")
break
Ausgabe:
5
4
3
2
1
Fire
Der <code>break</code>-Befehl wird etwas später noch einmal kurz thematisiert.
=== for ===
Struktogramm einer for-Schleife:
[[File:Zählschleife.png|200px]]
In Python bspw. so:
for x in range(6):
print(x*2)
Ausgabe:
0
2
4
6
8
10
Die Schleife läuft von 0 bis 5. Ausgegeben wird jeweils der Wert x*2. Aquivalent kann diese Schleife auch so geschrieben werden:
for x in range(0, 11, 2):
print(x)
Die Ausgabe ist wie oben. Der Startwert sei 0, der Endwert ist 11-1 und die Schrittweite ist 2.
Ein anderes Beispiel sei
for x in "text":
print(x)
Ausgabe:
t
e
x
t
== Schleifen abbrechen ==
=== break ===
<code>break</code> bricht die Schleife ab und setzt mit dem nächsten Befehl außerhalb der Schleife fort.
for var in range(100):
print(var)
if var == 5:
break
Ausgabe:
0
1
2
3
4
5
=== continue ===
<code>continue</code> bricht den aktuellen Schleifendurchlauf ab und setzt mit dem nächsten Schleifendurchlauf fort.
for var in range (11):
if var == 5:
continue
print(var)
Ausgabe:
0
1
2
3
4
6
7
8
9
10
== try - except ==
try:
z1 = 12 / 0
print(z1)
except ZeroDivisionError:
print("Das Ergebnis ist unendlich")
except:
print("Kann nicht berechnet werden!")
print("Bitte die Formel korrigieren!")
print("Setze Programm fort!")
Ausgabe:
Das Ergebnis ist unendlich
Setze Programm fort!
Es wird versucht, eine Zahl durch Null zu dividieren. Das ist nicht möglich, es wird eine Ausnahme ausgelöst. Das Programm springt daher in den except-ZeroDivisionError-Block und führt die dort gelisteten Anweisungen aus (in unserem Fall eine print-Anweisung). Danach wird das Programm fortgesetzt. Würden wir dieses Programm ohne try-except ausführen, so ergibt sich aus
z1 = 12 / 0
print(z1)
folgende Fehlermeldung und ein unmittelbarer Programmabbruch
Traceback (most recent call last):
File "C:\tmp\test1.py", line 1, in <module>
z1 = 12 / 0
ZeroDivisionError: division by zero
Mit dem try-except-Mechanismus können also Ausnahmen oder Fehler aufgefangen und behandelt werden. In unserem Beispiel ist das eher trivial, aber bei größeren Programmen kann das durchaus Sinn machen.
Neu in Python 3.14 ist, dass mehrere Ausnahmen auch ohne Klammern angegeben werden können, z.B.:
bis inkl. Python 3.13 nur:
except (ZeroDivisionError, ValueError):
ab Python 3.14 auch:
except ZeroDivisionError, ValueError:
== pass ==
Ein leerer Block muss in Python mittels dem Schlüsselwort <code>pass</code> dargestellt werden. Z.B.
x = 2
if x == 1:
print("Wert ist ", x)
else:
pass
Würde man das <code>pass</code> im else-Block weglassen, so würde man eine Fehlermeldung erhalten:
IndentationError: expected an indented block after 'else' statement on line 5
= Funktionen =
== Aufrufen von Funktionen ==
Funktionen sind uns im Rahmen dieses Kurses schon zuhauf begegnet. Sei es die print()-, die math.sin()- oder die hex()-Funktion. All diese Funktionen werden von Python zur Verfügung gestellt, ohne dass man sie explizit programmieren müsste. Aufgerufen werden diese Funktionen, indem man ihren Namen eintippt, gefolgt von runden Klammern. In diesen Klammern können noch Argumente übergeben werden. Auch Rückgabewerte sind möglich.
== Funktionen selber schreiben ==
Funktionen werden mit dem def-Schlüsselwort (man definiert die Funktion) eingeleitet, danach folgt der Funktionsname, danach wiederum runde Klammern, in denen formale Argumente stehen können. Abgeschlossen wird die def-Zeile mit einem Doppelpunkt. Danach folgt der Funktionskörper. Dieser Funktionskörper muss wiederum eingerückt werden (wie von den Verzweigungen und Schleifen bekannt). Aufgerufen wird diese Funktion, indem man ihren Funktionsnamen eingibt, gefolgt von runden Klammern (ggf. mit den aktuellen Parametern). Z.B.
# Funktion definieren
def halloWelt(i):
# i ... beliebige Ganzzahl
print("Hallo " * i, end="")
print("Welt!")
# Funktion aufrufen
halloWelt(3)
Ausgabe:
Hallo Hallo Hallo Welt!
Unterschied zwischen formalen und aktuellen Parametern:
[[Datei:PythonIng_func1.jpg]]
<small>Aktuelle Parameter werden auch Argumente genannt.</small>
Rückgabe von Funktionswerten:
# Funktion definieren
def mathFunc(a, b):
r1 = a + b
r2 = a * b
return r1, r2
# Funktion aufrufen
c, d = mathFunc(3, 5)
# Ausgabe der zurückgegebenen Werte
print(c)
print(d)
Ausgabe:
8
15
Es werden r1 und r2 zurückgegeben und den Variablen c und d zugewiesen. (r1, r2) und (c, d) sind Tupel. Was Tupel konkret sind, siehe etwas später in diesem Kapitel. 3 und 5 sind die aktuellen Parameter (die Argumente). a und b sind die formalen Parameter. Die Zuweisung der aktuellen zu den formalen Parametern erfolgt in der gegebenen Reihenfolge, also die Zahl 3 wird an a übergeben und die Zahl 5 an b.
Vorgabeparameter, z.B.:
def mathFunc(a=10, b=20):
r1 = a + b
r2 = a * b
return r1, r2
c, d = mathFunc(3, 5)
print(c)
print(d)
e, f = mathFunc(5)
print(e)
print(f)
g, h = mathFunc(b=6)
print(g)
print(h)
Ausgabe:
8
15
25
100
16
60
Erklärung:
* Erster <code>mathFunc</code>-Aufruf: Es werden, wie weiter oben, die Argumente 3 und 5 an die formalen Parameter a und b übergeben. Die Rückgabewerte r1 und r2 werden an c und d übergeben. Somit ist c=8 und d=15.
* Zweiter <code>mathFunc</code>-Aufruf: Es wird nur das Argment 5 an a übergeben. b behält den Vorgabewert 20. D.h. e= 25 und f=100.
* Dritter <code>mathFunc</code>-Aufruf: Es wird nur die Zahl 6 an b übergeben, a behält seinen Vorgabewert 10. Somit ergibt sich g=16 und h=60.
Beispiel (Schlüsselwortargumente vs. Positionsargumente):
def mathFunc(a, b):
r1 = a - b
r2 = a / b
return r1, r2
c, d = mathFunc(b=3, a=5) # Schlüsselwortargumente
e, f = mathFunc(3, 5) # Positionsargumente
print(c)
print(d)
print(e)
print(f)
Ausgabe:
2
1.6666666666666667
-2
0.6
Durch die Verwendung von Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge angegeben werden. Bei den Positionsargumenten ist die Reihenfolge vorgegeben. Daraus resultiert auch der Unterschied bei den obigen Ausgaben. Werden beide Arten in einem Aufruf gemischt, so müssen die Positionsargumente zuerst angegeben werden. Den Unterschied zwischen beiden Argumentarten zu kennen ist wichtig, nicht nur bei selbst erstellten Funktionen. Auch beim Aufruf von Python-Funktionen verfolgt einen die Mischung von Schlüsselwort- und Positionsargumenten auf Schritt und Tritt, z.B. beim etwas später folgenden Abschnitt über "Grafiken zeichnen":
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
Bei dieser <code>plot</code>-Funktion aus dem Modul <code>matplotlib.pyplot</code> sind <code>x</code> und <code>y1</code> Positionsargumente. <code>label, lw</code> und <code>ls</code> sind die Namen der Schlüsselwortargumente. Die Schlüsselwortargumente könnten auch in anderer Reihenfolge angeschrieben werden, nicht jedoch die Positionsargumente!
Siehe zu <code>matplotlib.pyplot.plot</code> auch die Seite [https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html].
== Lambda-Funktionen ==
print((lambda a, b: a*b) (3, 5))
Ausgabe:
15
Eingeleitet wird eine Lambda-Funktion (auch Lambda-Form, Lambda-Operator oder anonyme Funktion genannt) mit dem Schlüsselwort <code>lambda</code>. Es folgen die formalen Argumente, danach ein Doppelpunkt, die Berechnungsvorschrift und ggf. abschliessend in Klammern die aktuellen Parameter.
Man kann einer Lambda-Funktion auch einen Funktionsnamen geben und die Funktion über diesen Namen aufrufen, z.B.
prod = lambda a, b: a*b
print(prod(3, 5))
Als Ausgabe wird wieder die Zahl 15 geliefert.
== Rekursive Funktionen ==
Funktionen können wiederum andere Funktionen aufrufen. Von einem rekursiven Funktionsaufruf spricht man, wenn die aufgerufene Funktion gleich der aufrufenden ist.
def printFunc(i):
if (i >= 5):
return
else:
print("Hallo Welt")
printFunc(i+1)
printFunc(1)
Ausgabe:
Hallo Welt
Hallo Welt
Hallo Welt
Hallo Welt
== Funktionsannotationen ==
Python ist sehr flexibel, was Typen angeht. Im Vorhergehenden haben wir generell keine Typangaben gemacht. Will man Typen angeben, so bietet Python das Konzept der Funktionsannotation.
def calcFunc(a: int, b: int) -> int:
return a+b
r1 = calcFunc(8, 9)
r2 = calcFunc(8.0, 9.0)
r3 = calcFunc("Hallo", "Welt")
print(r1)
print(r2)
print(r3)
Ausgabe:
17
17.0
HalloWelt
Jetzt sieht man auf den ersten Blick, welche Typen der Programmierer im Sinn hatte, als er die Funktion erstellte. Das Problem dabei ist nur, dass es Python ziemlich egal ist, welche Typen man im Endeffekt eingibt. Im obigen Beispiel können statt Integer-Typen u.a. auch Float- oder String-Typen eingegeben werden.
<small>
Siehe zum Thema "Type Checking" aber auch den später folgenden Abschnitt [[Ing_Mathematik:_Python#Type_Checker]].
</small>
== Variadische Funktionen ==
Python-Code:
def test1(a, *b):
print(a);
for c in b:
print(c);
test1("Hallo", "Welt", "Schweizer", "und alle anderen")
Ausgabe:
Hallo
Welt
Schweizer
und alle anderen
Mit dem Stern (auch als Splat-Operator bezeichnet) in der formalen Parameterliste bei der Funktion <code>test1</code> wird angezeigt, dass eine beliebige Anzahl von Argumenten übergeben wird. <small> Dies entspricht in etwa dem, was in anderen Programmiersprachen (PHP etc.) mittels Ellipse (<code>...</code>) angezeigt wird.</small>
= Tupel, Listen und andere =
[[Datei:Python 3. The standard type hierarchy.png|mini|hochkant=1.7|Datentypen und Strukturen]]
== Tupel und Listen ==
Tupel, Listen und einige andere sind Datenstrukturen oder Sequenzen.
Listen (z.B. eine Einkaufsliste) sind veränderbar (mutable). Ein Tupel kann dagegen nicht verändert werden (immutable). Listen werden beim Anlegen in eckige Klammern eingeschlossen, Tupel in runde Klammern. Beim Tupel können die Klammern auch weggelassen werden. Ein Tupel mit nur einem Element muss mit einem Beistrich abgeschlossen werden. Der Grund ist, dass Python sonst nicht entscheiden kann, ob ein Tupel angelegt werden soll, oder nur ein geklammerter Wert.
Als Gedächtnisstütze kann man sich den Unterschied zwischen Tupel und Liste ev. so leichter merken:
: T'''u'''pel ... r'''u'''nde Klammern, '''u'''nveränderlich
: L'''i'''ste ... eck'''i'''ge Klammern, veränderl'''i'''ch.
Nachfolgend werden einige Operationen mit Listen und Tupel dargestellt.
# Liste und Tupel
liste = [1, 2, "Hallo"]
tupel = (1, 2, "Hallo")
# Ausgabe von liste und tupel
print(liste)
print(tupel)
# Ausgabe von Einzelelementen
print(liste[1])
print(tupel[2])
# Element an Liste anhängen und einfügen
liste.append(55)
liste.insert(4, "Welt")
print(liste)
# Element aus Liste entfernen
liste.remove(1)
print(liste)
# einige weitere Beispiele
liste2 = [1,]
tupel2 = 1, 2
tupel3 = (1,)
print(liste2)
print(tupel2)
print(tupel3)
Ausgabe:
[1, 2, 'Hallo']
(1, 2, 'Hallo')
2
Hallo
[1, 2, 'Hallo', 55, 'Welt']
[2, 'Hallo', 55, 'Welt']
[1]
(1, 2)
(1,)
Beispiel (eine Liste von Wörtern zu einem einzigen zusammenhängenden Text verbinden):
woerter = ["Hallo", "Welt"]
satz = " ".join(woerter)
print(satz)
Ausgabe:
Hallo Welt
== Dictionaries und Mengen ==
Zu den Datenstrukturen gehören weiters auch Mengen und Dictionaries. Mengen sind von der Mathematik bekannt, sie sind ungeordnet und es kommen keine mehrfachen Elemente vor. Dictionaries sind durch Schlüssel :Wert-Paare gekennzeichnet. Mengen werden beim Anlegen wie Dictionaries in geschweifte Klammern eingeschlossen.
dict = {"vorname":"Hugo", "nachname":"Meister" }
menge = {1, 1, 3, 4, 4, 4, "Hallo"}
print(dict)
print(menge)
print(dict["vorname"])
Ausgabe:
{'vorname': 'Hugo', 'nachname': 'Meister'}
{1, 3, 4, 'Hallo'}
Hugo
Geschweifte Klammern ohne Inhalt stellen Dictionaries dar und keine Mengen:
di = {}
print(type(di))
Ausgabe:
<class 'dict'>
Leere Mengen lassen sich mit <code>set()</code> erzeugen:
menge = set() # leere Menge
print(menge)
menge.add("Hallo") # Element hinzufügen
print(menge)
Ausgabe:
set()
{'Hallo'}
Beispiel (einige Mengenoperationen):
mengeA = {"Hallo", "Welt"}
mengeB = {1, 2, "Welt", 3}
# Vereinigung
print(mengeA | mengeB)
print(mengeA.union(mengeB))
# Durchschnitt
print(mengeA & mengeB)
print(mengeA.intersection(mengeB))
# Differenz
print(mengeA - mengeB)
print(mengeA.difference(mengeB))
# Symmetrische Differenz
print(mengeA ^ mengeB)
print(mengeA.symmetric_difference(mengeB))
# Teilmenge
print(mengeA.issubset(mengeB))
# Mehrere Elemente hinzu
mengeA.update(["Super", 67, 125])
print(mengeA)
# Element löschen
mengeA.discard("Hallo")
print(mengeA)
Ausgabe:
{1, 2, 3, 'Welt', 'Hallo'}
{1, 2, 3, 'Welt', 'Hallo'}
{'Welt'}
{'Welt'}
{'Hallo'}
{'Hallo'}
{1, 2, 3, 'Hallo'}
{1, 2, 3, 'Hallo'}
False
{67, 'Super', 'Welt', 'Hallo', 125}
{67, 'Super', 'Welt', 125}
Es gibt schon seit "ewigen" Zeiten unveränderbare Mengen, die mittels <code>frozenset</code> eingeleitet werden. Neu ab Python 3.15 ist dagegen das Pendant <code>frozendict</code>, das unveränderbare Dictionaries darstellt.
fdict = frozendict({"vorname":"Hugo", "nachname":"Meister"})
fset = frozenset({"A", 1, "A"})
print(fdict)
print(fdict["vorname"])
print (fset)
try:
fdict["vorname"] = "Max"
print(fdict["vorname"])
except TypeError as e:
print(f"Fehler: {e}")
try:
fset.add("B")
print(fset)
except AttributeError as e:
print(f"Fehler: {e}")
Ausgabe:
frozendict({'vorname': 'Hugo', 'nachname': 'Meister'})
Hugo
frozenset({1, 'A'})
Fehler: 'frozendict' object does not support item assignment
Fehler: 'frozenset' object has no attribute 'add'
== List Comprehensions ==
Aus einer Eingabeliste soll eine Ausgabeliste erzeugt werden. Das kann folgendermaßen geschehen.
Mathematische Schreibweise: <math>lc = \{2x|x\in\ \mathbb{N}, 1\le x < 11\}</math>
Python-Code:
lc = [x*2 for x in range(1,11)]
print(lc)
Ausgabe:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Mathematische Schreibweise: <math>lc = \{2x | x \in \mathbb{N}, 1\le x < 11, x \bmod 2 = 0 \}</math>
Python-Code:
lc = [x*2 for x in range(1,11) if x%2 == 0]
print(lc)
Ausgabe:
[4, 8, 12, 16, 20]
Siehe auch {{W|List Comprehension}}.
== Set Comprehensions ==
Dies ist sehr ähnlich wie im vorigen Abschnitt beschrieben. Es wird aber keine Liste, sondern eine Menge erzeugt.
sc = {x*2 for x in range(1,11)}
print(sc)
Ausgabe:
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
== Listen zusammenführen - zip() ==
li1 = ["A", "B", "C", "D"]
li2 = [1, 2, 3, 4]
li3 = [5.5, 6.6, 7.7, 8.8]
z = zip(li1, li2, li3)
print(z)
li4 = list(z)
print(li4)
Ausgabe:
<zip object at 0x00000283B6C6AC80>
[('A', 1, 5.5), ('B', 2, 6.6), ('C', 3, 7.7), ('D', 4, 8.8)]
== Generatorausdruck ==
g = (i*2 for i in range(1,11))
print(g)
t = tuple(g)
print(t)
print(t[1:3])
Ausgabe:
<generator object <genexpr> at 0x00000241D2A4A5A0>
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
(4, 6)
== Slicing ==
slice ... Scheibe, Teil, in Scheiben schneiden
Beispiel: Zugriff auf Elemente eines geordneten sequentiellen Objekttyps (Liste, Tupel oder String):
str1 = "Hallo"
# Das erste Element wird mit dem Index 0 angesprochen
# [start (inkl.) : stop (exkl.) : step (default=1)]
str2 = str1[0:2]
# Alternativ auch: str2 = str1[:2]
print(str2)
tup1 = (0,1,2,3)
# Das letzte Element hat auch den Index -1, das vorletzte den Index -2 usw.
tup2 = tup1[-3:-1]
print(tup2)
lst1 = [[1, 5, 10, 20],
[30, 40, 50, 60]]
lst2 = lst1[1][1]
print(lst2)
Ausgabe:
Ha
(1, 2)
40
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2])
print(x[-3])
print(x)
print(x[:])
print(x[2:])
print(x[:2])
print(x[::-1])
Ausgabe:
c
c
('a', 'b', 'c', 'd', 'e')
('a', 'b', 'c', 'd', 'e')
('c', 'd', 'e')
('a', 'b')
('e', 'd', 'c', 'b', 'a')
Visualisierung:
'''a''' '''b''' '''c''' '''d''' '''e'''
+-----------------------------+
| 0 | 1 |//'''2'''//| 3 | 4 |
+-----------------------------+
| -5 | -4 |/'''-3'''//| -2 | -1 |
+-----------------------------+
|/////////////////////////////|
+-----------------------------+
|/////////////''':'''///////////////|
+-----------------------------+
| | |///////'''2:'''////////|
+-----------------------------+
|////''':2'''/////| | | |
+-----------------------------+
|\\\\\<--\\\\\'''::-1'''\\\\<--\\\\\|
+-----------------------------+
Beispiel:
x = ("a", "b", "c", "d", "e")
print(x[2::2])
print(x[2::-1])
print(x[2:0:-1])
Ausgabe:
('c', 'e')
('c', 'b', 'a')
('c', 'b')
Hier sieht man sehr schön, dass beim letzen <code>print</code>-Befehl die 0, die in diesem Fall den Buchstaben "a" repräsentiert, als letzer Wert nicht mehr dazugehört (wie weiter oben angedeutet ist der End- oder Stoppwert exklusiv). Will man den Buchstaben "a" dazunehmen, so ist die vorletzte Zeile die richtige.
Beispiel: Umdrehen von Strings
str1 = "Hallo"
str2 = str1[::-1]
print(str2)
Ausgabe:
ollaH
Mit zweidimensionalen Listen/Tupels wird das Ganze schon bedeutend komplexer.
Beispiel: Verkettetes Slicing
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
print(A[2::][::2])
Ausgabe:
[['20', '21', '22', '23'], ['40', '41', '42', '43']]
Das erste Slicing erstellt folgenden Slice:
[["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
Das zweite Slicing wird dann auf diesen Slice angewendet und ergibt das genannte Endergebnis. Will man Spalten statt Zeilen, so funktioniert dieser direkte Weg nicht. Man verwendet dann List Comprehensions oder die NumPy-Bibliothek. Diese Bibliothek erlaubt zweidimensionales Slicing. Sie wird erst später bei den Grafiken eingeführt. Deshalb wird hier dazu noch kein Beispiel gezeigt.
= Objektorientierte Programmierung =
{{Wikipedia|Objektorientierte Programmierung}}
* {{W|Klasse (Objektorientierung)|Klasse}} ... die Schablone oder der Bauplan, enthält Methoden und Attribute
* {{W|Objekt (Programmierung)|Objekt}} ... eine Klasseninstanz (die konkrete Ausprägung der Klasse)
* {{W|Attribut (Programmierung)|Attribute}} ... die Eigenschaften eines Objekts
* {{W|Methode (Programmierung)|Methoden}} ... die Aktionen (Operationen), die ein Objekt ausführen kann
* {{W|Vererbung (Programmierung)|Vererbung}} ... neue Klassen (Subklassen, Unterklassen, abgeleitete Klassen) aus vorhandenen Klassen (Superklassen, Oberklassen, Basisklassen, Elternklassen) ableiten. Ermöglicht den Aufbau von Klassenhierarchien. Die Subklasse "erbt" Attribute und Methoden von der Superklasse. Python unterstützt (so wie C++, aber im Gegensatz zu Java) Mehrfachvererbung.
== UML ==
* {{W|Unified Modeling Language|UML}} ... '''U'''nified '''M'''odeling '''L'''anguage, eine Modellierungssprache. Die UML enthält zahlreiche Diagrammarten, um Programme zu modellieren. Im Nachfolgenden wird nur das {{W|Klassendiagramm}} verwendet.
[[File:UmlCd Klasse-3.svg|300px]]
* {{W|Sichtbarkeit (Programmierung)|Sichtbarkeit}}:
** + ... public (öffentlich)
** - ... private
** # ... protected
* {{W|Attribut_(UML)#Attribute_für_Instanzen_und_für_Klassen|Klassenattribute}} (statische Attribute): Werden nur einmal pro Klasse angelegt. Im Klassendiagramm werden sie unterstrichen.
[[File:Attribute-3.png|200px]]
* Vererbung:
<gallery>
InheritancePgmUML.svg | Abgeleitete Klasse erbt von Basisklasse (Einfachvererbung)
Diamond inheritance.svg | D erbt von B und C (Mehrfachvererbung). B und C erben von A (Einfachvererbung)
</gallery>
Für weitergehende Betrachtungen zur UML wird auf Spezialliteratur verwiesen, z.B.:
* Seidl et al.: UML@Classroom. dpunkt, 2012, ISBN 978-3-89864-776-2
* Rupp et al.: UML 2 glasklar. Hanser, 4. Aufl., 2012, ISBN 978-3-446-43057-0
== Eine einfache Klasse ==
[[Datei:PythonIng_uml1.svg | 200px]]
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
fahr = Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die Klasse Fahrzeug wird durch das class-Schlüsselwort eingeleitet. raeder ist ein Klassenattribut und public. __init__ wird bei der Objekterzeugung automatisch aufgerufen (ist der sogenannte Konstruktor). Man achte darauf, dass diese Methode immer mit zwei Unterstrichen eingeleitet und abgeschlossen wird. Instanzattributen wird das Wort self vorangestellt. Wir sehen uns z.B. das Attribut self.__geschwind an. Auch hier werden zwei Unterstriche verwendet. Das bedeutet, dass dieses Attribut strikt/stark private ist. Wird nur ein Unterstrich verwendet, so deutet dies auf schwach/weakly private hin. Letzteres wird in Python deutlich häufiger verwendet. Bei den Methoden wird immer self als erster Parameter angegeben. Beim Aufruf der entsprechenden Funktion wird das self aber nicht berücksichtigt.
Besonderheiten bei stark und schwach private:
* '''stark private''':
** zwei führende Unterstriche
** Name Mangling: Name wird zu <code>_Klassenname__variablenname</code>
** Schutz vor Namenskollisionen bei Vererbung
** am Ende des Namens dürfen keine zwei Unterstriche verwendet werden. Das wären dann Magic Methods oder Dunder-Methods (z.B. __init__). Diese sind public.
* '''schwach private''':
** ein führender Unterstrich
** Name bleibt gleich
** ist nur ein Hinweis an die Programmierer, kein starker Schutz
** <code>from modul import *</code>: Objekte mit einem führenden Unterstrich werden standardmäßig nicht importiert
** Standard für die Kapselung bei Python. Schätzung: Weit mehr als 80% der nicht-öffentlichen Attribute/Methoden werden als schwach private deklariert. Weniger als 5-10% als stark private (Quelle: Google KI)
== Klassen importieren ==
Häufig ist es sinnvoll und übersichtlicher Klassen in eigenen Dateien zu speichern. Das sind dann eigene Module. Abgespeichert werden Sie mit der Endung py, wie bisher auch praktiziert. Aufgerufen werden Sie mit der import-Anweisung. Dann ist aber nur der Dateiname ohne Endung py zu verwenden. Klarer wird das mit einem Beispiel.
Datei c:\tmp\fahrzeug.py
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
Datei c:\tmp\test1.py
import fahrzeug
fahr = fahrzeug.Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die üblichen import-Anweisungen lauten wie folgt:
{| {{prettytable}}
! import-Befehl
! Instanz
|-
| import xyz || xyz.Klasse
|-
| import xyz as x || x.Klasse
|-
| from xyz import Klasse || Klasse
|-
| from xyz import * || Klasse
|}
Der Vorteil der ersten beiden import-Anweisungen ist, dass es kaum zu Namenskollisionen kommen kann. Dafür hat man bei den letzten beiden Varianten weniger Tipparbeit.
== Vererbung ==
=== Einfachvererbung ===
[[Datei:PythonIng_uml2.svg | 200px]]
Datei fahrzeug.py:
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
class Luftfahrzeug(Fahrzeug):
def __init__(self, geschwindigkeit, leistung, fluegel):
super().__init__(geschwindigkeit, leistung)
self.__flueg = fluegel
def getFlueg(self):
return self.__flueg
Datei test1.py:
import fahrzeug
fahr = fahrzeug.Luftfahrzeug(150, 90, 4)
print(fahr.getFlueg())
Ausgabe:
4
=== Mehrfachvererbung ===
Mit Python ist auch Mehrfachvererbung möglich, z.B.:
class A:
def _printA(self):
print("Klasse A")
class B:
def _printB(self):
print("Klasse B")
class C(A,B):
def __init__(self):
self._printA()
self._printB()
c = C()
Ausgabe:
Klasse A
Klasse B
Die Klasse C erbt von A und B. In UML sieht das in etwa so aus:
+-----------------------------+ +-------------------------+
| A | | B |
+-----------------------------+ +-------------------------+
| | | |
+-----------------------------+ +-------------------------+
| # printA() | | # printB() |
+-----------------------------+ +-------------------------+
. .
/ \ / \
--- ---
| |
| |
+---------------------+
| C |
+---------------------+
| |
+---------------------+
| |
+---------------------+
<code>printA()</code> und <code>printB()</code> sind schwach private (in UML als <code>protected</code> mit einem # dargestellt). Es ist aber zu beachten, dass schwach private nur Konvention ist. Praktisch könnte man auch von außerhalb auf diese Methoden zugreifen. Das soll man aber nicht tun, und das wird in Python durch einen Unterstrich angedeutet.
= Grafiken zeichnen =
Für das Zeichnen von Grafiken wird hier das Modul <code>matplotlib</code> verwendet. <code>matplotlib</code> ist ein externes Modul und muss vor der ersten Verwendung installiert werden. Das geht so:
# Starten Sie ein Terminal (bei Windows die Eingabeaufforderung).
# Führen Sie darin folgenden Befehl aus <code>c:\devel\Python\Scripts\pip.exe install matplotlib</code>
pip ist übrigens der Paketmanager von Python ({{W|Pip_(Python)}}).
Optimalerweise installieren wir auch gleich das Modul <code>numpy</code> (Numerical Python). Wir werden es im Folgenden oft benötigen (nicht nur bei den Grafiken). Das funktioniert vom Prinzip her genauso, wie für <code>matplotlib</code> gezeigt.
<small>Verwenden Sie Spyder, so sind diese Schritte nicht nötig. Spyder inkludiert diese Pakete standardmäßig. Unter openSUSE Tumbleweed lassen sich diese Pakete mittels YaST oder zypper installieren.</small>
== 2D ==
=== Graph einer Funktion ===
Es soll die cosh-Funktion im Intervall <math>x\in[-3,3]</math> gezeichnet werden. Der Programmcode lautet in der einfachsten Form:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x)
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh1.jpg]]
Der Code ist quasi selbsterklärend. Das Untermodul pyplot des matplotlib-Moduls und das numpy-Modul werden importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plt.plot()" ist der Zeichenbefehl. "plt.show" ist notwendig, um das Fenster mit der Grafik anzuzeigen.
Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen. "plt.grid()" zeichnet ein Gitter in die Grafik (kann auch weggelassen werden).
Die Bezeichnungen plt und np könnten auch anders gewählt werden. Es ist aber Konvention, diese so wie hier gezeigt zu wählen. Die "arange"-Funktion aus der NumPy-Bibliothek wird später ein bisschen genauer behandelt (siehe [[Ing_Mathematik:_Python#Zahlenfolgen|Zahlenfolgen]]).
<small>Mit der im obigen Bild gezeigten Menüleiste kann die dargestellte Grafik nachträglich noch geändert werden (Zoom, Pan, Achsenparameter, Kurvenparameter etc.). Natürlich kann man das alles auch direkt programmieren. Wie das funktioniert wird ansatzweise etwas später gezeigt.</small>
Ein etwas komplexeres Beispiel ist Folgendes:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x) + 2**x
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh4.png]]
Man beachte, dass im Gegensatz zu Octave und Julia der ominöse Punkt (.) bei 2**x mit Python nicht benötigt wird. Das macht das Programmiererleben etwas einfacher.
Die Farbe des Graphen kann man über den <code>color</code>-Schalter einstellen, z.B. auf rot setzen:
plt.plot(x, y, color="red")
Das ist nur eine Möglichkeit, es gibt auch andere, z.B. mittels
* hexadezimaler Zahl, z.B. <code>color="#ff0000"</code>
* Kurzform, z.B. <code>"r"</code>
Statt <code>color</code> kann auch die Kurzform <code>c</code> verwendet werden.
<u>Kleine Aufgabe:</u> Probieren Sie diese "Farbspielereien" am Computer aus.
=== Graphen mehrerer Funktionen und weiteres ===
==== Mehrere Funktionen in einen Plot zeichnen ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x")
plt.plot(x, y2, label = "sin(x) * cos(x)")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh2.png]]
Um die Linienstile etwas individueller zu gestalten, ist folgender Programmcode gedacht:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
plt.plot(x, y2, label = "sin(x) * cos(x)", lw=3, ls="--")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh3.png]]
Einige weitere Bespiele zu <code>ls</code></code>:
* - ... durchgezogene Linie
* -. ... Strichpunkt-Linie
* dashed ... gestrichelte Linie
==== Marker ====
Desweiteren kann man Marker verwenden.
Beispiel:
import matplotlib.pyplot as plt
plt.plot(10, 10, "ob", markersize=30)
plt.plot(20,20, ".r")
plt.plot(30,30, "Dg", ms=15)
plt.plot(40, 40, "ok", ms=20, mec="#FF5733", mew=3)
plt.plot(50, 50, "vk", ms=20, mec="yellow", mew=3)
plt.grid()
plt.show()
Das erste Zeichen im String nach den Koordinaten im plot-Befehl symbolisiert die Form (z.B. o für einen Kreis). Das zweite Zeichen steht für die Farbe (z.B. b für blue). <code>markersize</code> oder <code>ms</code> setzt die Größe des Markers.
Ausgabe:
[[Bild:PythonIng_formatpara1.svg|200px]]
Einige weitere Marker:
* * ... Stern
* + ... Plus
* h oder H ... Sechseck
Man kann mit den Parametern
* <code>markeredgecolor</code> oder kurz <code>mec</code> die Farbe des Markerrandes
* <code>markeredgewidth</code> oder kurz <code>mew</code> die Dicke des Randes
* <code>markerfacecolor</code> oder kurz <code>mfc</code> die Innenfarbe des Markers
bestimmen.
=== Funktion in Parameterdarstellung ===
Es soll die archimedische Spirale <math>x = t \cos(t), y = t \sin(t)</math> im Intervall <math>[0, 6\pi[</math> gezeichnet werden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.show()
[[Datei:PythonIng_spirale1.png]]
Diese Darstellung erscheint verzerrt. Will man gleiche Achsenskalierungen, so kann man den plt.axis()-Befehl verwenden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.axis("equal")
plt.show()
[[Datei:PythonIng_spirale2.png]]
=== Funktion in Polardarstellung ===
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
r = np.arange(0, 1, 0.01)
theta = r**3
line = ax.plot(theta, r)
plt.show()
[[Datei:PythonIng_polar1.png]]
=== Logarithmische Achsenskalierung ===
==== Semilog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.semilogy()
plt.show()
Ausgabe:
[[Datei:PythonIng_semilog1.png]]
==== LogLog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.loglog()
plt.show()
[[Datei:PythonIng_loglog1.png]]
=== Gefüllte Fläche ===
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 3, 0.1)
y1 = 3*x - 1
y2 = x**2
plt.plot(x, y1, x, y2, color='black')
plt.fill_between(x, y1, y2, where=y1>=y2)
plt.show()
[[Datei:PythonIng_gefuellt.png]]
=== Linien, Pfeile, Rechtecke, Kreise und Texte ===
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
r = mpl.patches.Rectangle((0, 0), 3, 3, angle=30, fill=False)
c = mpl.patches.Circle((4, 4), 2, fill=False)
ax.add_patch(r)
ax.add_patch(c)
ax.plot([-2, 7], [-2, 0], color="black")
ax.arrow(0, 7, 5, 0, length_includes_head=True, head_width=0.5, head_length=1.5,
color="black")
ax.set_aspect("equal")
plt.axis([-3, 8, -3, 8])
plt.show()
[[Datei:PythonIng_linien_pfeile_etc.png]]
Text kann mit <code>ax.text(x, y, "Text")</code> hinzugefügt werden, bspw.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
ax.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
Oder einfacher auch ohne <code>subplots</code>
import matplotlib.pyplot as plt
plt.text(0.1, 0.1, "Hallo")
plt.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text1.png]]
Auch Sonderzeichen (griechische Buchstaben etc.) können verwendet werden (siehe dazu auch [https://matplotlib.org/stable/users/explain/text/mathtext.html]).
import matplotlib.pyplot as plt
plt.text(.3, .5,
r'$\Omega\ \psi\ \oint\ \nabla\ \dot a\ \frac{a}{b}\ a_b$',
size="20")
plt.show()
[[Datei:PythonIng_text20.svg]]
Jetzt wird noch gezeigt, wofür <code>subplots</code> sinnvoll eingesetzt werden können.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(0.1, 0.1, "Hallo")
ax[1].text(0.1, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text2.png]]
=== Anmerkungen hinzufügen ===
Anmerkungen (engl. annotations) lassen sich mit matplotlib einfach hinzufügen. Unter Anmerkung wird hier ein Pfeil mit Text verstanden.
Beispiel:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1,10], [1,10])
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0))
plt.show()
Ausgabe:
[[Datei: PythonIng_ann1.svg|400px]]
<code>shrink</code> verkürzt den Pfeil. Sinnvoll sind beim obigen Beispiel Werte irgendwo zwischen 0.0 und 0.3.
<u>Kleine Aufgabe:</u> Probieren Sie verschiedene Pfeillängen aus.
Die Schriftgröße verändern können Sie übrigens mit <code>fontsize</code> oder <code>size</code>, z.B.
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops=dict(facecolor="red", shrink=0.0), fontsize=25)
Eine andere Schreibweise für Dictionaries, die wir weiter oben schon kennengelernt haben, die wir aber nochmals explizit aufschreiben wollen, ist
ax.annotate("Test", xy=(2, 2), xytext=(3, 5),
arrowprops={"facecolor":"red", "shrink":0.0})
=== Figure, Axes etc.===
[[Bild:PythonIng_figure33.svg|350px]]
* fig (figure) ... das übergeordnete Fenster
* ax (axes) ... "Plot", das eigentliche Zeichenfenster
* axis ... die Koordinatenachsen
* spine ... Begrenzungslinien des Zeichenfensters
* tick ... Markierung an den Achsen des Zeichenfensters
Beispiel (eine figure mit 6 axes, ax-Titel, y-axis-Titel):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=3, ncols=2)
ax[0][0].text(0.1, 0.5, "11")
ax[0][1].text(0.1, 0.5, "12")
ax[1][0].text(0.1, 0.5, "21")
ax[1][1].text(0.1, 0.5, "22")
ax[2][0].text(0.1, 0.5, "31")
ax[2][1].text(0.1, 0.5, "32")
ax[0][0].set(ylabel="y-label", title="axes 1")
plt.show()
[[Bild:PythonIng_figure34.png|350px]]
Beispiel (Achsenbereiche setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-1, 10, 1, 12))
plt.show()
[[Bild:PythonIng_figure35.svg|350px]]
Beispiel (Gitter einschalten):
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(5, 5, "Hallo Welt")
ax[1].text(.5, .5, "Servus")
ax[0].axis((-5, 10, 1, 12))
ax[0].minorticks_on()
ax[0].grid(which='minor')
ax[1].grid(which='major')
plt.show()
[[Bild:PythonIng_figure36.svg|350px]]
Beispiel (ticks setzen)
import matplotlib.pyplot as plt
import matplotlib.ticker as tick
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
pos = [0, .2, .5]
lab = ["a", "b", "c"]
ax.xaxis.set_major_locator(tick.FixedLocator(pos))
ax.xaxis.set_major_formatter(tick.FixedFormatter(lab))
plt.show()
[[Bild:PythonIng_figure37.svg|350px]]
Beispiel (Achsenkreuz beliebig setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.5, "11")
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position(('data', 0.3))
ax.spines['left'].set_position(('data', 0.5))
plt.show()
[[Bild:PythonIng_figure38.svg|350px]]
Beispiel (Inset):
import matplotlib.pyplot as plt
# Hauptplot erstellen
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
# Inset hinzu:
axin = ax.inset_axes([0.4, 0.4, 0.3, 0.3])
axin.text(0, 0, "Servus")
axin.plot()
plt.show()
[[Bild:PythonIng_figure40.svg|350px]]
Beispiel (Hintergrundfarben setzen):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_facecolor("green")
fig.set_facecolor("yellow")
plt.plot([1, 3], [6, 8])
plt.show()
[[Bild:PythonIng_figure39.svg|300px]]
=== GridSpec ===
Mit figures und axes lassen sich schon jede Menge an Grafikdetails einstellen. GridSpec ist dann der Turbo oder Raketenantrieb den matplotlib eingebaut hat. Naja, vielleicht ist das etwas übertrieben, aber GridSpec ist sozusagen ein flexibler Layout-Manager. Bisher haben wir immer gleich große axes gezeichnet. Mit GridSpec können wir Subplots über mehrere Zeilen und Spalten ziehen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(3, 3)
ax1 = fig.add_subplot(gs[0, :])
ax1.set_title("Bereich 1: gs[0, :]")
ax2 = fig.add_subplot(gs[1:, 0])
ax2.set_title("Bereich 2: gs[1:, 0]")
ax3 = fig.add_subplot(gs[1, 1:])
ax3.set_title("Bereich 3: gs[1, 1:]")
ax4 = fig.add_subplot(gs[2, 1:])
ax4.set_title("Bereich 4: gs[2, 1:]")
plt.show()
[[Bild:PythonIng_gridspec1.svg|350px]]
Erklärung zu <code>(gs[zeile, spalte])</code>: Slicing; damit legen Sie fest, welche Zellen ein Subplot belegt. Achtung! Die Indizes beginnen bei 0 und nicht bei 1 (d.h., die erste Zeile/Spalte hat den Index 0)
* : ... alle
* 1: ... 1 bis Ende
* etc.
<code>constrained_layout=True</code> sorgt dafür, dass sich die Subplots nicht überlappen.
Aber auch die Spaltenbreiten und Zeilenhöhen lassen sich anpassen.
Beispiel:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
fig = plt.figure(constrained_layout=True)
# Verhältnis erste zu zweite Zeile = 1.5:1
# Verhältnis erste zu zweite Spalte = 1:4
gs = fig.add_gridspec(2, 2, figure=fig, height_ratios=[1.5, 1], width_ratios=[1, 4])
ax1 = fig.add_subplot(gs[0, 0])
ax1.set_title("Bereich 1: gs[0, 0]")
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_title("Bereich 2: gs[0, 0]")
ax3 = fig.add_subplot(gs[1, 0])
ax3.set_title("Bereich 3: gs[1, 0]")
ax4 = fig.add_subplot(gs[1, 1:])
ax4.set_title("Bereich 4: gs[1, 1]")
plt.show()
[[Bild:PythonIng_gridspec2.svg|350px]]
Auch die Ränder lassen sich einstellen.
Beispiel 1:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.1, right=0.9, bottom=0.1,
top=0.9, wspace=0.2, hspace=0.2)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec3.svg|300px]]
* hspace ... height space, vertikaler Abstand zwischen den Zeilen
* wspace ... width space, horizontaler Abstand zwischen den Spalten
Und im Vergleich dazu Beispiel 2:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, left=0.3, right=0.7, bottom=0.3,
top=0.7, wspace=0.3, hspace=0.3)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0])
ax3 = fig.add_subplot(gs[0, 1])
ax4 = fig.add_subplot(gs[1, 1])
plt.show()
[[Bild:PythonIng_gridspec4.svg|300px]]
Es gibt noch einige weitere Details, die sich mit GridSpec variieren lassen (z.B. SubGridSpec ... verschachtelte Grid-Layouts). Aber wir belassen es vorerst dabei. Das bisher Gezeigte sollte für die meisten Probleme ausreichend sein.
=== Aufgaben ===
* Zeichnen Sie die Strophoide <math>x = \frac{a(t^2-1)}{t^2+1}, y = \frac{at(t^2-1)}{t^2+1}, a = 2, -3 \leq t \leq 3</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_strophoide.jpg|300px|center]]
* Zeichnen Sie die verschlungene Hypozykloide <math>x = (R-r)\cos t + c\cos\frac{R-r}{r}t, y = (R-r)\sin t - c\sin\frac{R-r}{r}t, c = 3, r = 2, R = 6, -15 \leq t \leq 15</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_hypozykloide.jpg|300px|center]]
* Testen Sie bei den obigen Übungsaufgaben verschiedene Linienstile und Farben. Farben können mit dem plt.plot()-Parameter color gewählt werden.
* Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.
* Zeichnen Sie folgendes Bild (die Achsenbeschriftungen positionieren Sie z.B. mit den Befehlen <code>ax.set_xlabel("x", loc="right"); ax.set_ylabel("y", loc="top")</code>):
[[Bild:PythonIng_aufgabe24.svg|400px|center]]
* Zeichnen Sie mit Python, matplotlib und NumPy folgendes Bild:
[[Bild:PythonIng_figure41.svg|400px|center]]
* Zeichnen Sie mit GridSpec ein Layout, das in etwa wie folgendes aussieht (<code>height_ratios=[1, 2], width_ratios=[2, 1]</code>):
[[Bild:PythonIng_aufgabe23.svg|300px|center]]
== 3D ==
=== Räumliche Kurven ===
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0, 6*np.pi, 0.1)
x = t * np.cos(t)
y = t * np.sin(t)
z = t
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot(x, y, z)
plt.show()
[[Datei:PythonIng_raumkurve1.png]]
=== Flächen ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z)
plt.show()
[[Datei:PythonIng_fläche1.png]]
Das Ganze in Netzdarstellung läßt sich so programmieren:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = np.arange(0, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_wireframe(x, y, z)
plt.show()
[[Datei:PythonIng_fläche2.png]]
Ein etwas komplexeres Beispiel:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.1, 10, 0.1)
y = np.arange(0.1, 10, 0.1)
x, y = np.meshgrid(x, y)
z1 = np.sin(x) + 3 * np.cos(y)
z2 = np.sin(x) + np.log(y)
z3 = x + np.cos(y)
z4 = x**2 - y
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, nrows=2, ncols=2)
ax[0][0].plot_surface(x, y, z1)
ax[0][1].plot_surface(x, y, z2)
ax[1][0].plot_surface(x, y, z3)
ax[1][1].plot_surface(x, y, z4)
plt.show()
[[Datei:PythonIng_subplot1.png]]
Man beachte, dass man die Unterbilder im Bild nach dem Ausführen des Scripts z.B. mit der mittleren Maustaste einzeln drehen, oder über die Einträge in der Menüzeile einzeln bearbeiten kann. Mit ein paar Zeilen Programmtext lässt sich also eine Menge an Funktionalität generieren.
Die Farbgebung lässt sich über <code>colormaps</code> variieren.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm)
plt.show()
[[Datei:PythonIng_colormap1.png]]
Es gibt eine Menge an Colormaps, z.B. <code>plasma, Greys, Dark2, ocean</code>. Zwecks detaillierterer Infos siehe die matplotlib-Dokumentation. <small>Verwendet man die IDE namens IDLE, so gibt es dort auch die automatische Codevervollständigung. D.h. es werden alle Möglichkeiten (in unserem Fall nach dem Eintippen von <code>cm.</code> alle verfügbaren Colormaps) angezeigt.</small>
Die "edgecolor" und Linienbreite können auch frei gewählt werden:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm, edgecolor="black", linewidth=1.0)
plt.show()
[[Datei:PythonIng_colormap2.png]]
=== Höhenlinien ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
ax.contour(x, y, z)
plt.show()
[[Datei:PythonIng_höhenlinien1.png|400px]]
Etwas abgewandelt sieht das so aus:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contour(x, y, z)
ax.clabel(hl, inline = True)
plt.show()
[[Datei:PythonIng_höhenlinien2.png|400px]]
Und noch eine Variante (mit einem Farbbalken) sei gezeigt.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contourf(x, y, z)
fig.colorbar(hl)
plt.show()
[[Datei:PythonIng_höhenlinien5.svg|400px]]
=== Aufgaben ===
* Zeichnen Sie die räumliche Kurve <math>x = 2 \cdot \cosh(t)</math>, <math>y = 5 \cdot \sin(t)</math>, <math> z = t^{2} - t</math>, <math>0 \leq t \leq 3\pi</math>.
* Zeichnen Sie die Fläche <math>z = \log(x) + \cos(y)</math>.
== Animationen und fortgeschrittenes 3D ==
=== Mit matplotlib ===
Auch mit matplotlib sind Animationen möglich. Das ist ein bisschen komplizierter und wird deshalb hier nur mit einem sehr einfachen Beispiel dargestellt (bei Interesse siehe z.B. auch das [https://matplotlib.org/stable/users/explain/animations/animations.html#animations Animations using Matplotlib-Tutorial]).
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib
import numpy as np
def update(frame):
line.set_xdata(x[:frame])
line.set_ydata(y[:frame])
return (line)
fig, ax = plt.subplots()
x = np.arange(0, 10, .1)
y = np.sin(x)
line, = ax.plot(x[0], y[0])
ax.set(xlim=[0, 10], ylim=[-1, 1])
a = ani.FuncAnimation(fig=fig, func=update, frames=100, interval=20)
plt.show()
# Speichere die Animation in einem animierten GIF (optional)
a.save(filename="c:/tmp/PythonIng_anim5.gif", writer="pillow")
[[Datei:PythonIng_anim5.gif]]
Es wird eine Sinuskurve auf den Bildschirm gezeichnet. In der letzten Zeile wird diese Animation in ein animiertes GIF gespeichert. Das ist natürlich optional und kann auch weggelassen werden.
=== Mit VPython ===
Aber auch mit dem Modul VPython lassen sich einfache 3D-Animationen erstellen. VPython ist ein externes Modul, das vorab installiert werden muss. Unter openSUSE Tumbleweed gibt es dzt. kein entsprechendes rpm-Paket. Die übliche Methode der Installation mittels YaST oder zypper ist somit nicht möglich. Auch eine direkte Verwendung von pip führt nur zu einer Fehlermeldung (<code>error: externally-managed-environment</code>). Es empfiehlt sich dort folgende Vorgehensweise:
# Erstelle zuerst eine virtuelle Umgebung, z.B.: <code>python3.11 -m venv ~/tmp/venv1</code>
# Wechsle das Verzeichnis: <code>cd ~/tmp/venv1/bin</code>
# Installiere das entsprechende Paket: <code>./pip install vpython</code>
# Führe das entsprechende Skript aus: <code>./python ~/tmp/test1.py</code>
Aktuell (März 2026) ist dieses Programmpaket lt. der [https://vpython.org/presentation2018/install.html VPython-Homepage] nur für die Python-Versionen 3.8 bis 3.12 verfügbar.
Ein Beispiel zu einer einfachen Animation wird nachfolgend geliefert.
from vpython import *
scene.width = 1200
scene.height = 600
scene.center = vector(20,0,0)
scene.background = color.white
cylinder(pos=vector(0,0,0), axis=vector(20,0,0), radius=5,
color=color.blue)
cone(pos=vector(0,0,0), axis=vector(-10,0,0), radius=5,
color=color.blue)
helix(pos=vector(20,0,0), axis=vector(40,0,0), radius=2,
coils=10, thickness=0.5, color=color.blue)
ball = sphere(pos=vector(20,0,0), color = color.green, radius = 1)
ball.p = vector(0.15, 0, 0)
toc = True
while True:
rate(200)
if(ball.pos.x <= 60 and toc == True):
ball.pos += ball.p
else:
toc = False
ball.pos -= ball.p
if(ball.pos.x <= 20 and toc == False):
toc = True
[[Datei:PythonIng_vpython_anim.JPG]]
Idealerweise öffnet sich beim Ausführen des Scripts ein Browserfenster. Darin wird die programmierte Animation gezeigt (siehe auch den obigen Screenshot). Eine Größenänderung können Sie mit der mittleren Maustaste initiieren. Die Szenerie drehen können Sie mit der rechten Maustaste.
=== Mit build123d ===
Hiermit lassen sich einfach 3D-Modelle für CAD-Systeme erstellen. [https://build123d.readthedocs.io/en/latest/ build123d] ist ein externes Modul und muss vorab, wie schon für mehrere andere Module gezeigt, installiert werden (pip, venv etc.).
Beispielcode:
from build123d import *
# Bauteil
with BuildPart() as bauteil:
# Zylinder erstellen
Cylinder(100, 60)
# Bohrung
with BuildSketch(bauteil.faces().sort_by(Axis.Z)[-1]) as loch:
Circle(radius=10)
# negativ extrudieren
extrude(amount=-60, mode=Mode.SUBTRACT)
# Dem Bauteil z.B. die Farbe rot zuweisen
# bauteil.part.color = Color("red", alpha=1.0)
# Fertiges Modell exportieren
export_step(bauteil.part, "bauteil.step")
Ausgabe ({{W|Standard for the exchange of product model data | STEP}}-Datei, z.B. in {{W|FreeCAD}} importiert, Screenshot):
[[Datei:PythonIng_build123d.jpg | 300px]]
FreeCAD ist ein freies 3D-CAD-System. Die [[Ing_Mathematik:_Python#FreeCAD | Makroprogrammierung]] in diesem System wird später noch gezeigt. STEP steht für "'''St'''andard for the '''e'''xchange of '''p'''roduct model data" und ist ein Datenaustauschformat.
=== Mit VTK ===
Komplexer, aber auch mächtiger als VPython ist die Verwendung von VTK ('''V'''isualization '''T'''ool'''k'''it). Genauer gesagt des Python-Wrappers von VTK. Dieses externe Python-Modul muss vorab installiert werden (z.B. mittels YaST, pip oder in eine virtuelle Umgebung). VTK ist eine Softwarebibliothek zur 3D-Visualisierung und wurde ursprünglich in C++ geschrieben. Verbreitet eingesetzt wird diese Bibliothek in der Wissenschaft und Forschung, z.B.
* in der medizinischen Bildgebung
* für Strömungssimulationen
* für Klimadaten
VTK funktioniert nach dem {{W|Grafikpipeline|Pipeline-Prinzip}}:
Source (Quellen) -> Filter -> Mapper (Senken) -> Actor/Renderer
Daten fließen von den Quellen zu den Senken.
Als einfaches Beispiel wird die Darstellung eines Zylinders gezeigt, der mit den Maustasten gedreht oder in der Größe geändert werden kann:
import vtk
# Zylinder erzeugen
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
# Geometrie in darstellbare Daten umwandeln
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
# Objekt in der Szene
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Szene verwalten
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# Render-Fenster
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
# Maus/Tastatur-Steuerung
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Starten
render_window.Render()
interactor.Start()
Ausgabe:
[[Datei:PythonIng_VTK_1.png]]
Gleiches Beispiel wie oben, aber mit einer Animationssequenz:
import vtk
import time
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
render_window.Render()
time.sleep(0.01)
Das Grafikfenster schließt sich nach Ablauf der Schleife. Das Fenster bleibt geöffnet, wenn Sie am Programmende folgenden Befehl hinschreiben
interactor.Start()
Um den animierten Zylinder grün einzufärben, müssen Sie Folgendes im obigen Programm ergänzen (Farbnamen):
colors = vtk.vtkNamedColors()
actor.GetProperty().SetColor(colors.GetColor3d("Green"))
Als Namen können Sie u.a. die CSS3 Web-Farben verwenden (siehe z.B. [https://wiki.selfhtml.org/wiki/Farbe/Farbangaben] und {{W|Webfarbe#CSS_3}}).
Alternativ funktioniert auch das ({{W|RGB-Farbraum|RGB}}):
actor.GetProperty().SetColor(0.0, 0.6, 0.0)
Wie der Zylinder mit einer Textur versehen wird, zeigt folgendes Programm:
import vtk
import time
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(30)
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.CappingOn()
texture_coords = vtk.vtkTextureMapToCylinder()
texture_coords.SetInputConnection(cylinder.GetOutputPort())
texture_coords.PreventSeamOn()
reader = vtk.vtkJPEGReader()
reader.SetFileName("PythonIng_textur.jpg")
texture = vtk.vtkTexture()
texture.SetInputConnection(reader.GetOutputPort())
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(texture_coords.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.SetTexture(texture)
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
renderWindow.Render()
time.sleep(0.01)
interactor.Start()
<gallery>
PythonIng_textur.jpg | Textur-Datei
PythonIng_VTK_2.png | Ausgabe (Screenshot)
</gallery>
== Sonstige Grafikbibliotheken ==
=== Py5 ===
Im Buch ''Iacono et al.: Programmieren trainieren, mit über 150 Workouts in Java und Python; 3. Aufl., Hanser, 2023'' werden zahlreiche Aufgaben gestellt, die u.a. mit Processing zu lösen sind. Processing ist eine einfache Programmiersprache und Entwicklungsumgebung. Warum ich das erwähne? Weil in älteren Processing-Versionen auch die Programmiersprache Python 2 abgedeckt war. Bei neueren Versionen gibt es keine Python-Anbindung mehr (getestet nur mit openSUSE Tumbleweed und Python 3). Somit funktioniert der Python-Teil im genannten Buch zum Teil nicht mehr. Ist das tragisch, oder kann das Buch weggeschmissen werden? Nein! Es gibt Alternativen zu Processing. Zum einen die im Buch selbst genannten Bibliotheken tkinter oder pygame. Pygame wird dort auch kurz anhand eines Beispiels thematisiert. Aber noch besser ist es, die py5-Bibliothek zu verwenden (lt. Google KI vom 30. Sept. 2026: ''Der echte, moderne „spirituelle Nachfolger“''). Damit ist die Funktionalität von Processing gewährleistet. Man kann aber beliebige Editoren oder IDEs zur Programmerstellung verwenden, ohne an Processing als IDE gebunden zu sein. Nachfolgend werden ein paar Beispiele zu dieser externen Bibliothek gegeben. Der erste Schritt ist wieder, die py5-Bibliothek zu installieren (z.B. mittels pip in eine virtuelle Umgebung; Python>=3.10 und ein JDK>=17 müssen auch installiert sein (Stand Okt. 2026)). Dann kann es schon mit dem Programmieren losgehen.
Beispiel (angelehnt an die ''Aufgabe W.2.3 Haus'' des genannten Buchs, jedoch etwas erweitert):
import py5
def setup():
py5.size(600, 600) # Fenstergröße 600px x 600px
py5.background(255, 255, 255) # Hintergrundfarbe ... weiss
def draw():
# Haus zeichnen
py5.fill(255, 255, 255) # Hintergrundfarbe ... weiss
py5.stroke(255, 0, 0) # Linienfarbe ... rot
py5.stroke_weight(3) # Linienbreite ... 3px
py5.rect(150, 200, 300, 300) # Rechteck zeichnen (x, y, b, h)
py5.triangle(150, 200, 300, 100, 450, 200) # Dreieck zeichnen
py5.circle(250, 300, 70) # Kreis zeichnen (x, y, d)
# Bemassung zeichnen
py5.stroke(0, 255, 0)
py5.stroke_weight(1)
py5.line(300, 100, 550, 100) # Linie zeichnen
py5.line(450, 200, 550, 200)
py5.line(450, 500, 550, 500)
py5.line(150, 500, 150, 550)
py5.line(450, 500, 450, 550)
py5.text_size(20) # Textgroesse
py5.fill(0, 255, 0) # Textfarbe
py5.text("300", 280, 550) # Text zeichnen
py5.text("100", 500, 150)
py5.text("300", 500, 350)
# Gedrehtes Rechteck zeichnen
py5.stroke(255, 255, 0)
py5.stroke_weight(3)
py5.fill(200, 200, 200)
py5.translate(320, 260)
py5.rotate(0.3) # Drehung (in Radiant)
py5.rect(0, 0, 100, 50)
# Startet den Sketch
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_1.png|300px]]
Das skizzierte Haus ist mit einer rudimentären Bemaßung versehen und hat zwei Fenster, ein rundes und ein gedrehtes, trübes rechteckiges.
Beispiel (Mausoperationen):
import py5
def setup():
py5.size(600, 600)
py5.background(255, 255, 255)
def draw():
pass
def mouse_pressed():
py5.text_size(15)
py5.fill(0, 0, 255)
x = py5.mouse_x
y = py5.mouse_y
py5.text("(%d, %d)" %(x, y), x, y) # Positionsdaten bei Maus-Klick schreiben
py5.run_sketch()
Ausgabe:
[[Datei:PythonIng_py5_2.png|300px]]
Obiges Bild zeigt das Resultat nach einigen Mausklicks. Man erkennt, dass links-oben der Koordinatennullpunkt ist. Die x-Achse zeigt nach rechts, die y-Achse nach unten.
Beispiel (Fünfeck):
import py5
import random
def setup():
py5.size(400, 400)
py5.no_loop() # statisches Bild (schont die Ressourcen)
def draw():
py5.translate(py5.width / 2, py5.height / 2) # KS setzen
radius = 150
eck_anzahl = 5
py5.fill(random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255)) # Füllfarbe auf Zufallswert setzen
py5.stroke(155, 0, 0)
py5.stroke_weight(5)
# Fünfeck als Polygon zeichnen
py5.begin_shape()
for i in range(eck_anzahl):
winkel = i * py5.TWO_PI / eck_anzahl - py5.HALF_PI
x = py5.cos(winkel) * radius
y = py5.sin(winkel) * radius
py5.vertex(x, y)
py5.end_shape(py5.CLOSE)
py5.run_sketch()
Ausgabe, bspw.:
[[Datei:PythonIng_py5_5.png|200px]]
<u>Kleine Aufgaben:</u>
* Um die Funktionsweise von <code>py5.no_loop()</code> zu verstehen, kommentieren Sie die Anweisung im Beispiel einfach aus, und starten Sie das Programm erneut.
* Zeichnen Sie ein Siebeneck.
* Was passiert, wenn man <code>py5.CLOSE</code> im <code>py5.end_shape()</code>-Befehl weglässt?
Beispiel (Grafik laden und zeichnen):
import py5
image1 = None
def setup():
global image1
py5.size(600, 600)
py5.no_loop()
image1 = py5.load_image("PythonIng_py5_1.png")
def draw():
py5.image(image1, 0, 0)
py5.run_sketch()
Hier wird einfach das Bild vom Haus-Beispiel (Screenshot von weiter oben) geladen und gezeichnet.
Beispiel (angelehnt an ''W.5.10 Wurfparabel'' des genannten Buches; mit OOP erstellt):
import py5
class Wurfparabel(py5.Sketch):
def __init__(self, v0, angle):
super().__init__()
self.v0 = v0
self.angle = self.radians(angle)
self.g = 9.81
self.t = 0.0
self.scale = 1.5
def settings(self):
self.size(800, 600)
def setup(self):
self.background(0, 0, 0)
def draw(self):
self.t += 0.1
self.translate(50, 500)
# KS Zeichnen
self.fill(255, 255, 0)
self.stroke(255, 255, 0)
self.stroke_weight(1)
self.line(0, 0, 0, -300)
self.line(0, 0, 700, 0)
# Punkt zeichnen
cx = self.v0 * self.cos(self.angle) * self.t * self.scale
cy = -(self.v0 * self.sin(self.angle) * self.t - \
self.g/2 * self.t**2) * self.scale
self.fill(255, 0, 0)
self.stroke(255, 0, 0)
self.circle(cx, cy, 3)
# Stoppen bei Bodenkontakt
if cy >= -5:
self.no_loop()
def wurfparabel(v0=50, angle=45):
sketch = Wurfparabel(v0, angle)
sketch.run_sketch()
v0 = float(input("v0 = "))
winkel = float(input("winkel = "))
wurfparabel(v0=v0, angle=winkel)
Eingabe auf der Konsole:
v0 = 60
winkel = 45
Ausgabe:
[[Datei:PythonIng_py5_13.png|200px]]
Die benötigten Formeln der Bewegungsgleichung kann man leicht herleiten, bzw. man benutzt folgende Grafik als Hilfestellung:
[[Datei:Wurfparabel_Zusammenfassung_aktualisierung.png|700px]]
<u>Aufgabe:</u> Berechnen Sie den Scheitelpunkt und die Wurfweite bei gegebener Anfangsgeschwindigkeit und gegebenem Abwurfwinkel. Die Abwurfhöhe <math>y_0</math> sei 0. Der Wurf soll auf der Erde stattfinden (g = 9.81 m/s²). Die dazu benötigten Formeln können aus obiger Grafik entnommen werden (oder Sie leiten sie selbst her). Geben Sie die Ergebnisse auf der Konsole aus.
Beispiel (eine einfache Animation):
import py5
i = 0
def setup():
py5.size(600, 600)
py5.frame_rate(5)
py5.stroke_weight(20)
def draw():
global i
py5.background(255, 255, 255)
py5.translate(py5.width/2, py5.height/2)
py5.rotate(py5.PI/8 * i)
py5.line(-100, 0, 100, 0)
i += 1
py5.run_sketch()
Es wird eine rotierende Linie gezeichnet (z.B. wie bei einem Installationsprozess verwendet - zeigt an, dass der Installationsfortschritt nicht eingefroren ist). Hierbei ist nur aufzupassen, dass der Hintergrund in <code>draw()</code> gesetzt wird, ansonsten würden die Linien additiv gezeichnet. Das ist zwar auch schön, aber eben nicht das gewünschte Resultat.
Hiermit belassen wir es mit der py5-Bibliothek und wenden uns wieder "mathematischeren" Themen zu.
= Vektoren und Matrizen =
== Zahlenfolgen ==
Für das Erstellen von Zahlenfolgen bieten sich die Funktionen <code>arange</code> und <code>linspace</code> aus dem <code>numpy</code>-Modul an.
from numpy import *
start = 0
stop = 10
step = 2
num = 10
r = arange(start, stop, step) # step ... Schrittweite
l = linspace(start, stop, num) # num ... Anzahl der Werte
print("r = ", r)
print("l = ", l)
Ausgabe:
r = [0 2 4 6 8]
l = [ 0. 1.11111111 2.22222222 3.33333333 4.44444444 5.55555556
6.66666667 7.77777778 8.88888889 10. ]
Bei <code>arange</code> ist der <code>stop</code>-Wert nicht im Ergebnis enthalten, bei <code>linspace</code> standardmäßig aber sehr wohl. Jedoch kann man das bei <code>linspace</code> auch ändern. Dann ist der Stoppwert nicht mehr enthalten:
linspace(start, stop, num, endpoint=False)
== Vektoren ==
Vektoren sollten jedem aus der Linearen Algebra bekannt sein.
=== Arrays ===
In Python mit NumPy kann man Vektoren durch die Funktion array erzeugen.
import numpy as np
l1 = (-5, 3, 2)
l2 = (1, 1, 4)
a1 = np.array(l1)
a2 = np.array(l2)
a3 = a1 + a2
a4 = 2 * a2
print(a1)
print(a2)
print(a3)
print(a3[2])
print(a4)
Ausgabe:
[-5 3 2]
[1 1 4]
[-4 4 6]
6
[2 2 8]
=== Zeilen- und Spaltenvektoren ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
print(z)
print(s)
Ausgabe:
[ [-5 3 2] ]
[[1]
[1]
[4]]
=== Skalarprodukt ===
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
skalarprodukt = np.dot(a1, a2)
print(skalarprodukt)
Ausgabe:
6
=== Vektorprodukt ===
<math>a\ast b=\left(\begin{array}{c}
a_{1}\\
a_{2}\\
a_{3}
\end{array}\right)\ast\left(\begin{array}{c}
b_{1}\\
b_{2}\\
b_{3}
\end{array}\right)=\left(\begin{array}{c}
a_{2}b_{3}-a_{3}b_{2}\\
a_{3}b_{1}-a_{1}b_{3}\\
a_{1}b_{2}-a_{2}b_{1}
\end{array}\right)
</math>
Python-Code:
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
vektorprodukt = np.cross(a1, a2)
print(vektorprodukt)
Ausgabe:
[10 22 -8]
=== Transponierter Vektor ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
# transponierter Vektor
z_tp = np.transpose(z)
# transponierter Vektor
s_tp = np.transpose(s)
print(z_tp)
print(s_tp)
Ausgabe:
[[-5]
[ 3]
[ 2]]
[ [1 1 4] ]
=== Vektorfelder visualisieren ===
import matplotlib.pyplot as plt
import numpy as np
# Daten generieren
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
X, Y = np.meshgrid(x, y)
U = X * Y
V = Y + X
# Plotten
fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='xy')
plt.show()
Ausgabe:
[[Datei:PythonIng_quiver1.png]]
== Matrizen==
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
print(m1)
Ausgabe:
[[1 2 3]
[4 5 6]]
=== Zugriff auf Matrizenelemente ===
Beispiel:
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
# Element aus Zeile 2 und Spalte 3 (Achtung! Index startet bei Null)
print(m1[1,2])
Ausgabe:
6
Visualisierung:
0 1 2
+-----------+
0 | 1 | 2 | 3 |
+-----------+
1 | 4 | 5 | '''6''' |
+-----------+
Beispiel:
import numpy as np
A = [["00", "01", "02", "03"],
["10", "11", "12", "13"],
["20", "21", "22", "23"],
["30", "31", "32", "33"],
["40", "41", "42", "43"]]
B = np.matrix(A)
print(B[2::, ::2])
Ausgabe:
[['20' '22']
['30' '32']
['40' '42']]
Mit der NumPy-Bibliothek funktioniert das zweidimensionale Slicing. Mit normalen Listen/Tupels geht das nicht, was wir schon früher thematisiert haben.
=== Addition und Subtraktion von Matrizen ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
m2 = np.matrix([[0, 0, 2], [1, 3, 2]])
print(m1 + m2)
print(m1 - m2)
Ausgabe:
[[1 2 5]
[5 8 8]]
[[1 2 1]
[3 2 4]]
=== Transponierte Matrix ===
import numpy as np
m = np.matrix([[1, 2, 3], [4, 5, 6]])
mt = np.transpose(m)
print(m)
print(mt)
Ausgabe:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]
=== Rang einer Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
rg = np.linalg.matrix_rank(m)
print(rg)
Ausgabe:
2
=== Inverse Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
mi = np.linalg.inv(m)
print(mi)
Ausgabe:
[[ 1. 0.6]
[-0. -0.2]]
=== Multiplikation von Matrizen (falksches Schema) ===
import numpy as np
m1 = np.matrix([[1, 3, 4], [0, -5, 1]])
m2 = np.matrix([[1, 2], [2, 3], [0, 2]])
print(m1 @ m2)
Ausgabe:
[[ 7 19]
[-10 -13]]
=== Eigenwerte und Eigenvektoren ===
import numpy as np
m = np.matrix([[5, 8], [1, 3]])
D,V = np.linalg.eig(m)
# Eigenwerte
print(D)
# Eigenvektoren
print(V)
Ausgabe:
[7. 1.]
[[ 0.9701425 -0.89442719]
[ 0.24253563 0.4472136 ]]
=== Teilmatrizen ===
import numpy as np
m = np.matrix([[1, 3, 4], [0, -5, 1]])
print("m = ", m)
# Erste Zeile extrahieren
m1 = m[0,:]
print("m1 = ", m1)
# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
m2 = m[0,1]
print("m2 = ", m2)
# Zweite Spalte extrahieren
m3 = m[:, 1]
print("m3 = ", m3)
Ausgabe:
m = [[ 1 3 4]
[ 0 -5 1]]
m1 = [ [1 3 4] ]
m2 = 3
m3 = [[ 3]
[-5]]
=== Spezielle Matrizen ===
==== Nullmatrix ====
import numpy as np
z = np.zeros((3, 2))
print(z)
Ausgabe:
[[0. 0.]
[0. 0.]
[0. 0.]]
==== Einheitsmatrix ====
import numpy as np
z = np.eye(3)
print(z)
Ausgabe:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
==== Matrix mit lauter Einsen ====
import numpy as np
z = np.ones((3, 2))
print(z)
Ausgabe:
[[1. 1.]
[1. 1.]
[1. 1.]]
=== Spärlich besetzte Matrizen ===
Das Thema spärlich besetzter Matrizen wird hier nur kurz angerissen. Nähere Details siehe unter dem Weblink [https://docs.scipy.org/doc/scipy/reference/sparse.html#module-scipy.sparse].
Beispiel:
import numpy as np
import scipy
A = scipy.sparse.csr_array(np.eye(5))
print(A)
Ausgabe:
<Compressed Sparse Row sparse array of dtype 'float64'
with 5 stored elements and shape (5, 5)>
Coords Values
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
(4, 4) 1.0
csr steht für '''c'''ompressed '''s'''parse '''r'''ow.
Andere Möglichkeiten:
* coo-Format ('''coo'''rdinate Format): <code>scipy.sparse.coo_array()</code>
* lil-Format ('''li'''st of '''l'''ists): <code>scipy.sparse.lil_array()</code>
* csc-Format ('''c'''ompressed '''s'''parse '''c'''olumn): <code>scipy.sparse.csc_array()</code>
Es gibt auch <code>scipy.sparse.csr_matrix()</code> etc. Diese Befehle sind aber veraltet und es wird empfohlen, statt dessen die <code>..._array()</code>-Funktionen zu verwenden.
<u>Aufgaben:</u>
Recherchieren Sie im Internet
* generell zum Thema "spärlich besetzte Matrizen mit Python".
* Was sind die Vor-/Nachteile von csr-arrays gegenüber coo- und lil-arrays?
* Wann verwendet man sinnvollerweise csr- und wann csc-arrays?
* Wie wandelt man coo-arrays in csr-arrays um?
= Lineare Gleichungssysteme =
Sei <math>Ax = b</math> ein lineares Gleichungssystem. <math>A</math> sei die Koeffizientenmatrix, <math>x</math> der Lösungsvektor und <math>b</math> ein bekannter Vektor.
Beispiel:
import numpy as np
A = np.array([[5, 1], [0, 2]])
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)
Ausgabe:
[0. 1.]
Siehe dazu auch das Kapitel [[Ing Mathematik: Numerisches Lösen von linearen Gleichungssystemen]]. Dort wird dieses Themengebiet u.a. mit weitergehenden Python-Skripten vertieft.
== Aufgabe ==
* Lösen Sie folgendes Gleichungssystem mittels Python (und zur Kontrolle auch händisch):
5x + 6y - 2z = 12
3x - y - 3z = 6
2x + 2y + 4z = 5
= Polynome =
== Ein erstes einfaches Beispiel ==
Gegeben sei das Polynom <math>7x^3+5x^2+1</math>. In Python:
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p)
Ausgabe:
3 2
7 x + 5 x + 1
== Einzelne Polynomwerte berechnen ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p(1.5))
Ausgabe:
35.875
== Polynome integrieren und differenzieren ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
# 1. Ableitung
p1 = p.deriv()
p2 = p.deriv(1)
# 2. Ableitung
p3 = p.deriv(2)
# Integral
p4 = p.integ()
print(p1)
print(p2)
print(p3)
print(p4)
Ausgabe:
2
21 x + 10 x
2
21 x + 10 x
42 x + 10
4 3
1.75 x + 1.667 x + 1 x
== Nullstellen bestimmen ==
import numpy as np
p = np.poly1d([2, 5, 0, 4])
r = np.roots(p)
print(r)
Ausgabe:
[-2.7621427 +0.j 0.13107135+0.84077099j 0.13107135-0.84077099j]
== Aufgaben ==
* Berechnen Sie den Wert für x = 3 des Polynoms <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Differenzieren und integrieren Sie das Polynom <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Berechnen Sie die Nullstellen von <math>y = 7x^5 - 3x^2 + 12</math>.
= Nichtlineare Gleichungen und Gleichungssysteme =
== Nullstellenbestimmung ==
Löse eine beliebige Gleichung f(x) = 0, z.B. <math> f(x) = x^2 - 5\cos(x) - 10 = 0 </math>:
import scipy
import numpy as np
def f(x):
return x**2 - 5*np.cos(x) - 10
xstart = [-1, 1] # Startwerte
xn = scipy.optimize.root(f, xstart)
print(xn.x)
Ausgabe:
[-2.46813009 2.46813009]
Funktionsgraph:
[[Datei:octave_nichtlin2.jpg]]
== Gleichungssysteme ==
SymPy ist ein externes Modul, das symbolisches Rechnen ('''Sym'''bolic '''Py'''thon) ermöglicht.
Folgende Aufgabe ist dem Buch "Knorrenschild: Numerische Mathematik, Hanser, 2017, Seite 72" entnommen. Zu lösen ist das nichtlineare Gleichungssystem
<math>f_1 = 2x_1 + 4x_2 = 0 </math>
<math>f_2 = 4x_1 + 8x_2^3 = 0</math>
Mit Python ist das so möglich:
import sympy
x1, x2 = sympy.symbols("x1 x2")
f1 = 2*x1 + 4*x2
f2 = 4*x1 + 8*x2**3
s = sympy.solve((f1, f2), x1, x2)
print(s)
Ausgabe:
[(-2, 1), (0, 0), (2, -1)]
Plot:
[[Datei:IngPython_nl_gleichung1.svg|500px]]
= Komplexe Zahlen =
Die imaginäre Einheit wird in Python durch den Buchstaben <code>j</code> symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:
* Kartesische Darstellung <math>z = \Re(z) + j \cdot \Im(z)</math>
* Polardarstellungen <math>z = r \cdot (\cos(\phi) + j \cdot \sin(\phi)) = r \cdot e^{j\cdot \phi}</math>
Die konjugiert komplexe Zahl ist <math>z^* = \Re(z) - j \cdot \Im(z)</math>
Nachfolgend einige mathematische Operationen mit Python und NumPy.
import numpy as np
z1 = 2 + 5j # kartesische Darstellung
z2 = 3 * np.exp(3j) # Polardarstellung
# Addition
res = z1 + z2
print("z1 + z2 = ", res)
# Multiplikation
res = z1 * z2
print("z1 * z2 = ", res)
# Realteil
res = np.real(z2)
print("Realteil von z2 = ", res)
# Imaginärteil
res = np.imag(z2)
print("Imaginaerteil von z2 = ", res)
# Betrag
res = np.abs(z1)
print("Betrag von z1 = ", res)
# Argument
res = np.angle(z1)
print("Argument von z1 = ", res)
# Konjugiert komplexe Zahl
res = np.conj(z1)
print("Konjugiert komplexe Zahl von z1 = ", res)
Ausgabe:
z1 + z2 = (-0.9699774898013365+5.423360024179601j)
z1 * z2 = (-8.05675510050068-14.003167400647481j)
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = (2-5j)
= Interpolation =
import numpy as np
import scipy
import matplotlib.pyplot as plt
# Stützpunkte
xp = np.arange(1, 6)
yp = (0, -5, 2, 7, 6)
ti = np.arange(1, 5, 0.01)
i1 = scipy.interpolate.interp1d(xp, yp, kind = "linear")
i2 = scipy.interpolate.interp1d(xp, yp, kind = "cubic")
plt.plot(xp, yp, "rx")
plt.plot(xp, i1(xp))
plt.plot(ti, i2(ti))
plt.show()
Ausgabe:
[[Datei:PythonIng_interpol1.png]]
= Differenzialrechnung =
== Numerisches Differenzieren ==
Als Beispiel differenzieren wir <math>y = 5x\sin{x}</math> und stellen das Ganze grafisch dar.
from findiff import Diff
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
f = 5 * x * np.sin(x)
dx = x[1] - x[0]
# Ableitung
d_dx = Diff(0, dx)
df_dx = d_dx(f)
# Grafik
plt.plot(x, f, label = "y")
plt.plot(x, df_dx, label = "y'")
plt.grid()
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:octave_diff1.jpg]]
<small>findiff ist ein externes Modul. Dieses muss installiert werden (z.B. so: ...\Python\Scripts\pip.exe install --upgrade findiff). Für die Vorgehensweise unter openSUSE Tumbleweed siehe das Kapitel [[Ing_Mathematik:_Python#Mit_VPython | VPython]], nur dass das Ganze mit einer aktuelleren Python-Version exekutiert wird, z.B. mit Python 3.13. Das im Buch "Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler, Rheinwerk" verwendete Modul "scipy.misc" ist veraltet (deprecated ... missbilligt). Lt. [https://docs.scipy.org/doc/scipy-1.17.0/dev/roadmap-detailed.html#misc SciPy-Dokumentation für die Version 1.17.0] wurden alle entsprechenden Features schon entfernt.</small>
== Symbolisches Differenzieren ==
Differenzieren Sie die Funktionen <math>f_1(x) = x^2</math> und <math>f_2(x) = \sin(x)\cos\left(\frac{x}{2}\right)</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2;
f2 = sympy.sin(x) * sympy.cos(x/2.)
d1 = sympy.diff(f1, x)
d2 = sympy.diff(f2, x)
print(d1)
print(d2)
Ausgabe:
2*x
-0.5*sin(0.5*x)*sin(x) + cos(0.5*x)*cos(x)
== Aufgaben ==
* Differenzieren Sie die Funktion <math>y = \log(x) + 10x</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
* Differenzieren Sie die Funktion <math>y = \frac{\sinh(x)}{(1+x)}</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
= Integralrechnung =
== Numerisches Integrieren ==
Berechnen Sie das Integral <math>\int_{0}^{3}x^2 dx</math>.
import scipy
def f(x):
return x**2
i = scipy.integrate.quad(f, 0, 3)
print(i)
Ausgabe:
(9.000000000000002, 9.992007221626411e-14)
Das trifft den exakten Wert 9.0 ziemlich genau.
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} dx</math>.
import scipy
import numpy as np
def f(x):
return 2**(-x)
i = scipy.integrate.quad(f, 0, np.inf)
print(i)
Ausgabe:
(1.4426950408889556, 4.486558477977586e-09)
== Symbolisches Integrieren ==
Berechnen Sie <math>\int x^2 \text{d}x</math> und <math>\int \sin{x}\cos{\frac{x}{2}} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2
f2 = sympy.sin(x) * sympy.cos(x/2.)
i1 = sympy.integrate(f1, x)
i2 = sympy.integrate(f2, x)
print(i1)
print(i2)
Ausgabe:
x**3/3
-0.666666666666667*sin(0.5*x)*sin(x) - 1.33333333333333*cos(0.5*x)*cos(x)
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f = 2**(-x)
i = sympy.integrate(f, (x, 0, sympy.oo))
print(i)
Ausgabe:
1/log(2)
<code>sympy.oo</code> steht für das {{W|Unendlichzeichen}} <math>\infty</math> (die liegende Acht oder das Möbiusband). Mit <code>sympy.pprint(i)</code> ließe sich letzere Ausgabe etwas schöner schreiben:
1
──────
log(2)
Man beachtete, <code>log</code> steht hier für den natürlichen Logarithmus <code>ln</code>.
== Aufgaben ==
* Integrieren Sie die Funktion <math>y = \log(x) + 10x</math> von 1 bis 5.
* Integrieren Sie die Funktion <math>y = x^3</math> von 0 bis 4.
* Integrieren Sie <math>\int x^x(\log (x) + 1)\mathrm dx</math> symbolisch.
= Gewöhnliche Differenzialgleichungen =
== DGL numerisch lösen ==
Für die Lösung von Differenzialgleichungen steht u.a. die Funktion scipy.integrate.solve_ivp() zur Verfügung. Diese Funktion implementiert auch das Runge-Kutta-Verfahren (RK45).
{{Wikipedia | Runge-Kutta-Verfahren}}
Beispiel <math>y' = x^2 + y^3</math>:
import scipy
import numpy as np
import matplotlib.pyplot as plt
def dy_dx(x, y):
return x**2 + y**3
y0 = [1]
xi = [0, 1]
x = np.arange(0, 1, 0.01)
z = scipy.integrate.solve_ivp(dy_dx, xi, y0, method="RK45", dense_output=True)
y = z.sol(x)
plt.plot(x, y.T)
plt.grid()
plt.show()
[[Datei:PythonIng_dgl1.png]]
== DGL symbolisch lösen ==
Beispiel <math>y' = x^2 + y^3</math>:
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
print(lsg)
Ausgabe:
[Eq(f(x), (-x**2)**(1/3)), Eq(f(x), (-x**2)**(1/3)*(-1 - sqrt(3)*I)/2), Eq(f(x), (-x**2)**(1/3)*(-1 + sqrt(3)*I)/2)]
Mit <code>sympy.pprint</code> (pretty print) lässt sich die Ausgabe etwas übersichtlicher darstellen.
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
sympy.pprint(lsg)
Ausgabe:
⎡ _____ _____ ⎤
⎢ _____ 3 ╱ 2 3 ╱ 2 ⎥
⎢ 3 ╱ 2 ╲╱ -x ⋅(-1 - √3⋅ⅈ) ╲╱ -x ⋅(-1 + √3⋅ⅈ)⎥
⎢f(x) = ╲╱ -x , f(x) = ────────────────────, f(x) = ────────────────────⎥
⎣ 2 2 ⎦
== Aufgaben ==
* Lösen Sie die Differenzialgleichung <math>y' = \frac{1}{x\cdot y}</math> mit Python. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>m' = -k\cdot m</math>. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>y' = \sqrt{|y|}</math>.
=Laplace-Transformation=
Laplace-Transformation:
<math>F(s) =\mathcal{L} \left\{f\right\}(s) = \int_{0}^{\infty} f(t) \mathrm e^{-st} \,\mathrm{d}t, \qquad s\in\mathbb{C}
</math>
Inverse Laplace-Transformation:
<math>\mathcal{L}^{-1} \left\{F\right\}(t)
= \frac{1}{2 \pi \mathrm j} \int_{ \gamma - \mathrm j \infty}^{ \gamma + \mathrm j \infty} \mathrm e^{st} F(s)\,\mathrm ds
= \begin{cases}
f(t) & \text{für } t \geq 0 \\
0 & \text{für } t < 0
\end{cases}
</math>
Siehe auch [[Ing_Mathematik:_Laplace-Transformation]]
Code:
import sympy
from sympy.abc import t, s
# Laplace-Transformation der Funktion f(t) = 1 (Heaviside-Fkt.)
f = 1
# alternativ: f = sympy.Heaviside(t)
F = sympy.laplace_transform(f, t, s, noconds=True)
print("Laplace-Transformierte F(s):", F)
# Inverse Laplace-Transformation zurück in den Zeitbereich
f_inv = sympy.inverse_laplace_transform(F, s, t)
print("Inverse Transformation f(t):", f_inv)
Ausgabe:
Laplace-Transformierte F(s): 1/s
Inverse Transformation f(t): Heaviside(t)
Die Zeile
from sympy.abc import t, s
steht alternativ für
t = sympy.symbols("t")
s = sympy.symbols("s")
<u>Aufgaben</u>: Ermitteln Sie mittels SymPy die <math>\mathcal{L}</math>-Transformierten und dann wieder die <math>\mathcal{L}^{-1}</math>-Transformationen (ähnlich wie beim obigen Beispiel):
* <math>\sin(t) \circ\! -\! \bullet \ ?</math>
* <math>t^3 \circ\! -\! \bullet \ ?</math>
* <math>\text{e}^{\omega t} \circ\! -\! \bullet \ ?</math>
=Fourier-Reihen=
<math>
f(x)\approx \frac{a_{0}}{2}+\sum_{k=1}^{\infty}\left(a_{k}\cos\left(kx\right)+b_{k}\sin\left(kx\right)\right)
</math>
<math>
a_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\cos\left(kx\right)\mathrm dx\quad\text{für }k\geq0
</math>
<math>
b_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\sin\left(kx\right)\mathrm dx\quad\text{für }k\geq1
</math>
Für die Sägezahnfunktion <math>y=x;\, 0 < x < 2\pi</math> sei die Fourierreihe mit einem Python-Programm (unter Mithilfe von sympy) hergeleitet.
Code:
from sympy import fourier_series, pi, symbols, pprint
x = symbols('x')
f = x
s = fourier_series(f, (x, 0, 2*pi))
pprint(s.truncate(n=4))
Ausgabe:
2⋅sin(3⋅x)
-2⋅sin(x) - sin(2⋅x) - ────────── + π
3
Siehe auch [[Ing Mathematik: Fourierreihen]].
Ein komplizierteres Beispiel:
[[Datei:IngMath fourier bsp13.svg | 300px]]
<math>0\le t < T/2\text{:}\quad f(t) = H</math>
<math>T/2 \le t \le T\text{:}\quad f(t) = \frac{2H}{T}\left( t-\frac{T}{2}\right)</math>
Code:
import sympy as sp
H = sp.Symbol('H', positive=True)
T = sp.Symbol('T', positive=True)
t = sp.Symbol('t')
f = sp.Piecewise(
(H, (t > 0) & (t < T/2)),
(2*H/T*(t-T/2), (t > T/2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Ausgabe:
⎛2⋅π⋅t⎞ ⎛4⋅π⋅t⎞ ⎛6⋅π⋅t⎞ ⎛2⋅π⋅t⎞ ⎛6⋅π⋅t⎞
H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ 2⋅H⋅cos⎜─────⎟ 2⋅H⋅cos⎜─────⎟
⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ 3⋅H
──────────── - ──────────── + ──────────── + ────────────── + ────────────── + ───
π 2⋅π 3⋅π 2 2 4
π 9⋅π
=Rechnen mit wirklich großen Zahlen=
Bekannt ist, dass Python kaum Einschränkungen beim Wertebereich von Ganzzahlen hat, z.B.
print(10**300)
Ausgabe (gekürzt):
100000000000000000000...00000000000000000000000000000000000000000000000000000000000000000000000
Ähnliches geht auch mit Gleitpunktzahlen, z.B. durch die Verwendung des Moduls [https://mpmath.org/ mpmath]:
import mpmath
print(mpmath.mpf(1500.4)**mpmath.mpf(300))
Ausgabe:
7.27975299218612e+952
Anderes Beispiel:
from mpmath import mp, pi
mp.dps = 100
print(pi)
Ausgabe:
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
mpmath kann noch einiges mehr, dazu sei aber auf die entsprechende Dokumentation auf der mpmath-Homepage verwiesen. mpmath ist Bestandteil von SymPy, kann aber auch separat installiert werden.
Aber auch Python selbst besitzt eine Möglichkeit, um mit großen bzw. exakten Gleitpunktzahlen zu rechnen, nämlich das interne Modul decimal. Dieses hat einige Vorteile gegenüber mpmath, aber auch gravierende Nachteile. Diese seien hier nicht detailliert aufgezählt. Grob gesagt hat decimal im Finanzwesen seine Berechtigung. Für wissenschaftliche Anwendungen wird aber mpmath vorzuziehen sein, da es u.a. vielfältige mathematische Funktionen bereit stellt. Nachfolgend ein einfaches Beispiel mit decimal:
import decimal
print("Potenzierung:", decimal.Decimal(1500.4) ** decimal.Decimal(300.0))
print("Einfache Addition:", 0.1 + 0.2)
decimal.getcontext().prec = 50
print("Addition mit decimal:", decimal.Decimal("0.1") + decimal.Decimal("0.2"))
Ausgabe:
Potenzierung: 7.279752992186121551039839134E+952
Einfache Addition: 0.30000000000000004
Addition mit decimal: 0.3
<u>Aufgabe:</u> Recherchieren Sie im Internet die genauen Vor- und Nachteile von decimal und mpmath. Verwenden Sie dazu auch KI (z.B. von Google, chatgpt).
= pint - mit physikalischen Größen rechnen =
[[File:Pint-Glas_UK.jpg|right|100px]]
pint ist ein externes Python-Paket zur Manipulation von physikalischen Einheiten. Es muss vor der ersten Benutzung installiert werden (Vorgehensweise wie immer: pip, YaST, via venv etc.).
Beispiel:
import pint
import numpy as np
ureg = pint.UnitRegistry()
# Einfache Berechnung
print(3 * ureg.meter + 4 * ureg.cm)
# Mit NumPy
npeinzel = [3, 4] * ureg.meter + [2, 5] * ureg.cm
print(npeinzel)
npsum = np.sum(npeinzel)
print(npsum)
# Konvertierung von Einheiten
npsum_inch = npsum.to(ureg.inch)
print(npsum_inch)
print(npeinzel.magnitude)
print(npeinzel.units)
print(npeinzel.dimensionality)
Ausgabe:
3.04 meter
[3.02 4.05] meter
7.07 meter
278.3464566929134 inch
[3.02 4.05]
meter
[length]
Die Dokumentation zu pint findet sich auf [https://pint.readthedocs.io/en/stable/].
=Regelungstechnische Aufgabenstellungen=
Für regelungstechnische Aufgaben gibt es u.a. das externe Paket <code>control</code>. Hier soll nicht detailliert darauf eingegangen werden. Anhand eines Beispiels soll anschließend nur die Visualisierung in Form eines Bode-Diagramms und der Sprungantwort gezeigt werden. Gegeben sei ein P-Regler mit <math>R = \frac{5}{2}</math> und eine Strecke <math>S= \frac{1}{30s^3+20s^2+10s+1,5}</math>. Gesucht sei vorerst ein Bode-Diagramm für den offenen Regelkreis und das Führungsverhalten.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke # oder: G0 = ct.series(regler, strecke)
Gw = ct.feedback(G0)
ct.bode_plot(G0, label='G0')
ct.bode_plot(Gw, label='Gw')
plt.show()
[[Datei:PythonIng_bode1.svg]]
Nun noch für obiges Beispiel die Sprungantwort. Diese zeigt einige große Überschwinger, d.h. der Regler kann sicher noch optimiert werden.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke
Gw = ct.feedback(G0)
t, y = ct.step_response(Gw)
plt.plot(t,y)
plt.title('Sprungantwort')
plt.xlabel('t')
plt.ylabel('h(t)')
plt.grid()
plt.show()
[[Datei:PythonIng_bode3.svg]]
Einige weitere wichtige Daten (Phasenreserve, Amplitudenreserve, Durchtrittsfrequenz) lassen sich mittels der <code>control</code>-Funktion <code>margin()</code> ermitteln. Die Ortskurve lässt sich mit der Funktion <code>nyquist_plot()</code> zeichnen. Dies sei hier aber nicht weiter ausgeführt.
==Aufgaben==
* Zeichen Sie mit Python die Ortskurve für obiges Beispiel.
* Was passiert, wenn man die Reglerverstärkung weiter aufdreht (z.B. auf <math>R = \frac{25}{2}</math>)?
* Wie sehen das Bode-Diagramm und die Sprungantwort aus, wenn ein PI-Regler verwendet wird?
= Stereostatik etc. =
Das Modul SymPy bietet einige Möglichkeiten einfache Bauwerke zu berechnen, z.B. Balken oder Fachwerke. Nachfolgend wird ein einfaches Fachwerk berechnet und gezeichnet.
Python-Code:
from sympy.physics.continuum_mechanics.truss import Truss
t = Truss()
# Knoten
t.add_node(("A", -3, 0), ("B", 0, 0), ("C", 4, 0), ("D", 7, 0),
("E", 6, 1.5), ("F", 2, 3), ("G", -2, 1.5))
# Stäbe
t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D"))
t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F"))
t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E"))
t.add_member(("FE","F","E"), ("DE","D","E"))
# Auflager; roller ... Loslager, pinned ... Festlager
t.apply_support(("A","roller"), ("D","pinned"))
# Einwirkende Kräfte
t.apply_load(("G", 5, 270), ("E", 3, 90))
# Berechnung
t.solve()
print("Reaction Forces: ", t.reaction_loads)
print("Internal Forces: ", t.internal_forces)
# Fachwerk zeichnen
p = t.draw()
p.show()
Ausgabe auf der Konsole:
Reaction Forces: {'R_A_y': 4.20000000000000, 'R_D_x': 0, 'R_D_y': -2.20000000000000}
Internal Forces: {'AB': 2.80000000000000, 'BC': 0.333333333333333, 'CD': -1.46666666666667,
'AG': -5.04777178564958, 'GB': -2.05555555555556, 'GF': -1.23413387432364,
'BF': 0.411111111111111*sqrt(13), 'FC': -0.3*sqrt(13), 'CE': 1.50000000000000,
'FE': 0.284800124843917, 'DE': 2.64407093534026}
Zeichnung:
[[File:PythonIng_fachwerk1.svg|300px]]
Details zu diesem Thema siehe z.B. [https://docs.sympy.org/latest/modules/physics/continuum_mechanics/index.html Continuum Mechanics] oder [https://docs.sympy.org/latest/tutorials/physics/continuum_mechanics/index.html Continuum Mechanics Tutorials]. Auch andere mechanische Probleme werden von SymPy abgehandelt ([https://docs.sympy.org/latest/tutorials/physics/index.html Physics Tutorials]).
== Aufgabe ==
Gegeben sei ein einseitig eingespannter Kragträger. Belastet wird er durch eine Einzellast am Trägerende. Für die Daten siehe folgende ASCII-Skizze:
| 20 kN
//|---> x |
//| V
//|----------------------
//| 10 m |
Elastizitätsmodul E = 2,1*10⁵ N/mm²
Flächenträgheitsmoment I = 0.001 m⁴
Berechnen Sie die Auflagerreaktionen, den Querkraft- und Biegemomentenverlauf, sowie die Verformungen.
Stellen Sie dies mit Hilfe von SymPy graphisch und auch mittels Formeln dar. Verwenden Sie dazu auch pprint (pretty print) aus dem SymPy-Modul. Zwecks Lösungsansatz siehe die oben aufgeführte Seite "Continuum Mechanics Tutorials". Achten Sie auch auf die Einheiten! Kontrollieren Sie das Ganze mittels händischer Rechnung. In dem genannten Tutorial ist von "Singularity Functions" die Rede. Gemeint ist damit in diesem Kontext die {{W|Föppl-Klammer}}.
Einige Python-Programme, vorrangig zu Maschinenelementen, finden sich auf [https://baymp.de/download_python.html BayMP für Python] (Balken, Zahnräder, Stabknickung usw.).
=Thermodynamik=
== PYroMat ==
Für thermodynamische Aufgabenstellungen gibt es verschiedene externe Module. Eines davon ist PYroMat (siehe auch [http://pyromat.org]). Damit lassen sich thermodynamische Stoffdaten für viele Substanzen berechnen.
Beispiel (einige Stoffdaten für Wasser bei 400°C und 20 bar berechnen):
import pyromat as pm
# Wasserdaten laden:
H2O = pm.get('mp.H2O')
# Stoffdaten berechnen:
T = 673.15 # Temperatur in Kelvin
p = 20 # Druck in bar
v = H2O.v(T, p)
h = H2O.h(T, p)
s = H2O.s(T, p)
print(f"Spezifisches Volumen: {v} m³/kg")
print(f"Spezifische Enthalpie: {h} kJ/kg")
print(f"Spezifische Entropie: {s} kJ/(kg K)")
Ausgabe:
Spezifisches Volumen: [0.1512163] m³/kg
Spezifische Enthalpie: [3248.3789473] kJ/kg
Spezifische Entropie: [7.12924142] kJ/(kg K)
<small>
PYroMat muss vorab installiert werden (z.B. mittels pip, in eine virtuelle Umgebung)
</small>
<code>mp</code> steht für "multi phase". Für ein ideales Gas wäre <code>ig</code> zuständig, z.B. <code>'ig.O2'</code>.
Beispiel (T-s-Diagramm für Wasser zeichnen):
import numpy as np
import matplotlib.pyplot as plt
import pyromat as pm
# Konfigurieren
pm.config["unit_pressure"] = "bar"
pm.config["unit_temperature"] = "K"
fluid = pm.get("mp.H2O")
# Temperaturbereich für das Nassdampfgebiet
T_tripel = 273.16
T_crit = 647.096
T = np.linspace(T_tripel, T_crit - 0.1, 200)
# Sättigungslinien berechnen und zeichnen
for x in np.linspace(0.0, 1.0, 5):
s = fluid.s(T=T, x=x)
if(x<=0.0):
plt.plot(s, T, label="Siedelinie x=%3.1f" % x, linewidth=2.0)
elif(x>=1.0):
plt.plot(s, T, label="Taulinie x=%3.1f" % x, linewidth=2.0)
else:
plt.plot(s, T, label="x=%3.1f" % x, linewidth=1.0)
# Isobaren zeichnen
p_values = [0.1, 1, 10, 50, 100]
T_isobar = np.linspace(T_tripel, 1000, 200)
t = 0.7
for p in p_values:
s_iso = fluid.s(T=T_isobar, p=p)
plt.plot(s_iso, T_isobar, 'k-', alpha=0.8, linewidth=0.8)
t += .05
idx = int(len(s_iso) * t)
plt.text(s_iso[idx], T_isobar[idx], f"{p} bar", fontsize=9, alpha=0.8)
# Diagramm zeichnen
plt.title("T-s-Diagramm für Wasser")
plt.xlabel("Spezifische Entropie s in kJ/kg K", fontsize=10)
plt.ylabel("Temperatur T in K", fontsize=10)
plt.legend(loc="best")
plt.grid(True)
plt.show()
Ausgabe (in etwa so):
[[Datei:T-s-Diagramm fuer Wasser.svg|400px]]
== CoolProp ==
Auch mit CoolProp können Stoffdaten berechnet werden. Siehe auch [https://coolprop.org/coolprop/wrappers/Python/index.html]
Beispiel (Wasser bei 20bar und 400°C):
import CoolProp.CoolProp as CP
fluid = 'Water'
T = 673.15 # Temperatur in Kelvin
P = 20e5 # Druck in Pascal
dichte = CP.PropsSI('D', 'T', T, 'P', P, fluid)
enthalpie = CP.PropsSI('H', 'T', T, 'P', P, fluid)
entropie = CP.PropsSI('S', 'T', T, 'P', P, fluid)
print(f"Spez. Volumen: {1/dichte:.6f} m³/kg")
print(f"Spez. Enthalpie: {enthalpie:.2f} J/kg")
print(f"Spez. Entropie: {entropie:.2f} J/kgK")
Ausgabe:
Spez. Volumen: 0.151215 m³/kg
Spez. Enthalpie: 3248344.02 J/kg
Spez. Entropie: 7129.16 J/kgK
== iapws ==
Um Werte für Wasser(dampf) zu erhalten (IAPWS; '''I'''nternational '''A'''ssociation for the '''P'''roperties of '''W'''ater and '''S'''team) gibt es die Bibliothek iapws. Siehe auch [https://iapws.org/] und [https://pypi.org/project/iapws/]
Beispiel (Wasser für 20bar und 400°C):
from iapws import IAPWS97
dampf = IAPWS97(P=2.0, T=673.15)
print(f"Spezifisches Volumen: {dampf.v:.6f} m³/kg")
print(f"Spezifische Enthalpie: {dampf.h:.2f} kJ/kg")
print(f"Spezifische Entropie: {dampf.s:.4f} kJ/(kgK)")
print(f"Phase: {dampf.phase}")
Ausgabe:
Spezifisches Volumen: 0.151208 m³/kg
Spezifische Enthalpie: 3248.23 kJ/kg
Spezifische Entropie: 7.1290 kJ/(kgK)
Phase: Gas
== TESPy ==
Ein anderes Modul für einen anderen Aufgabenzweck ist TESPy ('''T'''hermal '''E'''ngineering '''S'''ystems in '''Py'''thon). Dieses Modul ist für die Anlagensimulation zuständig. Für nähere Informationen siehe [https://tespy.readthedocs.io/en/main/getting_started/introduction.html]. Als Beipiel sei hier vorerst Code, der von der Google KI generiert wurde, angeführt. Der Code wurde überarbeitet, damit keine Warnungen auftreten. Bitte aber den Code trotzdem mit Vorsicht genießen, auch KI-generierter Code kann Fehler aufweisen. Eine Pumpe wird berechnet:
from tespy.components import Sink, Source, Pump
from tespy.connections import Connection
from tespy.networks import Network
# 1. Netzwerk definieren (Zentrales Steuerungselement)
# Wir wählen Wasser als Fluid und bar/Celsius als Einheiten
nw = Network(fluids=["water"])
nw.units.set_defaults(pressure="bar", pressure_difference="bar",
temperature="°C", enthalpy="kJ / kg")
# 2. Komponenten erstellen
eingang = Source("Wasserquelle")
ausgang = Sink("Wasserspeicher")
pumpe = Pump("Speisewasserpumpe")
# 3. Verbindungen definieren (Komponenten miteinander verknüpfen)
c1 = Connection(eingang, "out1", pumpe, "in1")
c2 = Connection(pumpe, "out1", ausgang, "in1")
# Verbindungen dem Netzwerk hinzufügen
nw.add_conns(c1, c2)
# 4. Randbedingungen und Parameter festlegen
# Zustand am Eingang (Druck, Temperatur, Massenstrom, Fluid-Zusammensetzung)
c1.set_attr(
v=1, # Massenstrom: 1 kg/s
T=20, # Temperatur: 20 °C
p=1, # Druck: 1 bar
fluid={"water": 1}, # 100% Wasser
)
# Zustand am Ausgang / Zielwerte der Pumpe
c2.set_attr(p=10) # Ziel-Druck nach der Pumpe: 10 bar
# Pumpeneigenschaften festlegen
pumpe.set_attr(eta_s=0.8) # Isentroper Wirkungsgrad von 80%
# 5. Simulation ausführen
nw.solve(mode="design")
# 6. Ergebnisse ausgeben
nw.print_results()
# Spezifische Werte direkt auslesen
print("\n--- Auswertung ---")
print(f"Erforderliche Pumpenleistung: {pumpe.P.val / 1000:.2f} kW")
print(f"Temperatur nach der Pumpe: {c2.T.val:.2f} °C")
Ausgabe (gekürzt):
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 7.04e+04 | 12 % | 9.96e+02 | 0.00e+00 | 8.81e+04 | 0.00e+00 | 0.00e+00
2 | 5.91e-12 | 100 % | 1.11e-13 | 0.00e+00 | 7.39e-12 | 0.00e+00 | 0.00e+00
3 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
4 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.01 s, Iterations per second: 480.85
##### RESULTS (Pump) #####
+-------------------+----------+----------+-----------+----------+----------+----------+
| | P | pr | dp | eta | eta_s | head |
|-------------------+----------+----------+-----------+----------+----------+----------|
| Speisewasserpumpe | 1.12e+06 | 1.00e+01 | -9.00e+00 | 8.00e-01 | 8.00e-01 | 9.19e+01 |
+-------------------+----------+----------+-----------+----------+----------+----------+
...
...
--- Auswertung ---
Erforderliche Pumpenleistung: 1124.77 kW
Temperatur nach der Pumpe: 20.07 °C
= Stochastik =
Die {{W|Stochastik}} ist ein sehr weites Feld. Hier werden etliche wichtige Themen kurz angerissen. Python stellt mit den Moduln math und statistics Software zu diesem Zwecke bereit. math und statistics sind bereits im Lieferumfang von Python enthalten. Aber auch mit den externen Modulen NumPy, SciPy, stochastic und pandas kann man Stochastik in Python betreiben. Die Theorie der Wahrscheinlichkeitsrechnung und Statistik soll etwas später in Band 5 dieser Buchreihe behandelt werden.
== Lageparameter ==
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
m1 = statistics.mean(werte)
m2 = statistics.mode(werte)
m3 = statistics.median(werte)
print("Arithmetischer Mittelwert = ", m1)
print("Modalwert = ", m2)
print("Median = ", m3)
Ausgabe:
Arithmetischer Mittelwert = 3.5
Modalwert = 1
Median = 3.0
== Streuungsparameter ==
Beispiel (Berechnung der Standardabweichung):
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
s = statistics.stdev(werte)
print("Standardabweichung = ", s)
Ausgabe:
Standardabweichung = 2.6770630673681683
Beispiel (Berechnung des Variationskoeffizienten V = Standardabweichung/Mittelwert)
import numpy as np
from scipy import stats
import statistics
k = 50
dat1 = [14, 21, 18, 25, 30, 17, 20]
dat = np.array(dat1)
# Mit SciPy
v = stats.variation(dat)
vddof = stats.variation(dat, ddof=1)
print("V SciPy: ", v)
print("V DDOF SciPy: ", vddof)
print(k*"-")
# mit NumPy
mittelwert1 = np.mean(dat)
std_abw1 = np.std(dat)
std_abw1ddof = np.std(dat, ddof=1)
v1= std_abw1 / mittelwert1
v1ddof = std_abw1ddof / mittelwert1
print("Mittelwert NumPy: ", mittelwert1)
print("Std.abw. NumPy: ", std_abw1)
print("Std.abw. DDOF NumPy: ", std_abw1ddof)
print("V NumPy: ", v1)
print("V DDOF NumPy: ", v1ddof)
print(k*"-")
# nur mit reinem Python
mittelwert2 = statistics.mean(dat1)
std_abw2 = statistics.stdev(dat1)
v2 = std_abw2 / mittelwert2
print("Mittelwert Python: ", mittelwert2)
print("Std.abw. Python: ", std_abw2)
print("V Python:", v2)
print(k*"-")
Ausgabe:
V SciPy: 0.23890355966467272
V DDOF SciPy: 0.25804533701889254
--------------------------------------------------
Mittelwert NumPy: 20.714285714285715
Std.abw. NumPy: 4.948716593053935
Std.abw. DDOF NumPy: 5.3452248382484875
V NumPy: 0.23890355966467272
V DDOF NumPy: 0.2580453370188925
--------------------------------------------------
Mittelwert Python: 20.714285714285715
Std.abw. Python: 5.3452248382484875
V Python: 0.2580453370188925
--------------------------------------------------
Der Unterschied bei der Standardabweichung zwischen reinem Python und den externen Bibliotheken SciPy und NumPy entsteht dadurch, dass einmal durch (n-1) und das andere Mal nur durch n dividiert wird. Dies kann bei NumPy und SciPy dadurch entschärft werden, indem <code>ddof=1</code> gesetzt wird. ddof steht für '''D'''elta '''D'''egrees '''o'''f '''F'''reedom. <small>Je größer die Anzahl der Datensätze n wird, umso weniger spielt das eine Rolle.</small>
== Kombinatorik ==
Beispiel:
import math
n = 7
k = 5
print("n! = ", math.factorial(n))
print("Kombinationen (n über k) = ", math.comb(n, k))
Ausgabe:
n! = 5040
Kombinationen (n über k) = 21
Siehe zu diesem Thema auch [[Ing Mathematik: Permutationen, Kombinationen, binomischer Lehrsatz]]. Die Anzahlen lassen sich einfach aus den dortigen Formeln ermitteln, z.B. bei Permutationen mit <math>n!</math> oder Variationen mit Wiederholungen als <math>n^k</math>. Will man die Kombinationen oder Variationen aber auch als Liste ausgeben, so kann das Modul <code>itertools</code> nützlich sein.
Beispiel (Variationen ohne Wiederholung):
from itertools import permutations
menge = ["A", "B", "C", "D"] # n = 4
k = 3
variationen = list(permutations(menge, k))
for v in variationen:
print("".join(v))
print(50*"-")
print(len(variationen))
Ausgabe (gekürzt):
ABC
ABD
ACB
...
DCA
DCB
--------------------------------------------------
24
Siehe zum Modul <code>itertools</code> auch die Website [https://docs.python.org/3/library/itertools.html].
* Variationen mit Wiederholung: <code>itertools.product()</code>
* Kombinationen ohne Wiederholung: <code>itertools.combinations()</code>
* Kombinationen mit Wiederholung: <code>itertools.combinations_with_replacement()</code>
== Zufallszahlen ==
Beispiel:
import random
# Ganzzahlige Zufallszahl von 1 bis 10
zufallszahl1 = random.randint(1, 10)
# Gleitpunktzahlen
# zwischen 0.0 und 1.0
zufallszahl2 = random.random()
# Zahl zwischen 1.5 und 9.5
zufallszahl3 = random.uniform(1.5, 9.5)
# aus Liste auswählen
farbe = ["Rot", "Grün", "Blau"]
zufallswert = random.choice(farbe)
print(zufallszahl1)
print(zufallszahl2)
print(zufallszahl3)
print(zufallswert)
Ausgabe, z.B.:
5
0.14147945849015753
6.894003397570905
Rot
Benötigt man mehrere Zufallszahlen, so ist das Modul <code>numpy</code> zu bevorzugen, z.B.:
* Normalverteilung: <code>np.random.normal(...)</code>
* Gleichverteilung: <code>np.random.uniform(...)</code>
== Histogramm ==
Zum Thema Histogramm siehe {{W|Histogramm}}.
Beispiel (mit Matplotlib):
import matplotlib.pyplot as plt
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
plt.hist(daten, bins=25, edgecolor='darkgray')
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm.svg|300px]]
Beispiel (mit Seaborn):
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
sns.set_theme(style="darkgrid")
sns.histplot(data=daten)
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm2.svg|300px]]
Das Kürzel <code>sns</code> ist Konvention und steht für die fiktive Figur '''S'''amuel '''N'''orman '''S'''eaborn aus der US-Fernsehserie {{W|The West Wing – Im Zentrum der Macht | The West Wing}}.
== Box-Plot ==
[[File:Elements of a boxplot.svg|400px]]
Siehe auch {{W|Box-Plot}}.
Beispiel (mit Seaborn erstellt):
import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("tips")
sns.boxplot(data=df, x="day", y="tip", hue="day", legend=False)
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot.svg|400px]]
Beispiel (mit Matplotlib erstellt):
import matplotlib.pyplot as plt
daten = [12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25]
plt.boxplot(daten, patch_artist=True)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot2.svg|300px]]
Um mehrere Box-Plots unterschiedlicher Farbe mit Matplotlib in einem Diagramm zu zeichnen, können Sie folgendermaßen vorgehen:
import matplotlib.pyplot as plt
daten = [[12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25],
[10, 19, 20, 21, 20, 30, 19, 40, 11, 17, 19, 21]]
farben = ["green", "blue"]
boxplot = plt.boxplot(daten, patch_artist=True)
for patch, farbe in zip(boxplot['boxes'], farben):
patch.set_facecolor(farbe)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
== Regressionsrechnung ==
Beispiel:
import numpy as np
import matplotlib.pyplot as plt
# Messpunkte
x = np.array([1, 3, 5, 6, 8, 10, 20])
y = np.array([3, 4, 5, 5, 7, 9, 11])
# Regressionskurve (Grad 1 = lineare Regression, 2 = Polynom-Regression 2. Gr.)
# y = kx + d
k, d = np.polyfit(x, y, deg=1)
# y = ax**2 + bx + c
a, b, c = np.polyfit(x, y, deg=2)
x_l = np.linspace(1, 20, 100)
y_p = a * x_l**2 + b * x_l + c
# Zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.plot(x, k*x + d, color='blue', label='Regressionsgerade')
plt.plot(x_l, y_p, color='red', label='Regressionspolynom 2. Gr.')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:IngMath_regression.svg|400px]]
== Korrelationsrechnung ==
Beispiel:
import pandas as pd
import matplotlib.pyplot as plt
# Messdaten
x = [1, 3, 4, 5, 6]
y = [2, 4, 6, 8, 5]
daten = {'X': x, 'Y': y}
df = pd.DataFrame(daten)
# Korrelation
korr = df['X'].corr(df['Y'])
print(f"Korrelationskoeff.: {korr}")
# Messpunkte zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
Korrelationskoeff.: 0.7556096518348252
[[Datei:IngMath_korrelation.svg|300px]]
== Mengen und Venn-Diagramme ==
Beispiel:
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
menge_a = {1, 2, 3, 4, 5, 6}
menge_b = {4, 5, 6, 7, 8}
vereinigung = menge_a | menge_b
schnitt = menge_a & menge_b
print("Vereinigungsmenge = ", vereinigung)
print("Schnittmenge = ", schnitt)
venn2([menge_a, menge_b], set_labels=('Menge A', 'Menge B'))
plt.show()
Ausgabe:
Vereinigungsmenge = {1, 2, 3, 4, 5, 6, 7, 8}
Schnittmenge = {4, 5, 6}
[[Datei:IngMath_venn.svg|300px]]
Siehe auch {{W|Mengendiagramm#Venn-Diagramme}}.
== Verteilungs- und Dichtefunktion ==
* CDF ... '''C'''umulative '''D'''istribution '''F'''unction, Verteilungsfunktion
* PDF ... '''P'''robability '''D'''ensity '''F'''unction, Dichtefunktion
Beispiel (Normalverteilung):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
my, sigma = 0, 1
x = np.linspace(-4, 4, 50)
pdf = norm.pdf(x, my, sigma)
cdf = norm.cdf(x, my, sigma)
plt.plot(x, pdf, lw=2, label="Dichtefunktion")
plt.plot(x, cdf, lw=2, label="Verteilungsfunktion")
plt.legend()
plt.grid()
plt.show()
Ausgabe:
[[Datei:IngMath_cdf_pdf.svg|300px]]
Beispiel (<math>\chi^2</math>-Verteilung):
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
x = np.linspace(0, 20, 500)
# df ... degree of freedom, Freiheitsgrad
pdf = (stats.chi2.pdf(x, df=2), stats.chi2.pdf(x, df=5), stats.chi2.pdf(x, df=10))
for i in range(0,3):
if(i==0):
lab = "Freiheitsgrad 2"
elif(i==1):
lab = "Freiheitsgrad 5"
else:
lab = "Freiheitsgrad 10"
plt.plot(x, pdf[i], label=lab, lw=2)
plt.grid()
plt.legend()
plt.show()
Ausgabe:
[[Datei:IngMath_chi2.svg | 300px]]
== Schätzen und Testen ==
=== Intervallschätzung ===
Als Beispiel seien Daten gegeben, die von ''Dürr, Mayer: Wahrscheinlichkeitsrechnung und Schließende Statistik; 7. Aufl., Hanser, 2014, Seite 137'' stammen. Und zwar soll das 95%-Vertrauensintervall für den Mittelwert des Kaloriengehalts (kcal/100g) von Hähnchen ermittelt werden. Wir wollen das mit Python inkl. NumPy und SciPy durchführen. Die Stichprobe ist groß (50 Hähnchen):
Python-Code:
import numpy as np
import scipy.stats as stats
# Stichprobe
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203]
# Parameter definieren
konfidenzniveau = 0.95
mean = np.mean(daten)
std = np.std(daten, ddof=1)
stdfehler = stats.sem(daten)
intervall = stats.norm.interval(confidence=konfidenzniveau, loc=mean, scale=stdfehler)
print(f"Mittelwert: {mean}")
print(f"Standardabweichung: {std}")
print(f"Konfidenzintervall: {intervall}")
Ausgabe:
Mittelwert: 215.48
Standardabweichung: 33.14238915925757
Konfidenzintervall: (np.float64(206.29356722321992), np.float64(224.66643277678006))
Diese Werte stimmen gerundet mit denen im genannten Buch überein. Zum Code selbst:
* sem steht für '''s'''tandard '''e'''rror of the '''m'''ean.
* <code>scipy.stats.norm</code> ... Modul für die Normalverteilung.
=== Punktschätzung ===
Gleiche Daten wie oben bei der Intervallschätzung.
Python-Code:
import numpy as np
from scipy import stats
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203
]
mu_hat, sigma_hat = stats.norm.fit(daten)
print(f"Schätzer für den Erwartungswert (μ): {mu_hat:.4f}")
print(f"Schätzer für die Standardabweichung (σ): {sigma_hat:.4f}")
Ausgabe:
Schätzer für den Erwartungswert (μ): 215.4800
Schätzer für die Standardabweichung (σ): 32.8093
=== Hypothesentests ===
Beispiel:
import numpy as np
import scipy.stats as stats
x_quer = 12.075 # Stichproben-Mittelwert
var = 0.069 # Stichproben-Varianz
n = 90 # Stichprobengröße
my_0 = 12.0 # Nullhypothese
alpha = 0.05 # Signifikanzniveau
z_stat = (x_quer - my_0) / np.sqrt(var / n)
p_val = 2 * (1 - stats.norm.cdf(np.abs(z_stat)))
print(f"Z-Statistik: {z_stat:.4f}")
if p_val < alpha:
print(f"p-Wert: {p_val:.6f} < alpha:", alpha)
print("Die Nullhypothese wird verworfen.")
else:
print(f"p-Wert: {p_val:.6f} > alpha:", alpha)
print("Die Nullhypothese wird nicht verworfen.")
Ausgabe:
Z-Statistik: 2.7087
p-Wert: 0.006755 < alpha: 0.05
Die Nullhypothese wird verworfen.
== Statistische Qualitätskontrolle ==
Beispiel (Mittelwertkarte):
import numpy as np
import matplotlib.pyplot as plt
# Gegeben
sollwert = 50.0
varianz = 4.0
stichproben_umfang = 1
daten = [49.5, 50.2, 53.0, 48.1, 52.6, 53.4, 49.8]
# Berechnung
standardabweichung = np.sqrt(varianz)
streuung = standardabweichung / np.sqrt(stichproben_umfang)
cl = sollwert
ucl = cl + 3 * streuung
lcl = cl - 3 * streuung
# Darstellung
plt.plot(daten, marker='o', linestyle='-', color='b', label='Messdaten')
plt.axhline(cl, color='green', linestyle='-', label=f'CL: {cl}')
plt.axhline(ucl, color='red', linestyle='--', label=f'UCL: {ucl:.2f}')
plt.axhline(lcl, color='red', linestyle='--', label=f'LCL: {lcl:.2f}')
plt.title('Mittelwertkarte')
plt.xlabel('Stichprobe')
plt.ylabel('Wert')
plt.legend(loc='lower left')
plt.grid(True)
plt.show()
Ausgabe:
[[Datei:IngMath_mittelwertkarte.svg|300px]]
Siehe auch {{W|Shewhart-Regelkarte}} und {{W|Qualitätsregelkarte}}.
* UCL ... '''U'''pper '''C'''ontrol '''Limit''', Obere Eingriffsgrenze
* LCL ... '''L'''ower '''C'''ontrol '''Limit''', Untere Eingriffsgrenze
* CL ... '''C'''enter '''L'''ine, Mittellinie
= Ein- und Ausgabe =
== print ==
Die Anweisung print haben wir schon oft verwendet. Hier soll anhand von Beispielen kurz beschrieben werden, was der Befehl print leisten kann.
print("Hallo", "Welt", 1, sep="-")
print("Hallo", end=" ")
print("Welt")
Ausgabe:
Hallo-Welt-1
Hallo Welt
== input ==
a = int(input("Zahl 1: "))
b = int(input("Zahl 2: "))
print("a + b = ", a+b)
Ausgabe (nach Eingabe der beiden Ganzzahlen):
Zahl 1: 4
Zahl 2: 5
a + b = 9
== Aus Dateien lesen ==
Es seinen die datei.txt
Hallo Welt.
Wie geht es dir?
...
und test1.py
dat = open("datei.txt", mode = "r")
print(dat.read())
dat.close()
Ausgabe
Hallo Welt.
Wie geht es dir?
...
Mit dem open()-Befehl wird die Datei datei.txt im Lesemodus geöffnet (r ... read). Mit dem read()-Befehl wird die Datei eingelesen und mittels print ausgegeben.
== In Dateien schreiben ==
dat = open("datei.txt", mode = "a", encoding = "utf-8")
dat.write("Hänge Zeile an\n")
dat.close()
Die Datei datei.txt sieht nach Abarbeitung des obigen Skripts nun so aus
Hallo Welt.
Wie geht es dir?
...
Hänge Zeile an
Es wird die Datei im Schreibmodus geöffnet (a ... append (anhängend), w ... write (überschreibend)).
write() fügt hier also eine Zeile Text am Dateiende ein. close() schließt die Datei wieder.
Das close() kann man sich mit der with-Anweisung auch sparen.
with open("datei.txt", mode="a", encoding="utf-8") as dat:
dat.write("Hänge Zeile an\n")
= Benutzeroberflächen erstellen =
== tkinter ==
{{Wikipedia | Tkinter}}
Python bietet standardmäßig das Modul tkinter zur Programmierung von Benutzeroberflächen. Es müssen also bei der Verwendung von tkinter keine externen Module installiert werden. Hier wird eine (sehr) kurze Einführung in das Erstellen von grafischen Oberflächen mittels tkinter gegeben.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
win.minsize(300, 50)
but = tk.Button(win, text = "Push the button")
but.pack()
win.mainloop()
Ausgabe:
[[Datei:PythonIng_gui1.jpg]]
Ein etwas komplizierteres Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
def on_button_clicked():
str = ent1.get() + ent2.get()
lab2["text"] = str
ent1 = tk.Entry(win)
ent2 = tk.Entry(win)
lab1 = tk.Label(win, text="verknuepfen mit")
lab2 = tk.Label(win, text="")
but = tk.Button(win, text = "=", command=on_button_clicked)
ent1.pack(side="left")
lab1.pack(side="left")
ent2.pack(side="left")
but.pack(side="left")
ent2.pack(side="left")
lab2.pack(side="left")
win.mainloop()
Ausgabe (vor der Eingabe der Teilstrings):
[[Datei:PythonIng_gui2.jpg]]
Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):
[[Datei:PythonIng_gui3.jpg]]
== curses ==
{{Wikipedia | curses}}
Mit dem curses-Modul lassen sich u.a. TUIs ('''T'''ext '''U'''ser '''I'''nterfaces) erstellen. Ein sehr einfaches Beispiel zur allgemeinen Funktionsweise wird nachstehend geliefert.
import curses
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
stdscr.clear()
stdscr.addstr("Hallo Welt", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.endwin()
Als Ausgabe sollte <span style="color:#FF0000;">Hallo Welt</span> (rote Schrift auf weißem Hintergrund) auf dem Terminal/der Konsole erscheinen. Getestet wurde dies mit openSUSE Tumbleweed, Python-Version 3.13.12. Das entsprechende Python-curses-Package muss installiert sein.
Allgemeine Informationen zur Terminal-/Konsolengröße und Cursorposition liefert folgendes Programm:
import curses
stdscr = curses.initscr()
stdscr.addstr(3, 5, "LINES: %d" % curses.LINES)
stdscr.addstr(4, 5, "COLS: %d" % curses.COLS)
(y,x) = stdscr.getyx()
stdscr.addstr(5, 5, "Momentane Cursorposition: [%d, %d]" % (y, x))
(y,x) = stdscr.getbegyx()
stdscr.addstr(6, 5, "Koordinatenursprung: [%d, %d]" % (y, x))
(y,x) = stdscr.getmaxyx()
stdscr.addstr(7, 5, "Fenstergröße: [%d, %d]" % (y, x))
stdscr.addstr(11, 2, "Taste drücken -> Ende")
stdscr.refresh()
stdscr.getch()
curses.endwin()
Es sollte sich in etwa folgende Ausgabe ergeben:
LINES: 44
COLS: 110
Momentane Cursorposition: [4, 15]
Koordinatenursprung: [0, 0]
Fenstergröße: [44, 110]
Taste drücken -> Ende
Zur Funktionsweise von curses siehe auch das Wikibook [[ncurses]]. Zum Verständnis sind dort allerdings elementare Kenntnisse in der Programmiersprache C erforderlich.
== Qt ==
{{Wikipedia | Qt (Bibliothek)}}
Auch für das Qt-Framework gibt es eine Anbindung an Python. Nachfolgend ein einfaches Beispiel.
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hallo Welt!")
label.show()
sys.exit(app.exec())
Ausgabe:
[[Datei:PythonIng_gui10.png]]
== Gtk ==
{{Wikipedia | GTK (Programmbibliothek)}}
Eine idente Ausgabe, wie oben für Qt gezeigt, erzeugt z.B. folgendes Gtk-Programm:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
lab = Gtk.Label(label="Hallo Welt!")
win.set_child(lab)
win.present()
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
Auch für die Benutzung von Qt und Gtk müssen die jeweiligen Packages installiert sein. Getestet wurden die entsprechenden Python-Programme nur unter openSUSE Tumbleweed. Wie das GTK-Paket unter MS Windows 11 installiert wird, siehe z.B. [https://www.gtk.org/docs/installations/windows Setting up GTK for Windows].
Damit sei aber das Thema "Benutzeroberflächen erstellen" hier abgeschlossen, da dies schon ein sehr spezielles Aufgabengebiet ist, das eher Informatiker und nicht so sehr Ingenieure anspricht. Bei Bedarf siehe aber ggf. die entsprechenden Links unten in diesem Tutorial. Dort sind weiterführende Informationen zu finden.
= Pandas kurz erklärt =
Hier wird kurz auf das externe Modul Pandas eingegangen. Pandas steht für '''Pan'''el '''Da'''ta und ist ein Modul für die Datenanalyse und -manipulation.
== Series ==
Vorstellbar ist eine "Series" wie eine einzelne Spalte in einem Tabellenkalkulationsprogramm.
Beispiel (Index implizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5]) # Temperaturwerte
print(temp)
Ausgabe:
0 8.5
1 11.0
2 12.5
3 10.0
4 13.0
5 11.0
6 14.5
dtype: float64
Das Kürzel <code>pd</code> ist Konvention. Es seien Temperaturwerte gegeben. Die erste Spalte bei der Ausgabe ist der Index. Die zweite Spalte enthält die Werte.
Beispiel (separater Zugriff auf den Index und auf die Werte):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5])
print(temp.index)
print(temp.values)
Ausgabe:
RangeIndex(start=0, stop=7, step=1)
[ 8.5 11. 12.5 10. 13. 11. 14.5]
Beispiel (Index explizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
print("*** Die gesamte Series ***")
print(temp)
print("*** Temperatur am Donnerstag ***")
print(temp["Do"])
print("*** Tage wärmer als 12 Grad ***")
temp_gr_12 = temp[temp > 12]
print(temp_gr_12)
Ausgabe:
*** Die gesamte Series ***
Mo 8.5
Di 11.0
Mi 12.5
Do 10.0
Fr 13.0
Sa 11.0
So 14.5
dtype: float64
*** Temperatur am Donnerstag ***
10.0
*** Tage wärmer als 12 Grad ***
Mi 12.5
Fr 13.0
So 14.5
dtype: float64
== DataFrame ==
Ein DataFrame entspricht einer Tabelle.
Beispiel (Erzeugen eines DataFrames):
import pandas as pd
tag = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
v1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=tag)
v2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=tag)
v3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=tag)
tab = pd.concat([v1, v2, v3], axis=1)
tab.columns = stadt
print(tab)
print(type(tab))
Ausgabe:
Linz Salzburg Innsbruck
Mo 1 8 Hallo
Di 2 9 16
Mi 3 10 17
Do 4 11 18
Fr 5 12 19
Sa 6 13 20
So 7 14 21
<class 'pandas.core.frame.DataFrame'>
Wir haben hier drei Datenspalten (v1, v2, v3) mit den Spaltennamen "Linz", "Salzburg" und "Innsbruck", sowie sieben Zeilen "Mo" bis "So".
Beispiel (Zugriff auf eine Spalte):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab["Salzburg"])
Ausgabe:
Mo 8
Di 9
Mi 10
Do 11
Fr 12
Sa 13
So 14
Name: Salzburg, dtype: int64
Beispiel (Zugriff auf eine Zeile):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab.loc["Di"])
Ausgabe:
Linz 2
Salzburg 9
Innsbruck 16
Name: Di, dtype: object
== Grafiken erstellen ==
Hier sei nur ein Torten- oder Kreisdiagramm gezeichnet:
import pandas as pd
import matplotlib.pyplot as plt
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
expl = [0, 0.2, 0, 0, 0, 0, 0]
temp.plot.pie(figsize=(5,5), explode=expl)
plt.show()
Ausgabe:
[[Datei:IngPython_pandas1.svg|350px]]
Die <code>figsize</code> hat nichts mit der Spaltenanzahl zu tun, sondern setzt die Fenster- oder Diagrammgröße in Inches (Breite * Höhe).
Mit Pandas kann man auch noch andere Diagrammarten erstellen, z.B. Linien- oder Balkendiagramme. Dies wird hier aber nicht vorgeführt.
== Arbeiten mit CSV- und LibreOffice-Dateien ==
Gegeben sei eine CSV-Datei test1.csv:
Mai;Juni;Juli
12;17;45
15;65;65
16;32;23
4;14;7
23;17;Keine Daten verfügbar
67;Keine Daten verfügbar;45
15;24;12
Lesen von dieser CSV-Datei:
import pandas as pd
tab = pd.read_csv("test1.csv", sep=";")
print(tab)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Schreiben in eine CSV-Datei test2.csv:
import pandas as pd
val = pd.read_csv("test1.csv", sep=";")
val.to_csv("test2.csv", index=False)
Ausgabedatei:
Mai,Juni,Juli
12,17,45
15,65,65
16,32,23
4,14,7
23,17,Keine Daten verfügbar
67,Keine Daten verfügbar,45
15,24,12
Die Ausgabedatei ist beinahe gleich wie die Eingabedatei. Es werden aber Kommas statt Strichpunkten verwendet. Daher kommt auch der Name CSV ('''C'''omma '''S'''eparated '''V'''alue). Will man wieder Strichpunkte, so kann man dies über den Parameter <code>sep=";"</code> in der <code>to_csv</code>-Funktion machen.
Um direkt von einer ODS-Datei (LibreOffice Calc, '''O'''pen '''D'''ocument '''S'''preadsheet) zu lesen muss das Modul odfpy extra installiert sein (per YaST, pip etc.). Gelesen wird dann folgendermaßen:
import pandas as pd
df = pd.read_excel('test1.ods', engine='odf')
print(df)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Die Datei "test1.ods" sei die Datei, aus der das obige "test1.csv" generiert wurde. Schreiben kann man ebenfalls in eine ODS-Datei:
import pandas as pd
daten = {
"Name": ["Hugo", "Richie", "Wilhelmine"],
"Alter": [38, 30, 29],
"Ort": ["Linz", "Innsbruck", "Salzburg"]
}
tab = pd.DataFrame(daten)
with pd.ExcelWriter("test2.ods", engine="odf") as writer:
tab.to_excel(writer, sheet_name="Daten", index=False)
Es ergibt sich eine "test2.ods"-Datei (Screenshot):
[[Datei:IngPython_pandas2.png|250px]]
== Sonstiges ==
Hier seien stichpunktartig einige weitere Features von Pandas angeführt:
* {{W|Pivot-Tabelle|Pivot-Tabellen}} (pivot ... Dreh-, Angelpunkt): Zweck - große Datenmengen schnell zusammenfassen, filtern und analysieren.
* NaN ('''n'''ot '''a''' '''n'''umber): In einem Datensatz fehlt ein Wert oder ist nicht definiert.
* groupby-Funktion: Daten strukturieren, aggregieren oder Zwischensummen bilden.
* {{W|Binning#Datenverarbeitung_und_-analyse|Binning}}: Klassenbildung.
* Mehrstufige Indizierung (Hierarchical Indexing oder MultiIndex)
* Zeitreihen (Time Series)
Für tiefergehende und weiterführende Informationen wird auf das Buch von ''Klein: Numerisches Python; Hanser, 2023'' und [https://pandas.pydata.org/ pandas] verwiesen.
= Style Guide, flake8, pylint, Black etc. =
== Style Guide ==
Wie man schönen und richtigen Python-Code schreibt, erfahren Sie in
* [https://peps.python.org/pep-0008/ PEP 8 – Style Guide for Python Code]
== Formatter und Linter ==
Ein Modul, das prüft, ob die Richtlinien im Style Guide eingehalten wurden, ist ''flake8'':
* [https://flake8.pycqa.org/en/latest/ Flake8: Your Tool For Style Guide Enforcement]
Code formatieren kann man auch mit [https://pypi.org/project/black/ Black]. Z.B. übersetzt <code>black test1.py</code> die Datei <code>test1.py</code>
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)),
(2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
in
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)), (2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Die Programmausgabe ist
reformatted test1.py
All done! ✨ 🍰 ✨
1 file reformatted.
Der Unterschied zwischen Black und Flake8:
* Black ist ein Code-Formatter. Er formatiert Ihren Code um, sodass er im Einklang mit PEP 8 steht.
* Flake8 ist ein {{W|Lint (Programmierwerkzeug) | Code-Linter}}. Flake8 verändert Ihren Code nicht, sondern durchsucht ihn nach potenziellen Fehlern etc.
Am obigen Beispiel sieht man auch, dass flake8 und Black nicht immer einer Meinung sind. Flake8 (<code>flake8 test1.py</code>) würde standardmäßig den mit Black formatierten Code bemängeln:
test1.py:8:80: E501 line too long (80 > 79 characters)
Diese Diskrepanz kann beseitigt werden. Da 79 Zeichen auf modernen Bildschirmen meist als zu kurz empfunden werden, ist ein Limit von 88 Zeichen (Black-Standard) oder mehr empfehlenswert. Um dies zu implementieren, erstellen Sie in Ihrem Projektverzeichnis eine <code>.flake8</code>-Datei mit dem Inhalt
[flake8]
max-line-length = 88
Und schon ignoriert Flake8 dieses Problem.
Ein anderer Linter ist pylint. Der würde beim Abarbeiten des obigen Beispiels, z.B. mit <code>pylint test1.py</code> noch eine Kleinigkeit bemängeln:
************* Module test1
/home/hr/tmp/test1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)
Auch pylint muss vor der ersten Verwendung installiert werden (z.B. mittels pip, virtuelle Umgebung, YaST). Die Dokumentation zu pylint findet sich auf [https://pylint.readthedocs.io/en/latest/].
<u>Aufgabe:</u> Fügen Sie einen "module docstring" in die <code>test1.py</code>-Datei ein und testen Sie erneut mit flake8, Black und pylint. <small>Sehen Sie zum Thema docstrings auch [https://peps.python.org/pep-0257/#what-is-a-docstring PEP 257 – Docstring Conventions].</small>
Es gibt noch weitere Formatierungswerkzeuge für Python-Code. Z.B. [https://docs.astral.sh/ruff/ Ruff], ein moderner Code-Formatter und -Linter. Mittels <code>ruff check test1.py</code> würde obiger Code geprüft (Linter). <code>ruff format test1.py</code> formatiert den Code (Formatter).
== Type Checker ==
"Type Checker" sind z.B.
* mypy
* pyright
* ty
Diese prüfen die Datentypen, z.B. in folgendem Code
def greetings(name: str) -> str:
return "Hello, %s" % name
print(greetings(42))
Python selbst, flake8, ruff oder black würden diesen Code ohne zu murren akzeptieren. "Type Checker" würden aber sehr wohl Alarm schlagen, z.B. liefert <code>mypy</code> folgende Ausgabe
test1.py:5: error: Argument 1 to "greetings" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Das funktioniert übrigens nicht nur bei Funktionsannotationen, sondern auch mit Variablen etc.
from typing import Final
# "Konstante", ab Python 3.8
NUMBER: Final = 123
print(NUMBER)
NUMBER = 125
print(NUMBER)
# Variable
a: int = 345
print(a)
a = "Irgendwas"
print(a)
# Variable (Pipe-Symbol), ab Python 3.10
b : int|str = 567
print(b)
b = "sonstiges"
print(b)
Ausgabe mit python:
123
125
345
Irgendwas
567
sonstiges
Ausgabe mit mypy:
test3.py:6: error: Cannot assign to final name "NUMBER" [misc]
test3.py:12: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
Found 2 errors in 1 file (checked 1 source file)
Python kennt übrigens keine Konstanten. Man kann diese mittels Großbuchstaben andeuten. Das ist aber nur Konvention, hat aber keine sonstigen Auswirkungen. Oder man verwendet wie oben gezeigt <code>Final</code>. Dann werfen Typchecker Errors aus.
==pydoc==
pydoc ist ein Werkzeug, um Python-Module, -Funktionen und -Klassen zu dokumentieren.
Beispiel <code>test1.py</code>:
"""Rechen-Modul.
Funktionen die von pydoc gelesen werden.
"""
def multiply(a, b):
"""Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a * b
def add(a, b):
"""Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a + b
if __name__ == '__main__':
print(multiply(3, 5))
print(add(4, 6))
Ausgabe mit <code>python3.13 -m pydoc test1</code> auf der Konsole:
Help on module test1:
NAME
test1 - Rechen-Modul.
DESCRIPTION
Funktionen die von pydoc gelesen werden.
FUNCTIONS
add(a, b)
Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
multiply(a, b)
Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
FILE
/home/xyz/tmp/test1.py
Siehe zu diesem Thema z.B. auch [https://docs.python.org/3/library/pydoc.html]. Mittels <code>python3.13 -m pydoc -w test1</code> kann man auch eine HTML-Dokumentation erstellen.
Wofür <code>if __name__ == '__main__':</code> steht, siehe z.B. etwas später im Abschnitt [[Ing_Mathematik:_Python#Doctests]].
== Sonstige Tools ==
Andere Tools für die {{W|Statische Code-Analyse|statische Codeanalyse}}, die aber für Ingenieure weniger interessant sein dürften, sind z.B.
* Radon: Liefert verschiedene {{W|Softwaremetrik|Codemetriken}} (Komplexität, Wartbarkeitsindex ...)
* Bandit: Findet Sicherheitslücken
Tools für die {{W|Dynamisches Software-Testverfahren|dynamische Codeanalyse}}, z.B.:
* DynaPyt (Framework zur dynamischen Programmanalyse)
* cProfile (Profiler)
* Memory Profiler (Speicheranalyse)
* Memray (Speicheranalyse)
* tracemalloc (Speicheranalyse)
Paket- und Projektmanagement (pip-Ersatz etc.):
* uv
* Poetry
* Conda
* pipx
Packaging-Tools (Freezer) und {{W|Compiler#Sonderformen|Transpiler}} :
* pyinstaller
** erstellt eigenständige, ausführbare Binärdatei
** kein Cross-Compiler
** kein Schutz vor Reverse-Engineering
** langsam
** packt alles in eine Datei
** sehr große Datei
** Befehl, z.B.: <code>pyinstaller --onefile test1.py</code>
** GUI: <code>auto-py-to-exe</code>
* cx_Freeze
* nuitka
** Übersetzt Python-Code in C/C++-Code und weiter in eine ausführbare Datei
** kein Cross-Compiler
** Schutz vor Reverse-Engineering
** Befehl, z.B.: <code>nuitka --standalone --onefile test1.py</code>
* cython
= Einige Integrierte Entwicklungsumgebungen (IDEs)=
Werden Programmtexte größer und umfangreicher, so ist das Arbeiten mit der interaktiven Programmierumgebung bzw. das direkte Ausführen von Python-Skripten mühsam. Man wünscht sich z.B. Hilfen zum Debuggen oder die automatische Code-Vervollständigung. Zu diesem Zweck wurden IDEs (Integrated Development Environments) geschaffen. Von diesen seinen nachfolgend auszugsweise einige kurz beschrieben. Testen Sie einfach aus, welche davon für Sie bzw. für Ihr Python-Projekt geeignet sind.
== IDLE ==
IDLE ist die mit dem Python-Programmpaket mitgelieferte IDE. Der Name leitet sich einerseits ab vom Monty-Python-Mitglied Eric Idle, andererseits steht es als Abkürzung für "'''I'''ntegrated '''D'''evelopment and '''L'''earning '''E'''nvironment. IDLE ist einfach zu bedienen, bietet aber schon einen beachtlichen Leistungsumfang. Nachfolgend wird ein Screenshot zu IDLE geliefert. Rechts ist das Editor-Fenster zu sehen, links die interaktive Programmierumgebung. Um das Beispiel selbst nachvollziehen zu können, starten Sie IDLE. Das geht ähnlich, wie Sie die interaktive Programmierumgebung von Python starten (nur, dass Sie eben das IDLE-Icon doppelklicken und nicht das Python-Icon. Unter Linux geben Sie einfach in einem Terminal <code>idle3.13</code> o. Ä. ein). Weiter geht es mit "File - Open - ...". Die auszuführende Datei auswählen (im konkreten Fall ein "Hallo-Welt"-Programm). Es erscheint das rechte Fenster. Dort "Run - Run Module" auswählen. Und schon wird im linken Fenster "Hallo Welt!" ausgegeben.
[[Datei:PythonIng_idle1.jpg | 600px]]
Siehe auch {{W|IDLE}}.
== PyCharm ==
PyCharm ist ein kommerzielles Produkt. Es gab aber auch eine kostenlose Community Edition. Seit 2025 sind beide Varianten vereint. Für die ersten 30 Tage sind die Pro-Funktionen frei verfügbar, danach nur noch die Kernfunktionalitäten (oder man bezieht kostenpflichtig die Pro-Version). Zu beziehen ist PyCharm unter dem Weblink [https://www.jetbrains.com/pycharm/]. Nachfolgend ein etwas abgewandeltes "Hallo Welt"-Programm, editiert und ausgeführt mit PyCharm.
[[Datei:PyCharm_IDE_2023_screenshot.png | 600px]]
Siehe auch {{W|PyCharm}}.
== Eric ==
Auch eric ist Open Source und steht unter der GNU General Public License Version 3 oder später. Zu beziehen ist diese Software unter [https://eric-ide.python-projects.org/].
[[Datei:Screenshot_Eric_4.png | 600px]]
Siehe auch {{W|eric (Software)}}.
<small>
Unter openSUSE Tumbleweed sollte sich eric auch mit YaST installieren lassen. Bei mir gibt es aber dann beim Ausführen des eric-Programms eine Fehlermeldung (Stand März 2026):
...
ModuleNotFoundError: No module named 'PyQt6.QtPdfWidgets'
Umgehen kann man dieses Problem aber wieder mit dem Erstellen einer virtuellen Umgebung, in etwa so
python3.13 -m venv ~/tmp/venv1
cd ~/tmp/venv1/bin
./python3.13 -m pip install --upgrade --prefer-binary eric-ide
./eric7_ide
</small>
== PyScripter ==
Vom Funktionsumfang vergleichbar mit den vorherigen IDEs ist PyScripter. Auch PyScripter ist Open Source. Die Projekt-Homepage findet sich auf [https://sourceforge.net/projects/pyscripter/]. PyScripter ist nur für MS Windows verfügbar.
[[Datei:PythonIng_pyscripter1.jpg | 600px]]
== Spyder IDE ==
Spyder enthält bereits eine stabile Python-Version und etliche Module (z.B. matplotlib, numpy, control). Ansonsten kann dieses Softwarepaket vom Funktionsumfang her mit den anderen genannten IDEs locker mithalten. Spyder wurde unter der MIT-Lizenz veröffentlicht. Diese Software findet sich auf [https://www.spyder-ide.org].
[[Datei:Spyder-windows-screenshot.png | 600px]]
Siehe auch {{W|Spyder (Software)}}
== Eclipse IDE==
Die {{W|Eclipse_(IDE)|Eclipse-IDE}} kann für Python aufgerüstet werden. Dazu gibt es das PyDev-Plugin. Installiert wird es über
* Help > Eclipse Marketplace...
* Find - PyDev - Install
Danach muss noch der Pfad zum Python-Interpreter festgelegt werden
* Window > Preferences > PyDev > Interpreters > Python Interpreter > New ...
Das Ergebnis ist ähnlich wie im folgenden Bild, nur dass statt C/C++ Python Verwendung findet.
[[Datei:Setting Up Eclipse CDT helloout.png | 600px]]
== Sonstige ==
Die genannten IDEs sind nicht die Einzigen. Es gibt, um dem Image Pythons als beliebteste Programmiersprache gerecht zu werden, noch einige andere. Sowohl Open Source-Programme als auch kommerzielle Programme sind im Web zu finden, z.B. Thonny oder {{W|Visual Studio Code}}. Unter Linux kann man auch {{W|KDevelop}}, ausgestattet mit dem Python3-Plugin, einsetzen. Braucht man den Umfang von ausgewachsenen IDEs nicht, so kann man auch normale Texteditoren verwenden (z.B. {{W|Geany}} oder {{W|Kate_(Texteditor)|Kate}}).
= Debuggen und Testen =
Das Debuggen und Testen von Programmen sind wichtige Bestandteile der Programmierung. Syntaxfehler lassen sich i.A. leicht beheben. Schwieriger ist das Eingrenzen von logischen Fehlern, die ev. nur in bestimmten Situationen auftreten und keine explizite Fehlermeldung hervorrufen. Das Programm liefert falsche Ergebnisse oder es stürzt aus heiterem Himmel ab. Um das zu verhindern gibt es verschiedene Werkzeuge, die bei der Fehlersuche behilflich sein können. Vorerst siehe aber zwecks Begriffsklärung noch folgende Links:
* {{W|Debuggen}}
* {{W|Debugger}}
* {{W|Softwaretest}}
<gallery>
First Computer Bug, 1947.jpg
Test ganzheitlich.png
V-Modell.svg
</gallery>
== Das Modul pdb ==
Python bringt schon ein Modul zum Debuggen mit. Siehe z.B. [https://docs.python.org/3/library/pdb.html pdb — The Python Debugger].
Komfortabler lässt sich das aber mittels Integrierter Entwicklungsumgebungen (IDEs) angehen.
== Debuggen mit IDEs ==
Für die IDEs IDLE und Spyder sei kurz auf die entsprechenden Webseiten verwiesen:
* [https://www.cs.uky.edu/~keen/help/debug-tutorial/debug.html Debugging under IDLE].
* [https://docs.spyder-ide.org/current/panes/debugging.html Spyder Debugger]
Dort wird die Vorgehensweise auch mittels Screenshots erläutert.
== assert ==
assert ... behaupten, zusichern ({{W|Assertion (Informatik)}})
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10., 0.)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10., 0.)
File "/home/hr/Develop/test1.py", line 4, in print1
assert y != 0.0
^^^^^^^^
AssertionError
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1("10.", "5.")
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Aber auch bei nachfolgendem Code gibt es eine Fehlermeldung:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10, 5)
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Damit letzteres funktioniert, kann man den Programmcode so umschreiben:
def print1(x, y):
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
2.0
Und jetzt fangen wir den <code>AssertionError</code> auf:
def print1(x, y):
try:
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
except(AssertionError):
print("Hallo")
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Hallo
Ich hoffe, es ist wenigstens im Ansatz klar geworden, wofür <code>assert</code> gut sein kann. Ausschalten kann man die <code>assert</code>-Überprüfung übrigens mit dem Python-Schalter <code>-O</code>.
== Doctests ==
Innerhalb eines Docstrings kann die Arbeit im interaktiven Modus simuliert werden. Nach den Promptzeichen (>>>) erfolgen dann bei unserem Beispiel innerhalb des Docstrings simulierte Aufrufe der Funktion <code>print1()</code>. Danach folgen jeweils die Sollresultate. Wird das Modul oder die Datei als Hauptprogramm aufgerufen, so wird die Funktion <code>doctest.testmode()</code> aufgerufen und ein Bericht auf der Konsole ausgegeben. Wird das Modul nicht als Hauptprogramm aufgerufen, sondern importiert, dann wird diese <code>testmod</code>-Funktion nicht aufgerufen. D.h. dieser Code kann sowohl für Testzwecke als auch für den produktiven Einsatz verwendet werden. Das ist auch sinnvoll, weil wenn man Teile der Datei immer löschen bzw. einfügen müsste, so würden sich Fehlerquellen auftun. Das würde den Sinn und Zweck von Doctests konterkarieren.
def print1(x=0., y=1.):
""" Dividiere zwei Zahlen
Autor: Intruder
Datum: 12.08.2025
>>> print1(2., 1.)
2.0
>>> print1(5., 2.)
2.5
>>> print1(5.)
5.0
"""
print(x/y)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Ausgabe:
Trying:
print1(2., 1.)
Expecting:
2.0
ok
Trying:
print1(5., 2)
Expecting:
2.5
ok
Trying:
print1(5.)
Expecting:
5.0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.print1
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Das gezeigte Beispiel ist so ziemlich das einfachste, das es gibt. Für weiterführende Details siehe z.B.:
* [https://peps.python.org/pep-0257/ PEP 257 – Docstring Conventions]
* [https://docs.python.org/3/library/doctest.html doctest — Test interactive Python examples]
''Einschub:'' Ganz ähnlich kann man auch Klassen testen, z.B. in folgendem Code-Fragment
class Fahrzeug:
# siehe Abschnitt "Objektorientierte Programmierung"
# ...
if __name__ == "__main__":
vauweh = Fahrzeug(170, 90)
beemweh = Fahrzeug(200, 120)
print(vauweh.convertGeschw())
print(beemweh.convertGeschw())
Wird das Script als Hauptprogramm ausgeführt (z.B. zu Testzwecken), so erfolgt die Ausgabe der zwei, via <code>convertGeschw()</code>, umgerechneten Geschwindigkeiten. Wird es aber als Modul eingebunden, so wird der letzte Programmabschnitt nicht ausgeführt (<code>__name__ == "__main__"</code> ergibt <code>False</code>).
== pytest ==
Siehe zu diesem Thema auch {{W|Modultest}}.
pytest ist ein externes Modul und muss vorab installiert werden, z.B. mittels
pip install -U pytest
pip install -U pytest-html
Python-Code, Datei test1.py:
def add(x, y):
return x + y
def test_answer():
assert add(1, 1) == 3
Starten von pytest in der Konsole:
pytest test1.py
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py F [100%]
========================================================= FAILURES ==========================================================
________________________________________________________ test_answer ________________________________________________________
def test_answer():
> assert add(1, 1) == 3
E assert 2 == 3
E + where 2 = add(1, 1)
test1.py:6: AssertionError
================================================== short test summary info ==================================================
FAILED test1.py::test_answer - assert 2 == 3
===================================================== 1 failed in 0.09s =====================================================
Hier erhalten wir einen Fehler, da 1+1 eindeutig ungleich 3 ist. Aber aus irgendeinem Grund wollte der Programmierer oder Tester in diesem Fall, dass dies so ist. Testfälle werden übrigens mit dem Präfix <code>test_</code> eingeleitet.
Python-Code:
def add(x, y):
return x + y + 1
def test_answer():
assert add(1, 1) == 3
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py . [100%]
===================================================== 1 passed in 0.01s =====================================================
Jetzt ist alles in Ordnung. Weiterführendes siehe z.B.
* [https://docs.pytest.org/en/stable/ pytest: helps you write better programs]
== unittest ==
Auch unittest dient zur Durchführung von Testreihen, ist aber Bestandteil von Python. Hier wird vorerst nicht näher darauf eingegangen. Siehe z.B.
* [https://docs.python.org/3/library/unittest.html unittest — Unit testing framework]
Lt. ''Inden: Python Challenge; dpunkt, 2021, Seite 481'' soll unittest weniger komfortabel als pytest sein.
Einen Vergleich von unittest mit pytest findet man in
* [https://knapsackpro.com/testing_frameworks/difference_between/pytest/vs/unittest pytest vs unittest]
= Python und Anwendungsprogramme =
Bisher stand immer alleine die Programmiersprache Python (ev. unter Einbeziehung von Modulen) im Mittelpunkt der Betrachtungen. Aber Python kann auch als Makrosprache für Anwendungsprogramme auftreten. Als Beispiele seien {{W|FreeCAD}} und {{W|LibreOffice}} genannt.
== FreeCAD ==
FreeCAD ist ein freies 3D-CAD-Programm. Hier soll nicht auf die Bedienung dieses CAD-Pakets eingegangen werden, sondern nur auf die Möglichkeit, mittels Python Makros zu schreiben. Als einfacher Einstieg soll ein Makro erstellt werden, welches eine Kugel (rot) und einen Quader (blau) zeichnet. Folgende Vorbereitungsschritte sind erforderlich (es sei vorausgesetzt, dass FreeCAD schon am Rechner installiert ist. Downloaden können Sie das Programm von der Website [https://www.freecad.org/downloads.php?lang=en]):
* FreeCAD starten
* Leere Datei erstellen
* Makro > Makros > Erstellen ...
Es öffnet sich ein leeres Editorfenster, in das Sie folgenden Code eingeben können:
import FreeCAD
import Part
doc = FreeCAD.newDocument()
# Kugel
kugel = Part.makeSphere(10)
form_element = doc.addObject("Part::Feature", "Kugel")
form_element.Shape = kugel
kug = FreeCAD.ActiveDocument.getObject("Kugel")
kug.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
neuePosition = App.Vector(5, 2.5, 2.5)
kug.Placement = App.Placement(neuePosition, kug.Placement.Rotation)
# Quader
quader = Part.makeBox(5, 5, 50)
form_element = doc.addObject("Part::Feature", "Quader")
form_element.Shape = quader
quad = FreeCAD.ActiveDocument.getObject("Quader")
quad.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
doc.recompute()
Diesen Code können Sie nun ausführen:
* Makro > Makro ausführen
Es ergibt sich folgende Ausgabe (gedreht und gezoomt):
[[Datei: PythonIng_freecad1.png|500px]]
Siehe auch [https://wiki.freecad.org/Python_scripting_tutorial/de# Anleitung Skripterstellung mit Python]. Getestet wurde obiges Beispiel mit FreeCAD 1.1.3 unter Linux und 1.1.1 unter MS Windows.
== LibreOffice ==
LibreOffice ist ein freies Officepaket ([https://de.libreoffice.org/]). Hier soll nur das Tabellenkalkulationsprogramm Calc kurz betrachtet werden. Es seinen in den ersten 3 Zellen (A1 bis A3) Zahlen gegeben. Diese sollen mit einem Python-Makro addiert und das Resultat in der Zelle A5 ausgegeben werden. Auch hier sind Vorbereitungsarbeiten nötig:
* zuerst muss unter Linux das Verzeichnis <code>~/.config/libreoffice/4/user/Scripts/python</code> erstellt werden
* für MS Windows ist es das Verzeichnis <code>%APPDATA%\LibreOffice\4\user\Scripts\python</code>
** drücken Sie zuerst Win + R (es öffnet sich das Ausführen-Fenster)
** geben Sie <code>%appdata%</code> ein, danach drücken Sie Enter (es öffnet sich der Explorer)
** navigieren Sie zu dem genannten Verzeichnis bzw. erstellen Sie das Verzeichnis
* in diesem Verzeichnis wird dann mit einem beliebigen Texteditor das Python-Makro erstellt, in unserem Fall die Datei <code>summiere_zellen.py</code>:
import uno
def summiere_zellen(*args):
# Zugriff auf das aktuelle Dokument und das aktive Tabellenblatt
ctx = uno.getComponentContext()
smgr = ctx.getServiceManager()
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.getCurrentController().getActiveSheet()
# Werte aus den Zellen A1 bis A3 auslesen
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
# Addition der drei Werte
summe = w1 + w2 + w3
# Ergebnis in die Zelle A5 schreiben
sheet.getCellRangeByName("A5").Value = summe
* siehe dazu ggf. auch [https://help.libreoffice.org/latest/de/text/sbasic/python/python_locations.html?DbPAR=BASIC].
Weiter geht es in LibreOffice Calc mit dem Menü ''Extras > Makros > Makros verwalten > Python''. Dort wird das Makro <code>summiere_zellen</code> ausgeführt. Es ergibt sich z.B. folgendes Resultat
[[Datei:PythonIng_libreoffice1.png]]
Das Kürzel <code>uno</code> steht für '''U'''niversal '''N'''etwork '''O'''bjects. Etwas einfacher geht's auch so:
def summiere_zellen():
desktop = XSCRIPTCONTEXT.getDesktop()
model = desktop.getCurrentComponent()
sheets = model.getSheets()
sheet = sheets.getByIndex(0)
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
cell = sheet.getCellRangeByName("A5")
cell.setValue(w1 + w2 + w3)
Empfohlen wird auch, das Erweiterungspaket APSO ('''A'''lternative '''P'''ython '''S'''cript '''O'''rganizer, apso.oxt) zu installieren. Die Vorgehensweise wird hier nicht gezeigt, sondern nur darauf hingewiesen, dass man das einfach "googeln" kann. Siehe zur Python-Programmierung für LibreOffice auch [https://wiki.documentfoundation.org/Macros/Python_Guide/de Makros/Python-Handbuch]. Getestet wurden obige Beispiele mit LibreOffice 26.2.5.1 unter Linux und 26.2.1.2 unter MS Windows.
= Ausblick =
Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Python. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks, Bücher und die Python-Hilfefunktion verwiesen. Python kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Module fast beliebig erweiterbar.
= Weblinks=
== Python allgemein ==
* [https://www.python.org/ Python Homepage]
== Externe mathematische Module ==
* [https://numpy.org/ NumPy]
* [https://numpy.org/doc/stable/user/numpy-for-matlab-users.html NumPy for MATLAB users]
* [https://scipy.org/ SciPy]
* [https://www.sympy.org/en/index.html SymPy]
* [https://pandas.pydata.org/ pandas]
* [https://github.com/maroba/findiff findiff]
* [https://mpmath.org/ mpmath]
== Externe Module für Grafiken ==
* [https://matplotlib.org/ Matplotlib]
* [https://vpython.org/ VPython]
* [https://build123d.readthedocs.io/en/latest/ build123d]
* [https://docs.vtk.org/en/latest/api/python.html VTK]
* [https://docs.bokeh.org/en/latest/docs/first_steps.html bokeh]
* [https://py5coding.org/ py5]
== Erstellung von User Interfaces ==
* [https://docs.python.org/3/library/tkinter.html tkinter - Python interface to Tcl/Tk]
* [https://docs.python.org/3/library/curses.html curses - Terminal handling for character-cell displays]
* [https://wiki.qt.io/Qt_for_Python Qt for Python]
* [https://www.gtk.org/docs/language-bindings/python GTK and Python]
== Erstellen virtueller Umgebungen ==
* [https://docs.python.org/3/library/venv.html venv - Creation of virtual environments]
== Sonstige ==
* [https://python-control.readthedocs.io/en/stable/ Python Control Systems Library]
* [https://pypi.org/project/regex/ regex - Regular Expressions]
* [http://pyromat.org/ PYroMat]
* [https://coolprop.org/coolprop/wrappers/Python/index.html CoolProp]
* [https://pypi.org/project/iapws/ iapws]
* [https://tespy.readthedocs.io/en/main/getting_started/introduction.html TESPy - Thermal Engineering Systems in Python]
* [https://pint.readthedocs.io/en/stable/ pint]
= Bücher =
== Gedruckte Bücher, OpenBooks, Magazine ==
* Diverse: c't Python Lernen, Verstehen, Anwenden; Heise, 2022
* Ernesti, Kaiser: Python3 - das umfassende Handbuch; 5. Aufl., Rheinwerk, [https://openbook.rheinwerk-verlag.de/python/ OpenBook]
* Iacono et al.: Programmieren trainieren; 3. Aufl., Hanser, 2023, ISBN 978-3-446-47766-7
* Inden: Python Challenge; dpunkt, 2021, ISBN 978-3-86490-809-5
* Klein: Numerisches Python; 2. Aufl., Hanser, 2023, ISBN 978-3-446-47170-2
* Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler; Rheinwerk, 2021, ISBN 978-3-8362-7316-9
* Weigend: Python 3 - Das umfassende Praxisbuch; 9. Aufl., mitp, 2022, ISBN 978-3-7475-0544-1
* Woyand: Python für Ingenieure und Naturwissenschaftler; 4. Aufl., Hanser, 2021, ISBN 978-3-446-46483-4
== Andere Wikibooks ==
* [[:en:Subject:Python_programming_language | Englische Wikibooks zum Thema Python]]
* [[Python|Deutschsprachiges Python-Wikibook]] [[Bild:2von10.png|20%]]
* [[Python unter Linux|Python 2.7 unter Linux]] [[Bild:10von10.png|100%]]
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
b5rwtgczlmlk7wn53xv7tn8ku7w8cmh
Traktorenlexikon: Allis-Chalmers 7050
0
123163
1091889
2026-10-03T13:14:10Z
Baupit
56622
Neue Seite (vgl. [[WB:AZ]])
1091889
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = ALLIS-CHALMERS
| MODELLREIHE = 7.000 er - Baureihe
| MODELL = 7050
| BILD =
| BILDBESCHREIBUNG =
| BAUWEISE = Blockbauweise
| PRODUKTIONSBEGINN = 1973
| PRODUKTIONSENDE = 1974
| STÜCKZAHL = 2.302
| EIGENGEWICHT = 4.908
| LÄNGE = 4.140
| BREITE = 2.426
| HÖHE = 2.184
| RADSTAND = 2.692
| BODENFREIHEIT = 559
| SPURWEITE =
| SPURWEITE VORNE = 1.664-2.273
| SPURWEITE HINTEN = 1.727-2.337
| WENDERADIUS MIT LENKBREMSE = 3.658
| WENDERADIUS OHNE LENKBREMSE = 5.003
| BEREIFUNG VORNE = 14 L-16.1 ASF
| BEREIFUNG HINTEN = 20.8-38 AS
| LEISTUNG KW = 117,7
| LEISTUNG PS = 160
| NENNDREHZAHL = 2.300
| ZYLINDER = 6
| HUBRAUM = 6.982
| DREHMOMENTANSTIEG =
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Wasserkühlung
| ANTRIEBSTYP = Heckantrieb
| GETRIEBE = 20 V/4 R
| HÖCHSTGESCHWINDIGKEIT = 30
| KATEGORIESORTIERUNG =
}}
Parallel wurden im Jahr 1973 die ALLIS-CHALMERS Modelle 7030 und 7050 vorgestellt. Mit diesen Schleppern zielte ALLIS-CHALMERS ganz bewusst auf leistungsstarke Reihenkulturschlepper ab, ein Markt der lange Zeit von JOHN DEERE, INTERNATIONAL HARVESTER und CASE dominiert worden war. Diese beiden Traktoren teilen sich das gleiche Aggregat, jedoch wurde beim ALLIS-CHALMERS 7050 ein Ladeluftkühler hinzugefügt. Verblockt war dieses Aggregat mit einem zweistufigen 20/4-Gänge Schnellganggetriebe. Zusätzlich war das CLOSED-CENTER-Hydrauliksystem mit LOAD-SENSING, ein weiters wichtiges Verkaufsargumente.
==Motor==
* ALLIS-CHALMERS, Typ: 3700 TI, stehender-wassergekühlter Viertakt-Sechszylinder-Reihen-OHC-Saugmotor mit Direkteinspritzverfahren, hängenden Ventilen, zahnradgetriebener Nockenwelle, Kolben-Ölkühlung, ROOSA-MASTER-Einspritzpumpe, Leichtmetall-Kolben, Trockenluftfilter, siebenfach-gelagerter Kurbelwelle, mechanischer Fliehkraftregler, Turbolader incl. Ladeluftkühlung, Druckumlaufschmierung mittels Zahnradpumpe, Motorölkühler, ALLIS-CHALMERS-Mehrlochdüse und Lamellenkühler mit Lüfter.
* Bohrung = 107,95 mm, Hub = 127 mm
* Verdichtungsverhältnis = 16:1
* Max. Drehmoment = 954 Nm bei 1.500 U/min.
* Mittlere Kolbengeschwindigkeit = 9,74 m/s
* Geregelter Drehzahlbereich = 700 bis 2.550 U/min
* Max. Einspritzdruck = 230 bar
* Roosa-Master Einspritzpumpe, Modell: DM-4
==Kupplung==
* Pedal-betätigte, trockene Einscheibenkupplung Typ: 12"
Fahrkupplung mit 304,8 mm Scheibendurchmesser
* Interne-nasse Lamellenkupplung als Zapfwellenkupplung ausgebildet
==Getriebe==
* Im Ölbad laufendes, synchronisiertes POWER-DIRECTOR-Getriebe
* Wechselgetriebe mit fünf Vorwärts-und einem Rückwärtsgang
* Mechanisches Gruppengetriebe mit zwei Gruppen, in die Gruppen L und H unterteilt
* Zweistufige hydraulische Lastschaltung, sie teilt jeden der mechanischen Gänge in zwei hydraulische Stufen (LOW / OVERDRIVE)
* Ölförderleistung = 51,1 l/min.
20 Vorwärts- und 4 Rückwärtsgänge
==Geschwindigkeiten vor- und rückwärts==
"Geschwindigkeiten mit Bereifung 20.8-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! GRUPPE - L / STUFE - LOW ||
|-
| 1.Gang || 2,57 km/h
|-
| 2.Gang || 4,99 km/h
|-
| 3.Gang || 6,92 km/h
|-
| 4.Gang || 9,01 km/h
|-
| 5.Gang || 11,43 km/h
|-
| 1.Rückwärtsgang || 4,67 km/h
|-
! GRUPPE - L / STUFE - OVERDRIVE ||
|-
| 1.Gang || 3,22 km/h
|-
| 2.Gang || 6,28 km/h
|-
| 3.Gang || 8,69 km/h
|-
| 4.Gang || 11,27 km/h
|-
| 5.Gang || 14,16 km/h
|-
| 2.Rückwärtsgang || 5,95 km/h
|-
! GRUPPE - H / STUFE - LOW !!
|-
| 1.Gang || 5,63 km/h
|-
| 2.Gang || 11,27 km/h
|-
| 3.Gang || 15,45 km/h
|-
| 4.Gang || 20,12 km/h
|-
| 5.Gang || 25,27 km/h
|-
| 3.Rückwärtsgang || 10,46 km/h
|-
! GRUPPE - H / STUFE - OVERDRIVE !!
|-
| 1.Gang || 7,08 km/h
|-
| 2.Gang || 14,16 km/h
|-
| 3.Gang || 19,47 km/h
|-
| 4.Gang || 25,11 km/h
|-
| 5.Gang || 31,70 km/h
|-
| 4.Rückwärtsgang || 13,20 km/h
|-
|}
==Zapfwelle==
* Mechanisch-betätigte, unabhängige und lastschaltbare Motorzapfwelle
* Stummel = 1 3/8"- 6 Keile oder 1 3/8"- 20 teilig
* Zweifach schaltbar, 540/1.000 U/min.
* 540 U/min. mit 2.230 U/min.- Motordrehzahl
Oder 557 U/min. mit Nenndrehzahl
* 1.000 U/min. mit 2.253 U/min.- Motordrehzahl
Übertragbare Leistung = 158,8 DIN-PS
* Oder 1.021 U/min. mit Nenndrehzahl
Übertragbare Leistung = 158,7 DIN-PS
==Bremsen==
* Pedal-betätigte, nasse Mehrscheibenbremse auf die Differentialseitenwellen wirkend, als Einzelrad-Bremse ausgebildet
* Handhebel-betätigte Feststellbremse auf die Getriebe-Zwischenwelle wirkend
==Achsen==
* Pendelnd-aufgehängte Stahlvorderachse
Verstellbare Spurweite mit Bereifung 14 L-16.1 = 1.664 bis 2.273 mm (Bereifung 10.00-16 = 1.524 bis 2.235 mm und Bereifung 11.00-16 = 1.575 bis 2.286 mm)
* Hinterachse mit Kegelradgetriebe und Endantrieb als Stirnradübersetzung
* Mechanisch-betätigte Differentialsperre
Verstellbare Spurweite mit Bereifung 18.4-38 und 20.8-38 = 1.727 bis 2.337 mm (Bereifung 24.5-32 = 1.803 bis 2.642 mm und Bereifung 30.5-32 = 1.880 bis 2.794 mm)
Mit langer Achse und Bereifung 18.4-38 und 20.8-38 = 1.727 bis 2.870 mm (Bereifung 24.5-32 = 1.803 bis 3.175 mm und Bereifung 30.5-32 = 1.880 bis 3.327 mm)
* Vordere Achslast = 1.789 kg
* Hintere Achslast = 4.799 kg
==Lenkung==
* Hydrostatische Lenkung
Förderleistung = 35,96 l/min.
==Hydrauliksystem und Kraftheber==
* Hydraulischer Blockkraftheber mit Unterlenkerregelung
* Einfachwirkender Hubzylinder
* Dreipunktkupplung der Kategorie III/II
"Funktionen:"
* Heben, Senken, Schwimmstellung, Zugkraft- und Lageregelung
* LOAD-SENSING System mit einer Förderleistung von 83,3 l/min bei 175 bar und Nenndrehzahl
Max. Hubkraft 610 mm hinter den Koppelpunkten = 3.039 kg
==Steuergeräte==
* Ein einfach- oder doppelt-wirkendes Steuergerät
* Auf Wunsch bis zu drei einfach- oder doppelt-wirkende Steuergeräte
==Elektrische Ausrüstung==
"12 Volt-Einrichtung"
==Maße und Abmessungen==
* Länge über alles = 4.140 mm
* Breite je nach Hinterachse = 2.426 bis 2.946 mm
* Höhe über Motorhaube = 1.727 mm
* Höhe über Lenkrad = 2.184 mm
* Höhe über Auspuff = 2.946 mm
* Radstand = 2.692 mm
* Bodenfreiheit unter der Vorderachse = 559 mm
* Betriebsgewicht = 6.588 kg
==Bereifung==
"Standardbereifung:"
* Vorne = 14 L-16.1 AS Front
* Hinten = 20.8-38 AS
"Optional:"
* Vorne = 10.00-16 und 11.00-16 AS Front
* Hinten = 18.4-38, 20.8-34, 24.5-32 und 30.5-32 AS
==Füllmengen==
* Tankinhalt = 193,0 l (Optional plus Zusatztank = 63,0 l)
* Motoröl mit Filter = 18,0 bis 23,7 l
* Kühlsystem = 30,3 l
* Getriebe = 28,0 l
* Differential = 63,2 l
==Verbrauch==
* Kraftstoffverbrauch = 37,2 l/h bei 116,7 kW und Nenndrehzahl
==Kabine==
* Gummigelagerte Sicherheitskabine (79,5 dB) mit Komfortsitz, Öldruck- und Batterieanzeige, Motortemperaturanzeige, Kraftstoffanzeige, Traktormeter mit Betriebsstunden, verstellbares Lenkrad, Heizung, Aschenbecher, integriertes Frischluft-Überdrucksystem und ausstellbare Seitenscheiben.
* Optional: Radio, Luxussitz, Klimaanlage und Arbeitsscheinwerfer
==Sonderausrüstung==
* Zusatzgewichte
* Arbeitsscheinwerfer
* Klimaanlage
* Radio
* PowerShift-Triebwerk
==Literatur & Weblinks==
* tractordata.com
* Allis-Chalmers Agricultural Equipment Brochure
* koneviesti.fi
* digitalcommons.unl.edu (Test-Nr. 1120/73)
<references />
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
cngt2a3rogt85nnamz5uuuha0trig1p
Traktorenlexikon: Allis-Chalmers 7060
0
123164
1091894
2026-10-03T17:32:47Z
Baupit
56622
Neue Seite (vgl. [[WB:AZ]])
1091894
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = ALLIS-CHALMERS
| MODELLREIHE = 7.000 er - Baureihe
| MODELL = 7060
| BILD =
| BILDBESCHREIBUNG =
| BAUWEISE = Blockbauweise
| PRODUKTIONSBEGINN = 1974
| PRODUKTIONSENDE = 1981
| STÜCKZAHL = 7.796
| EIGENGEWICHT = 6.346/6.643
| LÄNGE = 4.140
| BREITE = 2.426
| HÖHE = 2.210
| RADSTAND = 2.692
| BODENFREIHEIT = 533
| SPURWEITE =
| SPURWEITE VORNE = 1.600-2.311
| SPURWEITE HINTEN = 1.676-2.845
| WENDERADIUS MIT LENKBREMSE = 3.658
| WENDERADIUS OHNE LENKBREMSE = 5.004
| BEREIFUNG VORNE = 14 L-16.1 ASF
| BEREIFUNG HINTEN = 20.8-38 AS
| LEISTUNG KW = 141,2
| LEISTUNG PS = 192
| NENNDREHZAHL = 2.300
| ZYLINDER = 6
| HUBRAUM = 6.982
| DREHMOMENTANSTIEG =
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Wasserkühlung
| ANTRIEBSTYP = Heckantrieb
| GETRIEBE = 20 V/4 R oder 12 V/2 R
| HÖCHSTGESCHWINDIGKEIT = 30
| KATEGORIESORTIERUNG =
}}
Ende des Jahres 1974 löste der leistungsstärkere ALLIS-CHALMERS 7060, das Modell 7050 ab. Der verwendete hauseigene Sechszylinder-Turbodiesel mit Ladeluftkühlung leistete 192 PS. Mit einem 12/2-Gänge POWERSHIFT-Teillastschaltgetriebe und einem 20/4-Gänge POWER-DIRECTOR Triebwerk, standen zwei Getriebevarianten zur Auswahl. Für die damalige Zeit recht fortschrittlich, war das druck- und durchflusskompensiertes Hydrauliksystem und die als ACOUSTA-CAB bezeichnete Kabine. Mit 7.796 Exemplaren war der ALLIS-CHALMERS 7060, das meistgebaute Modell der 7000 er-Reihe. Im Jahr 1978 wurde das Design angepasst. Dabei wurde die neue ACOUSTA-CAB II eingeführt und die Lackierung des Fahrgestells wechselte von Orange auf Schwarz.
==Motor==
* ALLIS-CHALMERS, Typ: 3700 TI, stehender-wassergekühlter Viertakt-Sechszylinder-Reihen-OHC-Saugmotor mit Direkteinspritzverfahren, hängenden Ventilen, zahnradgetriebener Nockenwelle, Kolben-Ölkühlung, ROOSA-MASTER-Einspritzpumpe, Leichtmetall-Kolben, Trockenluftfilter, siebenfach-gelagerter Kurbelwelle, mechanischer Fliehkraftregler, Turbolader incl. Ladeluftkühlung, Druckumlaufschmierung mittels Zahnradpumpe, Motorölkühler, Mehrlochdüse und Lamellenkühler mit Lüfter.
* Bohrung = 107,95 mm, Hub = 127 mm
* Verdichtungsverhältnis = 16:1
* Max. Drehmoment = 813 Nm bei 1.500 U/min.
* Mittlere Kolbengeschwindigkeit = 9,74 m/s
* Geregelter Drehzahlbereich = 700 bis 2.645 U/min
* Max. Einspritzdruck = 230 bar
==Kupplung==
* Pedal-betätigte, trockene Einscheibenkupplung Typ: 12"
Fahrkupplung mit 304,8 mm Scheibendurchmesser
* Interne-nasse Lamellenkupplung als Zapfwellenkupplung ausgebildet
==Getriebe==
* Im Ölbad laufendes, synchronisiertes POWER-DIRECTOR-Getriebe
* Wechselgetriebe mit fünf Vorwärts-und einem Rückwärtsgang
* Mechanisches Gruppengetriebe mit zwei Gruppen, in die Gruppen L und H unterteilt
* Zweistufige hydraulische Lastschaltung, sie teilt jeden der mechanischen Gänge in zwei hydraulische Stufen (LOW / OVERDRIVE)
* Ölförderleistung = 51,1 l/min.
20 Vorwärts- und 4 Rückwärtsgänge
"Optional:"
* Im Ölbad laufendes, synchronisiertes POWER-SHIFT-Getriebe
* Sechs Lastschaltstufen die ohne Betätigung des Kupplungspedals, unter voller Last direkt nacheinander hoch- oder runtergeschaltet werden können
* Die Lastschalteinheit verfügt über drei Planetenradsätze und sechs hydraulisch-betätigten Lamellenkupplungen
* Innerhalb jeder gewählten Gruppe stehen sechs Gänge zur Verfügung
* Mechanisches Gruppengetriebe mit zwei Gruppen, in die Gruppen L und H unterteilt
12 Vorwärts- und 2 Rückwärtsgänge
==Geschwindigkeiten vor- und rückwärts==
"Geschwindigkeiten 20/4-Triebwerk, mit Bereifung 20.8-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! GRUPPE - L / STUFE - LOW ||
|-
| 1.Gang || 2,74 km/h
|-
| 2.Gang || 5,47 km/h
|-
| 3.Gang || 7,56 km/h
|-
| 4.Gang || 8,37 km/h
|-
| 5.Gang || 11,27 km/h
|-
| 1.Rückwärtsgang || 5,15 km/h
|-
! GRUPPE - L / STUFE - OVERDRIVE ||
|-
| 1.Gang || 3,38 km/h
|-
| 2.Gang || 6,76 km/h
|-
| 3.Gang || 9,33 km/h
|-
| 4.Gang || 10,46 km/h
|-
| 5.Gang || 14,00 km/h
|-
| 2.Rückwärtsgang || 6,28 km/h
|-
! GRUPPE - H / STUFE - LOW !!
|-
| 1.Gang || 6,12 km/h
|-
| 2.Gang || 12,23 km/h
|-
| 3.Gang || 16,74 km/h
|-
| 4.Gang || 18,67 km/h
|-
| 5.Gang || 25,27 km/h
|-
| 3.Rückwärtsgang || 11,43 km/h
|-
! GRUPPE - H / STUFE - OVERDRIVE !!
|-
| 1.Gang || 7,56 km/h
|-
| 2.Gang || 15,13 km/h
|-
| 3.Gang || 20,76 km/h
|-
| 4.Gang || 23,17 km/h
|-
| 5.Gang || 31,22 km/h
|-
| 4.Rückwärtsgang || 14,00 km/h
|-
|}
"Geschwindigkeiten 12/2-Triebwerk, mit Bereifung 20.8-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! STUFE - LOW ||
|-
| 1.Gang || 2,90 km/h
|-
| 2.Gang || 4,02 km/h
|-
| 3.Gang || 5,63 km/h
|-
| 4.Gang || 7,08 km/h
|-
| 5.Gang || 8,69 km/h
|-
| 6.Gang || 10,94 km/h
|-
| 1.Rückwärtsgang || 4,83 km/h
|-
! STUFE - OVERDRIVE !!
|-
| 1.Gang || 7,89 km/h
|-
| 2.Gang || 10,94 km/h
|-
| 3.Gang || 15,13 km/h
|-
| 4.Gang || 18,99 km/h
|-
| 5.Gang || 23,50 km/h
|-
| 6.Gang || 29,61 km/h
|-
| 2.Rückwärtsgang || 12,87 km/h
|-
|}
==Zapfwelle==
* Mechanisch-betätigte, unabhängige und lastschaltbare Motorzapfwelle
* Stummel = 1 3/8"- 6 Keile oder 1 3/8"- 20 teilig
* Zweifach schaltbar, 540/1.000 U/min.
* 540 U/min. mit 2.230 U/min.- Motordrehzahl
Oder 557 U/min. mit Nenndrehzahl
* 1.000 U/min. mit 2.253 U/min.- Motordrehzahl
Übertragbare Leistung = 163,9 DIN-PS
* Oder 1.021 U/min. mit Nenndrehzahl
Übertragbare Leistung = 163,8 DIN-PS
==Bremsen==
* Pedal-betätigte, nasse Mehrscheibenbremse auf die Differentialseitenwellen wirkend, als Einzelrad-Bremse ausgebildet
* Handhebel-betätigte Feststellbremse auf die Getriebe-Zwischenwelle wirkend
==Achsen==
* Pendelnd-aufgehängte Stahlvorderachse
Verstellbare Spurweite mit Bereifung 14 L-16.1 = 1.600 bis 2.311 mm (Bereifung 10.00-16 = 1.524 bis 2.235 mm und Bereifung 11.00-16 = 1.575 bis 2.286 mm )
* Hinterachse mit Kegelradgetriebe und Endantrieb als Stirnradübersetzung
* Mechanisch-betätigte Differentialsperre
Verstellbare Spurweite mit Bereifung 20.8-38 = 1.676 bis 2.845 mm
* Vordere Achslast POWER-DIRECTOR = 1.753 kg
* Hintere Achslast POWER-DIRECTOR = 4.593 kg
* Vordere Achslast POWER-SHIFT = 1.783 kg
* Hintere Achslast POWER-SHIFT = 4.860 kg
==Lenkung==
* Hydrostatische Lenkung
Förderleistung = 35,96 l/min.
==Hydrauliksystem und Kraftheber==
* Hydraulischer Blockkraftheber mit Unterlenkerregelung
* Einfachwirkender Hubzylinder
* Dreipunktkupplung der Kategorie III/II
"Funktionen:"
* Heben, Senken, Schwimmstellung, Zugkraft- und Lageregelung
* LOAD-SENSING System mit einer Förderleistung von 83,3 l/min bei 175 bar und Nenndrehzahl
Max. Hubkraft 610 mm hinter den Koppelpunkten = 3.039 kg
==Steuergeräte==
* Ein einfach- oder doppelt-wirkendes Steuergerät
* Auf Wunsch bis zu drei einfach- oder doppelt-wirkende Steuergeräte
==Elektrische Ausrüstung==
"12 Volt-Einrichtung"
==Maße und Abmessungen==
* Länge über alles = 4.140 mm
* Breite über alles = 2.426 mm
* Höhe über Motorhaube = 1.727 mm
* Höhe über Lenkrad = 2.210 mm
* Höhe über Auspuff = 2.946 mm
* Radstand = 2.692 mm
* Bodenfreiheit unter der Vorderachse = 533 mm
* Betriebsgewicht mit POWER-DIRECTOR Getriebe = 6.346 kg
* Betriebsgewicht mit POWER-SHIFT Getriebe = 6.643 kg
==Bereifung==
"Standardbereifung:"
* Vorne = 14 L-16.1 AS Front
* Hinten = 20.8-38 AS
"Optional:"
* Vorne = 10.00-16 und 11.00-16 AS Front
* Hinten = 18.4-38, 20.8-34, 24.5-32 und 30.5-32 AS
==Füllmengen==
* Tankinhalt = 193,0 l (Optional plus Zusatztank = 63,0 l)
* Motoröl mit Filter = 18,0 l
* Kühlsystem = 29,3 l
* Getriebe = 28,0 l
* Differential = 63,2 l
==Verbrauch==
* Kraftstoffverbrauch = 38,5 l/h bei 120,4 kW und Nenndrehzahl
==Kabine==
* Gummigelagerte Sicherheitskabine (79,5 dB) mit Komfortsitz, Öldruck- und Batterieanzeige, Motortemperaturanzeige, Kraftstoffanzeige, Traktormeter mit Betriebsstunden, verstellbares Lenkrad, Heizung, Aschenbecher, integriertes Frischluft-Überdrucksystem und ausstellbare Seitenscheiben.
* Optional: Radio, Luxussitz, Klimaanlage und Arbeitsscheinwerfer
==Sonderausrüstung==
* Zusatzgewichte
* Arbeitsscheinwerfer
* Klimaanlage
* Radio
* PowerShift-Triebwerk
==Literatur & Weblinks==
* tractordata.com
* Allis-Chalmers Agricultural Equipment Brochure
* koneviesti.fi
* digitalcommons.unl.edu (Test-Nr. 1167/74 + 1197/75)
<references />
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
il47bcfrn5c4xfbnw12xrmc4ddij25d
Traktorenlexikon: Allis-Chalmers 7080
0
123165
1091896
2026-10-03T18:36:55Z
Baupit
56622
Neue Seite (vgl. [[WB:AZ]])
1091896
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = ALLIS-CHALMERS
| MODELLREIHE = 7.000 er - Baureihe
| MODELL = 7080
| BILD =
| BILDBESCHREIBUNG =
| BAUWEISE = Blockbauweise
| PRODUKTIONSBEGINN = 1975
| PRODUKTIONSENDE = 1981
| STÜCKZAHL = 7.796
| EIGENGEWICHT = 6.625
| LÄNGE = 4.140
| BREITE = 2.426
| HÖHE = 2.210
| RADSTAND = 2.692
| BODENFREIHEIT = 533
| SPURWEITE =
| SPURWEITE VORNE = 1.816-2.527
| SPURWEITE HINTEN = 1.727-3.251
| WENDERADIUS MIT LENKBREMSE = 3.810
| WENDERADIUS OHNE LENKBREMSE = 5.156
| BEREIFUNG VORNE = 18.4-16.1 ASF
| BEREIFUNG HINTEN = 20.8-38 AS
| LEISTUNG KW = 150,8
| LEISTUNG PS = 205
| NENNDREHZAHL = 2.550
| ZYLINDER = 6
| HUBRAUM = 6.982
| DREHMOMENTANSTIEG =
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Wasserkühlung
| ANTRIEBSTYP = Heckantrieb
| GETRIEBE = 20 V/4 R
| HÖCHSTGESCHWINDIGKEIT = 30
| KATEGORIESORTIERUNG =
}}
Der im Jahr 1975 eingeführte ALLIS-CHALMERS war das Spitzenmodell der Baureihe. Der verwendete hauseigene Sechszylinder-Turbodiesel mit Ladeluftkühlung leistete 205 DIN-PS bzw. 210 SAE-PS. Bis zum Jahr 1978 wurde das verwendete Aggregat als Typ: 3750 MARK II bezeichnet, in der Folge änderte sich die Typenbezeichnung in 670 HI. Serienmäßig stand das 20/4-Gänge POWER-DIRECTOR Triebwerk zur Verfügung. Für die damalige Zeit recht fortschrittlich, war das druck- und durchflusskompensiertes Hydrauliksystem und die als ACOUSTA-CAB bezeichnete Kabine. Im Jahr 1978 wurde das Design angepasst. Dabei wurde die neue ACOUSTA-CAB II eingeführt und die Lackierung des Fahrgestells wechselte von Orange auf Schwarz.
==Motor==
* ALLIS-CHALMERS, Typ: 3750 MARK-II bzw. 670 HI, stehender-wassergekühlter Viertakt-Sechszylinder-Reihen-OHC-Saugmotor mit Direkteinspritzverfahren, hängenden Ventilen, zahnradgetriebener Nockenwelle, Kolben-Ölkühlung, ROOSA-MASTER-Einspritzpumpe, Leichtmetall-Kolben, Trockenluftfilter, siebenfach-gelagerter Kurbelwelle, mechanischer Fliehkraftregler, Turbolader incl. Ladeluftkühlung, Druckumlaufschmierung mittels Zahnradpumpe, Motorölkühler, Mehrlochdüse und Lamellenkühler mit Lüfter.
* Bohrung = 107,95 mm, Hub = 127 mm
* Verdichtungsverhältnis = 16:1
* Mittlere Kolbengeschwindigkeit = 10,8 m/s
* Geregelter Drehzahlbereich = 725 bis 2.850 U/min
* Max. Einspritzdruck = 230 bar
==Kupplung==
* Pedal-betätigte, trockene Einscheibenkupplung Typ: 12"
Fahrkupplung mit 304,8 mm Scheibendurchmesser
* Interne-nasse Lamellenkupplung als Zapfwellenkupplung ausgebildet
==Getriebe==
* Im Ölbad laufendes, synchronisiertes POWER-DIRECTOR-Getriebe
* Wechselgetriebe mit fünf Vorwärts-und einem Rückwärtsgang
* Mechanisches Gruppengetriebe mit zwei Gruppen, in die Gruppen L und H unterteilt
* Zweistufige hydraulische Lastschaltung, sie teilt jeden der mechanischen Gänge in zwei hydraulische Stufen (LOW / OVERDRIVE)
* Ölförderleistung = 51,1 l/min.
20 Vorwärts- und 4 Rückwärtsgänge
==Geschwindigkeiten vor- und rückwärts==
"Geschwindigkeiten mit Bereifung 20.8-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.550
|-
! GRUPPE - L / STUFE - LOW ||
|-
| 1.Gang || 2,57 km/h
|-
| 2.Gang || 5,15 km/h
|-
| 3.Gang || 7,08 km/h
|-
| 4.Gang || 7,89 km/h
|-
| 5.Gang || 10,78 km/h
|-
| 1.Rückwärtsgang || 4,83 km/h
|-
! GRUPPE - L / STUFE - OVERDRIVE ||
|-
| 1.Gang || 3,22 km/h
|-
| 2.Gang || 6,44 km/h
|-
| 3.Gang || 8,85 km/h
|-
| 4.Gang || 9,82 km/h
|-
| 5.Gang || 13,20 km/h
|-
| 2.Rückwärtsgang || 5,95 km/h
|-
! GRUPPE - H / STUFE - LOW !!
|-
| 1.Gang || 5,79 km/h
|-
| 2.Gang || 11,59 km/h
|-
| 3.Gang || 15,77 km/h
|-
| 4.Gang || 17,70 km/h
|-
| 5.Gang || 23,82 km/h
|-
| 3.Rückwärtsgang || 10,78 km/h
|-
! GRUPPE - H / STUFE - OVERDRIVE !!
|-
| 1.Gang || 7,08 km/h
|-
| 2.Gang || 14,16 km/h
|-
| 3.Gang || 19,47 km/h
|-
| 4.Gang || 21,89 km/h
|-
| 5.Gang || 29,45 km/h
|-
| 4.Rückwärtsgang || 13,20 km/h
|-
|}
==Zapfwelle==
* Mechanisch-betätigte, unabhängige und lastschaltbare Motorzapfwelle
* Stummel = 1 3/8"- 20 teilig
* Einfach schaltbar, 1.000 U/min.
* 996 U/min. mit Nenndrehzahl
Übertragbare Leistung = 184,0 DIN-PS
==Bremsen==
* Pedal-betätigte, nasse Mehrscheibenbremse auf die Differentialseitenwellen wirkend, als Einzelrad-Bremse ausgebildet
* Handhebel-betätigte Feststellbremse auf die Getriebe-Zwischenwelle wirkend
==Achsen==
* Pendelnd-aufgehängte Stahlvorderachse
Verstellbare Spurweite mit Bereifung 18.4-16.1 = 1.816 bis 2.527 mm
* Hinterachse mit Kegelradgetriebe und Endantrieb als Stirnradübersetzung
* Mechanisch-betätigte Differentialsperre
Verstellbare Spurweite mit Bereifung 20.8-38 = 1.727 bis 3.251 mm
* Vordere Achslast = 1.857 kg
* Hintere Achslast = 4.767 kg
==Lenkung==
* Hydrostatische Lenkung
Förderleistung = 35,96 l/min.
==Hydrauliksystem und Kraftheber==
* Hydraulischer Blockkraftheber mit Unterlenkerregelung
* Einfachwirkender Hubzylinder
* Dreipunktkupplung der Kategorie III/II
"Funktionen:"
* Heben, Senken, Schwimmstellung, Zugkraft- und Lageregelung
* LOAD-SENSING System mit einer Förderleistung von 83,3 l/min bei 175 bar und Nenndrehzahl
Max. Hubkraft 610 mm hinter den Koppelpunkten = 3.039 kg
==Steuergeräte==
* Ein einfach- oder doppelt-wirkendes Steuergerät
* Auf Wunsch bis zu drei einfach- oder doppelt-wirkende Steuergeräte
==Elektrische Ausrüstung==
"12 Volt-Einrichtung"
==Maße und Abmessungen==
* Länge über alles = 4.140 mm
* Breite über alles = 2.426 mm
* Höhe über Motorhaube = 1.727 mm
* Höhe über Lenkrad = 2.210 mm
* Höhe über Auspuff = 2.946 mm
* Radstand = 2.692 mm
* Bodenfreiheit unter der Vorderachse = 533 mm
* Betriebsgewicht = 6.625 kg
==Bereifung==
"Standardbereifung:"
* Vorne = 18.4-16.1 AS Front
* Hinten = 20.8-38 AS
"Optional:"
* Vorne = 10.00-16 und 11.00-16 AS Front
* Hinten = 18.4-38, 24.5-32 und 30.5-32 AS
==Füllmengen==
* Tankinhalt = 242,0 l
* Motoröl mit Filter = 17,9 l
* Kühlsystem = 34,1 l
* Getriebe = 28,0 l
* Differential = 65,0 l
==Verbrauch==
* Kraftstoffverbrauch = 43,7 l/h bei 135,4 kW und Nenndrehzahl
==Kabine==
* Gummigelagerte Sicherheitskabine (79,5 dB) mit Komfortsitz, Öldruck- und Batterieanzeige, Motortemperaturanzeige, Kraftstoffanzeige, Traktormeter mit Betriebsstunden, verstellbares Lenkrad, Heizung, Aschenbecher, integriertes Frischluft-Überdrucksystem und ausstellbare Seitenscheiben.
* Optional: Radio, Luxussitz, Klimaanlage und Arbeitsscheinwerfer
==Sonderausrüstung==
* Zusatzgewichte
* Arbeitsscheinwerfer
* Klimaanlage
* Radio
==Literatur & Weblinks==
* tractordata.com
* Allis-Chalmers Agricultural Equipment Brochure
* koneviesti.fi
* digitalcommons.unl.edu (Test-Nr. 1168/74)
<references />
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
sen3cod1dzdqggj4581xz9epoexppby
Traktorenlexikon: Allis-Chalmers 8010
0
123166
1091897
2026-10-03T19:07:40Z
Baupit
56622
Neue Seite (vgl. [[WB:AZ]])
1091897
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = ALLIS-CHALMERS
| MODELLREIHE = 8000 er- Serie
| MODELL = 8010
| BILD =
| BILDBESCHREIBUNG =
| BAUWEISE = Blockbauweise
| PRODUKTIONSBEGINN = 1982
| PRODUKTIONSENDE = 1985
| STÜCKZAHL =
| EIGENGEWICHT = 5.729 (4 WD: 6.168 kg)
| LÄNGE = 4.750
| BREITE = 2.352
| HÖHE = 2.896
| RADSTAND = 2.692 (4 WD: 2.438)
| BODENFREIHEIT = 533 (4 WD: 445)
| SPURWEITE =
| SPURWEITE VORNE = 1.524-2.235 (1.575-1.778)
| SPURWEITE HINTEN = 1.499-2.464
| WENDERADIUS MIT LENKBREMSE = 3.670 (4 WD: 4.064)
| WENDERADIUS OHNE LENKBREMSE = 4.250 (4 WD: 5.207)
| BEREIFUNG VORNE = 10.00-16 ASF (4 WD: 13.6-28 AS)
| BEREIFUNG HINTEN = 18.4 R 38 AS
| LEISTUNG KW = 78,7
| LEISTUNG PS = 107
| NENNDREHZAHL = 2.300
| ZYLINDER = 6
| HUBRAUM = 4.932
| DREHMOMENTANSTIEG =
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Wasserkühlung
| ANTRIEBSTYP = Heck- oder Allradantrieb
| GETRIEBE = 16 V/4 R, 20 V/4 und 12 V/2 R
| HÖCHSTGESCHWINDIGKEIT = 30
| KATEGORIESORTIERUNG =
}}
Die 8000 er-Serie kam 1981 auf den Markt und war gleichzeitig die letzte Standardtraktoren-Baureihe von ALLIS-CHALMERS. Dabei bot ALLIS CHALMERS in dieser Baureihe, erstmals Allradantrieb für seine Großtraktoren an. Der ALLIS-CHALMERS 8010 war das Einstiegsmodell der Baureihe und konnte mit seinem aufgeladenen Sechszylinder-Aggregat 107 DIN-PS abrufen. Dazu konnte zwischen drei Getriebevarianten gewählt werden. Die neue Kabine war serienmäßig mit Heizung und Klimaanlage ausgestattet und optional mit Radio und Kassettenspieler erhältlich.
==Motor==
* ALLIS-CHALMERS, Typ: 649 T, stehender wassergekühlter Viertakt-Sechszylinder-Reihen-Turbomotor mit Direkteinspritzverfahren, hängenden Ventilen, Mehrloch-Düse, zahnradgetriebener Nockenwelle, Kolbenkühlung, Reihen-Einspritzpumpe, siebenfach-gelagerter Kurbelwelle, Trockenluftfilter mit Vorabscheider, integrierter Motorölkühlung, Fliehkraft-Verstellregler, Leichtmetall-Kolben, Druckumlaufschmierung mittels Zahnradpumpe, AiResearch-Turbolader und Lamellenkühler mit Lüfter.
* Bohrung = 98,43 mm, Hub = 107,95 mm
* Verdichtungsverhältnis = 15,5:1
* Mittlere Kolbengeschwindigkeit = 8,28 m/s
* Geregelter Drehzahlbereich = 750 bis 2.580 U/min.
==Kupplung==
* Elektrohydraulisch-betätigte, nasse Mehrscheibenkupplung
==Getriebe==
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-DIRECTOR-Lastschaltgetriebe
* Synchronisiertes Wechselgetriebe mit vier Gängen
* Zweistufige Lastschaltung in die Bereiche: Lo und Hi unterteilt
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H und R unterteilt
16 Vorwärts- und 4 Rückwärtsgänge
"Optional:"
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-DIRECTOR-Lastschaltgetriebe
* Synchronisiertes Wechselgetriebe mit fünf Gängen
* Zweistufige Lastschaltung in die Bereiche: Lo und Hi unterteilt
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H und R unterteilt
20 Vorwärts- und 4 Rückwärtsgänge
"Wahlweise:"
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-SHIFT-Getriebe
* Synchronisiertes Wechselgetriebe mit sechs Vorwärts- und einem Rückwärtsgang
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H unterteilt
12 Vorwärts- und 2 Rückwärtsgänge
==Geschwindigkeiten vor- und rückwärts==
"Geschwindigkeiten Triebwerk 16/4, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! Gruppe - L ||
|-
| Laststufe - Lo ||
|-
| 1.Gang || 2,57 km/h
|-
| 2.Gang || 5,31 km/h
|-
| 3.Gang || 8,21 km/h
|-
| 4.Gang || 10,94 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 3,22 km/h
|-
| 2.Gang || 6,60 km/h
|-
| 3.Gang || 9,98 km/h
|-
| 4.Gang || 13,52 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 5,95 km/h
|-
| 2.Gang || 11,75 km/h
|-
| 3.Gang || 18,19 km/h
|-
| 4.Gang || 24,46 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 7,24 km/h
|-
| 2.Gang || 14,65 km/h
|-
| 3.Gang || 22,37 km/h
|-
| 4.Gang || 30,26 km/h
|-
! Rückwärtsgruppe !!
|-
! Gruppe - L !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 4,99 km/h
|-
| Laststufe - Hi ||
|-
| 2.Gang || 6,12 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 3.Gang || 10,94 km/h
|-
| Laststufe - Hi ||
|-
| 4.Gang || 13,52 km/h
|-
|}
"Geschwindigkeiten Triebwerk 20/4, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! Gruppe - L ||
|-
| Laststufe - Lo ||
|-
| 1.Gang || 2,57 km/h
|-
| 2.Gang || 5,31 km/h
|-
| 3.Gang || 7,24 km/h
|-
| 4.Gang || 8,21 km/h
|-
| 5.Gang || 10,94 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 3,22 km/h
|-
| 2.Gang || 6,60 km/h
|-
| 3.Gang || 9,01 km/h
|-
| 4.Gang || 9,98 km/h
|-
| 5.Gang || 13,52 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 5,95 km/h
|-
| 2.Gang || 11,75 km/h
|-
| 3.Gang || 16,25 km/h
|-
| 4.Gang || 18,19 km/h
|-
| 5.Gang || 24,46 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 7,24 km/h
|-
| 2.Gang || 14,65 km/h
|-
| 3.Gang || 20,12 km/h
|-
| 4.Gang || 22,37 km/h
|-
| 5.Gang || 30,26 km/h
|-
! Rückwärtsgruppe !!
|-
! Gruppe - L !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 4,99 km/h
|-
| Laststufe - Hi ||
|-
| 2.Gang || 6,12 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 3.Gang || 10,94 km/h
|-
| Laststufe - Hi ||
|-
| 4.Gang || 13,52 km/h
|-
|}
"Geschwindigkeiten Triebwerk 12/2, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! Gruppe - L ||
|-
| 1.Gang || 2,90 km/h
|-
| 2.Gang || 4,02 km/h
|-
| 3.Gang || 5,63 km/h
|-
| 4.Gang || 7,08 km/h
|-
| 5.Gang || 8,69 km/h
|-
| 6.Gang || 10,94 km/h
|-
| 1.Rückwärtsgang || 4,67 km/h
|-
! Gruppe - H !!
|-
| 1.Gang || 7,89 km/h
|-
| 2.Gang || 10,94 km/h
|-
| 3.Gang || 14,97 km/h
|-
| 4.Gang || 18,99 km/h
|-
| 5.Gang || 23,50 km/h
|-
| 6.Gang || 29,61 km/h
|-
| 2.Rückwärtsgang || 12,71 km/h
|-
|}
==Zapfwelle==
* Elektrohydraulisch-betätigte, kupplungsunabhängige Motorzapfwelle
* Stummel = 1 3/8"- 6 Keile und 1 3/8"- 21 teilig
* Zweifach schaltbar, 540/1.000 U/min.
* 540 U/min. bei 2.230 U/min.- Motordrehzahl
* 1.000 U/min. bei 2.252 U/min.- Motordrehzahl
Übertragbare Leistung = 111,1 DIN-PS
* Oder 1.021 U/min. mit Nenndrehzahl
Übertragbare Leistung = 108,9 DIN-PS
==Bremsen==
* Pedal-betätigte, hydraulisch-nasse Scheibenbremse, auf den Differentialseitenwellen wirkend, als Einzelrad-Bremse ausgebildet
Mechanisch-betätigte, unabhängige Feststellbremse, als trockene Scheibenbremse ausgebildet
==Achsen==
* Pendelnd-gelagerte Teleskop-Vorderachse
Verstellbare Spurweite = 1.524 bis 2.235 mm
* Pendelnd-gelagerte, elektrohydraulisch-betätigte und lastschaltbare Planetenachse, mit zentraler Gelenkwelle und Selbstsperrdifferential
Zwei Spurweiten durch Radumschlag = 1.575 oder 1.778 mm
* Hinterachse mit Kegelradgetriebe und Stirnradübersetzung
* Elektrohydraulisch-betätigte Differentialsperre
Verstellbare Spurweite = 1.499 bis 2.463 mm
* Vordere Achslast = 1.656 kg
* Hintere Achslast = 4.073 kg
==Lenkung==
* Hydrostatische Lenkung
Förderleistung = 36,0 l/min.
==Hydrauliksystem und Kraftheber==
* Hydraulischer Kraftheber, mit mechanischer Unterlenkerregelung und TRANSFERMATIC-System
* Einfachwirkender Hubzylinder
* Sicherheitsventil des Arbeitszylinder auf 260 bar eingestellt
* Dreipunktkupplung der Kategorie II mit Schnellkuppler
"Funktionen:"
* Heben, Senken, Neutral- und Schwimmstellung, Zugwiderstands- und Lageregelung sowie stufenlose Mischregelung
* Hubhöhenbegrenzung und hydraulisch-mechanische Transportsicherung
Open Center mit einer Förderleistung von 170,3 l/min. bei 178 bar
* Max. Hubkraft 610 mm hinter den Koppelpunkten = 3.030 kg
==Steuergeräte==
* Ein einfach- oder doppelt-wirkendes Steuergerät
* Auf Wunsch bis zu drei einfach- oder doppelt-wirkende Steuergeräte
==Elektrische Ausrüstung==
"12 Volt-Einrichtung"
==Maße und Abmessungen==
* Länge über alles = 4.750 mm
* Breite mit kleinster Spurweite = 2.352 mm
* Höhe über Motorhaube = 1.753 mm
* Höhe über Kabine = 2.896 mm
* Höhe über Auspuff = 2.870 mm
* Radstand = 2.692 mm (4 WD = 2.438 mm)
* Bodenfreiheit = 533 mm (4 WD = 445 mm)
* Betriebsgewicht = 5.729 kg (4 WD = 6.168 kg)
==Bereifung==
"Standardbereifung:"
* Vorne = 10.00-16 AS Front (4 WD = 13.6-28 AS)
* Hinten = 18.4 R 38 AS
"Optional:"
* Vorne = 11.00-16, 14 L-16 und 18.4-16 AS Front (4 WD = 14.9-24 und 14.9-28 AS)
* Hinten = 20.8-38, 16.9-38 und 18.4-42 AS
==Füllmengen==
* Tankinhalt = 227,0 l
* Motoröl mit Filter = 15,1 l
* Kühlsystem = 24,6 l
* Getriebe = 28,0 l
* Differential = 63,0 l
==Verbrauch==
* Kraftstoffverbrauch = 27,5 l/h bei 80,1 kW und Nenndrehzahl
==Kabine==
* Vollverglaste, gummigelagerte, staub- und schallisolierte Kabine mit ebenen Boden, Komfort-Sitz, Öldruck- und Ladeanzeige, Kraftstoffanzeige, Betriebsstundenzähler, höhenverstellbares Lenkrad, Heizung und Klimaanlage
* Optional mit Arbeitsscheinwerfern
==Sonderausrüstung==
* Zusatzgewichte
* Arbeitsscheinwerfer
==Literatur & Weblinks==
* tractordata.com
* Allis Corporation-Brochure
* digitalcommons.unl.edu (Test-Nr. 1446/82)
* koneviesti.fi
<references />
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
djbxqchs4un0lb1epaflcxtvvtfq8ah
Traktorenlexikon: Allis-Chalmers 8030
0
123167
1091899
2026-10-03T19:31:04Z
Baupit
56622
Neue Seite (vgl. [[WB:AZ]])
1091899
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = ALLIS-CHALMERS
| MODELLREIHE = 8000 er- Serie
| MODELL = 8030
| BILD =
| BILDBESCHREIBUNG =
| BAUWEISE = Blockbauweise
| PRODUKTIONSBEGINN = 1981
| PRODUKTIONSENDE = 1985
| STÜCKZAHL =
| EIGENGEWICHT = 5.194 (4 WD: 6.811 kg)
| LÄNGE = 4.750
| BREITE = 2.372
| HÖHE = 2.921
| RADSTAND = 2.692 (4 WD: 2.438)
| BODENFREIHEIT = 533 (4 WD: 445)
| SPURWEITE =
| SPURWEITE VORNE = 1.524-2.235 (1.575-1.778)
| SPURWEITE HINTEN = 1.499-2.464
| WENDERADIUS MIT LENKBREMSE = 3.800 (4 WD: 4.064)
| WENDERADIUS OHNE LENKBREMSE = 4.250 (4 WD: 5.207)
| BEREIFUNG VORNE = 10.00-16 ASF (4 WD: 13.6-28 AS)
| BEREIFUNG HINTEN = 18.4 R 38 AS
| LEISTUNG KW = 98,5
| LEISTUNG PS = 134
| NENNDREHZAHL = 2.300
| ZYLINDER = 6
| HUBRAUM = 6.981
| DREHMOMENTANSTIEG = 20
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Wasserkühlung
| ANTRIEBSTYP = Heck- oder Allradantrieb
| GETRIEBE = 16 V/4 R, 20 V/4 und 12 V/2 R
| HÖCHSTGESCHWINDIGKEIT = 30
| KATEGORIESORTIERUNG =
}}
Der ALLIS-CHALMERS 8030 war das zweite Modell der Baureihe und konnte mit seinem hauseigenen aufgeladenen Sechszylinder-Aggregat 134 DIN-PS abrufen. Dieses Aggregat verschaffte dem ALLIS-CHALMERS 8030 ein breiteres Drehmomentband und bessere Durchzugseigenschaften. Leider führte das zu einem höheren Kraftstoffverbrauch. Mit drei Getriebe-Varianten standen viele Einsatzmöglichkeiten offen.
==Motor==
* ALLIS-CHALMERS, Typ: 670 T, stehender wassergekühlter Viertakt-Sechszylinder-Reihen-Turbomotor mit Direkteinspritzverfahren, hängenden Ventilen, Mehrloch-Düse, zahnradgetriebener Nockenwelle, Kolbenkühlung, ROOSA-MASTER-Reihen-Einspritzpumpe, siebenfach-gelagerter Kurbelwelle, Trockenluftfilter mit Vorabscheider, integrierter Motorölkühlung, Fliehkraft-Verstellregler, Leichtmetall-Kolben, Druckumlaufschmierung mittels Zahnradpumpe, Abgas-Turbolader und Lamellenkühler mit Lüfter.
* Bohrung = 107,95 mm, Hub = 127 mm
* Verdichtungsverhältnis = 15,5:1
* Drehmoment = 414 Nm mit Nenndrehzahl
* Mittlere Kolbengeschwindigkeit = 9,74 m/s
* Geregelter Drehzahlbereich = 750 bis 2.580 U/min.
==Kupplung==
* Elektrohydraulisch-betätigte, nasse Mehrscheibenkupplung
==Getriebe==
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-DIRECTOR-Lastschaltgetriebe
* Synchronisiertes Wechselgetriebe mit vier Gängen
* Zweistufige Lastschaltung in die Bereiche: Lo und Hi unterteilt
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H und R unterteilt
16 Vorwärts- und 4 Rückwärtsgänge
"Optional:"
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-DIRECTOR-Lastschaltgetriebe
* Synchronisiertes Wechselgetriebe mit fünf Gängen
* Zweistufige Lastschaltung in die Bereiche: Lo und Hi unterteilt
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H und R unterteilt
20 Vorwärts- und 4 Rückwärtsgänge
"Wahlweise:"
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-SHIFT-Getriebe
* Synchronisiertes Wechselgetriebe mit sechs Vorwärts- und einem Rückwärtsgang
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H unterteilt
12 Vorwärts- und 2 Rückwärtsgänge
==Geschwindigkeiten vor- und rückwärts==
"Geschwindigkeiten Triebwerk 16/4, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! Gruppe - L ||
|-
| Laststufe - Lo ||
|-
| 1.Gang || 2,57 km/h
|-
| 2.Gang || 5,31 km/h
|-
| 3.Gang || 8,21 km/h
|-
| 4.Gang || 10,94 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 3,22 km/h
|-
| 2.Gang || 6,60 km/h
|-
| 3.Gang || 9,98 km/h
|-
| 4.Gang || 13,52 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 5,95 km/h
|-
| 2.Gang || 11,75 km/h
|-
| 3.Gang || 18,19 km/h
|-
| 4.Gang || 24,46 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 7,24 km/h
|-
| 2.Gang || 14,65 km/h
|-
| 3.Gang || 22,37 km/h
|-
| 4.Gang || 30,26 km/h
|-
! Rückwärtsgruppe !!
|-
! Gruppe - L !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 4,99 km/h
|-
| Laststufe - Hi ||
|-
| 2.Gang || 6,12 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 3.Gang || 10,94 km/h
|-
| Laststufe - Hi ||
|-
| 4.Gang || 13,52 km/h
|-
|}
"Geschwindigkeiten Triebwerk 20/4, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! Gruppe - L ||
|-
| Laststufe - Lo ||
|-
| 1.Gang || 2,57 km/h
|-
| 2.Gang || 5,31 km/h
|-
| 3.Gang || 7,24 km/h
|-
| 4.Gang || 8,21 km/h
|-
| 5.Gang || 10,94 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 3,22 km/h
|-
| 2.Gang || 6,60 km/h
|-
| 3.Gang || 9,01 km/h
|-
| 4.Gang || 9,98 km/h
|-
| 5.Gang || 13,52 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 5,95 km/h
|-
| 2.Gang || 11,75 km/h
|-
| 3.Gang || 16,25 km/h
|-
| 4.Gang || 18,19 km/h
|-
| 5.Gang || 24,46 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 7,24 km/h
|-
| 2.Gang || 14,65 km/h
|-
| 3.Gang || 20,12 km/h
|-
| 4.Gang || 22,37 km/h
|-
| 5.Gang || 30,26 km/h
|-
! Rückwärtsgruppe !!
|-
! Gruppe - L !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 4,99 km/h
|-
| Laststufe - Hi ||
|-
| 2.Gang || 6,12 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 3.Gang || 10,94 km/h
|-
| Laststufe - Hi ||
|-
| 4.Gang || 13,52 km/h
|-
|}
"Geschwindigkeiten Triebwerk 12/2, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! Gruppe - L ||
|-
| 1.Gang || 2,90 km/h
|-
| 2.Gang || 4,02 km/h
|-
| 3.Gang || 5,63 km/h
|-
| 4.Gang || 7,08 km/h
|-
| 5.Gang || 8,69 km/h
|-
| 6.Gang || 10,94 km/h
|-
| 1.Rückwärtsgang || 4,67 km/h
|-
! Gruppe - H !!
|-
| 1.Gang || 7,89 km/h
|-
| 2.Gang || 10,94 km/h
|-
| 3.Gang || 14,97 km/h
|-
| 4.Gang || 18,99 km/h
|-
| 5.Gang || 23,50 km/h
|-
| 6.Gang || 29,61 km/h
|-
| 2.Rückwärtsgang || 12,71 km/h
|-
|}
==Zapfwelle==
* Elektrohydraulisch-betätigte, kupplungsunabhängige Motorzapfwelle
* Stummel = 1 3/8"- 6 Keile und 1 3/8"- 21 teilig
* Zweifach schaltbar, 540/1.000 U/min.
* 540 U/min. bei 2.230 U/min.- Motordrehzahl
* 1.000 U/min. bei 2.252 U/min.- Motordrehzahl
Übertragbare Leistung = 136,3 DIN-PS
* Oder 1.021 U/min. mit Nenndrehzahl
Übertragbare Leistung = 135,6 DIN-PS
==Bremsen==
* Pedal-betätigte, hydraulisch-nasse Scheibenbremse, auf den Differentialseitenwellen wirkend, als Einzelrad-Bremse ausgebildet
Mechanisch-betätigte, unabhängige Feststellbremse, als trockene Scheibenbremse ausgebildet
==Achsen==
* Pendelnd-gelagerte Teleskop-Vorderachse
Verstellbare Spurweite = 1.524 bis 2.235 mm
* Pendelnd-gelagerte, elektrohydraulisch-betätigte und lastschaltbare Planetenachse, mit zentraler Gelenkwelle und Selbstsperrdifferential
Zwei Spurweiten durch Radumschlag = 1.575 oder 1.778 mm
* Hinterachse mit Kegelradgetriebe und Stirnradübersetzung
* Elektrohydraulisch-betätigte Differentialsperre
Verstellbare Spurweite = 1.499 bis 2.463 mm
* Vordere Achslast = 1.821 kg
* Hintere Achslast = 4.990 kg
==Lenkung==
* Hydrostatische Lenkung
Förderleistung = 36,0 l/min.
==Hydrauliksystem und Kraftheber==
* Hydraulischer Kraftheber, mit mechanischer Unterlenkerregelung und TRANSFERMATIC-System
* Einfachwirkender Hubzylinder
* Optional mit Zusatzhubzylinder
* Sicherheitsventil des Arbeitszylinder auf 260 bar eingestellt
* Dreipunktkupplung der Kategorie II mit Schnellkuppler
"Funktionen:"
* Heben, Senken, Neutral- und Schwimmstellung, Zugwiderstands- und Lageregelung sowie stufenlose Mischregelung
* Hubhöhenbegrenzung und hydraulisch-mechanische Transportsicherung
Geschlossenes System mit einer Förderleistung von 83,3 l/min. bei 178 bar
* Gesamte Förderleistung (Getriebe, Lenkung, Hydraulik) = 170,3 l/min.
Max. Hubkraft 610 mm hinter den Koppelpunkten = 3.030 kg (Optional = 3.720 kg)
==Steuergeräte==
* Ein einfach- oder doppelt-wirkendes Steuergerät
* Auf Wunsch bis zu drei einfach- oder doppelt-wirkende Steuergeräte
==Elektrische Ausrüstung==
"12 Volt-Einrichtung"
==Maße und Abmessungen==
* Länge über alles = 4.750 mm
* Breite mit kleinster Spurweite = 2.372 mm
* Höhe über Motorhaube = 1.753 mm
* Höhe über Kabine = 2.921 mm
* Höhe über Auspuff = 2.870 mm
* Radstand = 2.692 mm (4 WD = 2.438 mm)
* Bodenfreiheit = 533 mm (4 WD = 445 mm)
* Betriebsgewicht = 5.194 kg (4 WD = 6.811 kg)
==Bereifung==
"Standardbereifung:"
* Vorne = 10.00-16 AS Front (4 WD = 13.6-28 AS)
* Hinten = 18.4 R 38 AS
"Optional:"
* Vorne = 11.00-16, 14 L-16 und 18.4-16 AS Front (4 WD = 14.9-24 und 14.9-28 AS)
* Hinten = 20.8-38, 16.9-38 und 18.4-42 AS
==Füllmengen==
* Tankinhalt = 227,0 l
* Motoröl mit Filter = 18,0 l
* Kühlsystem = 29,3 l
* Getriebe = 28,0 l
* Differential = 63,0 l
==Verbrauch==
* Kraftstoffverbrauch = 33,6 l/h bei 99,7 kW und Nenndrehzahl
==Kabine==
* Vollverglaste, gummigelagerte, staub- und schallisolierte Kabine mit ebenen Boden, Komfort-Sitz, Öldruck- und Ladeanzeige, Kraftstoffanzeige, Betriebsstundenzähler, höhenverstellbares Lenkrad, Heizung und Klimaanlage
* Optional mit Arbeitsscheinwerfern
==Sonderausrüstung==
* Zusatzgewichte
* Arbeitsscheinwerfer
* Radio
==Literatur & Weblinks==
* tractordata.com
* Brochure Allis Corporation
* digitalcommons.unl.edu (Test-Nr. 1447/82)
* koneviesti.fi
<references />
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
jxwm57mcki1df4l7qci6c40f0mlt6vj
Traktorenlexikon: Allis-Chalmers 8050
0
123168
1091902
2026-10-03T19:45:00Z
Baupit
56622
Neue Seite (vgl. [[WB:AZ]])
1091902
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = ALLIS-CHALMERS
| MODELLREIHE = 8000 er- Serie
| MODELL = 8050
| BILD =
| BILDBESCHREIBUNG =
| BAUWEISE = Blockbauweise
| PRODUKTIONSBEGINN = 1981
| PRODUKTIONSENDE = 1985
| STÜCKZAHL = 2.336
| EIGENGEWICHT = 6.942 (4 WD: 7.393 kg)
| LÄNGE = 4.750
| BREITE = 2.426
| HÖHE = 2.921
| RADSTAND = 2.692 (4 WD: 2.438)
| BODENFREIHEIT = 559 (4 WD: 445)
| SPURWEITE =
| SPURWEITE VORNE = 1.600-2.311 (1.575-1.778)
| SPURWEITE HINTEN = 1.524-2.515
| WENDERADIUS MIT LENKBREMSE = 3.680 (4 WD: 4.064)
| WENDERADIUS OHNE LENKBREMSE = 4.270 (4 WD: 5.207)
| BEREIFUNG VORNE = 14 L-16 ASF (4 WD: 13.6-28 AS)
| BEREIFUNG HINTEN = 18.4 R 38 AS
| LEISTUNG KW = 113,3
| LEISTUNG PS = 154
| NENNDREHZAHL = 2.300
| ZYLINDER = 6
| HUBRAUM = 6.981
| DREHMOMENTANSTIEG =
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Wasserkühlung
| ANTRIEBSTYP = Heck- oder Allradantrieb
| GETRIEBE = 20 V/4 und 12 V/2 R
| HÖCHSTGESCHWINDIGKEIT = 30
| KATEGORIESORTIERUNG =
}}
Der ALLIS-CHALMERS 8050 war das dritte Modell der Baureihe und konnte mit seinem hauseigenen aufgeladenen Sechszylinder-Aggregat 154 DIN-PS abrufen. Er galt als direkter Nachfolge des ALLIS-CHALMERS 7060. Er besetzte die 150-PS-Klasse, die schon immer eine der verkaufsstärksten Sparten auf dem Markt darstellte. Dabei standen zwei Getriebevarianten zur Wahl. ALLIS CHALMERS bot erstmals Allradantrieb für seine Großtraktoren an.
==Motor==
* ALLIS-CHALMERS, Typ: 670 TI, stehender wassergekühlter Viertakt-Sechszylinder-Reihen-Turbomotor mit Direkteinspritzverfahren, hängenden Ventilen, Mehrloch-Düse, zahnradgetriebener Nockenwelle, Kolbenkühlung, ROOSA-MASTER-Reihen-Einspritzpumpe, siebenfach-gelagerter Kurbelwelle, Trockenluftfilter mit Vorabscheider, integrierter Motorölkühlung, Fliehkraft-Verstellregler, Leichtmetall-Kolben, Druckumlaufschmierung mittels Zahnradpumpe, Abgas-Turbolader incl. Ladeluftkühlung und Lamellenkühler mit Lüfter.
* Bohrung = 107,95 mm, Hub = 127 mm
* Verdichtungsverhältnis = 15,5:1
* Mittlere Kolbengeschwindigkeit = 9,74 m/s
* Geregelter Drehzahlbereich = 750 bis 2.580 U/min.
==Kupplung==
* Elektrohydraulisch-betätigte, nasse Mehrscheibenkupplung
==Getriebe==
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-DIRECTOR-Lastschaltgetriebe
* Synchronisiertes Wechselgetriebe mit fünf Gängen
* Zweistufige Lastschaltung in die Bereiche: Lo und Hi unterteilt
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H und R unterteilt
20 Vorwärts- und 4 Rückwärtsgänge
"Wahlweise:"
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-SHIFT-Getriebe
* Synchronisiertes Wechselgetriebe mit sechs Vorwärts- und einem Rückwärtsgang
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H unterteilt
12 Vorwärts- und 2 Rückwärtsgänge
==Geschwindigkeiten vor- und rückwärts==
"Geschwindigkeiten Triebwerk 20/4, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! Gruppe - L ||
|-
| Laststufe - Lo ||
|-
| 1.Gang || 2,74 km/h
|-
| 2.Gang || 5,47 km/h
|-
| 3.Gang || 7,56 km/h
|-
| 4.Gang || 8,37 km/h
|-
| 5.Gang || 11,43 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 3,38 km/h
|-
| 2.Gang || 6,76 km/h
|-
| 3.Gang || 9,33 km/h
|-
| 4.Gang || 10,46 km/h
|-
| 5.Gang || 14,00 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 6,12 km/h
|-
| 2.Gang || 12,23 km/h
|-
| 3.Gang || 16,74 km/h
|-
| 4.Gang || 18,83 km/h
|-
| 5.Gang || 25,27 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 7,56 km/h
|-
| 2.Gang || 15,13 km/h
|-
| 3.Gang || 20,76 km/h
|-
| 4.Gang || 23,17 km/h
|-
| 5.Gang || 31,22 km/h
|-
! Rückwärtsgruppe !!
|-
! Gruppe - L !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 5,15 km/h
|-
| Laststufe - Hi ||
|-
| 2.Gang || 6,28 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 3.Gang || 11,43 km/h
|-
| Laststufe - Hi ||
|-
| 4.Gang || 14,00 km/h
|-
|}
"Geschwindigkeiten Triebwerk 12/2, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.300
|-
! Gruppe - L ||
|-
| 1.Gang || 3,06 km/h
|-
| 2.Gang || 4,18 km/h
|-
| 3.Gang || 5,79 km/h
|-
| 4.Gang || 7,24 km/h
|-
| 5.Gang || 9,01 km/h
|-
| 6.Gang || 11,43 km/h
|-
| 1.Rückwärtsgang || 4,99 km/h
|-
! Gruppe - H !!
|-
| 1.Gang || 8,21 km/h
|-
| 2.Gang || 11,27 km/h
|-
| 3.Gang || 15,61 km/h
|-
| 4.Gang || 19,63 km/h
|-
| 5.Gang || 24,30 km/h
|-
| 6.Gang || 30,58 km/h
|-
| 2.Rückwärtsgang || 14,00 km/h
|-
|}
==Zapfwelle==
* Elektrohydraulisch-betätigte, kupplungsunabhängige Motorzapfwelle
* Stummel = 1 3/8"- 6 Keile und 1 3/8"- 21 teilig
* Zweifach schaltbar, 540/1.000 U/min.
* 540 U/min. bei 2.230 U/min.- Motordrehzahl
* 1.000 U/min. bei 2.252 U/min.- Motordrehzahl
Übertragbare Leistung = 157,3 DIN-PS
* Oder 1.021 U/min. mit Nenndrehzahl
Übertragbare Leistung = 154,5 DIN-PS
==Bremsen==
* Pedal-betätigte, hydraulisch-nasse Scheibenbremse, auf den Differentialseitenwellen wirkend, als Einzelrad-Bremse ausgebildet
Mechanisch-betätigte, unabhängige Feststellbremse, als trockene Scheibenbremse ausgebildet
==Achsen==
* Pendelnd-gelagerte Teleskop-Vorderachse
Verstellbare Spurweite = 1.600 bis 2.311 mm
* Pendelnd-gelagerte, elektrohydraulisch-betätigte und lastschaltbare Planetenachse, mit zentraler Gelenkwelle und Selbstsperrdifferential
Zwei Spurweiten durch Radumschlag = 1.575 oder 1.778 mm
* Hinterachse mit Kegelradgetriebe und Stirnradübersetzung
* Elektrohydraulisch-betätigte Differentialsperre
Verstellbare Spurweite = 1.524 bis 2.515 mm
* Vordere Achslast = 1.814 kg
* Hintere Achslast = 5.128 kg
==Lenkung==
* Hydrostatische Lenkung
Förderleistung = 36,0 l/min.
==Hydrauliksystem und Kraftheber==
* Hydraulischer Kraftheber, mit mechanischer Unterlenkerregelung und TRANSFERMATIC-System
* Einfachwirkender Hubzylinder
* Optional mit Zusatzhubzylinder
* Sicherheitsventil des Arbeitszylinder auf 260 bar eingestellt
* Dreipunktkupplung der Kategorie II mit Schnellkuppler
"Funktionen:"
* Heben, Senken, Neutral- und Schwimmstellung, Zugwiderstands- und Lageregelung sowie stufenlose Mischregelung
* Hubhöhenbegrenzung und hydraulisch-mechanische Transportsicherung
Geschlossenes System mit einer Förderleistung von 83,3 l/min. bei 178 bar
* Gesamte Förderleistung (Getriebe, Lenkung, Hydraulik) = 170,3 l/min.
Max. Hubkraft 610 mm hinter den Koppelpunkten = 3.030 kg (Optional = 3.720 kg)
==Steuergeräte==
* Ein einfach- oder doppelt-wirkendes Steuergerät
* Auf Wunsch bis zu drei einfach- oder doppelt-wirkende Steuergeräte
==Elektrische Ausrüstung==
"12 Volt-Einrichtung"
==Maße und Abmessungen==
* Länge über alles = 4.750 mm
* Breite mit kleinster Spurweite = 2.426 mm
* Höhe über Motorhaube = 1.753 mm
* Höhe über Kabine = 2.921 mm
* Höhe über Auspuff = 2.870 mm
* Radstand = 2.692 mm (4 WD = 2.438 mm)
* Bodenfreiheit = 559 mm (4 WD = 445 mm)
* Betriebsgewicht = 5.194 kg (4 WD = 6.811 kg)
==Bereifung==
"Standardbereifung:"
* Vorne = 14 L-16 AS Front (4 WD = 13.6-28 AS)
* Hinten = 18.4 R 38 AS
"Optional:"
* Vorne = 11.00-16, 10.00-16 und 18.4-16 AS Front (4 WD = 14.9-24 und 14.9-28 AS)
* Hinten = 20.8-38, 16.9-38 und 18.4-42 AS
==Füllmengen==
* Tankinhalt = 227,0 l
* Motoröl mit Filter = 18,0 l
* Kühlsystem = 30,3 l
* Getriebe = 28,0 l
* Differential = 63,0 l
==Verbrauch==
* Kraftstoffverbrauch = 36,8 l/h bei 113,6 kW und Nenndrehzahl
==Kabine==
* Vollverglaste, gummigelagerte, staub- und schallisolierte Kabine mit ebenen Boden, Komfort-Sitz, Öldruck- und Ladeanzeige, Kraftstoffanzeige, Betriebsstundenzähler, höhenverstellbares Lenkrad, Heizung und Klimaanlage
* Optional mit Arbeitsscheinwerfern
==Sonderausrüstung==
* Zusatzgewichte
* Arbeitsscheinwerfer
* Radio
==Literatur & Weblinks==
* tractordata.com
* Brochure Allis Corporation
* digitalcommons.unl.edu (Test-Nr. 1448/82)
* konviesti.fi
<references />
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
lmp99x0q52nckk3wmgj6i087pz8rlqc
Traktorenlexikon: Allis-Chalmers 8070
0
123169
1091904
2026-10-03T19:54:05Z
Baupit
56622
Neue Seite (vgl. [[WB:AZ]])
1091904
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = ALLIS-Chalmers
| MODELLREIHE = 8000 er- Serie
| MODELL = 8070
| BILD =
| BILDBESCHREIBUNG =
| BAUWEISE = Blockbauweise
| PRODUKTIONSBEGINN = 1981
| PRODUKTIONSENDE = 1985
| STÜCKZAHL = 2.354
| EIGENGEWICHT = 7.643 (4 WD: 7.847 kg)
| LÄNGE = 4.750
| BREITE = 2.426
| HÖHE = 2.946
| RADSTAND = 2.692 (4 WD: 2.438)
| BODENFREIHEIT = 559 (4 WD: 445)
| SPURWEITE =
| SPURWEITE VORNE = 1.829-2.540 (1.981-2.159)
| SPURWEITE HINTEN = 1.626-2.515
| WENDERADIUS MIT LENKBREMSE = 4.060 (4 WD: 4.400)
| WENDERADIUS OHNE LENKBREMSE = 4.390 (4 WD: 5.370)
| BEREIFUNG VORNE = 18.4-16 ASF (4 WD: 14.9-28 AS)
| BEREIFUNG HINTEN = 20.8-38 AS
| LEISTUNG KW = 126,5
| LEISTUNG PS = 172
| NENNDREHZAHL = 2.400
| ZYLINDER = 6
| HUBRAUM = 6.981
| DREHMOMENTANSTIEG =
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Wasserkühlung
| ANTRIEBSTYP = Heck- oder Allradantrieb
| GETRIEBE = 20 V/4 und 12 V/2 R
| HÖCHSTGESCHWINDIGKEIT = 30
| KATEGORIESORTIERUNG =
}}
Der ALLIS-CHALMERS 8070 war das Spitzenmodell der Baureihe und konnte mit seinem aufgeladenen Sechszylinder-Aggregat 172 DIN-PS abrufen. Als Triebwerk stand das komfortable POWER-DIRECTOR-Getriebe mit 20/4-Gängen zur Verfügung. Wahlweise konnte das einfachere POWER-SHIFT-Getriebe mit 12/2-Gängen geordert werden.
==Motor==
* ALLIS-CHALMERS, Typ: 670 TI, stehender wassergekühlter Viertakt-Sechszylinder-Reihen-Turbomotor mit Direkteinspritzverfahren, hängenden Ventilen, Mehrloch-Düse, zahnradgetriebener Nockenwelle, Kolbenkühlung, ROOSA-MASTER-Reihen-Einspritzpumpe, siebenfach-gelagerter Kurbelwelle, Trockenluftfilter mit Vorabscheider, integrierter Motorölkühlung, Fliehkraft-Verstellregler, Leichtmetall-Kolben, Druckumlaufschmierung mittels Zahnradpumpe, Abgas-Turbolader incl. Ladeluftkühlung und Lamellenkühler mit Lüfter.
* Bohrung = 107,95 mm, Hub = 127 mm
* Verdichtungsverhältnis = 15,5:1
* Mittlere Kolbengeschwindigkeit = 10,16 m/s
* Geregelter Drehzahlbereich = 800 bis 2.690 U/min.
==Kupplung==
* Elektrohydraulisch-betätigte, nasse Mehrscheibenkupplung
==Getriebe==
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-DIRECTOR-Lastschaltgetriebe
* Synchronisiertes Wechselgetriebe mit fünf Gängen
* Zweistufige Lastschaltung in die Bereiche: Lo und Hi unterteilt
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H und R unterteilt
20 Vorwärts- und 4 Rückwärtsgänge
"Wahlweise:"
* Im Ölbad laufendes ALLIS-CHALMERS-POWER-SHIFT-Getriebe
* Synchronisiertes Wechselgetriebe mit sechs Vorwärts- und einem Rückwärtsgang
* Synchronisiertes Gruppengetriebe mit drei Gruppen, in die Bereiche: L - H unterteilt
12 Vorwärts- und 2 Rückwärtsgänge
==Geschwindigkeiten vor- und rückwärts==
"Geschwindigkeiten Triebwerk 20/4, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.400
|-
! Gruppe - L ||
|-
| Laststufe - Lo ||
|-
| 1.Gang || 2,41 km/h
|-
| 2.Gang || 4,67 km/h
|-
| 3.Gang || 6,92 km/h
|-
| 4.Gang || 7,24 km/h
|-
| 5.Gang || 10,46 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 2,90 km/h
|-
| 2.Gang || 5,79 km/h
|-
| 3.Gang || 8,05 km/h
|-
| 4.Gang || 9,01 km/h
|-
| 5.Gang || 13,04 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 5,31 km/h
|-
| 2.Gang || 9,82 km/h
|-
| 3.Gang || 14,48 km/h
|-
| 4.Gang || 16,09 km/h
|-
| 5.Gang || 21,73 km/h
|-
| Laststufe - Hi ||
|-
| 1.Gang || 6,44 km/h
|-
| 2.Gang || 12,07 km/h
|-
| 3.Gang || 17,86 km/h
|-
| 4.Gang || 19,96 km/h
|-
| 5.Gang || 26,88 km/h
|-
! Rückwärtsgruppe !!
|-
! Gruppe - L !!
|-
| Laststufe - Lo ||
|-
| 1.Gang || 4,35 km/h
|-
| Laststufe - Hi ||
|-
| 2.Gang || 5,47 km/h
|-
! Gruppe - H !!
|-
| Laststufe - Lo ||
|-
| 3.Gang || 9,82 km/h
|-
| Laststufe - Hi ||
|-
| 4.Gang || 12,07 km/h
|-
|}
"Geschwindigkeiten Triebwerk 12/2, mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.400
|-
! Gruppe - L ||
|-
| 1.Gang || 3,06 km/h
|-
| 2.Gang || 4,35 km/h
|-
| 3.Gang || 5,95 km/h
|-
| 4.Gang || 7,40 km/h
|-
| 5.Gang || 9,17 km/h
|-
| 6.Gang || 11,59 km/h
|-
| 1.Rückwärtsgang || 4,99 km/h
|-
! Gruppe - H !!
|-
| 1.Gang || 7,08 km/h
|-
| 2.Gang || 9,66 km/h
|-
| 3.Gang || 13,36 km/h
|-
| 4.Gang || 16,74 km/h
|-
| 5.Gang || 20,92 km/h
|-
| 6.Gang || 26,23 km/h
|-
| 2.Rückwärtsgang || 11,43 km/h
|-
|}
==Zapfwelle==
* Elektrohydraulisch-betätigte, kupplungsunabhängige Motorzapfwelle
* Stummel = 1 3/8"- 21 teilig
* Einfach schaltbar, 1.000 U/min.
* 1.000 U/min. bei 2.253 U/min.- Motordrehzahl
Übertragbare Leistung = 173,8 DIN-PS
* Oder 1.065 U/min. mit Nenndrehzahl
Übertragbare Leistung = 173,1 DIN-PS
==Bremsen==
* Pedal-betätigte, hydraulisch-nasse Scheibenbremse, auf den Differentialseitenwellen wirkend, als Einzelrad-Bremse ausgebildet
Mechanisch-betätigte, unabhängige Feststellbremse, als trockene Scheibenbremse ausgebildet
==Achsen==
* Pendelnd-gelagerte Teleskop-Vorderachse
Verstellbare Spurweite = 1.829 bis 2.540 mm
* Pendelnd-gelagerte, elektrohydraulisch-betätigte und lastschaltbare Planetenachse, mit zentraler Gelenkwelle und Selbstsperrdifferential
Zwei Spurweiten durch Radumschlag = 1.981 oder 2.159 mm
* Hinterachse mit Kegelradgetriebe und Stirnradübersetzung
* Elektrohydraulisch-betätigte Differentialsperre
Verstellbare Spurweite = 1.626 bis 2.515 mm
* Vordere Achslast = 1.955 kg
* Hintere Achslast = 5.688 kg
==Lenkung==
* Hydrostatische Lenkung
Förderleistung = 36,0 l/min.
==Hydrauliksystem und Kraftheber==
* Hydraulischer Kraftheber, mit mechanischer Unterlenkerregelung und TRANSFERMATIC-System
* Einfachwirkender Hubzylinder
* Optional mit Zusatzhubzylinder
* Sicherheitsventil des Arbeitszylinder auf 260 bar eingestellt
* Dreipunktkupplung der Kategorie III mit Schnellkuppler
"Funktionen:"
* Heben, Senken, Neutral- und Schwimmstellung, Zugwiderstands- und Lageregelung sowie stufenlose Mischregelung
* Hubhöhenbegrenzung und hydraulisch-mechanische Transportsicherung
Geschlossenes System mit einer Förderleistung von 83,3 l/min. bei 178 bar
* Gesamte Förderleistung (Getriebe, Lenkung, Hydraulik) = 170,3 l/min.
Max. Hubkraft 610 mm hinter den Koppelpunkten = 3.720 kg
==Steuergeräte==
* Ein einfach- oder doppelt-wirkendes Steuergerät
* Auf Wunsch bis zu drei einfach- oder doppelt-wirkende Steuergeräte
==Elektrische Ausrüstung==
"12 Volt-Einrichtung"
==Maße und Abmessungen==
* Länge über alles = 4.750 mm
* Breite mit kleinster Spurweite = 2.426 mm
* Höhe über Motorhaube = 1.778 mm
* Höhe über Kabine = 2.946 mm
* Höhe über Auspuff = 2.896 mm
* Radstand = 2.692 mm (4 WD = 2.438 mm)
* Bodenfreiheit = 559 mm (4 WD = 445 mm)
* Betriebsgewicht = 7.643 kg (4 WD = 7.847 kg)
==Bereifung==
"Standardbereifung:"
* Vorne = 18.4-16 AS Front (4 WD = 14.9-28 AS)
* Hinten = 20.8-38 AS
"Optional:"
* Vorne = 11.00-16, 10.00-16 und 14 l-16 AS Front (4 WD = 14.9-24 und 13.6-28 AS)
* Hinten = 18.4-38, 16.9-38 und 18.4-42 AS
==Füllmengen==
* Tankinhalt = 227,0 l
* Motoröl mit Filter = 19,9 l
* Kühlsystem = 34,1 l
* Getriebe = 28,0 l
* Differential = 64,7 l
==Verbrauch==
* Kraftstoffverbrauch = 40,5 l/h bei 127,3 kW und Nenndrehzahl
==Kabine==
* Vollverglaste, gummigelagerte, staub- und schallisolierte Kabine mit ebenen Boden, Komfort-Sitz, Öldruck- und Ladeanzeige, Kraftstoffanzeige, Betriebsstundenzähler, höhenverstellbares Lenkrad, Heizung und Klimaanlage
* Optional mit Arbeitsscheinwerfern
==Sonderausrüstung==
* Zusatzgewichte
* Arbeitsscheinwerfer
* Radio
==Literatur & Weblinks==
* tractordata.com
* Brochure Allis Corporation
* digitalcommons.unl.edu (Test-Nr. 1449/82)
* koneviesti.fi
<references />
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
nm0hono3mks3f0dxqzhu4hyoa4xiadv