diff --git a/01-python-a-strongly-dynamically-duck-typed-interpreted-language/index.html b/01-python-a-strongly-dynamically-duck-typed-interpreted-language/index.html new file mode 100644 index 0000000..70612c5 --- /dev/null +++ b/01-python-a-strongly-dynamically-duck-typed-interpreted-language/index.html @@ -0,0 +1,278 @@ +Python: A Strongly, Dynamically, Duck Typed, Interpreted Language - Blogu

Python: A Strongly, Dynamically, Duck Typed, Interpreted Language

What is Python anyway?

I recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn’t think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing. This inspired me to write this post to help disambiguate Python and its runtime and static type systems.

A language itself is neither compiled nor interpreted. The terms “interpreted language” or “compiled language” signify that the canonical implementation of that language is an interpreter or a compiler, respectively. While interpretation and compilation are the two main means by which programming languages are implemented, they are not mutually exclusive, as most interpreting systems also perform some translation work, just like compilers. [1]

Compiled language implementations use a compiler to translate a program’s source code to the instructions of a target machine (machine code). For example, a + operation in source code could be compiled directly to the machine code ADD instruction. [2]

Interpreted language implementations use an interpreter to directly execute instructions without requiring them to have been compiled to machine code. An interpreter generally uses one of the following strategies for program execution:

  1. Parse the source code and perform its behavior directly. (Early versions of Lisp and BASIC)
  2. Translate source code into some efficient intermediate representation or object code and immediately execute that. (Python, Perl, MATLAB, and Ruby)
  3. Explicitly execute stored precompiled bytecode made by a compiler and matched with the interpreter Virtual Machine. (UCSD Pascal)

Some implementations may also combine two and three, such as contemporary versions of Java. [1]

Python has both compiled and interpreted implementations. CPython, Python’s reference implementation, can be defined as both an interpreter and a compiler, as it compiles Python code into bytecode before interpreting it. [3] PyPy, another Python implementation, is a just-in-time (JIT) compiler that compiles Python code into machine code at runtime.

In statically typed languages, variables have declared or inferred types, and a variable’s type cannot change. In dynamically typed languages like Python, values (runtime objects) have types, and variables are free to be reassigned to values of different types: [4]

1
+2
+
a = 42
+a = "hello world!"
+

There is no precise technical definition of what the “strength” of a type system means, [5] but for dynamically typed languages, it is generally used to refer to how primitives and library functions respond to different types.

Python is considered strongly typed since most type changes require explicit conversions. A string containing only digits doesn’t magically become a number, as in JavaScript (a weakly typed language):

1
+2
+
>>> "1" + 10
+"110"
+

In Python, + works on two numbers or two strings, but not a number and a string. This was a design choice made when + was implemented for these classes and not a necessity following from Python’s semantics. 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), and when you implement + for a custom type, you can implicitly convert anything to a number. [4]

Nominal typing is a static typing system that determines type compatibility and equivalence by explicit declarations and/or name matching. This means two variables are type-compatible if their declarations name the same type. [6] In general, Python’s static type system is nominally typed:

1
+2
+3
+4
+5
+6
+
def add_ints(a: int, b: int) -> int:
+    return a + b
+
+add_ints(1, 1)  # OK
+
+add_ints(1.0, 1.0)  # static typing error: "float" is not a subtype of "int"
+

Abstract base classes (see abc) allow you to define interfaces via inheritance, i.e. nominally. A class is abstract (not instantiable) if it inherits from abc.ABC or its metaclass is abc.ABCMeta and it has at least one abstract method (a method decorated by abc.abstractmethod). All abstract methods must be implemented by a subclass in order for that subclass to be concrete (instantiable).

When to use Protocols vs. ABCs
While not all ABC methods need to be abstract, if an ABC doesn’t have any non-abstract methods, I recommend using typing.Protocol as a less restrictive alternative.

abc.ABC.register allows you to register an abstract base class as a “virtual superclass” of an arbitrary type. This allows virtual subclasses to pass runtime type checks like isinstance and issubclass, but has no effect on static type compatibility:

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+
import abc
+
+class MyTuple(abc.ABC):
+    @abc.abstractmethod
+    def something_special(self) -> None:
+        ...
+
+MyTuple.register(tuple)
+
+assert issubclass(tuple, MyTuple)  # OK
+
+def do_something(obj: MyTuple) -> None:
+    ...
+
+do_something((1, 2, 3))  # static typing error: "tuple" is incompatible with "MyABC"
+

Structural typing is a static typing system that determines type compatibility and equivalence by the type’s actual structure or definition. [7] collections.abc.Iterable is an example of a structural type in Python. It accepts any type that implements the __iter__ method.

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+
from collections.abc import Iterable, Iterator
+
+def add_numbers(numbers: Iterable[int]) -> int:
+    return sum(n for n in numbers)
+
+class MyIterable:
+    def __iter__(self) -> Iterator[int]:
+        return iter([0, 1, 2])
+
+add_numbers([0, 1, 2])     # OK
+add_numbers((0, 1, 2))     # OK
+add_numbers({0, 1, 2})     # OK
+add_numbers(range(3))      # OK
+add_numbers(MyIterable())  # OK
+
+add_numbers(1)      # static typing error: "__iter__" is not present
+add_numbers("012")  # static typing error: "str" is not a subtype of "int"
+

collections.abc provides a set of common abstract base classes that are useful for typing function parameters based on the operations performed on them, namely:

operationmagic method
... in x__contains__
for ... in x__iter__
next(x)__next__
reversed(x)__reversed__
len(x)__len__
x(...)__call__
x[...]__getitem__
x[...] = ...__setitem__
del x[...]__delitem__
hash(x)__hash__

Similar to abc.ABC, subclasses of collections.abc classes are nominally typed, which limits their usefulness for static typing.

