Forum: PC-Programmierung Python, PDF an Browser senden, es kommt nur Müll


von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Servus,

ich wühle mich gerade in Python ein und hänge fest:

Platform: Win10, XAMPP, Firefox

Ich habe ein PDF auf der Platte und versuche es zu einem Browser zu
senden:
1
#!C:\Users\jd\AppData\Local\Programs\Python\Python38-32/python.exe
2
3
print( "Content-Type: text/html; charset=utf8\n")
4
print( "<iframe id='pdf' style='height:600px; width:600px;' src='applications.html'></iframe>")
5
print( "<iframe id='pdf' style='height:600px; width:600px;' src='getpdf.py?PDF=/htdocs/jdtmp.pdf'></iframe>")

getpdf.py:
1
#!C:\Users\jd\AppData\Local\Programs\Python\Python38-32/python.exe
2
3
import os
4
import sys
5
6
# QUERY_STRING in cgi-Dictionary ablegen
7
os.environ["QUERY_STRING"] = "PDF=jdtmp.pdf"
8
9
cgi = {}
10
sp = os.environ["QUERY_STRING"].split( "&")
11
for i in range( len( sp)):
12
  t = sp[i].split( "=")
13
  cgi[t[0]] = t[1].replace( "%20", " ")
14
15
# PDF lesen und abschicken
16
17
fd = open( cgi["PDF"], "rb")
18
buf = fd.read()
19
fd.close()
20
21
sys.stdout.buffer.write( b"Content-Type: application/pdf\n\n")
22
sys.stdout.buffer.write( buf)

Auf der Kommandozeile kommt das PDF auf sdtout in lesbar,
im Browser kommt ein ellenlanger String aus wahllosen Buchstaben
an den er nicht verarbeiten kann:

JVBERi0xLjQKJeLjz9MNCjMgMCBvYmoKPDwKL0xpbmVhcml6ZWQgMQovTCAyNTg0MAovSCBb 
ODI5IDkzXQovTyA1Ci9FIDI1NTI0Ci9OIDEKL1QgMjU3MzkKPj4KZW5kb2JqCnhyZWYKMyAy 
NgowMDAwMDAwMDE2IDAwMDAwIG4NCjAwMDAwMDA3ODEgMDAwMDAgbg0KMDAwMDAwMDkyMiAw 
MDAwMCBuDQowMDAwMDAxNDg3IDAwMDAwIG4NCjAwMDAwMDE1MzUgMDAwMDAgbg0KMDAwMDAw 
MTY2NiAwMDAwMCBuDQowMDAwMDAyMjg0IDAwMDAwIG4NCjAwMDAwMDMxMDUgMDAwMDAgbg0K 
MDAwMDAwMzI4MyAwMDAwMCBuDQowMDAwMDE4NTk1IDAwMDAwIG4NCjAwMDAwMTg3NTUgMDAw 
MDAgbg0KMDAwMDAxOTM5NyAwMDAwMCBuDQowMDAwMDE5Njc3IDAwMDAwIG4NCjAwMDAwMjAz 
MDQgMDAwMDAgbg0KMDAwMDAyMDc2NCAwMDAwMCBuDQowMDAwMDIxMTI0IDAwMDAwIG4NCjAw 
MDAwMjE1NDMgMDAwMDAgbg0KMDAwMDAyMjU2MiAwMDAwMCBuDQowMDAwMDIyODk0IDAwMDAw 
IG4NCjAwMDAwMjMyMDkgMDAwMDAgbg0KMDAwMDAyMzUyOSAwMDAwMCBuDQowMDAwMDIzODE3 
IDAwMDAwIG4NCjAwMDAwMjQxMzggMDAwMDAgbg0KMDAwMDAyNDQ2MyAwMDAwMCBuDQowMDAw 
MDI0NzQ0IDAwMDAwIG4NCjAwMDAwMDA4MjkgMDAwMDAgbg0KdHJhaWxlcgo8PAovU2l6ZSAy 
OQovUm9vdCA0IDAgUgovSW5mbyAyIDAgUgovSURbPGViMTFlM2U0NWU4NWY5NGY5YWE2M2Mz 
Mzg0Zjc5MTI2PjxlYjExZTNlNDVlODVmOTRmOWFhNjNjMzM4NGY3OTEyNj5dCi9QcmV2IDI1 
NzMxCj4

In C öffne ich das file, ein bißchen malloc, read und dann mit fwrite
raus - kein Problem.

Woran könnte das liegen ?

: Bearbeitet durch User
von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Es funktioniert auf einmal ...

Firefox hat ein Update gefahren und sich neu gestartet.
Was ist denn das für ein Kack ?

von DPA (Gast)


Lesenswert?

Der ellenlange String ist base64. Aber frag mich nicht, wie der da hin 
kommt.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Sieht mir auch nach base64 aus.

Die Stringbehandlung bei Python ist sehr gewöhnungsbedürftig.

von SR (Gast)


Lesenswert?

Du solltest vor der Datei noch einen entsprechenden Header senden damit 
der Browser weiß, was er tun soll.

Content-Type application/pdf

Und ggf. noch den passenden Content-Disposition, je nachdem ob du es 
inline anzeigen oder Downloaden möchtest.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition

Alles andere ist nur Zufall wenn es funktiniert.

Der String ist base64

von SR (Gast)


Lesenswert?

Joachim D. schrieb:
> sys.stdout.buffer.write( b"Content-Type: application/pdf\n\n")

Sorry, gerade erst gesehen.

Ist aber falsch, HTTP-Zeilen enden mit <CR><LF> also \r\n

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

'\n' ist zulässig.

Wie gesagt, ich bin komplett neu mit Python und verstehe die
(kruden) Gedanken die dahinterstecken, noch nicht.

stdout ist stdout. Wieso codiert Python einen String auf einmal
base64 abhängig davon ob es auf die Kommandozeile oder zum
Indianer geht ?

In der Doku zu sys.stdout.buffer.write() steht, es ginge 1:1
raus. Dann landet das base64 im Browser...

von B. W. (yesitsme)


Lesenswert?

Hattest du mal eine Version mit base64-encodierung? Dann könnte der 
Browsercache zugeschlagen haben.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

B. W. schrieb:
> Hattest du mal eine Version mit base64-encodierung? Dann könnte der
> Browsercache zugeschlagen haben.

Keine Ahnung. Könnte sein. Cache habe ich zwischendurch gelöscht.
Das PDF wird bei jedem Abruf neu erzeugt, eigentlich sollte das
nicht aus dem Cache kommen.

von DPA (Gast)


Lesenswert?

Joachim D. schrieb:
> '\n' ist zulässig.

Lies im rfc7230, dem Standard dafür, nochmal nach: 
https://tools.ietf.org/html/rfc7230#section-3
1
HTTP-message   = start-line
2
                 *( header-field CRLF )
3
                 CRLF
4
                 [ message-body ]

Da steht klar CRLF. Nicht LF, nicht (LF / CRLF), sondern ganz klar CRLF.

von B. W. (yesitsme)


Lesenswert?

@DPA wird der Header vom Apache CGI-parser nicht neu geschrieben?


Joachim D. schrieb:
> fd = open( cgi["PDF"], "rb")

Das wartet nur so auf einen Directory-traversal Angriff...

von Imonbln (Gast)


Lesenswert?

nach der Folgenden zeile ist der QUERY_STRING immer "PDF=jdtmp.pdf", 
egal was vom Client kommt, ich bin mir ziemlich sicher das willst du 
nicht.

Joachim D. schrieb:
> # QUERY_STRING in cgi-Dictionary ablegen
> os.environ["QUERY_STRING"] = "PDF=jdtmp.pdf"
>
> cgi = {}

das Iterieren über indexe macht man in Python eigentlich nicht,
Die meisten Objekte, wo es sinnvol ist, bringen einen eigenen iterator 
mit.
1
chunks = os.environ["QUERY_STRING"].split( "&")
2
for chunk in chunks:
3
    try:
4
        # stop spliting after first '=' sign
5
        key, value = chunk.split("=", 1)
6
    except ValueError:
7
        print(f"incomplete Parameter set: {chunk}", file=sys.stderr)
8
    else:
9
        # don't overwrite exiting key/value pairs, but append new one.
10
        cgi.setdefault(key, value.replace( "%20", " "))

> sp = os.environ["QUERY_STRING"].split( "&")
> for i in range( len( sp)):
>   t = sp[i].split( "=")
>   cgi[t[0]] = t[1].replace( "%20", " ")
>
> # PDF lesen und abschicken
>

Für das Lesen einer Datei sollte man in Python einen Sogenannten Context
manager verwenden, der Gibt die Ressourcen nach dem verlassen selbst 
wieder frei (auch bei einer Exception), außerdem kann man dem buildin 
print als parameter mitgeben, das es mit '\r\n' die ziele abschließen 
soll, aber das ist mein persönlicher still.
1
try:
2
    # write pdf to caller terminate with '\r\n'
3
    with open(cgi["PDF"], 'rb') as pdf:
4
        print( b'Content-Type: application/pdf', end='\r\n')
5
        # be prepared for huge pdfs
6
        for chk in iter(pdf.read, b''):
7
            print(chk, end='')
8
        print('', end='\r\n')
9
except KeyError:
10
        print(f"no 'PDF' key in cgi", file=sys.stderr)

> fd = open( cgi["PDF"], "rb")
> buf = fd.read()
> fd.close()
>
> sys.stdout.buffer.write( b"Content-Type: application/pdf\n\n")
> sys.stdout.buffer.write( buf)

von Sheeva P. (sheevaplug)


Lesenswert?

Joachim D. schrieb:
>
1
> #!C:\Users\jd\AppData\Local\Programs\Python\Python38-32/python.exe
2
> 
3
> print( "Content-Type: text/html; charset=utf8\n")
4
> print( "<iframe id='pdf' [...]")
5
> print( "<iframe id='pdf' [...]")
6
>

Es hat nichts mit Deinem Problem zu tun, aber in einem HTML-Dokument 
zweimal dieselbe ID zu vergeben, ist keine gute Idee -- nimm lieber 
class="". So eine id sollte ein eindeutiger Bezeichner sein.

> getpdf.py:
>
>
1
> #!C:\Users\jd\AppData\Local\Programs\Python\Python38-32/python.exe
2
> 
3
> import os
4
> import sys
5
> 
6
> # QUERY_STRING in cgi-Dictionary ablegen
7
> os.environ["QUERY_STRING"] = "PDF=jdtmp.pdf"
8
> 
9
> cgi = {}
10
> sp = os.environ["QUERY_STRING"].split( "&")
11
> for i in range( len( sp)):
12
>   t = sp[i].split( "=")
13
>   cgi[t[0]] = t[1].replace( "%20", " ")
14
> 
15
> # PDF lesen und abschicken
16
> 
17
> fd = open( cgi["PDF"], "rb")
18
> buf = fd.read()
19
> fd.close()
20
> 
21
> sys.stdout.buffer.write( b"Content-Type: application/pdf\n\n")
22
> sys.stdout.buffer.write( buf)
23
>
> [...]
> Woran könnte das liegen ?

Bitte entschuldige, aber Dein Python-Skript ist an so vielen Stellen 
kaputt... Zum Einen hat Python das Modul "cgi" dabei, daß sich ganz 
selbständig um das Parsen und Dekodieren von CGI-Environments kümmern 
kann.

Ich hab's nicht getestet, aber das hier scheint mir ein besserer 
Ausgangspunkt zu sein (Python 3):
1
#![shebang]
2
import cgi
3
import traceback
4
5
if __name__ == '__main__':
6
    form = cgi.FieldStorage()
7
    try:
8
        with open(form['PDF'], 'rb') as ifh:
9
            print('Content-Type: application/pdf')
10
            print()
11
            sys.stdout.write(ifh.read())
12
    except:
13
        print('Content-Type: text/plain')
14
        print()
15
        traceback.print_exc()

