Is Python Strongly Typed

Is Python strongly typed?

Python is strongly, dynamically typed.

  • Strong typing means that the type of a value doesn't change in unexpected ways. A string containing only digits doesn't magically become a number, as may happen in Perl. Every change of type requires an explicit conversion.
  • Dynamic typing means that runtime objects (values) have a type, as opposed to static typing where variables have a type.

As for your example

bob = 1
bob = "bob"

This works because the variable does not have a type; it can name any object. After bob=1, you'll find that type(bob) returns int, but after bob="bob", it returns str. (Note that type is a regular function, so it evaluates its argument, then returns the type of the value.)

Contrast this with older dialects of C, which were weakly, statically typed, so that pointers and integers were pretty much interchangeable. (Modern ISO C requires conversions in many cases, but my compiler is still lenient about this by default.)

I must add that the strong vs. weak typing is more of a continuum than a boolean choice. C++ has stronger typing than C (more conversions required), but the type system can be subverted by using pointer casts.

The strength of the type system in a dynamic language such as Python is really determined by how its primitives and library functions respond to different types. E.g., + is overloaded so that it works on two numbers or two strings, but not a string and an number. This is a design choice made when + was implemented, but not really a necessity following from the language's semantics. In fact, when you overload + on a custom type, you can make it implicitly convert anything to a number:

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)

Instance of class Foo can be added to other objects:

>>> a = Foo(42)
>>> a + "1"
43.0
>>> a + Foo
42
>>> a + 1
43.0
>>> a + None
42

Observe that even though strongly typed Python is completely fine with adding objects of type int and float and returns an object of type float (e.g., int(42) + float(1) returns 43.0). On the other hand, due to the mismatch between types Haskell would complain if one tries the following (42 :: Integer) + (1 :: Float). This makes Haskell a strictly typed language, where types are entirely disjoint and only a controlled form of overloading is possible via type classes.

Is Python a weakly typed language as variables can switch types?

Your example demonstrates dynamic typing, not weak typing. Dynamic typing generally means that the type of data an object can store is mutable; any target may hold a binding to any kind of object. Contrast that with, say, C#, which is statically typed [*].

int i = 5; // Okay.
i = "5"; // Illegal! i can only hold integers.

Strong typing means that once assigned a value of a particular kind, objects obey strict rules about how they can interact with other objects of various types. Weak typing means that such rules are more relaxed. This doesn't mean that strongly typed languages are necessarily superior in any way; it's just a language design choice.

Python is considered strongly typed because objects have a distinct notion of what they type they are. Incompatible operations between objects cause errors:

>>> 1 + 1          # Add two integers.
2
>>> "1" + "1" # Concatenate two strings.
'11'
>>> 1 + int("1") # Add two integers.
2
>>> "1" + str(1) # Concatenate two strings.
'11'
>>> 1 + "1" # Undefined! Adding integers and strings is meaningless.
Traceback (most recent call last):
File "", line 5, in ?
TypeError: unsupported operand type(s) for +: 'int' and 'str'

But in PHP, the rules are much more relaxed about what is acceptable. Thus it is considered more weakly typed than some other languages.

$x = 1 + "1"; // x is 2

[*] Technically, as of C# 4, C# is statically typed but with opt-in dynamic typing on a per-binding basis, thanks to the dynamic keyword. A lot of languages these days are adding dynamic capabilities and blurring the lines, so it's becoming increasingly harder to say that "language X is dynamic" and "language Y is static". It's much more of a sliding scale or a spectrum than it is a binary property.

What is the difference between a strongly typed language and a statically typed language?

What is the difference between a strongly typed language and a statically typed language?

A statically typed language has a type system that is checked at compile time by the implementation (a compiler or interpreter). The type check rejects some programs, and programs that pass the check usually come with some guarantees; for example, the compiler guarantees not to use integer arithmetic instructions on floating-point numbers.

There is no real agreement on what "strongly typed" means, although the most widely used definition in the professional literature is that in a "strongly typed" language, it is not possible for the programmer to work around the restrictions imposed by the type system. This term is almost always used to describe statically typed languages.

Static vs dynamic

The opposite of statically typed is "dynamically typed", which means that

  1. Values used at run time are classified into types.
  2. There are restrictions on how such values can be used.
  3. When those restrictions are violated, the violation is reported as a (dynamic) type error.

