Python ist stark dynamisch typisiert.
- Starke Typisierung bedeutet, dass sich der Typ eines Werts nicht auf unerwartete Weise ändert. Eine Zeichenfolge, die nur Ziffern enthält, wird nicht auf magische Weise zu einer Zahl, wie dies in Perl der Fall sein kann. Jede Änderung des Typs erfordert eine explizite Konvertierung.
- Dynamische Typisierung bedeutet, dass Laufzeitobjekte (Werte) einen Typ haben, im Gegensatz zur statischen Typisierung, bei der Variablen einen Typ haben.
Wie für Ihr Beispiel
bob = 1
bob = "bob"
Dies funktioniert, weil die Variable keinen Typ hat. es kann jedes Objekt benennen. Danach bob=1
werden Sie feststellen, dass es type(bob)
zurückkehrt int
, aber danach bob="bob"
kehrt es zurück str
. (Beachten Sie, dass dies type
eine reguläre Funktion ist. Daher wertet sie das Argument aus und gibt dann den Typ des Werts zurück.)
Vergleichen Sie dies mit älteren Dialekten von C, die schwach und statisch typisiert waren, so dass Zeiger und ganze Zahlen ziemlich austauschbar waren. (Modernes ISO C erfordert in vielen Fällen Konvertierungen, aber mein Compiler ist diesbezüglich standardmäßig nachsichtig.)
Ich muss hinzufügen, dass die starke oder schwache Typisierung eher ein Kontinuum als eine boolesche Wahl ist. C ++ hat eine stärkere Typisierung als C (mehr Konvertierungen erforderlich), aber das Typsystem kann mithilfe von Zeigerumwandlungen untergraben werden.
Die Stärke des Typsystems in einer dynamischen Sprache wie Python hängt wirklich davon ab, wie seine Grundelemente und Bibliotheksfunktionen auf verschiedene Typen reagieren. ZB +
ist überladen, so dass es mit zwei Zahlen oder zwei Zeichenfolgen funktioniert , aber nicht mit einer Zeichenfolge und einer Zahl. Dies ist eine Designentscheidung, die bei +
der Implementierung getroffen wurde, aber nicht wirklich eine Notwendigkeit, die sich aus der Semantik der Sprache ergibt. Wenn Sie +
einen benutzerdefinierten Typ überladen , können Sie ihn implizit in eine Zahl konvertieren lassen:
def to_number(x):
"""Try to convert function argument to float-type object."""
try:
return float(x)
except (TypeError, ValueError):
return 0
class Foo:
def __init__(self, number):
self.number = number
def __add__(self, other):
return self.number + to_number(other)
Eine Klasseninstanz Foo
kann anderen Objekten hinzugefügt werden:
>>> a = Foo(42)
>>> a + "1"
43.0
>>> a + Foo
42
>>> a + 1
43.0
>>> a + None
42
Beachten Sie, dass Python, obwohl es stark typisiert ist, völlig in Ordnung ist, Objekte vom Typ int
und hinzuzufügen, float
und ein Objekt vom Typ zurückgibt float
(z . B. int(42) + float(1)
Rückgaben 43.0
). Andererseits würde sich Haskell aufgrund der Nichtübereinstimmung zwischen den Typen beschweren, wenn man Folgendes versucht (42 :: Integer) + (1 :: Float)
. Dies macht Haskell zu einer streng typisierten Sprache, in der Typen völlig unzusammenhängend sind und nur eine kontrollierte Form der Überladung über Typklassen möglich ist.
True
oder umgewandelt wirdFalse
. Aber was ist mit Nummernwerbung?1.0 + 2
funktioniert in Python genauso gut wie in Perl oder C, obwohl"1.0" + 2
dies nicht der Fall ist. Ich stimme @jbrendel zu, dass dies keine implizite Konvertierung ist, sondern nur eine Überladung - aber im gleichen Sinne führt Perl auch keine implizite Konvertierung durch. Wenn Funktionen keine deklarierten Parametertypen haben, können implizite Konvertierungen nirgendwo stattfinden.if isValid(value) - 1
kann auslaufen. Der Boolesche Wert wird in eine Ganzzahl umgewandelt, die dann als wahrheitsgemäßer Wert ausgewertet wird.False - 1
wird wahr undTrue - 1
falsch, was zu einem peinlich schwierigen zweischichtigen Fehler beim Debuggen führt. In diesem Sinne ist Python meist stark typisiert; Typzwänge verursachen normalerweise keine logischen Fehler.Es gibt einige wichtige Punkte, die meiner Meinung nach alle vorhandenen Antworten übersehen haben.
Schwache Eingabe bedeutet, den Zugriff auf die zugrunde liegende Darstellung zu ermöglichen. In C kann ich einen Zeiger auf Zeichen erstellen und dann dem Compiler mitteilen, dass ich ihn als Zeiger auf Ganzzahlen verwenden möchte:
Auf einer Little-Endian-Plattform mit 32-Bit-Ganzzahlen wird daraus
i
ein Array der Zahlen0x64636261
und0x00676665
. Sie können sogar selbst Zeiger auf Ganzzahlen (der entsprechenden Größe) umwandeln:Und das bedeutet natürlich, dass ich Speicher überall im System überschreiben kann. *
* Natürlich verwenden moderne Betriebssysteme virtuellen Speicher und Seitenschutz, sodass ich nur den Speicher meines eigenen Prozesses überschreiben kann, aber nichts an C selbst bietet einen solchen Schutz, wie jeder, der jemals beispielsweise auf Classic Mac OS oder Win16 codiert hat, Ihnen sagen kann.
Traditionelles Lisp erlaubte ähnliche Arten von Hackerangriffen; Auf einigen Plattformen waren Doppelwort-Floats und Cons-Zellen vom gleichen Typ, und Sie konnten einfach eine an eine Funktion übergeben, die die andere erwartet, und es würde "funktionieren".
Die meisten Sprachen sind heute nicht ganz so schwach wie C und Lisp, aber viele von ihnen sind immer noch etwas undicht. Zum Beispiel jede OO-Sprache mit einem ungeprüften "Downcast" *, das ein Typleck ist: Sie sagen dem Compiler im Wesentlichen: "Ich weiß, ich habe Ihnen nicht genügend Informationen gegeben, um zu wissen, dass dies sicher ist, aber ich bin mir ziemlich sicher es ist, "wenn der springende Punkt eines Typsystems ist, dass der Compiler immer genug Informationen hat, um zu wissen, was sicher ist.
* Ein überprüfter Downcast macht das Typensystem der Sprache nicht schwächer, nur weil die Prüfung auf Laufzeit verschoben wird. Wenn dies der Fall wäre, wäre der Subtyp-Polymorphismus (auch bekannt als virtuelle oder volldynamische Funktionsaufrufe) dieselbe Verletzung des Typsystems, und ich glaube, niemand möchte das sagen.
Sehr wenige "Skriptsprachen" sind in diesem Sinne schwach. Selbst in Perl oder Tcl können Sie einen String nicht nehmen und seine Bytes nur als Ganzzahl interpretieren. * Aber es ist erwähnenswert, dass Sie in CPython (und ähnlich für viele andere Interpreter für viele Sprachen) wirklich hartnäckig sind kann verwendet
ctypes
werdenlibpython
, um ein Objekt zu laden , auf ein Objektid
zu werfenPOINTER(Py_Object)
und das Typsystem zum Auslaufen zu zwingen. Ob dies das Typsystem schwach macht oder nicht, hängt von Ihren Anwendungsfällen ab. Wenn Sie versuchen, eine Sandbox mit eingeschränkter Ausführung in der Sprache zu implementieren, um die Sicherheit zu gewährleisten, müssen Sie sich mit solchen Escape-Effekten auseinandersetzen.* Sie können eine Funktion wie verwenden
struct.unpack
, um die Bytes zu lesen und ein neues int aus "wie C diese Bytes darstellen würde" zu erstellen, aber das ist offensichtlich nicht undicht; sogar Haskell erlaubt das.In der Zwischenzeit unterscheidet sich die implizite Konvertierung wirklich von einem schwachen oder undichten System.
Jede Sprache, auch Haskell, hat Funktionen, um beispielsweise eine Ganzzahl in einen String oder ein Float umzuwandeln. Einige Sprachen führen einige dieser Konvertierungen jedoch automatisch für Sie durch, z. B. in C, wenn Sie eine Funktion aufrufen, die eine möchte
float
, und diese übergebenint
, wird sie für Sie konvertiert. Dies kann definitiv zu Fehlern mit beispielsweise unerwarteten Überläufen führen, aber es handelt sich nicht um die gleichen Arten von Fehlern, die Sie von einem schwachen Typsystem erhalten. Und C ist hier nicht wirklich schwächer; Sie können in Haskell ein int und ein float hinzufügen oder sogar ein float zu einer Zeichenfolge verketten. Sie müssen dies nur expliziter tun.Und mit dynamischen Sprachen ist das ziemlich trübe. In Python oder Perl gibt es keine "Funktion, die einen Float will". Es gibt jedoch überladene Funktionen, die unterschiedliche Aufgaben mit unterschiedlichen Typen ausführen, und es besteht ein starkes intuitives Gefühl, dass das Hinzufügen einer Zeichenfolge zu etwas anderem "eine Funktion ist, die eine Zeichenfolge möchte". In diesem Sinne scheinen Perl, Tcl und JavaScript viele implizite Konvertierungen durchzuführen (
"a" + 1
gibt Ihnen"a1"
), während Python viel weniger ausführt ("a" + 1
eine Ausnahme1.0 + 1
auslöst, Ihnen aber2.0
* gibt). Es ist nur schwer, diesen Sinn in formale Begriffe zu fassen - warum sollte es keine geben+
, die einen String und ein Int benötigt, wenn es offensichtlich andere Funktionen wie die Indizierung gibt, die dies tun?* Tatsächlich kann dies in modernem Python durch OO-Subtypisierung erklärt werden, da dies
isinstance(2, numbers.Real)
wahr ist. Ich glaube nicht, dass es in irgendeiner Weise2
eine Instanz des Stringtyps in Perl oder JavaScript gibt ... obwohl dies in Tcl tatsächlich der Fall ist, da alles eine Instanz eines Strings ist.Schließlich gibt es noch eine andere, vollständig orthogonale Definition von "stark" vs. "schwach", wobei "stark" kraftvoll / flexibel / ausdrucksstark bedeutet.
Mit Haskell können Sie beispielsweise einen Typ definieren, der eine Zahl, eine Zeichenfolge, eine Liste dieses Typs oder eine Zuordnung von Zeichenfolgen zu diesem Typ ist. Dies ist eine perfekte Möglichkeit, alles darzustellen, was aus JSON dekodiert werden kann. Es gibt keine Möglichkeit, einen solchen Typ in Java zu definieren. Aber zumindest hat Java parametrische (generische) Typen, sodass Sie eine Funktion schreiben können, die eine Liste von T verwendet und weiß, dass die Elemente vom Typ T sind. Andere Sprachen, wie das frühe Java, haben Sie gezwungen, eine Liste von Objekten und Downcasts zu verwenden. Zumindest mit Java können Sie jedoch neue Typen mit eigenen Methoden erstellen. Mit C können Sie nur Strukturen erstellen. Und BCPL hatte das nicht einmal. Und so weiter bis zur Montage, wo die einzigen Typen unterschiedliche Bitlängen sind.
In diesem Sinne ist das Haskell-Typsystem stärker als das moderne Java, das stärker ist als das frühere Java, das stärker ist als das C, das stärker als das BCPL ist.
Wo passt Python in dieses Spektrum? Das ist ein bisschen schwierig. In vielen Fällen können Sie mit der Eingabe von Enten alles simulieren, was Sie in Haskell tun können, und sogar einige Dinge, die Sie nicht können. Sicher, Fehler werden zur Laufzeit anstatt zur Kompilierungszeit abgefangen, aber sie werden immer noch abgefangen. Es gibt jedoch Fälle, in denen das Tippen von Enten nicht ausreicht. In Haskell können Sie beispielsweise feststellen, dass eine leere Liste von Ints eine Liste von Ints ist, sodass Sie entscheiden können, dass das Reduzieren
+
über diese Liste 0 * zurückgeben soll. In Python ist eine leere Liste eine leere Liste. Es gibt keine Typinformationen, die Ihnen bei der Entscheidung helfen, was eine Reduzierung+
bewirken soll.* Tatsächlich lässt Haskell Sie dies nicht zu. Wenn Sie die Reduktionsfunktion aufrufen, die keinen Startwert für eine leere Liste annimmt, wird eine Fehlermeldung angezeigt. Aber seine Art System ist leistungsfähig genug , dass man könnte diese Arbeit machen, und Python ist es nicht.
quelle
char sz[]
ist kein Zeiger auf char, sondern ein Array von char, und in der Zuweisung zerfällt es in einen Zeiger.Sie verwechseln "stark typisiert" mit "dynamisch typisiert" .
Ich kann den Typ von nicht
1
durch Hinzufügen der Zeichenfolge ändern'12'
, aber ich kann auswählen, welche Typen ich in einer Variablen speichere, und dies während der Laufzeit des Programms ändern.Das Gegenteil von dynamischer Typisierung ist statische Typisierung. Die Deklaration von Variablentypen ändert sich während der Lebensdauer eines Programms nicht. Das Gegenteil von starkem Tippen ist schwaches Tippen; Die Art der Werte kann sich während der Lebensdauer eines Programms ändern.
quelle
Laut diesem Wiki-Python- Artikel ist Python sowohl dynamisch als auch stark typisiert (bietet auch eine gute Erklärung).
Vielleicht denken Sie an statisch typisierte Sprachen, in denen sich die Typen während der Programmausführung nicht ändern können und die Typüberprüfung während der Kompilierungszeit erfolgt, um mögliche Fehler zu erkennen.
Diese SO-Frage könnte von Interesse sein: Dynamische Typensprachen im Vergleich zu statischen Typensprachen. Dieser Wikipedia-Artikel zu Typensystemen enthält weitere Informationen
quelle
TLDR;
Python gibt Dynamic ein, sodass Sie eine Zeichenfolgenvariable in eine int ändern können
Die Python-Eingabe ist stark, sodass Sie keine Typen zusammenführen können:
In schwach typisiertem Javascript passiert dies ...
In Bezug auf Typinferenz
Java zwingt Sie, Ihre Objekttypen explizit zu deklarieren
Kotlin verwendet Inferenz, um zu erkennen, dass es sich um eine handelt
int
Da jedoch beide Sprachen statische Typen verwenden,
x
kann diese nicht von einer geändert werdenint
. Keine der beiden Sprachen würde eine dynamische Veränderung zulassenquelle
'x' + 3
möglicherweiseoperator+
überladen und die Typkonvertierung hinter den Kulissen durchführen?Es wurde bereits einige Male beantwortet, aber Python ist eine stark typisierte Sprache:
Folgendes in JavaScript:
Das ist der Unterschied zwischen schwacher und starker Eingabe. Schwache Typen versuchen automatisch, je nach Kontext (z. B. Perl) von einem Typ in einen anderen zu konvertieren. Starke Typen konvertieren niemals implizit.
Ihre Verwirrung liegt in einem Missverständnis darüber, wie Python Werte an Namen bindet (allgemein als Variablen bezeichnet).
In Python haben Namen keine Typen, sodass Sie Folgendes tun können:
Und Namen können an alles gebunden werden:
Zur weiteren Lektüre:
https://en.wikipedia.org/wiki/Dynamic_dispatch
und die etwas verwandten, aber fortgeschritteneren:
http://effbot.org/zone/call-by-object.htm
quelle
"3"*4
in Python tun . Das Ergebnis ist natürlich"3333"
. Sie würden nicht sagen, dass es beides konvertiert. Das könnte natürlich nur eine Diskussion über die Semantik sein.float
aus der Kombination von erzeugtfloat
undint
den Typ implizit konvertiert. Es gibt eine natürliche Beziehung zwischen float und int, und tatsächlich formuliert die Typenerbarchie dies. Ich nehme an, Sie könnten argumentieren, dass Javascript genau definierte Operationen in Betracht zieht'3'+4
und'e'+4
beide genau so definiert sind, wie Python es als3.0 + 4
gut definiert betrachtet, aber zu diesem Zeitpunkt gibt es wirklich keine starken oder schwachen Typen, nur (un) definierte Operationen.Eine Python-Variable speichert einen untypisierten Verweis auf das Zielobjekt, das den Wert darstellt.
Jede Zuweisungsoperation bedeutet, dass die nicht typisierte Referenz dem zugewiesenen Objekt zugewiesen wird - dh das Objekt wird über die ursprüngliche und die neue (gezählte) Referenz geteilt.
Der Werttyp ist an das Zielobjekt gebunden, nicht an den Referenzwert. Die (starke) Typprüfung erfolgt, wenn eine Operation mit dem Wert ausgeführt wird (Laufzeit).
Mit anderen Worten, Variablen haben (technisch) keinen Typ - es ist nicht sinnvoll, in Form eines Variablentyps zu denken, wenn man genau sein will. Aber Referenzen werden automatisch dereferenziert und wir denken tatsächlich in Bezug auf den Typ des Zielobjekts.
quelle
Der Begriff "starke Typisierung" hat keine definitive Definition.
Daher hängt die Verwendung des Begriffs davon ab, mit wem Sie sprechen.
Ich betrachte keine Sprache, in der der Typ einer Variablen weder explizit deklariert noch statisch typisiert ist, als stark typisiert.
Starke Typisierung schließt nicht nur die Konvertierung aus (z. B. "automatische" Konvertierung von einer Ganzzahl in eine Zeichenfolge). Dies schließt eine Zuweisung aus (dh das Ändern des Typs einer Variablen).
Wenn der folgende Code kompiliert (interpretiert) wird, ist die Sprache nicht stark typisiert:
Foo = 1 Foo = "1"
In einer stark typisierten Sprache kann sich ein Programmierer auf einen Typ "verlassen".
Wenn beispielsweise ein Programmierer die Deklaration sieht,
UINT64 kZarkCount;
und er oder sie weiß, dass 20 Zeilen später kZarkCount immer noch ein UINT64 ist (solange es im selben Block vorkommt) - ohne den dazwischenliegenden Code untersuchen zu müssen.
quelle
Ich habe gerade eine großartige, prägnante Möglichkeit entdeckt, sie auswendig zu lernen:
quelle
Ich denke, dieses einfache Beispiel sollte Ihnen die Unterschiede zwischen starker und dynamischer Typisierung erklären:
Java:
quelle
Das Obige würde in einem großen System über einen langen Zeitraum einen Albtraum von nicht wartbarem Code erzeugen. Nennen Sie es wie Sie wollen, aber die Fähigkeit, einen Variablentyp "dynamisch" zu ändern, ist nur eine schlechte Idee ...
quelle