extends some class
or implements some interface, and polymorphism
means overriding methods that are defined in super classes or
implementing methods required by some interface.
So what mechanisms does Python have to support the four pillars?
class construct
for bringing together different pieces of data into a single
package. Note: Python terminology is to use "attribute" for
what would be called a field or method in Java.
__ (that is a double
underscore, BTW) shouldn't be used by
code outside the class ... at least not unless you know what
you know what you are doing.
The example below shows a class Pos in Java with a static
field sep and static method disp.
In OOP generally, we often refer to these as "class variables"
and "class methods".
Below we do the same thing in Python, i.e. we declare a class
Pos with class variable sep and
class method disp. Note that they Python syntax
for a class is
class Foo:
field/method 1
field/method 2
...
Note: there are no access specifiers, i.e. no "public", "private" or "protected". Python does not have these!
Note: the proper Python terminology is not "field" but rather "attribute". So we are really talking about "class attributes" rather than the Java terminology "static fields".
row and colp1.len()toString() instance method.
Note: overriding toString has special significance,
since Java (a) toString() is a method of Object, so it
exits for every class object, and (b) Java uses that
method automatically in, for example, calls to println.
Now we'll do the exact same thing in the Python version.
__init__(self,...).self.varname
inside a constructor. There is no "declaration" of fields
as there is in Java.
p1.len()self, which is why
we define len as: def len(self):
print(p1)
works like you would expect. Similar to Java, we need to
add an instance method with a special name, in this case the
name is
__str__(self)
new. So we create a new Pos object like
p1 = Pos(3,4)
TODO
pos.py in your VM and run it
like the example above.
__foo__. So far we
have __init__(self,...) for constructors, and
__str__(self) for when the language wants to
convert an object to a string. However from the line
>>> p1
<__main__.Pos object at 0x7334ad7d2650>
we see that the interpreter does not use __str__
to display values of type Pos in the interpreter. Instead
the interpreter relies on an instance method named
__repr__(self) for that. So add a definition
of __repr__(self) and verify that evaluating an
object like p1 in the interpreter displays the
Pos object in a nice way, like (3,4). For example:
>>> p1 = Pos(3,4) >>> p1 (3,4)
step(dir) that changes
the Pos's row/col coordinates according to dir,
which is one of: "N", "S", "E", "W". For example:
>>> p1 = Pos(5,3) # row 5, col 3 >>> p1.step("S") # to row 6, col 3 >>> p1.step("W") # to row 6, col 2 >>> p1 (6:2)Note: This can be done in a really nice data-driven kind of way by defining a map in which the keys are the four directions, and the values are tuples defining the changes in row and col.
>>> p1 = Pos(3,4) >>> p2 = Pos(3,4) >>> p1 == p2 FalseOnce again, we can tell Python how to "do" == for Pos objects by overloading an underscore-named method: in this case the method
__eq__(self,other), where
"other" is a second Pos object. Overload this so == takes
two Pos's to be equal if their row/col positions are equal.
[BTW: the name "other" isn't special ... it's just
suggestive.]
With this addition, the following should work:
$ python3 -i pos.py >>> p1 = Pos(3,4) >>> p2 = Pos(3,4) >>> p1.__eq__(p2) True >>> p1 == p2 True
TODO
getLabel instance method that returns the
instance's label:
$ python3 -i pos.py >>> T = [ LabPos(3,4,"A"), LabPos(9,2,"H"), LabPos(1,1,"D") ] >>> LabPos.labMerge(T) 'AHD'This is really easy with list comprehensions and joins (e.g. "".join(["x","y","z"]) ).
dist that takes two LabPos
objects and returns the "distance", which is the absolute
value of the difference in their rows plus the absolute
value of the difference in their cols.
>>> p1 = LabPos(11,2,"J") >>> p2 = LabPos(5,6,"K") >>> LabPos.dist(p1,p2) 10
>>> p1 = Pos(12,5) >>> p2 = Pos(9,4) >>> LabPos.dist(p1,p2) 4