Programming language background: what is an "object"

In the world of programming languages, the term "object" (lowercase "o") is anything that has both type and value. So we see in C that when we declare
int x = 42;
In Java we have "generics", which give the illusion of types being objects:
public class Node<T> {
  public T data;
  public Node next;
}
While this is a bit off in the weeds, "T" is not an object, because what really goes on is that with something like Node<String> the Java compiler makes a new class with "T" replaced with "String" at compile time. So by the time the code is executing, "T" does not exist.
the variable x is an object ... it has type 'int' and value '42'. An if statement like
if (x != 42)
  x = 42; 
is not an object - it has no type, it has no value. In C/C++/Java, types themselves (e.g. double) are not objects. So in C/C++/Java the *data* your executing program manipulates is stored in "objects", but the code itself (e.g. the "if" statement example, or operators like "||" ) and types (e.g. "String") are not "objects". In "Scheme", which you will look at in programming languages, all of these things are "objects".

Programming language background: what is a "variable"

We also have the further issue of whether a variable is the object, or whether a variable is a reference (aka pointer) to an object.

Let's start with C/C++:

int  x = 42; // x is an object: type = int,  value = 42
int *p = &x; // p is an object: type = int*, value = <some-memory-location>
	    
So variable x *is* an int object, while variable p both *is* an int* object, and is a *reference to* an int object. In C/C++ variables are always objects, though some objects are themselves references.

How about Java:

  int x = 42; // x is an object, we cannot have a pointer or reference to x
  String s = "hello"; // s is a *reference* to the string object "hello".