Was passiert? Nun, zunächst parst die Klasse cgi.FieldStorage Dein 
CGI-Environment in die Variable "form". Die entstandene Instanz der 
Klasse cgi.FieldStorage kann dann unter anderem wie ein Dictionary 
angesprochen werden, also gibt form["PDF"] (oder form['PDF'], das tut 
sich nichts) zurück, was als Query-Parameter "PDF" übergeben worden ist, 
in diesem Falle der Dateiname.

Die with-Syntax erzeugt einen eigenen Scope mit einem Objekt "ifh", das 
nur in diesem Scope zur Verfügung steht. Diesem Objekt wird zugewiesen, 
was der Aufruf hinter dem "with" zurückgibt, in diesem Falle also eine 
Instanz der Klasse "_io.BufferedReader". Sobald der Scope verlassen 
wird, wird die "magische" Spezialmethode "__exit__()" der Instanz 
aufgerufen und dieselbe zerstört, kurz gesagt: mit der with-Syntax 
(korrekt: einem Context Manager, also etwas, das die Methode 
"__exit__()" hat) kannst Du eine Datei öffnen und sicherstellen, daß sie 
korrekt geschlossen wird, wenn der mit "with" eingeleitete Block 
verlassen wird.

Außerdem habe ich dort ein -- zugegeben: sehr rudimentäres -- 
Exception-Handling eingebaut: wenn irgendetwas explodiert, wird die 
Exception abgefangen und als PlainText an den Browser zurückgesandt.

Nebenbei bemerkt: ein Browser ist vermutlich nicht das richtige 
Werkzeug, um das zu debuggen -- mit curl(1) geht das sicherlich besser, 
weil Du dann wirklich präzise sehen kannst, was da über die Leitung 
geht. Und dank WSL bzw. dem neuen WSL2 kannst Du curl(1) natürlich auch 
ganz einfach installieren und nutzen... ;-)

HTH.

von Sheeva P. (sheevaplug)


Lesenswert?

Joachim D. schrieb:
> Die Stringbehandlung bei Python ist sehr gewöhnungsbedürftig.

Wie kommst Du denn darauf? ;-)

von Sheeva P. (sheevaplug)


Lesenswert?

SR schrieb:
> Ist aber falsch, HTTP-Zeilen enden mit <CR><LF> also \r\n

Ja, aber darum sollte sich der Webserver kümmern.

von foobar (Gast)


Lesenswert?

Keine Ahnung von Python, aber zwei Sachen:

Hat stdout bei Windows-Python auch einen text/binär Modus?  Eine LF -> 
CRLF-Wandlung bei PDFs geht schief.

Ich würde mal zusätzlich zum Content-Type noch ein 
"Content-Transfer-Encoding: binary\r\n" mitschicken.  Die (vom Browser 
nicht verstandene) Base64-Wandlung muß ja wohl der Web-Server machen - 
wer weiß, was er da sonst noch anstellt.

von Sheeva P. (sheevaplug)


Lesenswert?

Imonbln schrieb:
> [code]
> try:
>     # write pdf to caller terminate with '\r\n'
>     with open(cgi["PDF"], 'rb') as pdf:
>         print( b'Content-Type: application/pdf', end='\r\n')
>         # be prepared for huge pdfs
>         for chk in iter(pdf.read, b''):
>             print(chk, end='')
>         print('', end='\r\n')

HTTP trennt Header und Body mit einer Leerzeile, das letzte print('', 
end...) muß also hinter das vorherige und vor die for-Loop -- oder das 
erste print() kann den Parameter end='\r\n\r\n' setzen und das zweite 
print() dann weggelassen werden. Aber, wie schon gesagt, darum sollte 
sich auch ein wohlerzogener Webserver kümmern, der Apache tat das IIRC 
schon in Version 1.irgendwas.

Mir ist auch schleierhaft, warum der Header "Content-Type" als 
Binärstring erzeugt und geschrieben wird... HTTP ist PlainText, oder?

von imonbln (Gast)


Lesenswert?

Sheeva P. schrieb:
> Mir ist auch schleierhaft, warum der Header "Content-Type" als
> Binärstring erzeugt und geschrieben wird... HTTP ist PlainText, oder?

Stimmt, ich habe das vom TO übernommen ohne darüber nachzudenken, ist 
etwas her das ich , dass letze mal Http selbst gesprochen habe ohne 
frameworks wie flask oder ähnliches.
Btw ich bin mir ziemlich sicher da sind noch andere Http Fehler in 
meinen Codefragement, zum Beispiel glaube ich nicht das man nur '%20' 
Ersetzen muss. Schon die Wikipedia kennt mehr (siehe 
https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_in_a_URI).

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

imonbln schrieb:
> Btw ich bin mir ziemlich sicher da sind noch andere Http Fehler in
> meinen Codefragement, zum Beispiel glaube ich nicht das man nur '%20'
> Ersetzen muss. Schon die Wikipedia kennt mehr (siehe

Klar. In C gehe ich da durch den String und ersetze
'\xx' durch den Zeichencode $xx. Mit einem Pointer ist
das einfach lösbar. Ohne Pointer fummelig ;)

von DPA (Gast)


Lesenswert?

imonbln schrieb:
> zum Beispiel glaube ich nicht das man nur '%20' Ersetzen muss

URL-Kodierung ist eine erstaunlich komplexe und problematische 
Geschichte.

Hinter einem % müssen immer 2 Hexadezimale zahlen kommen. Das encodiert 
ein Byte. Das mit der Encoding ist bei der URL-Codierung noch ein 
bisschen ein durcheinander. Die Teile, die keine %XX sind, nach utf-8 
Convertieren falls die nicht schon utf-8 sind, dann alles als byte Array 
auffassen, dabei die %XX zu bytes wandeln, und das nachher wieder in nen 
utf-8 String Convertieren. Dann müsste das alles decodiert sein. Es gibt 
ungültige URLs, z.B. wenn es kein gültiges UTF-8 ist, oder auf ein % 
keine 2 hex zahlen folgen. Und Früher waren die URLs glaub ich mal 
ASCII, das sorgt heute noch für Probleme, wenn man versehentlich codier 
und decodier Funktionen nutzt, die nicht beide von UTF-8 ausgehen, dann 
geht das bei Umlauten schief. Kleine JS Demo des Problems:
1
> decodeURIComponent(escape('ä'))
2
VM156:1 Uncaught URIError: URI malformed

So oder so, am besten ne Library nehmen, schauen, dass die UTF-8 nimmt, 
und Fehler abfangen.

von DPA (Gast)


Lesenswert?

Edit: Das wird dann zwar lustig, wenn man anhand einer URL auf Dateien 
mit nicht-UTF-8 Namen zugreifen will.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Eher ein akademisches Problem: dafür gibt es den 404 ;)

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Jetzt habe ich mir das Programmieren endgültig versaut:

Ständig 'printf' statt 'print' und retour, dann noch die Sache mit dem 
';' ;)

Danke nochmal für die Tipps !

von Sheeva P. (sheevaplug)


Lesenswert?

Joachim D. schrieb:
> Klar. In C gehe ich da durch den String und ersetze
> '\xx' durch den Zeichencode $xx. Mit einem Pointer ist
> das einfach lösbar. Ohne Pointer fummelig ;)

In Python ist das sogar noch einfacher, weil Objekte der Typen str und 
byte iterable und subscribable sind. Außerdem gehört zum Standardumfang 
von Python natürlich eine leistungsfähige Bibliothek für reguläre 
Ausdrücke.

von Sheeva P. (sheevaplug)


Lesenswert?

DPA schrieb:
> So oder so, am besten ne Library nehmen, schauen, dass die UTF-8 nimmt,
> und Fehler abfangen.
1
Python 3.8.0 (default, Oct 28 2019, 16:14:01) 
2
[GCC 8.3.0] on linux
3
Type "help", "copyright", "credits" or "license" for more information.
4
>>> from urllib.parse import quote, unquote
5
>>> s = 'ä ü'
6
>>> quote(s)
7
'%C3%A4%20%C3%BC'
8
>>> unquote(s)
9
'ä ü'
10
>>> unquote(quote(s))
11
'ä ü'

von Sheeva P. (sheevaplug)


Lesenswert?

Joachim D. schrieb:
> Jetzt habe ich mir das Programmieren endgültig versaut:
>
> Ständig 'printf' statt 'print' und retour, dann noch die Sache mit dem
> ';' ;)
>
> Danke nochmal für die Tipps !

Du kannst das ';' auch in Python schreiben, das tut ihm nichts. Und wenn 
Du in Python statt print() lieber printf() schreiben möchtest, nichts 
einfacher als das:
1
printf = print
2
printf('asdf');

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Interessant ... ;)

Mit den RegEx habe ich auch probiert, folgende Datei auszuwerten:
1
; rights.d: modified 02.03.17 / 07:29:24
2
3
; (1) Benutzergruppen
4
5
group GRUPPEA {
6
    testip
7
    tb.docs             (read view gaps   )
8
    tb.notes            (read view     )
9
    tb.system           (uquery.exe)
10
    ...
11
    exec.system                  (uslist.exe upass.exe udquery.exe uinfo.exe usquery.exe uuser.exe)
12
    }
13
14
user jd               { 
15
    abt ()
16
    name (Joe Drechsel                      ) 
17
    pass ($abeccf9ae147d85436534371f961c95b ) 
18
    mail ()
19
    expd (01.01.2020 ) group (adminall ) 
20
    filter (   )  }

Ich stolpere schon per RegEx über den Kommentar am Anfang.
Die Datei ist in C recht einfach auszuwerten. Sie enthält in
der Praxis ca 60 Benutzergruppen und ca 12000 User. Dauert
in C 0.01 sec. Das dürfte mit einem Interpreter nicht zu
erreichen sein.

Um den Kommentar am Anfang auszumerzen suche ich ein Zeichen
';' am Beginn und ein Zeichen '\n' bzw '\r\n' als letztes und
fülle den Bereich mit ' '. Es will nicht. Vermutlich scheitert
es an den ' '. Ich bin noch am probieren ...

von Sheeva P. (sheevaplug)


Lesenswert?

Joachim D. schrieb:
> Interessant ... ;)

Langsam beschleicht mich das Gefühl, daß Du eher nach Gründen dafür 
suchst, warum C "besser" (für beliebige Definitionen von "besser") sein 
soll als Python. Denn kaum bekommst Du eine Antwort für das jeweils 
geschilderte Problem, poppst Du mit dem nächsten Problem auf -- nicht 
ohne den Hinweis, daß das in C ja ganz einfach ist, und natürlich 
unbedingt performanter als in Python.

Zwischendurch zudem Deine Aussage, hinter Python stünden "(krude) 
Gedanken" die Stringbehandlung sei "sehr gewöhnungsbedürftig". Klar, was 
man nicht versteht, mag einem erst einmal "krude" erscheinen, aber ob 
man damit in einem öffentlichen Forum hausieren gehen sollte? Ich weiß 
ja nicht...

Besonders ulkig finde ich übrigens den Hinweis auf Pythons 
"gewöhnungsbedürftige" Stringbehandlung vor dem Hintergrund, daß C weder 
Strings noch ein Stringhandling kennt, sondern nur nullterminierte 
Arrays und ein paar Funktionen, die damit mal mehr, mal weniger gut 
umgehen können, ich sag nur strcpy(3) und strncpy(3) -- und erlaube mir 
den Verweis auf die etlichen Pufferüberläufe nicht zuletzt auch wegen 
fehlerhaften Stringvalidierungen, die auch erfahreneren C-Entwicklern 
bisweilen unterlaufen und für die die CVE mannigfaltige Zeugnisse 
bereithalten.

Sei mir nicht böse, aber wenn Du Python nicht lernen willst und von 
vorneherein eine Aversion gegen Skriptsprachen im Allgemeinen oder gegen 
Python im Besonderen hast, dann verstehe ich nicht, was das Ganze hier 
soll. Und wenn Du Python lernen willst, verstehe ich nicht, warum Du es 
immer wieder mit einer vollkommen anderen Sprache auf einer vollkommen 
anderen Höhe und mit vollkommen anderen Paradigmen vergleichst und dann 
obendrein auch noch, nunja, vollmundige Urteile über verschiedene 
Aspekte der Sprache Python äußerst.