typing.Protocol provides a way to define custom structural types in Python. Any class that defines the same attributes and methods as a Protocol is considered to be a static subtype of that Protocol:

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+
from typing import Protocol
+
+class HasName(Protocol):
+    name: str
+
+class Person:
+    def __init__(self, name: str) -> None:
+        self.name = name
+
+class Place:
+    def __init__(self, name: str) -> None:
+        self.name = name
+
+def print_name(obj: HasName) -> None:
+    print(obj.name)
+
+print_name(Person("Matthew"))        # OK
+print_name(Place("San Francisco"))   # OK
+print_name("Austin")                 # static typing error: "name" is not present
+

typing.runtime_checkable is a decorator for Protocol classes that allows you to perform runtime type checks against Protocols (with one exception):

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+
from typing import Protocol, runtime_checkable
+
+@runtime_checkable
+class HasName(Protocol):
+    name: str
+
+class Person:
+    def __init__(self, name: str) -> None:
+        self.name = name
+
+assert isinstance(Person("Matthew"), HasName)  # OK
+assert issubclass(Person, HasName)             # TypeError: Protocols with non-method members don't support issubclass()
+
runtime_checkable Protocols only check for structure at runtime, not signatures or types
isinstance or issubclass checks against runtime_checkable Protocols only check for the presence of the required methods or attributes, not their type signatures or types.

Python’s runtime type system is duck typed. Duck typing is similar to structural typing but differs in that:

  1. Duck typing is a dynamic typing system.
  2. Compatibility is determined by checking only the parts of a type’s structure that are accessed at runtime.

It gets its name from the duck test: [8]

Duck test
If it walks like a duck and it quacks like a duck, then it must be a duck.
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+
class Duck:
+    def walk(self):
+        ...
+
+    def quack(self):
+        ...
+
+    def fly(self):
+        ...
+
+duck = Duck()
+
+class Person:
+    def walk(self):
+        ...
+
+    def quack(self):
+        ...
+
+person = Person()
+
+def do_duck_stuff(obj):
+    obj.walk()
+    obj.quack()
+
+do_duck_stuff(duck)
+do_duck_stuff(person)  # works, a "Person" can walk and quack like a "Duck"!
+
+def go_flying(obj):
+    obj.fly()
+
+go_flying(duck)
+go_flying(person)  # AttributeError: "Person" object has no attribute "fly"
+

Protocols are a natural complement to duck typing since neither use inheritance to determine type compatibility. In our example above, we could define and use:

 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+
from typing import Protocol
+
+class CanWalkAndQuack(Protocol):
+    def walk(self):
+        ...
+
+    def quack(self):
+        ...
+
+def do_duck_stuff(obj: CanWalkAndQuack) -> None:
+    obj.walk()
+    obj.quack()
+
+do_duck_stuff(duck)    # OK
+do_duck_stuff(person)  # OK
+
+class CanFly(Protocol):
+    def fly(self):
+        ...
+
+def go_flying(obj: CanFly) -> None:
+    obj.fly()
+
+go_flying(duck)    # OK
+go_flying(person)  # static typing error: "fly" is not present
+

[1] Wikipedia: Interpreter (computing)

[2] StackOverflow: Compiled vs. Interpreted Languages - Answer by mikera

[3] Wikipedia: CPython

[4] StackOverflow: Is Python strongly typed? - Answer by community wiki

[5] Wikipedia: Strong and weak typing

[6] Wikipedia: Nominal type system

[7] Wikipedia: Structural type system

[8] Wikipedia: Duck typing

