Extends the idea of typing.
Creating objects
Concepts:
4 Pillars of OOP
Class, type , sometimes prototype, are loosely interchangeable terms
Class is usually associated with higher order, a blueprint.
Object is an instance or implementation of a class.
int A
int B = 8
python
int is a type, A and B are instances of int.
in python…
=int(8)
A=int(8) B
python
int is a class, A and B are of int.
In C, the variable int A has a name, value, and address.
In python, int A has much more going on under the hood.
dir(A)
python
Things listed by dir are data that are encapsulated with A.
A.real
A.imag A.conjugate()
For example, A has a "real" and "imag" attributes
A has a conjugate method
Attributes and methods are the types data that are encapsulated with A.
Encapsulated data is accessible through ".", e.g. A.real
Attributes/properties are like variables tied to objects.
int(8).real # ending no parenthesis
int(8).imag # ending no parenthesis
# OR
getattr(a,"imag")
hasattr(a,"real") # True
getattr(a,"infinite") # False
help(a) # get help on object
help(int) # same as getting help on class
python
Methods are class specific functions encapsulated with objects
Two ways of looking at them:
As an attribute, A has the ability to compute its own conjugate:
# No parenthesis A.conjugate
python
The return value is the method itself
As an action, A computes its own conjugate:
# with parentheses A.conjugate()
python
The return value is what the action resulted in
Methods are encapsulated within objects/classes.
They are inseparable; they do not exists outside of the class
conjugate(int(8)); # this does not work
callable(a.conjugate) # check if method ... YES
callable(a.int) # NOT A METHOD
python
For the int class, "int()" is a special method called a constructor
Constructors create a new instance of a class.
Encapsulation allows self documentation
Its easy to find what int can do and can't do, what data its associated with it and what is not.
conjugate(int(8)); # this does not work
python
=int(8)
A=int(8) B
A and B are two separate instances of the same class, but not the same.
Different names, different, address, same value
Polymorphism the same class can be in different states.
Here objects differ by their name attributes and memory addresses.
Outside of python, integer could be thought of as a subclass of numbers.
Integers are numbers, but constrained or extended in particular ways.
Like not having decimal values, or being able to enumerate distinct objects.
Additionally, integers inherit properties from the parent class numbers.
Such as the ability to be added and subtracted to other numbers.
Integers are a primitive type in python, so are not subclasses of anything, but the principle holds.
We could in theory create subclasses from integers, like complex integers or imaginary integers.
Classes are also polymorphic by subclassing/subtyping.
=controller()
my_controller=ui()
my_ui=db()
my_db
my_controller.change_to_state_1()
=my_controller
my_ui.controller=my_controller
my_db.controller
my_controller.change_to_state_2()
myui and mydb have mycontroller assigned as attributes to "controller"
When mycontroller changes state, this is reflected in the other objects (both attributes would have mycontroller in state2.
This is because non-primitive objects in python are always bound to aliases/references/pointers.
The end users is expected not to interact with the underlying symbol that created internally.
A=mycontroller() is actually
= (some hidden symbol = ) my_controller A
What happens when we bind B to A?
= [ 1, 2, 3 ] # list type, with elements 1, 2, 3. Lists are not primitive
A =A
Bprint(A)
print(B)
0]=2
B[print(A)
print(B)
A is updated when B is.
Options of what could happen
del A
print(A)
print(B)
Appears to be a pointer to the end user.
If you need to copy a value, not the pointer
import copy # copy module
= [ 1, 2, 3 ]
A =copy.copy(A) #copy funciton in the copy module
B0]=2 B[
= int(8)
A =A
Bprint(A)
print(B)
=2
Bprint(A)
print(B)
Unlike lists, primitive types do not create intermediate variable aliased to then user-assigned variable.
More specifically, immutable types do not have this property.
Objects belonging to immutable classes have attributes that cannot be changed once created.
In the above example, when B is assign to two, a new variable is being declared rather than changing the one that exists.
Immutable types include all primitive types which are also not collection types or things that can be indexed.
All about memory efficient memory management.
Immutable types used as a foundation for the rest of the code base.
Immutable types limit human error, are faster.
Not much you can change strings/ranges by indexing
= [1, 2, 3]
mylist = (1, 2, 3)
mytuple
# Reassignment is valid in lists...
=mylist[0:2] + mylist[0:2]
mylistprint(mylist)
# and tuples...
=mytuple[0:2] + mytuple[0:2]
mytupleprint(mytuple)
# Changing elements is valid in lists...
0]=0 # works
mylist[print(mylist)
# not tuples
0]=1 # does not work
mytuple[
#workaround
=(0,) + mytuple[1:]
mytupleprint(mytuple)
python
Tuples and lists are identical other than syntax and mutability.
lists can change their elements in place, tuples cannot.
Primitive Types (immutable)
Collection Types (mutable)
Collection Types (immutable)
Iterable Types (immutable)
Dictionaries are only mutable in newer versions of python.
That said, its safer to just to view them as immutable.
Together, list is the only builtin type that should be viewed as mutable.
Rule of thumb: treat immutables as values, treat mutables as objects (with reference etc.)
Float are numbers with decimal precision.
Int is short for integer (no decimal precision).
type(8)
type(-8)
type(8.1)
=int(8)
A=float(8)
Btype(A+B)
print(A+B)
Python automatically interprets numbers without decimals as integers
Python automatically interprets numbers with decimals as float
If a int is combined with a float, the int will be cast to a float.
8+8 # addition
8-8 # addition
8*8 # multiplication
8/8 # division
8**8 # exponent
8.1%8 # modulus (remainder)
8.1//8 # flood diviision (division without remainder)
round(8.1)
abs(-8)
=3
b=-3
a>= abs(a) # Is b greater than abs(a)?
b <= abs(a) # Is b less than abs (a)?
b == 3 # Is b equal to 3? Notice to equal signs instead of 1.
b != 3 # Is b not equal to 3?
b <= 4 # Is b less than or equal to 4?
b >= 4 # Is b greater than or equal to 4?
b True==1 # True and 1 are are the same
False==0 # False and zero are the same
not True==False # not takes the compliment of a test (flips the sign)
= b==4 # Assigning result of logical test
c print(c)
Combined logic
not (b <= 4) # compliment of Is b less _greater_ than or equal to 4?
==5 | abs(a)==3 # OR
b==5 & abs(a)==3 # AND
b==3 & abs(a)==3 ) | c # Grouping (b
Unlike other languages, strings, not individual characters are primitive.
None type is simply an empty value.
Think of it as an extension to the other primitives.
None
=None
xprint(x)
print(not x):
Other than 0, False, and None, all other values of all other types will be cast to "True" when applied to logic.
The None type is a great placeholder.
Collection types are like containers that contain other types.
All collection types have ways of selecting individual elements by indexing
Zero indexing
Numeric indexing in python uses zero indexing, meaning that the first element in the collection is labeled 0, the second 1, and so on.
\(\underset{0}{\text{A}} \underset{1}{\text{B}} \underset{2}{\text{C}}\)
Element Selecting
\(\underset{0}{\text{A}} \underset{1}{\text{B}} \underset{2}{\text{C}}\)
0] # first element
mylist[-1] # last element
mylist[1] # 2nd element third
mylist[3] # 4th element
mylist[-2] # third to last element mylist[
Slicing
\(\text{ }_0\text{A}_1 \text{B}_2 \text{C}_3\)
0:1] # first element
mylist[-1] # last element
mylist[1:2] # 2nd to third
mylist[# all elements
mylist[:] 1:] # 2nd to last elements
mylist[-1] # 1 to second to last mylist[:
Slice type
The colon indexing used in previous examples is implicitly a slice type
=[1,2,3,4,5]
list1=[6,7,8,9,10]
list21:4]
list1[1:4]
list2[
# same indexing, but with explicitly called slices
=slice(1,4)
s
list1[s] list2[s]
Explicitly creating a slice variable is useful for slicing multiple things in the same way.
The Immutable collection
= ("apple", "banana", "cherry", "orange") mytuple
Use if you have a list that doesn't change.
Faster & protected from changing
Consider set as the base collection type.
Other collection types are tuples with more features
Check immutability
=mytuple[1:3] # a reassignment
mytuple0]="blueberry" # Doesn't work.
mytuple[
dir(mydict)
The Mutable Tuple
= ["apple", "banana", "cherry", "orange"]
mylist
"cherry")
mylist.append(
mylist.pop()"cherry")
mylist.count("watermelon","strawberry"])
mylist.extend([0,"cherry")
mylist.insert("cherry")
mylist.remove(
mylist.reverse()
mylist.sort()
dir(mydict)
The unordered tuple
Note: few use or even know about this builtin type.
= {"apple", "banana", "cherry", "orange"}
myset1 = {"apple", "banana"}
myset2 = {"apple"}
myset3 = {"apple","blueberry"}
myset4 = {"steak"}
myset5
myset4.intersection(myset4)
myset4.union(myset2)
myset4.difference(myset2)
myset4.isdisjoint(myset5)
myset4.isdisjoint(myset4)
myset4.issubset(myset1) myset4.issuperset(myset3)
The unordered tuple with mutability and key-pairs
Same curly brackets as sets, but each entry is a key and value
= {
mydict "apple": "yabloka",
"banana": "banan",
"cherry": "veeshnya",
"orange": "apelseen",
}
"apple"]
mydict[1]
mydict[
mydict.keys()
mydict.values() mydict.items()
Iterable types are like lists of sorted numbers whose values are generated on the fly.
There are two builtin iterable types, slices and ranges.
Slices were covered in "Indexing" above.
Ranges and will be covered again later, when discussing "for loops."