Wenn Du das wirklich willst, dann lern' Python doch erstmal mindestens 
bis zu einem halbwegs fundierten Anfängerniveau und schreib ein paar 
reale Programme damit, bevor Du solche Urteile herausposaunst. Dann 
wirst Du nämlich schnell feststellen, daß es sehr gute Gründe dafür 
gibt, warum Python in den einschlägigen Indizes mittlerweile zur 
beliebtesten Sprache avanciert ist und sogar den langjährigen 
Spitzenreiter Java überholt hat...

> Mit den RegEx habe ich auch probiert, folgende Datei auszuwerten:
>
>
1
> ; rights.d: modified 02.03.17 / 07:29:24
2
> 
3
> ; (1) Benutzergruppen
4
> 
5
> group GRUPPEA {
6
>     testip
7
>     tb.docs             (read view gaps   )
8
>     tb.notes            (read view     )
9
>     tb.system           (uquery.exe)
10
>     ...
11
>     exec.system                  (uslist.exe upass.exe udquery.exe 
12
> uinfo.exe usquery.exe uuser.exe)
13
>     }
14
> 
15
> user jd               {
16
>     abt ()
17
>     name (Joe Drechsel                      )
18
>     pass ($abeccf9ae147d85436534371f961c95b )
19
>     mail ()
20
>     expd (01.01.2020 ) group (adminall )
21
>     filter (   )  }
22
>
>
> Ich stolpere schon per RegEx über den Kommentar am Anfang.

Ist nicht wahr, ernsthaft? Dann empfehle ich die Lektüre von "Regular 
Expressions" von Jeffrey Friedl. Aber dafür braucht man natürlich keine 
RegEx, das geht einfach mit "line.strip().startswith(';')".

> Die Datei ist in C recht einfach auszuwerten. Sie enthält in
> der Praxis ca 60 Benutzergruppen und ca 12000 User. Dauert
> in C 0.01 sec. Das dürfte mit einem Interpreter nicht zu
> erreichen sein.

Na und? Muß es denn so schnell sein, ist das Dein wichtigstes Kriterium? 
Dann solltest Du Deinen Parser vielleicht direkt in Assembler 
implementieren, wenn Performanz so überaus wichtig ist. Aber ach, die 
Entwicklungszeit...

Nebenbei habe ich mir Deine Datei (was für ein irrsinniges Format, wer 
denkt sich sowas aus? Noch nie was von CSV, JSON, oder YAML gehört?) 
jetzt einmal spaßeshalber vorgenommen und sie mit RegExen geparst. Das 
dauert auf meinem alten Q9650 ungefähr 0.0022 Sekunden inklusive 
Einlesen der Datei -- die Startzeiten von Python habe ich dabei 
allerdings einfach mal herausgelassen. Nicht schlecht für langsame 
RegExen in einer langsamen Skriptsprache, nicht wahr?

Der Hashwert für das Benutzerpaßwort erscheint mir ziemlich kurz, 
womöglich könnte man da womöglich mal auf eine modernere Variante wie 
SHA gehen... zudem ist es heute eine gängige Praxis, auch einen Hinweis 
auf die Hashfunktion zu speichern, damit sie an neue Anforderungen 
angepaßt werden kann.

> Um den Kommentar am Anfang auszumerzen suche ich ein Zeichen
> ';' am Beginn und ein Zeichen '\n' bzw '\r\n' als letztes und
> fülle den Bereich mit ' '. Es will nicht. Vermutlich scheitert
> es an den ' '. Ich bin noch am probieren ...

Dafür brauchst Du keine RegExe, da reicht das "gewöhnungsbedürftige 
Stringhandling" von Python: line.strip().startswith(';'). Das findet 
sogar Kommentarzeilen, bei denen vor dem Semikolon noch Whitespace 
steht. Per RegEx wäre es r'^\s*?\;.*$' mit Leerzeichen vorm Semikolon, 
ansonsten kannst Du das '\s*?' am Anfang weglassen.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Danke. Und gleichzeitig bitte ich um Nachsicht.

Ich lebe seit über 35 Jahren in C, das ist jetzt mal so der erste
Ausflug in so etwas "objektorientiertes" und ich weiß, da bin
ich noch ziemlich am Anfang (nebenbei, der Regex-Parser ist in C
geschrieben).

Mit fehlt da noch der Überblick. Finde ich in der Standard-C-Lib
keine brauchbare Strringfunktion baue ich die halt schnell selbst.
So habe ich eine Unzahl an Funktionen.

line.strip().startswith(';') ok, wo finde ich was line kann ?
Da hängt es bei mir schon. Ich wühle mich durch die Websites die
irgendwas mit "Python" haben und stopple mir halt das zusammen.

Ich fange halt damit an, meine C-Sachen in Python zu probieren.
Nicht lebensnotwendig, halt interessant.

von cppbert (Gast)


Lesenswert?

Joachim D. schrieb:
> Ich lebe seit über 35 Jahren in C, das ist jetzt mal so der erste
> Ausflug in so etwas "objektorientiertes" und ich weiß, da bin
> ich noch ziemlich am Anfang

Beschwer dich einfach nicht und stell keine Vergleiche an - in Features 
schlägt Python C immer, aber vielleicht oft nicht immer in Performanz 
und die Syntax ist teilweise gewöhnungsbedürftig, das gleiche würde dir 
aber auch und schlimmer mit Schwester C++ passieren - und Doku und 
Beispiele lesen ist der Schlüssel, btw kannst du jeden deiner C 
Algorithmen so auch in Python implementieren

von leo (Gast)


Lesenswert?

Joachim D. schrieb:
> line.strip().startswith(';') ok, wo finde ich was line kann ?

Das ist wohl ein String, d.h. e.g.
https://www.w3schools.com/python/python_strings.asp

So schwer ist das nicht.
1
>>> type("abc")
2
<class 'str'>

leo

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Das wird schon noch. "Damals" mit C anzufangen war viel
schlimmer (da stand die ersten 2 Wochen der PC mehrmals
kurz davor aus dem Fenster zu fliegen).

Python ist recht mächtig - aber hauptsächlich aufgrund
seiner Zusatzmodule, die gibt es für C aber auch.

Das war jetzt aktuell nicht der Grund mich damit zu
beschäftigen. Eher "mal was Neues" und "wegen Corona ja
auch mal Zeit".

Einige Programme habe ich schon mit C++ gemacht, habe mal
mit Assembler (6502,8088, Z80) angefangen und auch Hexdumps
aus der mc abgetippt. Dann noch Pascal (sehr geschwätzig) und
dBase 3 und 4.

An Python finde ich den Funktionsumfang interessant, auch
daß sie mal eine ganz andere Optik des Quellcodes verwenden.
Ist halt mal was anderes ;)

von DPA (Gast)


Lesenswert?

cppbert schrieb:
> in Features schlägt Python C immer

Nein. Es gibt viele Features, die nur C hat. Das fängt unter anderem mit 
der statischen typisierung an, und geht mit allen Konstrukten weiter, 
die damit möglich werden. Immer wieder toll, sind die dadurch 
entstehenden Runtimefehler in python. Vertippt man sich in c bei einer 
Variable oder einer Funktion, bricht es gleich beim Kompilieren schon 
ab, und sagt einem wo man den Fehler gemacht hat. Python läuft erstmal 
einfach los, und trifft die fehlerhafte stelle dann vielleicht später 
irgend wann mal. Noch besser ist das vertippen beim Setzen einer 
Variablen, das macht Python doch gerne!

von Sheeva P. (sheevaplug)


Lesenswert?

Joachim D. schrieb:
> Danke. Und gleichzeitig bitte ich um Nachsicht.

Oh, nix für ungut... entschuldige bitte, war halt nur so ein Gefühl.

> Ich lebe seit über 35 Jahren in C, das ist jetzt mal so der erste
> Ausflug in so etwas "objektorientiertes" und ich weiß, da bin
> ich noch ziemlich am Anfang (nebenbei, der Regex-Parser ist in C
> geschrieben).

Ein sehr großer Teil der Python-Bibliotheken ist in C oder in C++ 
geschrieben, das gilt gleichermaßen für die gemeinhin mitgelieferten 
Standardlibraries, aber auch für externe Libraries wie numpy, und mit 
Python3 sind es sogar noch viel mehr. Deswegen ist Python oft 
ausgesprochen performant zur Laufzeit, hat gleichzeitig aber die großen 
Vorteile einer Skriptsprache bei der Entwicklungszeit und der 
Codedichte.

> Mit fehlt da noch der Überblick. Finde ich in der Standard-C-Lib
> keine brauchbare Strringfunktion baue ich die halt schnell selbst.
> So habe ich eine Unzahl an Funktionen.

In Python bringen die Klassen str und bytes bereits eine riesige Menge 
an Funktionen mit, mit "pydoc str" und "pydoc bytes" findest Du die 
Dokumentation dazu.

Eine der vielen Stärken von Python ist halt seine Infrastruktur, das 
betrifft die mitgelieferten Standardbibliotheken -- in denen schon viele 
fertige, getestete und performanceoptimierte Bibliotheken, Module und 
Frameworks vorhanden sind -- aber auch die unglaublich vielen 
verfügbaren Third-Party-Bibliotheken, die über ein zentrales Repository 
mit dem Paketmanager pip ganz einfach installiert werden können. Um zum 
Beispiel CSV-- oder JSON-Dateien zu lesen, muß ich mir in C, C++ und 
Java jeweils eine passende Bibliothek suchen (und sie nicht selten auch 
testen...), während Python für soetwas bereits fertige Bibliotheken mit 
den (vollkommen überraschenden) Namen csv und json mitliefert. Und 
(siehe oben) auch für CGIs...

Bitte behalte das immer im Hinterkopf, bevor Du selbst etwas 
implementierst. Ich habe schon etliche Python-Einsteiger gesehen, die 
sich selbst was zusammengeprokelt haben, das Python schon fertig 
mitgeliefert hat oder zumindest im PyPi, also dem zentralen 
Python-Paketrepository, vorhanden war.

> line.strip().startswith(';') ok, wo finde ich was line kann ?

Oh... bitte entschuldige, line ist in diesem Falle ein String bzw. eine 
Instanz der Klasse str. Das liegt daran, daß man in Python ganz einfach 
zeilenweise über eine Datei iterieren kann, entweder mit
1
f = open('datei.txt', 'r')
2
for line in f:
3
    if line.strip().startswith(';') or line.strip() == '': next
4
    print(line)
5
f.close()

oder, noch etwas schicker und moderner, mit einem Contextmanager:
1
with open('datei.txt', 'r') as f:
2
    for line in f:
3
        if line.strip().startswith(';') or line.strip() == '': next
4
        print(line)

Beide Codebeispiele öffnen eine Datei namens "datei.txt" im Lesemodus 
('r') und liest diese Zeilenweise in die Variable "line", die also 
einfach nur eine Instanz der Klasse str ist und damit alle Methoden und 
andere Möglichkeiten bietet, die diese Klasse hat und die Du mit "pydoc 
str" nachlesen kannst. Und, ach ja: über einen str() kannst Du natürlich 
wieder mit einer Schleife iterieren...

Denn eine der eigentlichen Stärken von Python liegt noch einmal 
woanders, ist aber nicht ganz einfach zu erklären -- ich versuche es 
trotzdem mal. Also, Python kennt neben konkreten eingebauten ("pydoc 
builtins") und selbstdefinierten Klassen (also Datentypen) auch noch 
bestimmte... Schnittstellen dafür, zum Beispiel Iterable oder Sequence 
-- und lustigerweise kann ein Iterable auch eine Sequence sein.

Ein iterable, um bei diesem Beispiel zu bleiben, kann vieles sein: zum 
Beispiel eine Datei, wie in den beiden Codebeispielen oben, oder auch 
eine list(), ein tuple(), ein str() oder eine selbstdefinierte Klasse, 
wenn diese die "magischen" Methoden __iter__() und __next__() definiert. 
Anders gesagt: ob eine Klasse eine bestimmte Schnittstelle 
implementiert, hängt von den Methoden ab, die sie... ach stimmt, das ist 
in anderen Sprachen wie Java & Co ja ganz ähnlich. ;-)