+
\ No newline at end of file diff --git a/01-python-a-strongly-dynamically-duck-typed-interpreted-language/index.md b/01-python-a-strongly-dynamically-duck-typed-interpreted-language/index.md new file mode 100644 index 0000000..952cbd7 --- /dev/null +++ b/01-python-a-strongly-dynamically-duck-typed-interpreted-language/index.md @@ -0,0 +1,267 @@ +# Python: A Strongly, Dynamically, Duck Typed, Interpreted Language + + +## Background and Motivation + +I recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn't think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing. This inspired me to write this post to help disambiguate Python and its runtime and static type systems. + +## Compiled vs. Interpreted Languages + +A language itself is neither compiled nor interpreted. The terms "interpreted language" or "compiled language" signify that the canonical implementation of that language is an interpreter or a compiler, respectively. While interpretation and compilation are the two main means by which programming languages are implemented, they are not mutually exclusive, as most interpreting systems also perform some translation work, just like compilers. [[1]](#1) + +Compiled language implementations use a [compiler](https://en.wikipedia.org/wiki/Compiler) to translate a program's source code to the [instructions](https://en.wikipedia.org/wiki/Instruction_set_architecture#Instructions) of a target machine ([machine code](https://en.wikipedia.org/wiki/Machine_code)). For example, a `+` operation in source code could be compiled directly to the machine code `ADD` instruction. [[2]](#2) + +Interpreted language implementations use an [interpreter](https://en.wikipedia.org/wiki/Interpreter_(computing)) to directly execute instructions without requiring them to have been compiled to machine code. An interpreter generally uses one of the following strategies for program execution: + +1. Parse the source code and perform its behavior directly. (Early versions of Lisp and BASIC) +2. Translate source code into some efficient intermediate representation or object code and immediately execute that. (Python, Perl, MATLAB, and Ruby) +3. Explicitly execute stored precompiled bytecode made by a compiler and matched with the interpreter Virtual Machine. (UCSD Pascal) + +Some implementations may also combine two and three, such as contemporary versions of Java. [[1]](#1) + +Python has both compiled and interpreted implementations. [CPython](https://en.wikipedia.org/wiki/CPython), Python's [reference implementation](https://en.wikipedia.org/wiki/Reference_implementation), can be defined as both an interpreter and a compiler, as it compiles Python code into [bytecode](https://en.wikipedia.org/wiki/Bytecode) before interpreting it. [[3]](#3) [PyPy](https://en.wikipedia.org/wiki/PyPy), another Python implementation, is a just-in-time (JIT) compiler that compiles Python code into machine code at runtime. + +## Dynamic vs. Static Typing + +In statically typed languages, variables have declared or inferred types, and a variable's type cannot change. In dynamically typed languages like Python, values (runtime objects) have types, and variables are free to be reassigned to values of different types: [[4]](#4) + +```python +a = 42 +a = "hello world!" +``` + +## Strong vs. Weak Typing + +There is no precise technical definition of what the "strength" of a type system means, [[5]](#5) but for dynamically typed languages, it is generally used to refer to how primitives and library functions respond to different types. + +Python is considered strongly typed since most type changes require explicit conversions. A string containing only digits doesn't magically become a number, as in JavaScript (a weakly typed language): + +```javascript +>>> "1" + 10 +"110" +``` + +In Python, `+` works on two numbers or two strings, but not a number and a string. This was a design choice made when `+` was implemented for these classes and not a necessity following from Python's semantics. 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`), and when you implement `+` for a custom type, you can implicitly convert anything to a number. [[4]](#4) + +## Nominal vs. Structural Typing + +Nominal typing is a static typing system that determines type compatibility and equivalence by explicit declarations and/or name matching. This means two variables are type-compatible if their declarations name the same type. [[6]](#6) In general, Python's static type system is nominally typed: + +```python +def add_ints(a: int, b: int) -> int: + return a + b + +add_ints(1, 1) # OK + +add_ints(1.0, 1.0) # static typing error: "float" is not a subtype of "int" +``` + +Abstract base classes (see [`abc`](https://docs.python.org/3/library/abc.html)) allow you to define interfaces via inheritance, i.e. nominally. A class is abstract (not instantiable) if it inherits from [`abc.ABC`](https://docs.python.org/3/library/abc.html#abc.ABC) or its [metaclass](https://docs.python.org/3/reference/datamodel.html#metaclasses) is [`abc.ABCMeta`](https://docs.python.org/3/library/abc.html#abc.ABCMeta) and it has at least one abstract method (a method decorated by [`abc.abstractmethod`](https://docs.python.org/3/library/abc.html#abc.abstractmethod)). All abstract methods must be implemented by a subclass in order for that subclass to be concrete (instantiable). + +{{< admonition type=tip title="When to use Protocols vs. ABCs " open=true >}} +While not all `ABC` methods need to be abstract, if an `ABC` doesn't have any non-abstract methods, I recommend using [`typing.Protocol`](#Protocol) as a less restrictive alternative. +{{< /admonition >}} + +[`abc.ABC.register`](https://docs.python.org/3/library/abc.html#abc.ABCMeta.register) allows you to register an abstract base class as a "virtual superclass" of an arbitrary type. This allows virtual subclasses to pass runtime type checks like `isinstance` and `issubclass`, but has no effect on static type compatibility: + +```python +import abc + +class MyTuple(abc.ABC): + @abc.abstractmethod + def something_special(self) -> None: + ... + +MyTuple.register(tuple) + +assert issubclass(tuple, MyTuple) # OK + +def do_something(obj: MyTuple) -> None: + ... + +do_something((1, 2, 3)) # static typing error: "tuple" is incompatible with "MyABC" +``` + +Structural typing is a static typing system that determines type compatibility and equivalence by the type's actual structure or definition. [[7]](#7) `collections.abc.Iterable` is an example of a structural type in Python. It accepts any type that implements the `__iter__` method. + +```python +from collections.abc import Iterable, Iterator + +def add_numbers(numbers: Iterable[int]) -> int: + return sum(n for n in numbers) + +class MyIterable: + def __iter__(self) -> Iterator[int]: + return iter([0, 1, 2]) + +add_numbers([0, 1, 2]) # OK +add_numbers((0, 1, 2)) # OK +add_numbers({0, 1, 2}) # OK +add_numbers(range(3)) # OK +add_numbers(MyIterable()) # OK + +add_numbers(1) # static typing error: "__iter__" is not present +add_numbers("012") # static typing error: "str" is not a subtype of "int" +``` + +[`collections.abc`](https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes) provides a set of common abstract base classes that are useful for typing function parameters based on the operations performed on them, namely: + +| operation | magic method | +|----------------|-----------------| +| `... in x` | `__contains__` | +| `for ... in x` | `__iter__` | +| `next(x)` | `__next__` | +| `reversed(x)` | `__reversed__` | +| `len(x)` | `__len__` | +| `x(...)` | `__call__` | +| `x[...]` | `__getitem__` | +| `x[...] = ...` | `__setitem__` | +| `del x[...]` | `__delitem__` | +| `hash(x)` | `__hash__` | + + + +Similar to `abc.ABC`, subclasses of `collections.abc` classes are nominally typed, which limits their usefulness for static typing. + +[`typing.Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol) provides a way to define **custom** structural types in Python. Any class that defines the same attributes and methods as a `Protocol` is considered to be a static subtype of that `Protocol`: + +```python +from typing import Protocol + +class HasName(Protocol): + name: str + +class Person: + def __init__(self, name: str) -> None: + self.name = name + +class Place: + def __init__(self, name: str) -> None: + self.name = name + +def print_name(obj: HasName) -> None: + print(obj.name) + +print_name(Person("Matthew")) # OK +print_name(Place("San Francisco")) # OK +print_name("Austin") # static typing error: "name" is not present +``` + +[`typing.runtime_checkable`](https://docs.python.org/3/library/typing.html#typing.runtime_checkable) is a decorator for `Protocol` classes that allows you to perform runtime type checks against `Protocol`s (with one exception): + +```python +from typing import Protocol, runtime_checkable + +@runtime_checkable +class HasName(Protocol): + name: str + +class Person: + def __init__(self, name: str) -> None: + self.name = name + +assert isinstance(Person("Matthew"), HasName) # OK +assert issubclass(Person, HasName) # TypeError: Protocols with non-method members don't support issubclass() +``` + +{{< admonition type=note title="runtime_checkable Protocols only check for structure at runtime, not signatures or types" open=true >}} +`isinstance` or `issubclass` checks against `runtime_checkable` `Protocol`s only check for the presence of the required methods or attributes, not their type signatures or types. +{{< /admonition >}} + +## Duck Typing + +Python's runtime type system is duck typed. Duck typing is similar to structural typing but differs in that: + +1. Duck typing is a dynamic typing system. +2. Compatibility is determined by checking only the parts of a type's structure that are accessed at runtime. + +It gets its name from the [duck test](https://en.wikipedia.org/wiki/Duck_test): [[8]](#8) + +{{< admonition type=quote title="Duck test" open=true >}} +If it walks like a duck and it quacks like a duck, then it must be a duck. +{{< /admonition >}} + +```python +class Duck: + def walk(self): + ... + + def quack(self): + ... + + def fly(self): + ... + +duck = Duck() + +class Person: + def walk(self): + ... + + def quack(self): + ... + +person = Person() + +def do_duck_stuff(obj): + obj.walk() + obj.quack() + +do_duck_stuff(duck) +do_duck_stuff(person) # works, a "Person" can walk and quack like a "Duck"! + +def go_flying(obj): + obj.fly() + +go_flying(duck) +go_flying(person) # AttributeError: "Person" object has no attribute "fly" +``` + +`Protocol`s are a natural complement to duck typing since neither use inheritance to determine type compatibility. In our example above, we could define and use: + +```python +from typing import Protocol + +class CanWalkAndQuack(Protocol): + def walk(self): + ... + + def quack(self): + ... + +def do_duck_stuff(obj: CanWalkAndQuack) -> None: + obj.walk() + obj.quack() + +do_duck_stuff(duck) # OK +do_duck_stuff(person) # OK + +class CanFly(Protocol): + def fly(self): + ... + +def go_flying(obj: CanFly) -> None: + obj.fly() + +go_flying(duck) # OK +go_flying(person) # static typing error: "fly" is not present +``` + +## Sources + +[1] [Wikipedia: Interpreter (computing)](https://en.wikipedia.org/wiki/Interpreter_(computing)) + +[2] [StackOverflow: Compiled vs. Interpreted Languages - Answer by mikera](https://stackoverflow.com/a/3265602/7059681) + +[3] [Wikipedia: CPython](https://en.wikipedia.org/wiki/CPython) + +[4] [StackOverflow: Is Python strongly typed? - Answer by community wiki](https://stackoverflow.com/a/11328980/7059681) + +[5] [Wikipedia: Strong and weak typing](https://en.wikipedia.org/wiki/Strong_and_weak_typing) + +[6] [Wikipedia: Nominal type system](https://en.wikipedia.org/wiki/Nominal_type_system) + +[7] [Wikipedia: Structural type system](https://en.wikipedia.org/wiki/Structural_type_system) + +[8] [Wikipedia: Duck typing](https://en.wikipedia.org/wiki/Duck_typing) + diff --git a/404.html b/404.html index 4ffc6e7..2d1ef7f 100644 --- a/404.html +++ b/404.html @@ -8,5 +8,5 @@ CancelPostsTagsCategoriesAboutResume