For example, Lua, a dynamically typed language, has a string type, a number type, and a Boolean type, among others. In Lua every value belongs to exactly one type, but this is not a requirement for all dynamically typed languages. In Lua, it is permissible to concatenate two strings, but it is not permissible to concatenate a string and a Boolean.

Strong vs weak

The opposite of "strongly typed" is "weakly typed", which means you can work around the type system. C is notoriously weakly typed because any pointer type is convertible to any other pointer type simply by casting. Pascal was intended to be strongly typed, but an oversight in the design (untagged variant records) introduced a loophole into the type system, so technically it is weakly typed.
Examples of truly strongly typed languages include CLU, Standard ML, and Haskell. Standard ML has in fact undergone several revisions to remove loopholes in the type system that were discovered after the language was widely deployed.

What's really going on here?

Overall, it turns out to be not that useful to talk about "strong" and "weak". Whether a type system has a loophole is less important than the exact number and nature of the loopholes, how likely they are to come up in practice, and what are the consequences of exploiting a loophole. In practice, it's best to avoid the terms "strong" and "weak" altogether, because

  • Amateurs often conflate them with "static" and "dynamic".

  • Apparently "weak typing" is used by some persons to talk about the relative prevalance or absence of implicit conversions.

  • Professionals can't agree on exactly what the terms mean.

  • Overall you are unlikely to inform or enlighten your audience.

The sad truth is that when it comes to type systems, "strong" and "weak" don't have a universally agreed on technical meaning. If you want to discuss the relative strength of type systems, it is better to discuss exactly what guarantees are and are not provided.
For example, a good question to ask is this: "is every value of a given type (or class) guaranteed to have been created by calling one of that type's constructors?" In C the answer is no. In CLU, F#, and Haskell it is yes. For C++ I am not sure—I would like to know.

By contrast, static typing means that programs are checked before being executed, and a program might be rejected before it starts. Dynamic typing means that the types of values are checked during execution, and a poorly typed operation might cause the program to halt or otherwise signal an error at run time. A primary reason for static typing is to rule out programs that might have such "dynamic type errors".

Does one imply the other?

On a pedantic level, no, because the word "strong" doesn't really mean anything. But in practice, people almost always do one of two things:

  • They (incorrectly) use "strong" and "weak" to mean "static" and "dynamic", in which case they (incorrectly) are using "strongly typed" and "statically typed" interchangeably.

  • They use "strong" and "weak" to compare properties of static type systems. It is very rare to hear someone talk about a "strong" or "weak" dynamic type system. Except for FORTH, which doesn't really have any sort of a type system, I can't think of a dynamically typed language where the type system can be subverted. Sort of by definition, those checks are bulit into the execution engine, and every operation gets checked for sanity before being executed.

Either way, if a person calls a language "strongly typed", that person is very likely to be talking about a statically typed language.

Is Haskell a strongly typed programming language?

Static — types are known at compile time. Java and Haskell have static typing. Also C/C++, C#, Go, Scala, Rust, Kotlin, Pascal to list a few more.