Diese "magischen" Methoden, deren Name mit zwei Unterstrichen beginnt 
und endet, sind die Grundlage für viele spannende Dinge, die man mit 
Python machen kann, vom Überladen von Operatoren bis hin zu bestimmten 
Charakteristiken, die man seinen eigenen Klassen verleihen kann -- wie 
eben Iterable.

Das Lustige dabei ist, das ein großer Teil der Python-Standardbibliothek 
bereits darauf ausgelegt sind, mit diesen Schnittstellen zu arbeiten. 
Zum Beispiel gibt es in der random-Bibliothek eine Funktion choice(), 
die zufällige Elemente aus einer Sequence auswählt:
1
import random
2
3
# Eine Liste von Zeichen (könnte auch eine von Strings sein...)
4
s = ['a', 'b', 'c']
5
print(random.choice(s))
6
7
# ein str(), ebenfalls eine Sequence
8
s = 'abc'
9
print(random.choice(s))
10
11
# Datei zeilenweise in eine list() lesen
12
with open('datei.txt', 'r) as ifh: s = ifh.readlines()
13
print(random.choice(s))
14
15
# Datei zeichenweise in eine list() lesen
16
with open('datei.txt', 'r) as ifh: s = ifh.read()
17
print(random.choice(s))

Die Variable s enthält hier jeweis eine Sequence: einmal eine list() aus 
Zeichen, dann einen str(), dann eine list() von Zeilen in einer Datei 
und dann eine list() von Zeichen in einer Datei.

> Da hängt es bei mir schon. Ich wühle mich durch die Websites die
> irgendwas mit "Python" haben und stopple mir halt das zusammen.
>
> Ich fange halt damit an, meine C-Sachen in Python zu probieren.
> Nicht lebensnotwendig, halt interessant.

Statt dieser Vorgehensweise empfehle ich eher eine klassische: Bücher. 
Gerade für Python gibt es viel herausragende Lektüre, vor allem beim 
Verlag O'Reilly. Meine Empfehlung wäre, mit der Einführung zu beginnen, 
die findest Du in "Learning Python", das es als "Einführung in Python" 
auch auf Deutsch gibt. Die sinnvollsten Folgelektüren wären wohl 
"Programming Python" und natürlich das "Python Cookbook", damit kommst 
Du schon sehr, sehr weit. Für erfahrene Pythonistas sind IMO "Fluent 
Python" und "High-Performance Python" gut geeignet, und ansonsten gibt 
es -- immer je nachdem, was Du mit Python machen möchtest -- 
entsprechende Fachliteratur von Büchern über numpy und scipy über Pandas 
für Datenfresser, Flask und Django für Webentwickler, und und und...

von Sheeva P. (sheevaplug)


Lesenswert?

Joachim D. schrieb:
> Das wird schon noch. "Damals" mit C anzufangen war viel
> schlimmer (da stand die ersten 2 Wochen der PC mehrmals
> kurz davor aus dem Fenster zu fliegen).
>
> Python ist recht mächtig - aber hauptsächlich aufgrund
> seiner Zusatzmodule, die gibt es für C aber auch.

Naja... aber für C, C++ und Java mußt Du Dir 90 Prozent dessen, was 
Python bereits standardmäßig mitliefert, erstmal mühsam zusammensuchen, 
die Lizenz überprüfen, und testen. Und von den übrigen 10 Prozent gibt 
es 99 Prozent leider gar nicht für C oder C++ (think Pandas, Flask, 
Django, Matplotlib, Bokeh, ...), das mußt Du Dir dabei aus drölfzig Libs 
richtig mühsam zusammenstoppeln und -basteln. ;-)

von Sheeva P. (sheevaplug)


Lesenswert?

DPA schrieb:
> cppbert schrieb:
>> in Features schlägt Python C immer
>
> Nein. Es gibt viele Features, die nur C hat. Das fängt unter anderem mit
> der statischen typisierung an, und geht mit allen Konstrukten weiter,
> die damit möglich werden.

Das bieten andere statisch typisierte Sprachen wie C++ und Java auch an, 
zum Teil erheblich ausgereifter und sicherer als in C. Erfreulicherweise 
bietet Python aber eine Introspektion an, wie leo oben mit seinem 
type()-Aufruf gezeigt hat und mit isinstance(), Type Hints ("def 
funktion(name: str)") und weiteren Methoden prima unterstützt.

Und dann ist es halt immer die Frage, welche Art von Interpreter gerade 
benutzt wird. Für Python gibt es da beispielsweise die 
Referenzimplementierung CPython, welche -- wie viele 
Skriptspracheninterpreter -- zunächst den Sourcecode nimmt, diesen in 
ausführbaren Bytecode umwandelt, und den Bytecode dann ausführt. Dann 
können viele Fehler bereits zur Entwicklungszeit gefunden werden.

Es gibt aber auch den Interpreter Pypy, der Just-In-Time (JIT) 
kompiliert und deswegen natürlich auch keine Fehler zur Entwicklungszeit 
finden kann, weil er natürlich immer nur den Code übersetzt, der gerade 
zur Ausführung ansteht. Aber dafür ist dieser Interpreter in vielen 
Anwendungsfällen extremst performant, vor allem natürlich wenn viele 
Bedingungen oder Schleifen durchlaufen werden müssen.

Natürlich gibt es auch Jyton und Ironpython, aber ich bin jetzt zu faul 
(oder habe im Falle von Ironpython kein Windows zum Ausprobieren), um zu 
schauen, wie die mit solchen Fehlern umgehen. Aber es gibt 
selbstverständlich immer die Möglichkeiten, Python in C- oder C++-Code 
zu übersetzen, mit nuitka [1] zum Beispiel. Und zudem existieren noch 
eine Reihe von Code-Checkern wie etwa pylint...

Ganz am Rande bemerkt: mir ganz persönlich ist es wesentlich lieber, 
wenn meine Programme zur Laufzeit mit einer aussagekräftigen 
Fehlermeldung abstürzen, als daß ich mir einen Buffer Overflow 
einhandele, der es einem Angreifer ermöglicht, meine Systeme zu 
übernehmen. YMMV.

Python ist übrigens, entgegen eines weitverbreiteten Irrglaubens, 
tatsächlich stark, jedoch dynamisch typisiert: der Typ einer Variable 
ist nicht an ihren Namen, sondern an ihren Wert gebunden.

> Immer wieder toll, sind die dadurch
> entstehenden Runtimefehler in python. Vertippt man sich in c bei einer
> Variable oder einer Funktion, bricht es gleich beim Kompilieren schon
> ab, und sagt einem wo man den Fehler gemacht hat. Python läuft erstmal
> einfach los, und trifft die fehlerhafte stelle dann vielleicht später
> irgend wann mal. Noch besser ist das vertippen beim Setzen einer
> Variablen, das macht Python doch gerne!

Ach ja, Daniel, das sind eben die typischen Unterschiede zwischen einer 
dynamisch, aber stark typisierten Skriptsprache wie Python, einer 
schwach typisierten Sprache wie Perl, und einer statisch kompilierten 
Sprache wie C, C++ oder Java. In Perl und PHP ergibt die Addition von 
"'4' + 3" tatsächlich 7, in Python und Ruby jedoch eine (abfangbare) 
Exception.

Nebenbei bemerkt, kann ich in jeder Spache Bullshit schreiben. Das als 
Argument für oder wider Spriptsprachen zu benutzen, halte ich aber für 
noch größeren Bullshit, denn letztlich haben beide Familien ihre 
spezifischen Vor- und Nachteile. Aber daß ein Entwickler Mist macht... 
meine Güte, soll das wirklich ein Argument sein? ;-)

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Sheeva P. schrieb:
> Statt dieser Vorgehensweise empfehle ich eher eine klassische: Bücher.

Natürlich. Im Moment lese ich da online einiges, es sind halt
"Einführungen" (dh: "mein erstes Programm" uÄ) (Nebenbei: die
Byers Übersetzungen / Neuschreibungen bei Vieweg über dBase IV
waren von mir).

Ich hänge an der "Idee" Pythons. zB warum die Unterscheidung
zwischen str (String) und byte (auch String). Ich verstehe den
Sinn dahinter nicht.

Python selbst mag etwas lahm sein, allerdings sind die meisten
Module in C geschrieben und die Befehle/Kommandos sehr mächtig.
Das relativiert das "lahm" ;)

Ich denke halt "wie geht das in C" und versuche so, das was
Python da gerade macht, nachzuvollziehen.

Wird noch ein wenig dauern, irgendwann macht es dann "klick".

Sheeva P. schrieb:
> "Learning Python"

Ich werde mir das besorgen.

Vielen Dank an alle !

von DPA (Gast)


Lesenswert?

Sheeva P. schrieb:
> DPA schrieb:
>> cppbert schrieb:
>>> in Features schlägt Python C immer
>>
>> Nein. Es gibt viele Features, die nur C hat. Das fängt unter anderem mit
>> der statischen typisierung an, und geht mit allen Konstrukten weiter,
>> die damit möglich werden.
>
> Das bieten andere statisch typisierte Sprachen wie C++ und Java auch an,
> zum Teil erheblich ausgereifter und sicherer als in C.

Ja schon, aber es ging nun mal um python und c.

> Erfreulicherweise
> bietet Python aber eine Introspektion an, wie leo oben mit seinem
> type()-Aufruf gezeigt hat und mit isinstance(),

Das ist aber etwas komplett anderes. Introspektion gibt es zu einem 
gewissen Grad auch in c. sizeof, offsetof, alignof _Generic, 
static_assert, etc. Zwar nur zur compile-time, und nicht ganz so toll 
wie in einigen anderen statisch typisierten Sprachen, aber definitiv 
vorhanden. An Java sieht man, das statische Typisierung und Runtime 
Introspektion sich auch nicht ausschliessen, aber man kann halt nicht 
alles haben.

> Type Hints ("def
> funktion(name: str)") und weiteren Methoden prima unterstützt.

Oh, type hints kannte ich noch nicht. Seit python 3.5, ist wohl relativ 
neu. Das ist zumindest mal ein Anfang. Ist aber immer noch nur ein 
runtime-check.

Sheeva P. schrieb:
>> Immer wieder toll, sind die dadurch
>> entstehenden Runtimefehler in python. Vertippt man sich in c bei einer
>> Variable oder einer Funktion, bricht es gleich beim Kompilieren schon
>> ab, und sagt einem wo man den Fehler gemacht hat. Python läuft erstmal
>> einfach los, und trifft die fehlerhafte stelle dann vielleicht später
>> irgend wann mal. Noch besser ist das vertippen beim Setzen einer
>> Variablen, das macht Python doch gerne!
>
> Ach ja, Daniel, das sind eben die typischen Unterschiede zwischen einer
> dynamisch, aber stark typisierten Skriptsprache wie Python, einer
> schwach typisierten Sprache wie Perl, und einer statisch kompilierten
> Sprache wie C, C++ oder Java.

Python würde ich aber nicht als stark Typisiert betrachten. Mit 
TypeScript gibt es eine Scriptsprache, die zwar auch kompiliert wird, 
und schon vor der Ausführung Typfehler und ähnliches finden kann, aber 
trotzdem nicht wirklich statisch ist. Das würde ich als stark Typisiert 
betrachten. Vielleicht bekommen wir ja irgendwann mal ein Python 4 oder 
so, wo das endlich mal besser wird ;)

> In Perl und PHP ergibt die Addition von
> "'4' + 3" tatsächlich 7, in Python und Ruby jedoch eine (abfangbare)
> Exception.

In C ergibt Pointer + Integer -> Pointer. Ich sehe nicht, was das mit 
Statischer vs. Dynamische Typisierung zutun haben soll.