The page you're looking for doesn't exist. Sorry.  -

+

\ No newline at end of file diff --git a/about/index.html b/about/index.html index f6f7c1f..e8a5f1c 100644 --- a/about/index.html +++ b/about/index.html @@ -1,6 +1,6 @@ - Blogu

Matthew Hoffman

Me

I am a research engineer at Protopia AI. At the moment I work almost exclusively in Python, mostly on our PyTorch SDK and model training framework. I’ve also worked on a real-time face recognition pipeline. You can check out my resume if you’d like to learn more about what I’ve worked on.

Design is at the core of my job as an engineer. Beyond the minimum requirements of every problem are the implicit requirements of usability, maintainability, scalability, extensibility… and it is through the application of design principles, adherence to best practices, and the utilization of the proper tools that I am able to create effective, adaptable software.

My goal for this blog is to create an in-depth technical reference for other Python enthusiasts looking to improve the code they write and the way they develop it. I hope this blog can be something you come back to time and again on your own Python journey.

+

Matthew Hoffman

Me

I am a research engineer at Protopia AI. At the moment I work almost exclusively in Python, mostly on our PyTorch SDK and model training framework. I’ve also worked on a real-time face recognition pipeline. You can check out my resume if you’d like to learn more about what I’ve worked on.

Design is the core of my craft as an engineer. Each solution brings the implicit challenges of efficiency, usability, maintainability, and scalability. It is through the application of design principles, adherence to best practices, and the utilization of the proper tools that I am able to create effective, adaptable software.

My goal for this blog is to create an in-depth technical reference for other Python enthusiasts looking to improve the code they write and the way they develop it. I hope this blog can be something you come back to time and again on your own Python journey.