So some variables *are* objects (these are the primitive type). Some variables are *references* to objects (these are the variables for Objects (capital "O"), like s in the example, and arrays. Variables, class fields and array elements can only be primitive types or references to non-primitive types. References can only point to Objects or arrays. There is no such thing as a reference to an int or a reference to a reference.

In this sense, the semantics of C/C++ is simple: we have pointer and non-pointer objects (objects that cannot be dereferenced with *), and any object can be pointed to. Java is uglier, with three categories of objects and very different rules for how the three operate. BTW: it's not that the designer of Java was dumb. It's because Java tries to strike a balance between being high-level / easy-to-use and being efficient.

So what about python?

So we have two fundamental questions to answer about Python:
  1. What is an object?
    In Python "[e]very object has an identity, a type and a value". The "type" and "value" part we are familiar with. What about "identity"? "An object’s *identity* never changes once it has been created; you may think of it as the object’s address in memory. The is operator compares the identity of two objects; the id() function returns an integer representing its identity."

    Important! Look at these examples and make sure you understand why each line gives the result that it does.

    The function 'type' tells you the type of an object.
    >>> type(42)
    <class 'int'>
    >>> type('foo')
    <class 'str'>
    >>> type(99.9)
    <class 'float'>
    >>> x = 42
    >>> type(x)
    <class 'int'>
    
    We also see from this already that, unlike C/C++/Java, *types* are objects in Python. Each call to type returns an object that *is* its type. So:
    >>> type(42)
    <class 'int'>
    >>> type(type(42))
    <class 'type'>
    Functions are objects in Python as well:
    >>> def sqr(x):
    ...     return x*x
    >>> type(sqr)
    <class 'function'>
    >>> foo = sqr
    >>> foo(3)
    9
    >>> type(foo)
    <class 'function'>
    >>> [ id(foo), id(sqr), id(type(foo)) ]
    [131194214638368, 131194214638368, 103412181081376]

  2. What is a variable? In Python objects are only ever accessed by references. That means:

    Important! In python, variables, class fields, list/tuple/set/dictionary elements are all references.

    Even basic types like ints or floats. Every variable, array element, expression evaluation or function-return value is a reference to an object, not an object itself. It's like with Java class objects.
    >>> id(42) # 42 is an object with location in memory
    128715286464016
    >>> x = 42
    >>> id(x)  # x is a reference, id(x) returns the location in memory of the int x points to (aka 42)
    128715286464016
    >>> y = x
    >>> id(y) # y is a reference, "y = x" set y to point to the same object x was pointing to
    128715286464016
Note: In fact, in Python every object it is a capital-O Object, as in object oriented programming, i.e. is an instance of a class. So even bool or float values have fields and methods that can be called. Because the interpreter supports tab completion, you can discover what methods or fields are available by pressing tab:
>>> x = .125
>>> x.<TAB> # i.e. press the tab key
x.as_integer_ratio()  x.hex()               x.real
x.conjugate()         x.imag                
x.fromhex(            x.is_integer()        
>>> x.as_integer_ratio() # ohhh, I wonder what the "as_integer_ratio() method does?
(1, 8)

ACTIVITY


Part 1: The basic types

The four most basic types you deal with in Python are int, float, bool and str (Python's name for string). TODO
  1. Run the interpreter, define s = 'aa:bb:cc:dd'. Then type s. and press TAB. See if you can find and a method for turning all the letters into capitals. Try it out on s. Did it work? Check the value of s, has it changed? Does the method modify s or create a new string?
  2. Important! To convert an object like an int to a string use str(·).
    Try "foo" + 'bar'. What happens? Try "foo" + 42, what happens? Try "foo" + str(42).
  3. Define a function inchToFootInch(·) that takes a number of inches as int argument and returns a string describing that number of inches in feet and inches in the following format:
    >>> print(inchToFootInch(42))
    42" = 3' 6"
    >>> print(inchToFootInch(8))
    8" = 0' 8"
    >>> print(inchToFootInch(24))
    24" = 2' 0"
    >>> print(inchToFootInch(255))
    255" = 21' 3"

Part 2: Format strings

One of the joys of Python are format string literals. The basic idea is simple: if your string literal looks like f'...' or f"...", it can include expressions in { }s, and what happens is that those expressions get evaluated, and the {...} gets replaced with the str(·) of that value. Here's an example:
>>> name = 'DrBrown'
>>> age = 32
>>> f'My name is {name} and I am {age - 2} years old' # Nobody ever tells the truth about their age, right?
'My name is DrBrown and I am 30 years old' 

TODO

  1. Modify your definition of function inchToFootInch(·) to make use of format string literals ... it will be glorious!

Part 3: Iterating over the characters of a string

You can iterate over the characters of a string in two ways, and neither should be a surprise. So, for example, to print the characters of a string, one per line:

mystr = "foobar"
for i in range(0,len(mystr)): 
    print(mystr[i])
mystr = "foobar" 
for c in mystr:
    print(c)

You can also convert a string back and forth between lists of characters (or, more acurately, lists of strings that just happen to have length one). If s is a string, list(s) is an array consisting of the characters of the string. If t is a string and L is a list of strings, t.join(L) concatenates together all the elements of L, in order, with copies of t in between them. Thus, "".join(L) just concatenates together the elements of L.
>>> mystr = "this is not a string"
>>> L = list(mystr)
>>> L
['t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'n', 'o', 't', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g']
>>> L[6] = '$'
>>> "".join(L)
'this i$ not a string'

TODO

  1. Write a function called vowelCount(s) that takes a string s and returns the number of vowels in s. Note: we will not count y as a vowel!
    Hint: remember the "set" from last python lesson!
    >>> vowelCount("this is a few words")
    5
    >>> vowelCount("the quick brown fox jumped over the lazy dog")
    12 
  2. Write a function vowelSwap(s) that takes a string s and returns a copy of s in which each "a" becomes "u", each "u" becomes "i", each "i" becomes "a", each "o" becomes "e" and each "e" becomes "o".
    >>> vowelSwap("go navy, beat army!")
    'ge nuvy, bout urmy!'	    
    >>> vowelSwap("when in the course of human events it becomes necessary")
    'whon an tho ceirso ef himun ovonts at bocemos nocossury'	  
    Hint: I would be tempted to define a a dictionary: D = { "a":"u", "u":"i", "i":"a", "o":"e", "e":"o" }
  3. Improve your vowelSwap(·) function so that it handles upper case as well as lower case vowels, and keeps the case the same when it swaps vowels.
    >>> vowelSwap("Go NAVY, beat ARMY!")
    'Ge NUVY, bout URMY!'
    >>> vowelSwap("One ring to rule them ALL / One ring to bind them.")
    'Eno rang te rilo thom ULL / Eno rang te band thom.'

Christopher W Brown