Sheeva P. schrieb:
> Nebenbei bemerkt, kann ich in jeder Spache Bullshit schreiben.

Klar kann man in allen Sprachen Bullshit schreiben. Aber in C muss man 
es wenigstens formal-richtig falsch programmieren. Diese Art von Fehler 
sieht man halt in C sofort, und in Python nicht. Es ist und bleibt ein 
Vorteil und ein Feature, das Python nicht hat. Und doch, das ist ein 
sehr gutes Argument gegen Python und co. Mein Argument beschränkte sich 
auch nicht nur auf die Fehler, die man so finden kann. Zur Compiletime 
Code generieren, im Vornherein wissen, das Methoden und Membervariablen 
da sind, den richtigen Type haben, Gross genug sind, die die Annahmen 
schon vor dem Ausführen checken, das geht halt in Python alles nicht 
oder nicht so einfach.

Und damit kommen wir wieder zu dem, worum es in dem Argument eigentlich 
ging. cppbert behauptete, in Features schlage Python C immer. Aber da es 
zwangsläufig Features in C gibt, die Python in der jetzigen Form nicht 
haben kann, kann das nicht stimmen.

> Das als
> Argument für oder wider Spriptsprachen zu benutzen, halte ich aber für
> noch größeren Bullshit, denn letztlich haben beide Familien ihre
> spezifischen Vor- und Nachteile.

Es geht mir nicht darum zu sagen, C wäre besser als Python, sondern 
darum, dass die Implikation, Python sei besser als C, genauso falsch 
ist.

Abgesehen davon, klar haben beide Familien ihre spezifischen Vor- und 
Nachteile. Nur deshalb ist es noch lange kein Bullshit, mal von einer 
Seite welche hervorzuheben, wenn es nötig wird. Wenn man alle Vor und 
Nachteile von Sprachen einfach als irrelevanter Bullshit abtut, wird es 
doch absolut Sinnfrei, über diese Argumentieren zu wollen.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

DPA schrieb:
> Es geht mir nicht darum zu sagen, C wäre besser als Python, sondern
> darum, dass die Implikation, Python sei besser als C, genauso falsch
> ist.

Das ist auch unwichtig.

Da könnte man auch argumentieren; Phyton ist in C geschrieben,
dann nehme ich gleich das Original ;)

Ich denke, das wird sich ergänzen. In C zB eine Mail senden
gibt locker 80 Zeilen Code, in Phyton sind es 2. Natürlich nur
einmal Arbeit (kann man ja wiederverwenden).

Mal schnell 10 GB an Daten irgendwo einsortieren dürfte unter
C erheblich schneller gehen.

SQLite geht auch unter Python.

Die Sachen die ich kenne und brauche sind alle vorhanden, ich
muß sie nur finden ...

von Sheeva P. (sheevaplug)


Lesenswert?

Vorweg: Entschuldige bitte, aber was soll denn das sein? Ich vermisse
Dein sonst so viel höheres Niveau.

Tatsächlich wirfst Du Python im Kern vor, daß es eine interpretierte
Programmiersprache ist, wodurch ein separater Kompilationsschritt, in
dem die Typen geprüft werden könnten, wegfällt. Wie unsinnig das ist,
erkennst Du sofort, wenn Du C anstatt mit einem Compiler mit einem der
verfügbaren C-Interpreter Ch, picoc oder tcc ausführst: sobald C nicht
kompiliert, sondern stattdessen interpretiert wird, ist das Verhalten
bei Typfehlern exakt dasselbe wie bei Python: der Interpreter steigt
zur Laufzeit aus. Huch!

Weder die statische Typisierung, noch deren Prüfung in einem separaten
Kompilationsschritt sind also Kernfeatures von C, sondern einer ganzen
Sprachfamilie, nämlich der Sprachfamilie der kompilierten Sprachen und
das auch nur dann, wenn sie kompiliert statt interpretiert werden. In
C's großem Bruder C++, das ebenfalls wesentlich mehr Features anbietet
als C, in Java und auch in Golang ist das alles nämlich genauso; dabei
handelt es sich also offenbar nicht um eine besondere Eigenschaft von
C, sondern ganz allgemein um eine Eigenschaft von statisch typisierten
und kompilierten Programmiersprachen. Python hingegen ist weder das
Eine noch das andere; Python ist aber eine dynamisch stark typisierte,
interpretierte Sprache.

Trotzdem ist Python, entgegen Deines Irrglaubens, stark typisiert; ein
Konstrukt wie die Addition eines String mit einer Integer läßt es also
nicht zu, sondern wirft eine Exception. Das ist etwas anderes als die
inhärente (und reichlich fehleranfällige) Zeigerarithmetik in C, die
Du unsinnigerweise als Beispiel zur Typisierung anführst -- und Deine
Argumentation für C's Typsicherheit selbst widerlegst. Übrigens, wo
Du Dich gerade über Laufzeitfehler ausgelassen hast: eine fehlerhafte
Zeigerarithmetik in C führt regelmäßig zu Laufzeitfehlern, und häufig
sogar zu überaus gefährlichen. Sich ausgerechnet über Programmier- und
Laufzeitfehler in Python zu beschweren und dann gleichzeitig eine der
fehleranfälligsten Laufzeitfehlerquellen in C als Argument zu bringen,
erscheint mir schon ein wenig absurd.

Schwach typisierte Sprachen wie Perl oder PHP hingegen lassen es zu,
Strings und Integers zu addieren. Das führt nicht selten zu logischen
Fehlern, die besonders schwer zu debuggen und zu finden sind, wie ich
aus eigener leidvoller Erfahrung mit beiden Sprachen weiß.

Python dagegen bietet seit fünf Jahren -- okay, der erste Vorschlag
für Type Hints ist von 2006, eingeführt wurden sie aber erst in der
Version 3.5, die vor fünf Jahren released wurde -- tatsächlich die
Möglichkeit, Typsicherheit zu gewährleisten. Prinzipbedingt geschieht
dies jedoch (erinnere Dich: es ist eine interpretierte Skriptsprache)
nicht zur Laufzeit, sondern mit einem separaten Typechecker (hierzu
verwende ich mypy(1) und pylint(1)). Wenn Du statische Typsicherheit
also wirklich haben willst, geht das auch in Python.

Soviel zum Vorwort, im Weiteren möchte ich gerne noch auf ein paar
besondere Passagen Deines Beitrages eingehen.

DPA schrieb:
> Sheeva P. schrieb:
>> DPA schrieb:
>>> cppbert schrieb:
>>>> in Features schlägt Python C immer
>>>
>>> Nein. Es gibt viele Features, die nur C hat. Das fängt unter anderem mit
>>> der statischen typisierung an, und geht mit allen Konstrukten weiter,
>>> die damit möglich werden.

Welche "Konstrukte" sollten das denn bitte sein? In C++ hätte ich ja
noch verstanden, wenn es im die Überladung von Methoden und Funktionen
geht, aber in C? Und von welchen anderen "Features" redest Du?

>> Erfreulicherweise
>> bietet Python aber eine Introspektion an, wie leo oben mit seinem
>> type()-Aufruf gezeigt hat und mit isinstance(),
>
> Das ist aber etwas komplett anderes. Introspektion gibt es zu einem
> gewissen Grad auch in c. sizeof, offsetof, alignof _Generic,
> static_assert, etc. Zwar nur zur compile-time, und nicht ganz so toll
> wie in einigen anderen statisch typisierten Sprachen, aber definitiv
> vorhanden. An Java sieht man, das statische Typisierung und Runtime
> Introspektion sich auch nicht ausschliessen, aber man kann halt nicht
> alles haben.

Echt jetzt, Du willst mir sizeof() & Co als Reflexion bzw. Introspektion
verkaufen? Das ist hoffentlich nicht Dein Ernst. Kannst Du damit denn
zum Beispiel herausfinden, welche (oder auch nur wieviele) Variablen
eine struct enthält? (Übrigens: wenn ich mich jetzt auf das Niveau von
Deiner Argumentation begeben würde, dann würde ich auch noch fragen,
wie Du die Methoden eines Objekts zur Laufzeit herausfinden kannst.)

Und ja, natürlich kann man alles haben, statische Typisierung und auch
Reflexion mit Introspektion. C++, Java und Golang machen ja vor, daß
das nicht nur besser, sondern auch wesentlich typsicherer geht als in
C. Und dann kommt auch noch erschwerend hinzu, daß C dank seines Typs
void leider gar nicht so typsicher ist, wie Du es darstellst.

> Python würde ich aber nicht als stark Typisiert betrachten.

Zum Glück hält sich der Rest der Welt an die üblichen Definitionen,
was starke und schwache Typisierung sind (oder auch, was Reflextion
und Introspektion sind). Und nach diesen Definitionen ist Python nun
einmal stark und dynamisch typisiert.

> Sheeva P. schrieb:
>> Nebenbei bemerkt, kann ich in jeder Spache Bullshit schreiben.
>
> Klar kann man in allen Sprachen Bullshit schreiben. Aber in C muss man
> es wenigstens formal-richtig falsch programmieren. Diese Art von Fehler
> sieht man halt in C sofort, und in Python nicht.

Natürlich muß man in Python ebenfalls formal korrekt programmieren --
und leider ist es nicht richtig, daß man formale Fehler in C sofort
sieht. Tatsächlich sieht man formale Fehler nämlich erst, wenn man
seinen Code kompiliert -- sei es im Normalfall durch Aufruf eines
Compilers, oder durch Aufruf eines der genannten C-Interpreter. Das
kann man in ähnlicher Form aber auch mit den bereits erwähnten Tools
pylint(1) und mypy(1) unter Python haben.

> Es ist und bleibt ein Vorteil und ein Feature, das Python nicht hat.

Wie gesagt und gezeigt, gibt es das Feature, => kein Vorteil für C.

> Und doch, das ist ein
> sehr gutes Argument gegen Python und co. Mein Argument beschränkte sich
> auch nicht nur auf die Fehler, die man so finden kann. Zur Compiletime
> Code generieren, im Vornherein wissen, das Methoden und Membervariablen
> da sind, den richtigen Type haben, Gross genug sind, die die Annahmen
> schon vor dem Ausführen checken, das geht halt in Python alles nicht
> oder nicht so einfach.

Methoden? Membervariablen? In C? Übrigens: ich habe gezeigt, daß es
das Feature auch in Python gibt, womit Dein "sehr gutes Argument gegen
Python und co." zweifellos entkräftet ist.

> Und damit kommen wir wieder zu dem, worum es in dem Argument eigentlich
> ging. cppbert behauptete, in Features schlage Python C immer. Aber da es
> zwangsläufig Features in C gibt, die Python in der jetzigen Form nicht
> haben kann, kann das nicht stimmen.

Also, nochmal: statische Typisierung geht auch in Python, ob Du das
nun wahrhaben willst oder nicht. Und damit erschöpfen sich die tollen
Features von C dann auch schon. C alleine, also ohne die Funktionen
seiner Standardbibliotheken oder zumindest des Betriebssystemkernels,
kann nämlich so ziemlich gar nichts, nichtmal eine Eingabe aus einer
Datei oder von Standard-Input lesen (dazu braucht es mindestens die
Funktionen open(2), read(2) und close(2), die alle Systemfunktionen
sind, oder die Bibliotheksfunktionen fopen(3), fread(3), fclose(3),
die ihrerseits Funktionen aus der Standardbibliothek sind).

Und selbst mit der Standardbibliothek ist C noch ziemlich arm, wenn es
um den Funktionsumfang geht. Multithreading? Fehlanzeige, dazu braucht
es die externe pthread-Bibliothek. Strings? Fehlanzeige, das höchste
der Gefühle sind nullterminierte Arrays von char oder wchar. Memory
Management? Nix da, das darf der arme C-Entwickler alles von Hand
machen -- und wenn er sich dabei mal vertut, egal ob es ein doppeltes
free() ist oder ein anderer Fehler -- führt das überaus regelmäßig zu
Abstürzen oder gar, noch schlimmer, zu bösen Sicherheitslücken.