A statically typed language might or might not have type inference. Java almost completely lacks type inference (but it's very slowly changing just a little bit); Haskell has full type inference (except with certain very advanced extensions).

(Type inference is when you only have to declare a minimal amount of types by hand, e.g. var isFoo = true and var person = new Person(), instead of bool isFoo = ... and Person person = ....)

Dynamic — Python, JavaScript, Ruby, PHP, Clojure (and Lisps in general), Prolog, Erlang, Groovy etc. Can also be called "unityped"; dynamic typing can be "emulated" in a static setting, but the reverse is not true except by using external static analysis tools. Some languages make it possible to mix dynamic and static (see gradual typing, e.g. https://typedclojure.org/).

Some languages enable static typing for one or more modules, applied at import time, for example: Python+Mypy, Typed Clojure, JavaScript+Flow, PHP+Hack to name a few.

Strong — values that are intended to be treated as Cat always are; trying to treat them like a Dog will cause a loud meeewww... I mean error.

Weak — this effectively boils down to 2 similar but distinct things: type coercion (e.g. "5"+3 equals 8 in PHP — or does it!) and memory reinterpretation (e.g. (int) someCharValue or (bool) somePtr in C, and C++ as well, but C++ wants you to explicitly say reinterpret_cast). So there's really coercion-weak and reinterpretation-weak, and different languages are weak in one or both of these ways.

Interestingly, note that coercion is implicit by nature and memory reinterpretation is explicit (except in Assembly) — so weak typing consists of an implicit and an explicit behavior. Maybe that's even more of a reason to refer to 2 distinct subcategories under weak typing.


There are languages with all 4 possible combinations, and variations/gradations thereof.

Haskell is static+strong; of course it has unsafeCoerce so it can be static+a bit reinterpret-weak at times, but unsafeCoerce is very much frowned upon except in extreme situations where you are sure about something being the case but just can't seem to persuade the compiler without going all the way back and retelling the entire story in a different way.

C is static+weak because all memory can freely be reinterpreted as something it originally was not meant to contain, hence weak. But all of those reinterpretations are kept track of by the type checker, so still fully static too. But C does not do implicit coercions, so it's only reinterpret-weak.

Python is dynamic+almost entirely strong — there are no types known on any given line of code prior to reaching that line during execution, however values that live at runtime do have types associated with them and it's impossible to reinterpret memory. Implicit coercions are also kept to a meaningful minimum, so one might say Python is 99.9% strong and 0.01% coercion-weak.

PHP and JavaScript are dynamic+mostly weak — dynamic, in that nothing has type until you execute and introspect its contents, and also weak in that coercions happen all the time and with things you'd never really expect to be coerced, unless you are only calling methods and functions and not using built-in operations. These coercions are a source of a lot of humor on the internet. There are no memory reinterpretations so PHP and JS are coercion-weak.


Furthermore, some people like to think that static typing is about variables having type, and strong typing is about values having type — this is a very useful way to go about understanding the full picture, but it's not quite true: some dynamically typed languages also allow variables/parameters to be annotated with types/constraints that are enforced at runtime.

In static typing, it's expressions that have a type; the fact of variables having type is only a consequence of variables being used as a means to glue bigger expressions together from smaller ones, so it's not variables per se that have types.

Similarly, in dynamic typing, it's not the variables that lack statically known type — it's all expressions! Variables lacking type is merely a consequence of the expressions they store lacking type.


One final illustration

In dynamic typing, all the cats, dogs and even elephants (in fact entire zoos!) are packaged up in identically sized boxes.

In static typing these boxes look different and have stickers on them saying what's inside.

Some people like it because they can just use a single box form factor and don't have to put any labels on the boxes — it's only the arrangement of boxes with regards to each other that implicitly (and hopefully) provides type sanity.

Some people also like it because it allows them to do all sorts of tricks with tigers temporarily being transported in boxes that smell like lions, and bears put in the same array of interconnected boxes as wolves or deer.

In such label-free setting of transport boxes, all the possible logicistics scenarios need to be played or simulated in order to detect misalignment in the implicit arrangement, like in a stage performance. No reliable guarantees can be given based on reasoning only, generally speaking. (ad-hoc test cases that need for the entire system to be started up for any partial conclusions to be obtained of its soundness)

With labels and explicit rules on how to deal with boxes of various labels, automated/mechanized logical reasoning can be used to draw up conclusions on what the logistics system won't do or will do for sure (static verification, formal proof, or at least pseudo-proof like QuickCheck), Some aspects of the logistics still need to be verified with trial runs, such as whether the logistics team even got the client right. (integration testing, acceptance testing, end user sanity checks).


Moreover, in weak typing dogs can be sliced up and reassembled as frankenstein cats. Whether they like it or not, and whether the result is ugly or not. (weak typing)

But if you add labels to the boxes, it still matters that Frankenstein cats be put in cat boxes. (static+weak typing)


In strong typing, while you can put a cat in the box of a dog, but you can only keep pretending it's a dog until you try to humiliate it by feeding it something only dogs would eat — if that happens, it will scream out loud, but until that time, if you're in dynamic typing, it will silently accept its place (in a static world it would refuse to be put in a dog's box before you can say "kitty").

is Java weak typed as this example demonstrates when compared with python?

Java is still strongly typed, despite your example. The code is equivalent to

String s = "hello ";
s = s + 4;

and Java will convert the 4 into a string, then perform the string concatenation. This is a language feature.

In Python, however, you cannot use + to concatenate 4 to your string, because the language will not take the liberty of converting it to a str. As you point out, Java does this for you under the hood.

python strong/weak dynamic/static type language?

The key is that an object retains its type no matter what you do to it. An int is an int is an int; a str is a str; a float is a float. In a weakly typed language, you can do something like

i = "1" 
j = i + 2

and get j == 3. In python, you get

TypeError: cannot concatenate 'str' and 'int' objects

A str is always a str, and can't be treated as an int even if the string contains a number.

Try this:

for a in {1, 'abc', 3.14159}:
print a
print type(a)

which will produce

3.14159
<type 'float'>
1
<type 'int'>
abc
<type 'str'>

A single variable can be set to refer to any type of object - that's the "dynamic" part of it. But the object is always of the same type no matter how you refer to it - that's the "strong" part of it.

Can Python be made statically typed?

If I interpret your question as "Is there a statically-typed mode for Python?", then Cython probably comes closest to offering that functionality.

Cython is a superset of Python syntax - almost any valid Python code is also valid Cython code. The Cython compiler translates the quasi-Python source code to not-for-human-eyes C, which can then be compiled into a shared object and loaded as a Python module.

You can basically take your Python code and add as many or as few static type declarations as you like. Wherever types are undeclared, Cython will add in the necessary boilerplate to correctly infer them, at the cost of worse runtime performance. This essentially allows you to choose a point in the continuum between totally dynamically typed Python code and totally statically typed C code, depending on how much runtime performance you need and how much time you are prepared to spend optimizing. It also allows you to call C functions directly, making it a very convenient way to write Python bindings for external libraries.

To get a better idea of how this works in practice, take a look at the official tutorial.

How did python implement Type free variables from a statically typed language

This is a huge subject.

The below document will give you more understanding.

https://intopythoncom.files.wordpress.com/2017/04/internalsofcpython3-6-1.pdf

Like you said a simple example for integer types

To hold an integer type object, there is structure defined in C as said below

typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;

The object of C structure PyIntObject (section 7.5 of above said document) holds the objects which are integer type.

If you are more interested, setup the environment and debug as said in same section 7.5 of the above document.

Objects/intobject.c and place a debug point on line number 89. Start
debugging the application.

PyTypeObject is at higher level for the types to be represented. (look section 7.3 of above said document)

As a programmer, it is curious aspect to know the internals. But do not spend too much time to understand unless you work at interpreter level.

Seeking clarification on apparent contradictions regarding weakly typed languages

UPDATE: This question was the subject of my blog on the 15th of October, 2012. Thanks for the great question!


What does it really mean for a language to be "weakly typed"?

It means "this language uses a type system that I find distasteful". A "strongly typed" language by contrast is a language with a type system that I find pleasant.

The terms are essentially meaningless and you should avoid them. Wikipedia lists eleven different meanings for "strongly typed", several of which are contradictory. This indicates that the odds of confusion being created are high in any conversation involving the term "strongly typed" or "weakly typed".

All that you can really say with any certainty is that a "strongly typed" language under discussion has some additional restriction in the type system, either at runtime or compile time, that a "weakly typed" language under discussion lacks. What that restriction might be cannot be determined without further context.

Instead of using "strongly typed" and "weakly typed", you should describe in detail what kind of type safety you mean. For example, C# is a statically typed language and a type safe language and a memory safe language, for the most part. C# allows all three of those forms of "strong" typing to be violated. The cast operator violates static typing; it says to the compiler "I know more about the runtime type of this expression than you do". If the developer is wrong, then the runtime will throw an exception in order to protect type safety. If the developer wishes to break type safety or memory safety, they can do so by turning off the type safety system by making an "unsafe" block. In an unsafe block you can use pointer magic to treat an int as a float (violating type safety) or to write to memory you do not own. (Violating memory safety.)

C# imposes type restrictions that are checked at both compile-time and at runtime, thereby making it a "strongly typed" language compared to languages that do less compile-time checking or less runtime checking. C# also allows you to in special circumstances do an end-run around those restrictions, making it a "weakly typed" language compared with languages which do not allow you to do such an end-run.

Which is it really? It is impossible to say; it depends on the point of view of the speaker and their attitude towards the various language features.



Related Topics



Leave a reply



Submit