\ No newline at end of file diff --git a/about/index.md b/about/index.md index 65d9b6b..215ccdf 100644 --- a/about/index.md +++ b/about/index.md @@ -8,7 +8,7 @@ I am a research engineer at [Protopia AI](https://www.linkedin.com/company/protopia%E2%80%94ai/posts/?feedView=all). At the moment I work almost exclusively in Python, mostly on our PyTorch SDK and model training framework. I've also worked on a real-time face recognition pipeline. You can check out my resume if you'd like to learn more about what I've worked on. -Design is at the core of my job as an engineer. Beyond the minimum requirements of every problem are the implicit requirements of usability, maintainability, scalability, extensibility... and it is through the application of design principles, adherence to best practices, and the utilization of the proper tools that I am able to create effective, adaptable software. +Design is the core of my craft as an engineer. Each solution brings the implicit challenges of efficiency, usability, maintainability, and scalability. It is through the application of design principles, adherence to best practices, and the utilization of the proper tools that I am able to create effective, adaptable software. ### What is this blog? diff --git a/categories/index.html b/categories/index.html index 5a558bf..c93aa8d 100644 --- a/categories/index.html +++ b/categories/index.html @@ -7,5 +7,5 @@ CancelPostsTagsCategoriesAboutResume -

All Categories

+
\ No newline at end of file diff --git a/categories/index.xml b/categories/index.xml index 4667031..8db4225 100644 --- a/categories/index.xml +++ b/categories/index.xml @@ -1 +1 @@ -Categories - Category - Bloguhttps://ringohoffman.github.io/categories/Categories - Category - BloguHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License. \ No newline at end of file +Categories - Category - Bloguhttps://ringohoffman.github.io/categories/Categories - Category - BloguHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.Thu, 17 Aug 2023 19:00:00 -0800Pythonhttps://ringohoffman.github.io/categories/python/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/categories/python/ \ No newline at end of file diff --git a/categories/python/index.html b/categories/python/index.html new file mode 100644 index 0000000..0f61973 --- /dev/null +++ b/categories/python/index.html @@ -0,0 +1,12 @@ +Python - Category - Blogu
+
\ No newline at end of file diff --git a/categories/python/index.xml b/categories/python/index.xml new file mode 100644 index 0000000..d148e7f --- /dev/null +++ b/categories/python/index.xml @@ -0,0 +1 @@ +Python - Category - Bloguhttps://ringohoffman.github.io/categories/python/Python - Category - BloguHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.Thu, 17 Aug 2023 19:00:00 -0800Python: A Strongly, Dynamically, Duck Typed, Interpreted Languagehttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Background and MotivationI recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn&rsquo;t think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing. \ No newline at end of file diff --git a/categories/python/page/1/index.html b/categories/python/page/1/index.html new file mode 100644 index 0000000..dd9786c --- /dev/null +++ b/categories/python/page/1/index.html @@ -0,0 +1 @@ +https://ringohoffman.github.io/categories/python/ \ No newline at end of file diff --git a/index.html b/index.html index a9d5998..1e8f668 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ -Blogu
/blogu.svg

A place where I document my learnings

+
/blogu.svg

A place where I document my learnings

Python: A Strongly, Dynamically, Duck Typed, Interpreted Language

Background and MotivationI recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn’t think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing.
\ No newline at end of file diff --git a/index.json b/index.json index f2af4c5..4fb7a18 100644 --- a/index.json +++ b/index.json @@ -1 +1 @@ -[{"categories":null,"content":" Matthew Hoffman ","date":"0001-01-01","objectID":"/about/:0:0","series":null,"tags":null,"title":"","uri":"/about/#matthew-hoffman"},{"categories":null,"content":" What I doI am a research engineer at Protopia AI. At the moment I work almost exclusively in Python, mostly on our PyTorch SDK and model training framework. I’ve also worked on a real-time face recognition pipeline. You can check out my resume if you’d like to learn more about what I’ve worked on. Design is at the core of my job as an engineer. Beyond the minimum requirements of every problem are the implicit requirements of usability, maintainability, scalability, extensibility… and it is through the application of design principles, adherence to best practices, and the utilization of the proper tools that I am able to create effective, adaptable software. ","date":"0001-01-01","objectID":"/about/:0:1","series":null,"tags":null,"title":"","uri":"/about/#what-i-do"},{"categories":null,"content":" What is this blog?My goal for this blog is to create an in-depth technical reference for other Python enthusiasts looking to improve the code they write and the way they develop it. I hope this blog can be something you come back to time and again on your own Python journey. ","date":"0001-01-01","objectID":"/about/:0:2","series":null,"tags":null,"title":"","uri":"/about/#what-is-this-blog"}] \ No newline at end of file +[{"categories":["Python"],"content":"Disambiguating Python and its runtime and static type systems with definitions and examples.","date":"2023-08-17","objectID":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/","series":null,"tags":["Python","Typing","Programming Languages"],"title":"Python: A Strongly, Dynamically, Duck Typed, Interpreted Language","uri":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/"},{"categories":["Python"],"content":" Background and MotivationI recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn’t think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing. This inspired me to write this post to help disambiguate Python and its runtime and static type systems. ","date":"2023-08-17","objectID":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/:1:0","series":null,"tags":["Python","Typing","Programming Languages"],"title":"Python: A Strongly, Dynamically, Duck Typed, Interpreted Language","uri":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/#background-and-motivation"},{"categories":["Python"],"content":" Compiled vs. Interpreted LanguagesA language itself is neither compiled nor interpreted. The terms “interpreted language” or “compiled language” signify that the canonical implementation of that language is an interpreter or a compiler, respectively. While interpretation and compilation are the two main means by which programming languages are implemented, they are not mutually exclusive, as most interpreting systems also perform some translation work, just like compilers. [1] Compiled language implementations use a compiler to translate a program’s source code to the instructions of a target machine (machine code). For example, a + operation in source code could be compiled directly to the machine code ADD instruction. [2] Interpreted language implementations use an interpreter to directly execute instructions without requiring them to have been compiled to machine code. An interpreter generally uses one of the following strategies for program execution: Parse the source code and perform its behavior directly. (Early versions of Lisp and BASIC) Translate source code into some efficient intermediate representation or object code and immediately execute that. (Python, Perl, MATLAB, and Ruby) Explicitly execute stored precompiled bytecode made by a compiler and matched with the interpreter Virtual Machine. (UCSD Pascal) Some implementations may also combine two and three, such as contemporary versions of Java. [1] Python has both compiled and interpreted implementations. CPython, Python’s reference implementation, can be defined as both an interpreter and a compiler, as it compiles Python code into bytecode before interpreting it. [3] PyPy, another Python implementation, is a just-in-time (JIT) compiler that compiles Python code into machine code at runtime. ","date":"2023-08-17","objectID":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/:2:0","series":null,"tags":["Python","Typing","Programming Languages"],"title":"Python: A Strongly, Dynamically, Duck Typed, Interpreted Language","uri":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/#compiled-vs-interpreted-languages"},{"categories":["Python"],"content":" Dynamic vs. Static TypingIn statically typed languages, variables have declared or inferred types, and a variable’s type cannot change. In dynamically typed languages like Python, values (runtime objects) have types, and variables are free to be reassigned to values of different types: [4] a = 42 a = \"hello world!\" ","date":"2023-08-17","objectID":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/:3:0","series":null,"tags":["Python","Typing","Programming Languages"],"title":"Python: A Strongly, Dynamically, Duck Typed, Interpreted Language","uri":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/#dynamic-vs-static-typing"},{"categories":["Python"],"content":" Strong vs. Weak TypingThere is no precise technical definition of what the “strength” of a type system means, [5] but for dynamically typed languages, it is generally used to refer to how primitives and library functions respond to different types. Python is considered strongly typed since most type changes require explicit conversions. A string containing only digits doesn’t magically become a number, as in JavaScript (a weakly typed language): \u003e\u003e\u003e \"1\" + 10 \"110\" In Python, + works on two numbers or two strings, but not a number and a string. This was a design choice made when + was implemented for these classes and not a necessity following from Python’s semantics. 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), and when you implement + for a custom type, you can implicitly convert anything to a number. [4] ","date":"2023-08-17","objectID":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/:4:0","series":null,"tags":["Python","Typing","Programming Languages"],"title":"Python: A Strongly, Dynamically, Duck Typed, Interpreted Language","uri":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/#strong-vs-weak-typing"},{"categories":["Python"],"content":" Nominal vs. Structural TypingNominal typing is a static typing system that determines type compatibility and equivalence by explicit declarations and/or name matching. This means two variables are type-compatible if their declarations name the same type. [6] In general, Python’s static type system is nominally typed: def add_ints(a: int, b: int) -\u003e int: return a + b add_ints(1, 1) # OK add_ints(1.0, 1.0) # static typing error: \"float\" is not a subtype of \"int\" Abstract base classes (see abc) allow you to define interfaces via inheritance, i.e. nominally. A class is abstract (not instantiable) if it inherits from abc.ABC or its metaclass is abc.ABCMeta and it has at least one abstract method (a method decorated by abc.abstractmethod). All abstract methods must be implemented by a subclass in order for that subclass to be concrete (instantiable). When to use Protocols vs. ABCs While not all ABC methods need to be abstract, if an ABC doesn’t have any non-abstract methods, I recommend using typing.Protocol as a less restrictive alternative. abc.ABC.register allows you to register an abstract base class as a “virtual superclass” of an arbitrary type. This allows virtual subclasses to pass runtime type checks like isinstance and issubclass, but has no effect on static type compatibility: import abc class MyTuple(abc.ABC): @abc.abstractmethod def something_special(self) -\u003e None: ... MyTuple.register(tuple) assert issubclass(tuple, MyTuple) # OK def do_something(obj: MyTuple) -\u003e None: ... do_something((1, 2, 3)) # static typing error: \"tuple\" is incompatible with \"MyABC\" Structural typing is a static typing system that determines type compatibility and equivalence by the type’s actual structure or definition. [7] collections.abc.Iterable is an example of a structural type in Python. It accepts any type that implements the __iter__ method. from collections.abc import Iterable, Iterator def add_numbers(numbers: Iterable[int]) -\u003e int: return sum(n for n in numbers) class MyIterable: def __iter__(self) -\u003e Iterator[int]: return iter([0, 1, 2]) add_numbers([0, 1, 2]) # OK add_numbers((0, 1, 2)) # OK add_numbers({0, 1, 2}) # OK add_numbers(range(3)) # OK add_numbers(MyIterable()) # OK add_numbers(1) # static typing error: \"__iter__\" is not present add_numbers(\"012\") # static typing error: \"str\" is not a subtype of \"int\" collections.abc provides a set of common abstract base classes that are useful for typing function parameters based on the operations performed on them, namely: operation magic method ... in x __contains__ for ... in x __iter__ next(x) __next__ reversed(x) __reversed__ len(x) __len__ x(...) __call__ x[...] __getitem__ x[...] = ... __setitem__ del x[...] __delitem__ hash(x) __hash__ Similar to abc.ABC, subclasses of collections.abc classes are nominally typed, which limits their usefulness for static typing. typing.Protocol provides a way to define custom structural types in Python. Any class that defines the same attributes and methods as a Protocol is considered to be a static subtype of that Protocol: from typing import Protocol class HasName(Protocol): name: str class Person: def __init__(self, name: str) -\u003e None: self.name = name class Place: def __init__(self, name: str) -\u003e None: self.name = name def print_name(obj: HasName) -\u003e None: print(obj.name) print_name(Person(\"Matthew\")) # OK print_name(Place(\"San Francisco\")) # OK print_name(\"Austin\") # static typing error: \"name\" is not present typing.runtime_checkable is a decorator for Protocol classes that allows you to perform runtime type checks against Protocols (with one exception): from typing import Protocol, runtime_checkable @runtime_checkable class HasName(Protocol): name: str class Person: def __init__(self, name: str) -\u003e None: self.name = name assert isinstance(Person(\"Matthew\"), HasName) # OK assert issubclass(Person, HasName) # TypeError: Protocols with non-method members don't support issubclass() runtime_checkable Protocols only check for structure at runtime","date":"2023-08-17","objectID":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/:5:0","series":null,"tags":["Python","Typing","Programming Languages"],"title":"Python: A Strongly, Dynamically, Duck Typed, Interpreted Language","uri":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/#nominal-vs-structural-typing"},{"categories":["Python"],"content":" Duck TypingPython’s runtime type system is duck typed. Duck typing is similar to structural typing but differs in that: Duck typing is a dynamic typing system. Compatibility is determined by checking only the parts of a type’s structure that are accessed at runtime. It gets its name from the duck test: [8] Duck test If it walks like a duck and it quacks like a duck, then it must be a duck. class Duck: def walk(self): ... def quack(self): ... def fly(self): ... duck = Duck() class Person: def walk(self): ... def quack(self): ... person = Person() def do_duck_stuff(obj): obj.walk() obj.quack() do_duck_stuff(duck) do_duck_stuff(person) # works, a \"Person\" can walk and quack like a \"Duck\"! def go_flying(obj): obj.fly() go_flying(duck) go_flying(person) # AttributeError: \"Person\" object has no attribute \"fly\" Protocols are a natural complement to duck typing since neither use inheritance to determine type compatibility. In our example above, we could define and use: from typing import Protocol class CanWalkAndQuack(Protocol): def walk(self): ... def quack(self): ... def do_duck_stuff(obj: CanWalkAndQuack) -\u003e None: obj.walk() obj.quack() do_duck_stuff(duck) # OK do_duck_stuff(person) # OK class CanFly(Protocol): def fly(self): ... def go_flying(obj: CanFly) -\u003e None: obj.fly() go_flying(duck) # OK go_flying(person) # static typing error: \"fly\" is not present ","date":"2023-08-17","objectID":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/:6:0","series":null,"tags":["Python","Typing","Programming Languages"],"title":"Python: A Strongly, Dynamically, Duck Typed, Interpreted Language","uri":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/#duck-typing"},{"categories":["Python"],"content":" Sources[1] Wikipedia: Interpreter (computing) [2] StackOverflow: Compiled vs. Interpreted Languages - Answer by mikera [3] Wikipedia: CPython [4] StackOverflow: Is Python strongly typed? - Answer by community wiki [5] Wikipedia: Strong and weak typing [6] Wikipedia: Nominal type system [7] Wikipedia: Structural type system [8] Wikipedia: Duck typing ","date":"2023-08-17","objectID":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/:7:0","series":null,"tags":["Python","Typing","Programming Languages"],"title":"Python: A Strongly, Dynamically, Duck Typed, Interpreted Language","uri":"/01-python-a-strongly-dynamically-duck-typed-interpreted-language/#sources"},{"categories":null,"content":" Matthew Hoffman ","date":"0001-01-01","objectID":"/about/:0:0","series":null,"tags":null,"title":"","uri":"/about/#matthew-hoffman"},{"categories":null,"content":" What I doI am a research engineer at Protopia AI. At the moment I work almost exclusively in Python, mostly on our PyTorch SDK and model training framework. I’ve also worked on a real-time face recognition pipeline. You can check out my resume if you’d like to learn more about what I’ve worked on. Design is the core of my craft as an engineer. Each solution brings the implicit challenges of efficiency, usability, maintainability, and scalability. It is through the application of design principles, adherence to best practices, and the utilization of the proper tools that I am able to create effective, adaptable software. ","date":"0001-01-01","objectID":"/about/:0:1","series":null,"tags":null,"title":"","uri":"/about/#what-i-do"},{"categories":null,"content":" What is this blog?My goal for this blog is to create an in-depth technical reference for other Python enthusiasts looking to improve the code they write and the way they develop it. I hope this blog can be something you come back to time and again on your own Python journey. ","date":"0001-01-01","objectID":"/about/:0:2","series":null,"tags":null,"title":"","uri":"/about/#what-is-this-blog"}] \ No newline at end of file diff --git a/index.xml b/index.xml index ae5e1ba..ed814bd 100644 --- a/index.xml +++ b/index.xml @@ -1 +1 @@ -Bloguhttps://ringohoffman.github.io/A place to document my learningsHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License. \ No newline at end of file +Bloguhttps://ringohoffman.github.io/A place to document my learningsHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.Thu, 17 Aug 2023 19:00:00 -0800Python: A Strongly, Dynamically, Duck Typed, Interpreted Languagehttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Background and MotivationI recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn&rsquo;t think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing. \ No newline at end of file diff --git a/matthewhoffman_resume.pdf b/matthewhoffman_resume.pdf index 1ce4262..6868595 100644 Binary files a/matthewhoffman_resume.pdf and b/matthewhoffman_resume.pdf differ diff --git a/posts/index.html b/posts/index.html new file mode 100644 index 0000000..33cc349 --- /dev/null +++ b/posts/index.html @@ -0,0 +1,12 @@ +All Posts - Blogu
+
\ No newline at end of file diff --git a/posts/index.xml b/posts/index.xml new file mode 100644 index 0000000..518b9bb --- /dev/null +++ b/posts/index.xml @@ -0,0 +1 @@ +All Posts - Bloguhttps://ringohoffman.github.io/posts/All Posts | BloguHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.Thu, 17 Aug 2023 19:00:00 -0800Python: A Strongly, Dynamically, Duck Typed, Interpreted Languagehttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Background and MotivationI recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn&rsquo;t think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing. \ No newline at end of file diff --git a/posts/page/1/index.html b/posts/page/1/index.html new file mode 100644 index 0000000..d7e2c89 --- /dev/null +++ b/posts/page/1/index.html @@ -0,0 +1 @@ +https://ringohoffman.github.io/posts/ \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index f8c766c..56b1d52 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -1 +1 @@ -https://ringohoffman.github.io/about/2022-12-14T07:12:37-06:00weekly0.5https://ringohoffman.github.io/weekly0.5https://ringohoffman.github.io/categories/weekly0.5https://ringohoffman.github.io/tags/weekly0.5 \ No newline at end of file +https://ringohoffman.github.io/2023-09-01T02:18:08-07:00weekly1https://ringohoffman.github.io/categories/2023-09-01T02:18:08-07:00weekly1https://ringohoffman.github.io/posts/2023-09-01T02:18:08-07:00weekly1https://ringohoffman.github.io/tags/programming-languages/2023-09-01T02:18:08-07:00weekly1https://ringohoffman.github.io/tags/python/2023-09-01T02:18:08-07:00weekly1https://ringohoffman.github.io/categories/python/2023-09-01T02:18:08-07:00weekly1https://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/2023-09-01T02:18:08-07:00weekly1https://ringohoffman.github.io/tags/2023-09-01T02:18:08-07:00weekly1https://ringohoffman.github.io/tags/typing/2023-09-01T02:18:08-07:00weekly1https://ringohoffman.github.io/about/2023-09-01T02:17:35-07:00weekly1 \ No newline at end of file diff --git a/tags/index.html b/tags/index.html index 675cbed..134ba09 100644 --- a/tags/index.html +++ b/tags/index.html @@ -7,5 +7,5 @@ CancelPostsTagsCategoriesAboutResume -

All Tags

+
\ No newline at end of file diff --git a/tags/index.xml b/tags/index.xml index 1bd42ba..730f94f 100644 --- a/tags/index.xml +++ b/tags/index.xml @@ -1 +1 @@ -Tags - Tag - Bloguhttps://ringohoffman.github.io/tags/Tags - Tag - BloguHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License. \ No newline at end of file +Tags - Tag - Bloguhttps://ringohoffman.github.io/tags/Tags - Tag - BloguHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.Thu, 17 Aug 2023 19:00:00 -0800Programming Languageshttps://ringohoffman.github.io/tags/programming-languages/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/tags/programming-languages/Pythonhttps://ringohoffman.github.io/tags/python/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/tags/python/Typinghttps://ringohoffman.github.io/tags/typing/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/tags/typing/ \ No newline at end of file diff --git a/tags/programming-languages/index.html b/tags/programming-languages/index.html new file mode 100644 index 0000000..003328e --- /dev/null +++ b/tags/programming-languages/index.html @@ -0,0 +1,12 @@ +Programming Languages - Tag - Blogu
+
\ No newline at end of file diff --git a/tags/programming-languages/index.xml b/tags/programming-languages/index.xml new file mode 100644 index 0000000..74e7ba2 --- /dev/null +++ b/tags/programming-languages/index.xml @@ -0,0 +1 @@ +Programming Languages - Tag - Bloguhttps://ringohoffman.github.io/tags/programming-languages/Programming Languages - Tag - BloguHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.Thu, 17 Aug 2023 19:00:00 -0800Python: A Strongly, Dynamically, Duck Typed, Interpreted Languagehttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Background and MotivationI recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn&rsquo;t think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing. \ No newline at end of file diff --git a/tags/programming-languages/page/1/index.html b/tags/programming-languages/page/1/index.html new file mode 100644 index 0000000..05e7bba --- /dev/null +++ b/tags/programming-languages/page/1/index.html @@ -0,0 +1 @@ +https://ringohoffman.github.io/tags/programming-languages/ \ No newline at end of file diff --git a/tags/python/index.html b/tags/python/index.html new file mode 100644 index 0000000..7cdd544 --- /dev/null +++ b/tags/python/index.html @@ -0,0 +1,12 @@ +Python - Tag - Blogu
+
\ No newline at end of file diff --git a/tags/python/index.xml b/tags/python/index.xml new file mode 100644 index 0000000..2f6fe0b --- /dev/null +++ b/tags/python/index.xml @@ -0,0 +1 @@ +Python - Tag - Bloguhttps://ringohoffman.github.io/tags/python/Python - Tag - BloguHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.Thu, 17 Aug 2023 19:00:00 -0800Python: A Strongly, Dynamically, Duck Typed, Interpreted Languagehttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Background and MotivationI recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn&rsquo;t think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing. \ No newline at end of file diff --git a/tags/python/page/1/index.html b/tags/python/page/1/index.html new file mode 100644 index 0000000..328048d --- /dev/null +++ b/tags/python/page/1/index.html @@ -0,0 +1 @@ +https://ringohoffman.github.io/tags/python/ \ No newline at end of file diff --git a/tags/typing/index.html b/tags/typing/index.html new file mode 100644 index 0000000..5c57968 --- /dev/null +++ b/tags/typing/index.html @@ -0,0 +1,12 @@ +Typing - Tag - Blogu
+
\ No newline at end of file diff --git a/tags/typing/index.xml b/tags/typing/index.xml new file mode 100644 index 0000000..2136365 --- /dev/null +++ b/tags/typing/index.xml @@ -0,0 +1 @@ +Typing - Tag - Bloguhttps://ringohoffman.github.io/tags/typing/Typing - Tag - BloguHugo -- gohugo.ioenringohoffman@me.com (Matthew Hoffman)ringohoffman@me.com (Matthew Hoffman)This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.Thu, 17 Aug 2023 19:00:00 -0800Python: A Strongly, Dynamically, Duck Typed, Interpreted Languagehttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Thu, 17 Aug 2023 19:00:00 -0800Matthew Hoffmanhttps://ringohoffman.github.io/01-python-a-strongly-dynamically-duck-typed-interpreted-language/Background and MotivationI recently had a conversation with a few of my coworkers where I had mentioned that Python is a strongly typed language. One of them didn&rsquo;t think that it was, and another explained that strong typing means that every object has a type, which is true about Python but is not the definition of strong typing. It surprised me to realize that even though my coworkers and I are experienced Python developers, none of us had a clear understanding of strong typing. \ No newline at end of file diff --git a/tags/typing/page/1/index.html b/tags/typing/page/1/index.html new file mode 100644 index 0000000..211094b --- /dev/null +++ b/tags/typing/page/1/index.html @@ -0,0 +1 @@ +https://ringohoffman.github.io/tags/typing/ \ No newline at end of file