> Es geht mir nicht darum zu sagen, C wäre besser als Python, sondern
> darum, dass die Implikation, Python sei besser als C, genauso falsch
> ist.

Niemand hat gesagt, Python sei besser als C. Diese Diskussion findet,
Pardon, ausschließlich in Deinem eigenen Kopf statt, und mit Deinem
eigenen Stohmann mußt Du leider selbst fechten.

Was cppbert gesagt hat, ist, daß Python hinsichtlich der Features C
jederzeit spielend schlägt, und ganz genau so ist das auch, wie ich
oben ja schon erklärt habe. C ist eben eine relativ alte und ziemlich
maschinennahe Sprache der dritten Generation mit einer relativ dünnen
Abstraktionsschicht zur ausführenden Hardware, während Python von
vorneherein als General-Purpose-Programmiersprache entworfen wurde und
schon viele Elemente einer Sprache der vierten Generation enthält.

Schau einfach mal kurz auf die Dokumentation der Standardbibliotheken
von Python unter https://docs.python.org/3/library/index.html -- und
dann frag' Dich mal bitte selbst, welche Features davon C mit seinen
Standardbibliotheken von Haus aus beherrscht. Dasselbe gilt noch viel
mehr, wenn Du die Standardbibliotheken außen vor läßt...

> Abgesehen davon, klar haben beide Familien ihre spezifischen Vor- und
> Nachteile. Nur deshalb ist es noch lange kein Bullshit, mal von einer
> Seite welche hervorzuheben, wenn es nötig wird. Wenn man alle Vor und
> Nachteile von Sprachen einfach als irrelevanter Bullshit abtut, wird es
> doch absolut Sinnfrei, über diese Argumentieren zu wollen.

Ist es denn -- für irgendeine beliebige Definition dieses Wortes --
"nötig"? Ich glaube nicht. Und sogar Dir fällt doch offenbar nichts
Besseres dazu ein, als Dich ausgerechnet auf etwas zu kaprizieren, das
weder ein Alleinstellungsmerkmal von C ist und darüber hinaus auch nur
ein Unterschied einerseits im Übersetzungs- und Ausführungsmodell der
verschiedenen Sprachfamilien und andererseits ein daran eng gebundener
Unterschied in der Typisierung dieser Familien ist. Und zweitens fällt
Dir dazu etwas ein, das eine beliebte Quelle von Laufzeitfehlern wie
Abstürzen und gefährlichen Sicherheitslücken ist... Dein Ernst? Sorry,
das ist nicht der hochkompetente Daniel, den ich kenne. Oder bist Du
nicht jener Daniel und hast seinen Account gekapert?

Abschließend möchte ich noch anmerken, daß es dazu noch einen weiteren
Aspekt gibt. Ja, richtig, Python und seine Referenzimplementierung
(die in C geschrieben ist) sind stark, aber dynamisch typisiert. Aber
der (in Python entwickelte) Interpreter PyPy verwendet intern ein
Subset von Python namens RPython, das statisch typisiert wird und von
einem JIT-Compiler so effizient ausgeführt wird, das es in speziellen
Fällen [1] sogar schneller sein kann als C.

Solche speziellen Fälle treten in der Realität übrigens gar nicht so
selten auf, weil C selbst so einen überschaubaren Funktionsumfang hat
und deswegen häufig Funktionen aus dynamischen geladenen Bibliotheken
benutzen muß. Die kann der Optimierer des Compilers aber leider nicht
inlinen, sondern muß relativ aufwändige Operationen betreiben, um den
Code aus der Bibliothek auszuführen.


[1] 
https://morepypy.blogspot.com/2011/02/pypy-faster-than-c-on-carefully-crafted.html

von Sheeva P. (sheevaplug)


Lesenswert?

Joachim D. schrieb:
> Da könnte man auch argumentieren; Phyton ist in C geschrieben,
> dann nehme ich gleich das Original ;)

Das stimmt. Aber wenn man diese Argumentation weiterdenkt, dann braucht 
man doch auch kein C. C wird ohnehin in Assembler übersetzt, also warum 
nicht gleich in Assembler entwickeln? Und ach, wozu eigentlich 
Assembler, das wird doch nur in Maschinencode übersetzt, da kann man 
doch gleich das Original... naja, viel Erfolg, YMMV! ;-)

> Ich denke, das wird sich ergänzen. In C zB eine Mail senden
> gibt locker 80 Zeilen Code, in Phyton sind es 2. Natürlich nur
> einmal Arbeit (kann man ja wiederverwenden).

Richtig, Python hat wie andere interpretierte Skriptsprachen eine 
deutlich höhere Abstraktionsebene. Deswegen muß man (unter anderem) 
keine Typen für die Variablen deklarieren und muß sich auch um das 
Speichermanagement nur sehr selten Gedanken machen, darum kümmert sich 
Python. Aber diese höhere Abstraktionsebene führt zu enormen Vorteilen 
hinsichtlich der Entwicklungszeit -- nicht nur, weil in Python dasselbe 
Ergebnis mit wesentlich weniger Code erzielt werden kann.

Für maximale Performanz, etwa bei aufwändigen Berechnungen von 
Massendaten oder in einem Betriebssystemkernel ist C daher zwar deutlich 
aufwändiger zu entwickeln, in seiner Performanz jedoch ungeschlagen. Und 
ja, auch erfahrene Assemblerentwickler können mit den Fähigkeiten 
moderner Optimizer in C nur selten mithalten.

Bei schätzungsweise deutlich über 90% der Programme, die geschrieben 
werden, spielt die Performanz aber eine vollkommen untergeordnete Rolle. 
Meist, weil das Programm ohnehin den Großteil seiner Laufzeit auf 
Eingaben wartet, entweder des Benutzers, von der Festplatte oder aus dem 
Netzwerk. Wenn ich ohnehin schon eine Sekunde lang auf die zu 
verarbeitenden Daten warten muß, spielt es auch keine große Rolle mehr, 
ob mein Programm eine Tausendstel oder eine Hundertstel Sekunde zur 
Verarbeitung dieser Daten braucht.

> Mal schnell 10 GB an Daten irgendwo einsortieren dürfte unter
> C erheblich schneller gehen.

Ja, ganz sicher tut es das, aber auch da würde ein kluger Entwickler 
vermutlich nicht C, sondern das viel komfortablere C++ nehmen. Das hat 
nämlich in seiner Standard Template Library (STL) (sowie den 
Boost-Bibliotheken) effiziente und ausgereifte Klassen und Funktionen 
für solche Operationen.

Mir selbst ist sowas vor einigen Jahren begegnet, dabei ging es ums 
Housekeeping einer Datenbank, in die täglich etwa 100.000 Schadensfälle 
mit Betrugsbewertungen eingeliefert wurden. Da viele Schadensfälle 
mehrfach eingeliefert wurden, jedoch lediglich die letzte und die 
höchste Betrugsbewertung gebraucht wurde, wollte ich eine intelligente 
Bereinigung der Datenbank um die nicht benötigten Fälle, um die 
Explosion der Datenbank (PostgreSQL) zu vermeiden.

Zuerst habe ich mich mit SQL drangegeben; nach vier Tagen hatte ich dann 
zwar ein korrektes Ergebnis, aber eine Laufzeit von einer Woche für die 
tägliche Reinigung der Datenbank... es liegt auf der Hand, daß das keine 
Lösung des Problems war. In Python dauerte die ganze Sache dann nurmehr 
acht Stunden, das wäre zwar gegangen, erschien mir aber auch nicht sehr 
erstrebenswert, zumal der Kunde hin und wieder fehlerhafte Daten 
geliefert hat und die dann jeweils gelöscht und die korrekten Daten 
neuprozessiert werden mußten.

Schließlich habe ich mich dann mit C++ daran gegeben, damit lag die 
Laufzeit des Programms bei nurmehr etwa einer halben Stunde. Kompilierte 
und maschinennahe Sprachen haben also sowohl ihre Berechtigung als auch 
ihre Vorteile, der Punkt bleibt allerdings: in den meisten Fällen 
spielen diese keine echte Rolle.

> SQLite geht auch unter Python.

Ja, natürlich, und mit einem OR-Mapper wie SQLObject oder SQLAlchemy, um 
einige der beliebtesten zu nennen, geht das häufig sogar viel einfacher 
und zudem unabhängig von der jeweiligen Datenbank. Mit so einem 
OR-Mapper kannst Du nämlich jederzeit von SQLite auf eine andere 
unterstützte Datenbank wechseln, für SQLObjekt zum Beispiel PostgreSQL, 
MySQL, MaxDB oder Sybase -- und alles, was Du dazu tun mußt, ist, den 
Connectionstring in der Konfiguration anzupassen.

Python selbst bietet mit PDO übrigens bereits einen Standard für den 
einfachen Zugriff auf verschiedene Datenbanken an. Das funktioniert 
prima, wenn man keine spezifischen Features der betreffenden Datenbank 
braucht. Andererseits kann das insbesondere bei großen Datenmengen und / 
oder komplexen Queries performanter sein als ein OR-Mapper. Da die 
OR-Mapper aber intern alle einen PDO-kompatiblen Treiber verwenden, an 
dessen Datenbankhandle man mit einigen kleinen Verrenkungen immer 
herankommen kann, läßt sich in solchen Fällen durchaus auch nativer 
SQL-Code mit solchen OR-Mappern verwenden, allerdings nur unter Einbuße 
der Unabhängigkeit von der jeweiligen Datenbankplattform.

> Die Sachen die ich kenne und brauche sind alle vorhanden, ich
> muß sie nur finden ...

Die Dokumentation von Python unter https://docs.python.org/ bietet eine 
sehr gute Übersicht über die Sprache in der Language Reference, über die 
Standardbibliotheken in der Library Reference, und unter 
https://pypi.org/ findest Du etliche Module aus Drittquellen. Wenn Du 
solche Third-Party-Module benutzen möchtest, will ich Dir noch die 
Installation und Benutzung von virtualenv [1] wärmstens nahelegen, damit 
kannst Du vom Rest des Systems abgeschottete Python-Umgebungen anlegen 
und benutzen, ohne etwas in Deine System- und Benutzerverzeichnisse zu 
installieren. Und es ist damit auch möglich, die installierte Version 
Deiner Third-Party-Module festzulegen, was hin und wieder durchaus 
hilfreich sein kann... HTH! ;-)

[1] https://virtualenv.pypa.io/en/latest/

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Hi Sheeva,

das ist alles korrekt und nachvollziehbar.

Ich bin aber mit zB dBASE IV ziemlich auf die Schnauze geflogen
weil das im Netzwerk nicht richtig funktioniert hatte (komplette
Netzwerksbstürze 1mal am Tag) und Ashton-Tate danach platt war.
Es war ein CAD-Postprozessor Calay auf Bestückautomaten und
Handbestückplätze für eine grüßere Bestücklinie. Das geht nicht.

Ich hatte mir damals geschworen nie mehr 3rd-Party einzusetzen.
Schreibe ich es selbst habe ich noch eine Chance ...

Über meinen Schatten bin ich dann mit Btrieve gesprungen, aber
auch erst nach brutalen Tests (volle Last Daten reinschreiben,
dann dem Server den Netzstecker ziehen, überlebt das die DB
ist das System ok). Btrieve ist genial aber zu teuer mittlerweile.

Bei SQLite habe ich den Vorteil: keine Administration. Ich
muß nicht den armen Admin dauernd mit Updates belästigen, es
läuft einfach. Wir müßten sonst in der Firma 2 Leute dafür
einstellen die es im Moment nicht wirklich gibt.

--

Die Pythondoku etc. wühle ich gerade durch. Ich muß ein
Gefühl für die Sprache entwickeln und das dauert halt.

Der Sprachvergleich ist irgendwie auch obsolet: Ich kann
definitiv in C alles machen, in Python kann ich halt Module,
die andere schon gebaut haben, auch verwenden und Arbeit
sparen. In Assembler geht das natürlich auch, hat erheblich
mehr Aufwand ;)

