The programming language, Python, is an object-oriented programming language which means it is based on objects rather than actions. These objects are defined by classes which define the data each object stores and the operations that can be performed on the objects as well as the operations that the objects can perform. This programming approach allows for the creation of modules and the addition of objects without having to reconfigure those modules, making Python a powerful language. The creation of objects can also consist of inheritance to use the attributes of another class in the instantiation of a more complex class. Classes define the attributes, fields of data and methods, that apply to any object instantiated from the class. When an object is created, it is an instantiation of a class and it takes on the attributes defined in that class. These are the basic principles of object-oriented languages like Python and explain a lot of the behavior observed by elements of the language.
Some useful Python tools to ascertain the class certain objects belong to and determine the true identity of Python objects are
type provides you with the type of the object you feed it, more specifically the class it is an instance of. For example:
>>> a = 5
id provides you with the object identifier which is essentially the memory address at which the object is stored in memory. Like the following:
>>> a = 5
type can be useful within programs for checking the type of inputs before you use the inputs.
id is more informational and is implicitly used within Python’s
is built-in uses the id’s of the objects being compared to determine is they really are the same object. This allows for a distinction between value and object. The memory address that
id provides is a location in memory where the value is stored. These tools for information play an important role when writing programs that need to verify the existence and kind of information you are taking in or handling.
Objects in Python have many attributes, but one of their most important attributes, only made apparent through error messages, is mutability. More precisely, some objects are mutable while others are immutable. This characteristic of certain data types, which are essentially classes of objects in Python, guides programmers when they write their programs and when they stage their variables to interact or react to operations. Mutable objects may be changed through their methods and remain the same object. However, if an object interacts with another object through a mathematical operation or another function then a new object is created. A good example of mutable objects are lists. For example:
>>> ex_list = [1, 2, 3]
[1, 2, 3, 4]
The example shows a list being initialized followed by it’s append method being utilized. The list changed. However, it would be the same object (i.e. it would have the same identifier if we were to use
id on it.) Opposite mutability is hashability. Objects that are hashable have a value that cannot change within their lifetimes. In other words they are immutable.
On the other side of mutability are immutable objects. These are objects whose value can not be changed. We can change which object a reference variable references but we can not change the value of the object. Immutable objects are hashed as well so two tuples may not have the same id, but they may have the same hash. Immutable objects include many different types of variables including integers, strings, boolean, etc. If two variables referenced the same immutable object, their identifiers would be the same as depicted here:
>>> a = "ExString"
>>> b = "ExString"
>>> a is b
In this case, two different variables that referenced the same string have the same identifier due to Python’s memory optimization features which, rather than storing a second identical string in memory, point both variables to the same object because it is immutable. This can only be accomplished with certain immutable objects like strings because they are guaranteed not to change, therefore this should prevent unexpected behavior when handling multiple variables. Another memory optimization procedure Python partakes in is preloading an array of numbers from -5 to 265. This allows for some more common numbers to be readily accessible and already loaded in memory rather than needing to load each one. The following example shows some integer objects are already loaded and assigning variables just references a single object, while larger numbers are loaded independently with each declaration therefore identifiers for variables assigned to larger numbers will be different.
>>> a = 10
>>> b = 10
>>> print(a is b)
True>>> a = 1000
>>> b = 1000
>>> print(a is b)
Mutable and immutable objects are pertinent to a solid foundation in Python because they illuminate the way variables are being stored and accessed in the background. These concepts give the programmer a sense of which operations will do what is or is not intended. The difference between how immutable and mutable objects is not much, but in certain cases it can have a large impact. General awareness about which variables point to which data is an important perspective to develop.
Arguments are passed by being copied into a function. A separate variable is given to the value of whatever is passed into the function. This means anything that happens to the input variable inside the function is discarded unless it’s a class method which changes an object outside of the function. A mutable object as well is changed outside of the function if manipulated within the function. Immutable objects remain untouched if only manipulated within a function.
Originally published at medium.com on January 11, 2019.