Grüße Joe (mit ausdrücklichem Dank für die interessanten
und ausführlichen Posts)

von vn nn (Gast)


Lesenswert?

DPA schrieb:
> Python würde ich aber nicht als stark Typisiert betrachten.

Tja, zum Glück ist es völlig irrelevant, was du würdest und was nicht.
Natürlich ist es stark typisiert, sonst würde '3' + 7 keine Exception 
werfen.

von DPA (Gast)


Lesenswert?

Ok, ich habe eventuell stark typisiert mit statisch typisiert 
verwechselt. Kann mal passieren.

Wie dem auch sei, betrachten wir mal den Typ von X hier:
1
def f(x):
2
  return 3 * x

Genau, zum jetzigen Zeitpunkt noch nicht bekannt. Das Problem ist halt, 
Metadaten nützen nur etwas, wenn sie da sind, und auch verwendet werden.

Klar, man könnte einen typ angeben, aber man muss nicht. Bei C hat 
man schon vor der Ausführung mehr Informationen über das Programm zur 
verfügung, als bei python. Klar, es gibt Sprachen (z.B. Rust), die dass 
noch viel weiter treiben. Klar, man kann in begrenztem Rahmen in python 
vor der Ausführung die Typen prüfen, die bekannt sind. Aber ohne das 
Programm auszuführen, kann man trotzdem viel weniger aussagen über ein 
Python Programm machen, als über ein C programm. Python ist halt trotz 
allem nicht statisch typisiert, und das ist und bleibt ein gutes 
Argument für C. (Dynamische typisierung kann natürlich auch ein Vorteil 
sein, aber den Blickwinkel haben wir ja schon.)

Sheeva P. schrieb:
> Echt jetzt, Du willst mir sizeof() & Co als Reflexion bzw. Introspektion
> verkaufen? Das ist hoffentlich nicht Dein Ernst.

Vielleicht nicht im engeren Sinne, aber im Grunde geht es bei all dem 
Zeugs doch nur darum Metadaten über einen Programmteil zu ermitteln, und 
im Programm zu nutzen.

Sheeva P. schrieb:
> Weder die statische Typisierung, noch deren Prüfung in einem separaten
> Kompilationsschritt sind also Kernfeatures von C, sondern einer ganzen
> Sprachfamilie,

Klar gibt es viele Sprachen mit den Eigenschaften, dass ändert nichts 
daran, dass C diese auch hat.

> DPA schrieb:
>> Sheeva P. schrieb:
>>> DPA schrieb:
>>>> cppbert schrieb:
>>>>> in Features schlägt Python C immer
>>>>
>>>> Nein. Es gibt viele Features, die nur C hat. Das fängt unter anderem mit
>>>> der statischen typisierung an, und geht mit allen Konstrukten weiter,
>>>> die damit möglich werden.
>
> Welche "Konstrukte" sollten das denn bitte sein? In C++ hätte ich ja
> noch verstanden, wenn es im die Überladung von Methoden und Funktionen
> geht, aber in C? Und von welchen anderen "Features" redest Du?

Denke z.B. an all die Dinge, die man in einen C header packen kann. 
Diese "Interfaces", vor der Ausführung formal festgelegte Garantien 
zwischen Programmteilen, und all das, was man damit machen kann.

> Und dann kommt auch noch erschwerend hinzu, daß C dank seines Typs
> void leider gar nicht so typsicher ist, wie Du es darstellst.

Das ist ber kein Problem, denn mit void kann man nichts tun. Man kann 
void nicht addieren, dereferenzieren, definieren, initialisieren, etc. 
Man kann einen Pointer darauf haben, aber um etwas sinvolles damit 
anfangen zu können, muss man es erst in einen anderen Typ casten. Und 
dann hat man den Typ ja sowieso wieder explizit, schon vor der 
Ausfürung, an der Stelle.

> Methoden? Membervariablen? In C?

Ja, so bezeichne ich meine Funktionspointer und Variablen in meinen 
structs. Man versteht doch, was gemeint ist, das ist das Wichtige.


> Multithreading? Fehlanzeige, dazu braucht
> es die externe pthread-Bibliothek.

C11 hat threads.h und stdatomics.h


>> Es geht mir nicht darum zu sagen, C wäre besser als Python, sondern
>> darum, dass die Implikation, Python sei besser als C, genauso falsch
>> ist.
>
> Niemand hat gesagt, Python sei besser als C.

Deshalb sag ich ja, Implikation. Es reicht, dass der Eindruck entsteht.


>> Abgesehen davon, klar haben beide Familien ihre spezifischen Vor- und
>> Nachteile. Nur deshalb ist es noch lange kein Bullshit, mal von einer
>> Seite welche hervorzuheben, wenn es nötig wird. Wenn man alle Vor und
>> Nachteile von Sprachen einfach als irrelevanter Bullshit abtut, wird es
>> doch absolut Sinnfrei, über diese Argumentieren zu wollen.
>
> Ist es denn -- für irgendeine beliebige Definition dieses Wortes --
> "nötig"? Ich glaube nicht. Und sogar Dir fällt doch offenbar nichts
> Besseres dazu ein, als Dich ausgerechnet auf etwas zu kaprizieren, das
> weder ein Alleinstellungsmerkmal von C ist

Muss es ja auch nicht.

> und darüber hinaus auch nur ein Unterschied einerseits im Übersetzungs- und 
Ausführungsmodell der

Man könnte sicher auch interpreter/script sprachen statisch typisieren.

> verschiedenen Sprachfamilien und andererseits ein daran eng gebundener
> Unterschied in der Typisierung dieser Familien ist. Und zweitens fällt
> Dir dazu etwas ein, das eine beliebte Quelle von Laufzeitfehlern wie
> Abstürzen und gefährlichen Sicherheitslücken ist...

Es ist nunmal halt leider der wichtigste Unterschied, daran kann ich 
nichts ändern.

von Sheeva P. (sheevaplug)


Lesenswert?

Joachim D. schrieb:
> Ich bin aber mit zB dBASE IV ziemlich auf die Schnauze geflogen
> weil das im Netzwerk nicht richtig funktioniert hatte (komplette
> Netzwerksbstürze 1mal am Tag) und Ashton-Tate danach platt war.
> Es war ein CAD-Postprozessor Calay auf Bestückautomaten und
> Handbestückplätze für eine grüßere Bestücklinie. Das geht nicht.

Nein, das geht nicht, das sehe ich genauso. Aber wenn man eine dermaßen 
wichtige Datenbank für seine Produktionslinie(n) braucht, gibt es 
natürlich Konzepte, um Hochverfügbarkeit umzusetzen. Vor zehn, fünfzehn 
Jahren wäre ich bei soetwas wohl bei PostgreSQL und seinen relativ 
einfachen, redundanzbasierten Lösungen gelandet, heutzutage würde ich 
allerdings eher auf etwas moderneres aus dem Umfeld des DC (Distributed 
Computing) gehen -- je Lastprofilen und Softwareumgebung vielleicht 
Redis, Elasticsearch, Aerospike, Cassandra, Hazelcast, ... oder 
womöglich Hana.

> Ich hatte mir damals geschworen nie mehr 3rd-Party einzusetzen.
> Schreibe ich es selbst habe ich noch eine Chance ...

Das Problem dabei ist, daß Deine Lebenszeit vermutlich ähnlich endlich 
ist wie meine, und daß auch selbstentwickelte Komponenten meistens 
Fehler haben -- die, insbesondere in Grenzfällen und 
Hochlastsituationen, schwierig bis gar nicht zu testen sind. Schau Dir 
mal die Tests für verteilte Datenbanken von Kyle Kingsbury auf 
http://jepsen.io/ an, das gibt Dir einen (groben) Vorgeschmack. 
(Nebenbei: wenn Dich Datenbanken und Datenhaltung interessiert, empfehle 
ich eines der mit Abstand großartigsten Bücher, die ich in den letzten 
Jahren gelesen habe: "Designing Data-Intensive Systems" von Martin 
Kleppmann).

Mein Weg ist übrigens genau andersherum verlaufen. Früher war ich so 
heiß auf das Entwickeln und häufig mißtrauisch gegenüber fertigen 
Systemen, daß ich bei jedem Problem erstmal den Editor angeworfen habe. 
Aber das führt letztlich nur zu einem wesentlich größeren Problem, das 
in der Softwarewelt unter NIH bekannt ist, "Not invented here". Dabei 
neigt der Entwickler dazu, immer nur sein gerade aktuelles Problem zu 
lösen, muß seine Software über ihren gesamten Lebenszyklus pflegen und 
warten, und bei neuen Anforderungen erweitern oder sogar neu 
schreiben... Kostet einen Riesenhaufen Zeit und Geld, und häufig ist das 
Ergebnis weder so funktional noch so stabil wie eine etablierte 
Standardlösung.

Was Datenbanken angeht, gibt es für mich daher mittlerweile nur noch 
eine, und das ist PostgreSQL. Klein, schnell, superstabil, hat 
wesentlich mehr Funktionsumfang als jede andere mir bekannte Datenbank, 
und läßt sich wunderbar erweitern -- auch mit Stored Procedures und 
Triggerfunktionen in Python. Und, wie gesagt, für wirklich wichtige 
Dinge gibt es neben mehreren klassischen HA-Methoden mittlerweile auch 
eine echte verteilte Version namens PostgresXL. Aber ich würde 
PostgreSQL niemals unter etwas anderem produktiv betreiben als unter 
Linux oder einem *BSD, obwohl ich schon ein stabiles PostgreSQL unter 
Windows mit > 1 TB Daten gesehen habe.

> Bei SQLite habe ich den Vorteil: keine Administration. Ich
> muß nicht den armen Admin dauernd mit Updates belästigen, es
> läuft einfach. Wir müßten sonst in der Firma 2 Leute dafür
> einstellen die es im Moment nicht wirklich gibt.

Klar, aber produktiv und unter Hochlast mit hoher Concurrency... dafür 
ist SQLite halt nicht ausgelegt. Als Spielzeug benutze ich das auch 
gerne, aber sonst bin ich da überaus skeptisch. Trotzdem, besser als was 
selbstgebasteltes ist das natürlich allemal, vor allem auf lange 
Sicht... ;-)

> Die Pythondoku etc. wühle ich gerade durch. Ich muß ein
> Gefühl für die Sprache entwickeln und das dauert halt.

Mach' Dir keinen Streß, das kommt schon noch. Als interessante Lektüre 
zum Thema empfehle ich gerne noch einen Artikel von Eric S. Raymond, 
Autor von fetchmail und "The Cathedral and The Bazaar": 
https://www.linuxjournal.com/article/3882 -- viel Vergnügen mit seinen 
Erfahrungen, die den meinen sehr ähneln. ;-)

> Der Sprachvergleich ist irgendwie auch obsolet: Ich kann
> definitiv in C alles machen, in Python kann ich halt Module,
> die andere schon gebaut haben, auch verwenden und Arbeit
> sparen. In Assembler geht das natürlich auch, hat erheblich
> mehr Aufwand ;)

Klar, da sind wir wieder bei dem Lebenszeit-Thema. Und mit der Zeit 
wirst Du merken, daß Du mit Python wesentlich größere Projekte angehen 
und in einer überschaubaren Zeit schaffen kannst, als das mit C möglich 
ist. Wie beim Versenden von Email, wie Du oben ja schon angemerkt hast: 
zwei Zeilen Python gegen achtzig Zeilen C, und wenn dann ein Kunde kommt 
und diese HTML- und Plaintext-Mails mit Templating haben will, nimmst Du 
eben Jinja2 als Templateengine und noch zwei Zeilen Python dazu... ;-)

von Sheeva P. (sheevaplug)


Lesenswert?

DPA schrieb:
> Ok, ich habe eventuell stark typisiert mit statisch typisiert
> verwechselt. Kann mal passieren.

Kein Thema. ;-)

> Wie dem auch sei, betrachten wir mal den Typ von X hier:
>
1
> def f(x):
2
>   return 3 * x
3
>
>
> Genau, zum jetzigen Zeitpunkt noch nicht bekannt. Das Problem ist halt,
> Metadaten nützen nur etwas, wenn sie da sind, und auch verwendet werden.

Danke für dieses schöne Beispiel, bei dem ich gern bleiben möchte. In 
Python mit seinem Duck Typing [1] kann x nämlich alles sein, das die 
Methode __rmul__() hat: eine Zahl (int, float, complex, ...), ein String 
(str -- siehe dazu den Sonderfall, den ich oben erwähnt habe), oder 
irgendeine Klasse, selbstdefiniert oder aus einem externen Modul: alles 
kein Problem, siehe dazu mein erweitertes Beispiel:
1
#!/usr/bin/env python
2
3
def f(x): return x * 3
4
5
class c(object):
6
    def __init__(self, val): self.val = val
7
    def __rmul__(self, val): return [val for val in range(self.val)]
8
9
if __name__ == '__main__':
10
    print(f(3))
11
    print(f(3.0))
12
    print(f('abc'))
13
    print(f(complex(3, 3)))
14
    print(f(c(3)))

In C müßte ich, weil es wegen seiner Funktionssignaturen keine 
Überladung kann, für jeden einzelnen Datentyp jeweils eine eigene 
Funktion implementieren. Denn im Kern ist statische Typisierung ja eine, 
wenngleich gewünschte, Beschränkung. Damit wird mein Code aber leider 
auch größer und unübersichtlicher.

C++ löst das Problem elegant mit Templates:
1
template <typename T> T f(T val) { return 3 * val; }

In C++ analysiert der Compiler anhand der statischen Typinformationen, 
was mein Code zur Laufzeit der Funktion f() an Datentypen übergibt, und 
erzeugt jeweils eigene Funktionen dafür alle diese Fälle -- es wäre mal 
spannend zu schauen, was er für beispielsweise std::any macht, aber dazu 
bin ich gerade zu faul.

C dagegen kann keine Objektorientierung, kein Überladen von Funktionen 
und / oder Operatoren, kein... genau. In C müßte ich für jeden Datentyp, 
mit dem ich mein f() benutzen will, eine eigene Version von f() 
schreiben -- natürlich mit einem eigenen Namen. Und C kennt viele 
numerische Datentypen: chat, int, long, float und double, gerne auch mit 
den Modifikatoren signed, unsigned, short und long. Schon eine tolle 
Sache, diese Typsicherheit. Ich persönlich würde vielleicht sogar dazu 
neigen, mir einen kleinen Python-Codegenerator dafür zu schreiben und 
mich darauf zu verlassen, daß der Optimizer des Compilers die 
ungenutzten Versionen wegoptimiert. ;-)

Aber, fragst Du, wie ist das denn mit der Typsicherheit in Python? Nun, 
wie oben bereits erwähnt, existieren Type Hints und Programme, die diese 
überprüfen. Aber natürlich gibt es auch eine "harte" Methode:
1
import numbers
2
3
def f(x):
4
    if not isinstance(x, numbers.Number):
5
        raise TypeError('%s is not a Number'%(str(x)))
6
    return x * 3

Klar, die schlägt auch erst zur Laufzeit an... Aber, wie oben bereits 
länglich und ausführlich erläutert, ist das eine Eigenschaft, die alle 
interpretierten Sprachen gemeinsam haben und dem Konzept "interpretierte 
Sprache" prinzipbedingt, um nicht zu sagen: zwangsläufig inhärent sind.


[1] “When I see a bird that walks like a duck and swims like a duck and 
quacks like a duck, I call that bird a duck.”

> Klar, man könnte einen typ angeben, aber man muss nicht. Bei C hat
> man schon vor der Ausführung mehr Informationen über das Programm zur
> verfügung, als bei python. Klar, es gibt Sprachen (z.B. Rust), die dass
> noch viel weiter treiben. Klar, man kann in begrenztem Rahmen in python
> vor der Ausführung die Typen prüfen, die bekannt sind. Aber ohne das
> Programm auszuführen, kann man trotzdem viel weniger aussagen über ein
> Python Programm machen, als über ein C programm. Python ist halt trotz
> allem nicht statisch typisiert, und das ist und bleibt ein gutes
> Argument für C. (Dynamische typisierung kann natürlich auch ein Vorteil
> sein, aber den Blickwinkel haben wir ja schon.)

Tut mir leid, aber ich sehe das immer noch nicht als Argument für C, 
wenn ich mir diese oben von mir bereits ausgeführte Sache mit den 
C++-Templates betrachte. Das kann C++ wesentlich besser, und deswegen 
sehe ich, mit Ausnahme von Domänen mit großen Mengen vorhandenen Codes 
wie der Kernelentwicklung, heute kein einziges Argument mehr für C -- 
jedoch einige für C++ und andere für Skriptsprachen.

Der wesentliche Kernpunkt bei der Entscheidung zwischen einer 
kompilierten oder einer interpretierten Sprache ist aber eine 
Ressourcenentscheidung. Was ist Dir wichtiger, Entwicklungszeit oder 
Rechenzeit? Und nein, ich meine nicht Laufzeit, denn die meisten 
Programme vertrödeln heute den Großteil ihrer Laufzeit mit dem Warten 
auf Input: vom Benutzer, vom Netzwerk, oder irgendeiner Persistierung.

> Sheeva P. schrieb:
>> Echt jetzt, Du willst mir sizeof() & Co als Reflexion bzw. Introspektion
>> verkaufen? Das ist hoffentlich nicht Dein Ernst.
>
> Vielleicht nicht im engeren Sinne, aber im Grunde geht es bei all dem
> Zeugs doch nur darum Metadaten über einen Programmteil zu ermitteln, und
> im Programm zu nutzen.

Ich bitte Dich, Daniel...

> Sheeva P. schrieb:
>> Weder die statische Typisierung, noch deren Prüfung in einem separaten
>> Kompilationsschritt sind also Kernfeatures von C, sondern einer ganzen
>> Sprachfamilie,
>
> Klar gibt es viele Sprachen mit den Eigenschaften, dass ändert nichts
> daran, dass C diese auch hat.

Aber genau das ist ja mein Punkt: es geht um verschiedene Konzepte.

>> DPA schrieb:
>>>> DPA schrieb:
>>>>> cppbert schrieb:
>>>>>> in Features schlägt Python C immer
>>>>>
>>>>> Nein. Es gibt viele Features, die nur C hat. Das fängt unter anderem mit
>>>>> der statischen typisierung an, und geht mit allen Konstrukten weiter,
>>>>> die damit möglich werden.
>>
> Denke z.B. an all die Dinge, die man in einen C header packen kann.
> Diese "Interfaces", vor der Ausführung formal festgelegte Garantien
> zwischen Programmteilen, und all das, was man damit machen kann.

Das können C++ und andere auch und ist also nichts, das "nur C" kann -- 
und in C sind es ja auch leider nur mittelprächtige Funktionssignaturen.

>> Und dann kommt auch noch erschwerend hinzu, daß C dank seines Typs
>> void leider gar nicht so typsicher ist, wie Du es darstellst.
>
> Das ist ber kein Problem, denn mit void kann man nichts tun.

Ich habe schon ein paar Funktionen gesehen, die zur Laufzeit böse 
explodiert sind, weil sie einen falsche void-Pointer erhalten haben...

>> Methoden? Membervariablen? In C?
>
> Ja, so bezeichne ich meine Funktionspointer und Variablen in meinen
> structs. Man versteht doch, was gemeint ist, das ist das Wichtige.

Nenn' mich vernagelt, aber es widerstrebt mir, objektorientierte 
Fachausdrücke auf etwas anzuwenden, das nicht objektorientiert ist. Es 
wäre sicherlich einfacher, mit Dir zu diskutieren, wenn Du davon 
absähest, eindeutig definierte Fachausdrücke für davon unabhängige Dinge 
zu mißbrauchen. ;-)

>> Multithreading? Fehlanzeige, dazu braucht
>> es die externe pthread-Bibliothek.
>
> C11 hat threads.h und stdatomics.h

Ui, das wußte ich nicht. Dann gibt es bestimmt bald auch Multi- und 
Asynchrones Processing, ich bin gespannt. ;-) Ist aber auch nur ein 
Punkt von den vielen, die ich genannt habe, oder nicht?

>>> Es geht mir nicht darum zu sagen, C wäre besser als Python, sondern
>>> darum, dass die Implikation, Python sei besser als C, genauso falsch
>>> ist.
>>
>> Niemand hat gesagt, Python sei besser als C.
>
> Deshalb sag ich ja, Implikation. Es reicht, dass der Eindruck entsteht.

Das wurde aber auch nie impliziert -- es wurde ja lediglich gesagt: "in 
Features schlägt Python C immer". Und das ist, egal wie Du es drehst und 
wendest, schlicht und ergreifend eine Tatsache.

>> und darüber hinaus auch nur ein Unterschied einerseits im Übersetzungs- und
> Ausführungsmodell der
>
> Man könnte sicher auch interpreter/script sprachen statisch typisieren.

Das tut aber niemand, und weißt Du, warum? Weil es Unfug ist! 
Skriptsprachen haben ohnehin keinen separaten Kompilationsschritt, in 
dem diese statische Typisierung überprüft werden kann. Man kann in 
Skriptsprachen -- unabhängig von der konkreten Typisierung -- viel 
schneller entwickeln, und zwei wesentliche Gründe dafür sind, daß auf 
eine manuelle Ressourcenverwaltung und auch auf eine statische 
Typisierung (weitestgehend) verzichtet wird.

Genau dieser Verzicht führt aber dazu, daß die Produktivität des 
Entwicklers in einer interpretierten Sprache viel höher ist als in einer 
kompilierten. Deswegen müssen wir im Kern über Ressourcen reden: 
Computerressourcen versus menschliche Arbeitszeit. Du fügst nun noch 
einen weiteren Punkt hinzu, die Fehlerbehandlung.

Ehrlich gesagt -- und in Kenntnis verschiedener Studien zu diesem Thema 
-- glaube ich nicht, daß Du Dich auf diese Diskussion einlassen 
möchtest. Entwickler sind wesentlich teurer als Computer, und deswegen 
haben die interpretierten Sprachen in der Breite schon längst gewonnen, 
außer in bestimmten Domänen: Hochperformanz und Betriebssystemkerne. 
Dort, wo es um schnelle Anpassungen und Veränderungen geht, insbesondere 
im Webdevelopment, gibt es so gut wie gar nichts Kompiliertes mehr, 
dort, wo es außerdem um Stabilität und Performanz geht, wird es für 
Kompilierte langsam wirklich eng: die größte Bank der Welt, 
Goldman-Sachs, beschäftigt etwa eintausend Python-Entwickler sicher 
nicht aus Vergnügen. Die NASA auch nicht...

Wobei das ja auch nicht ganz richtig ist: Hochperformanz wird heute sehr 
häufig in Python gemacht. Warum? Weil wir bekloppten Kids längst von 
einzelnen Rechnern weg sind und mit Clustern aus Commodity-Rechnern 
arbeiten. Okay, die Klügeren von uns jedenfalls. Was meinst Du wohl, 
warum es für Python solche coolen Erweiterungen wie numpy, scipy oder 
Pandas gibt, und warum etliche Distributed-Computing-Frameworks 
Schnittstellen für Python mitbringen? Genau.

Warum ist Python in der wissenschaftlichen Gemeinde so beliebt? Richtig: 
weil die Leute dort sich lieber auf ihre Domäne, also ihre Wissenschaft 
konzentrieren, als sich um Ressourcenverwaltung und Datentypisierung zu 
kümmern. Daten fressen und kommunizieren, das ist deren Job. Gibt es was 
wie Matplotlib oder Bokeh für C?

... an dieser Stelle könnte ich vermutlich noch zehntausend Zeilen 
weitermachen, aber ich möchte Dir nicht auf die Füße treten -- und auch 
zu den vielen anderen C-Freunden in diesem Forum nicht gemein sein. 
Alles gut, Daniel?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.