User Classes Pt2
Encapsulation in Python
In C++ and other languages, encapsulation is harped on pretty hard and the languages give you features that really allow for such a mechanism. In Python? Not so much. Well, not to the level of which we are used to.
Public
All member variables and methods are public by default in Python. Just do as you do if you want public.
"Protected"
A protected member (in C++ and Java) is accessible only from within the class and it’s subclasses. In C++, we can create idiot-proof ways to really protect things members. In Python? Well, it's more of a suggestion. By prefixing the name of your member with a single underscore, you’re telling others “don’t touch this, unless you’re a subclass”. And by others... we mean other programmers. Yes, you can still access the members outside of the class.
class Example:
def __init__(self, name):
self.name = name
self._number = None # "protected" variable
self._displayName()
def _displayName(self):
print "Hello, {}".format(self.name)
def setNumber(self, num):
self._number = num
def getNumber(self):
return self._number
print "====Proper Things====\n"
a = Example("Will")
a.setNumber(21012345678)
print a.name
print a.getNumber()
print "====Does it really work?====\n"
print a._number
a._displayName()
"Private"
Same thing really applies here. By declaring your data member private you mean, that nobody should be able to access it from outside the class. Python supports a technique called name mangling. This feature turns every member name prefixed with at least two underscores and suffixed with at most one underscore into _<className><memberName>
class Example:
def __init__(self, name):
self.name = name
self.__number = None # "private" variable
self.__displayName()
# private method
def __displayName(self):
print "Hello, {}".format(self.name)
def setNumber(self, num):
self.__number = num
def getNumber(self):
return self.__number
print "====Proper Things====\n"
a = Example("Will")
a.setNumber(21012345678)
print a.name
print a.getNumber()
print "====How to get around it====\n"
print a._Example__number # This works, though it is much more confusing and even throws errors
Python Specific Breakdown
__init__ (Constructor)
__del__ (Deconstructor)
- It's best to name the Python file after the class name/vise-versa.
class ClassName(object):-- to define class- Name classes using CapWords convention (camel-case)
- Variables defined under classes are shared though all instances
- Variables defined in methods using
selfare only for a single instance - When creating methods, the first parameter must be self. (similar to "this" in other languages)
- A "private" member can be created by prepending a double underscore (only prepend) to the name. It will not be visable outside of the class. __example
- Inheritance, multiple inheritance and polymorphism are all supported
- var.attrib = value is the common way to interact(dot notation)
- getattr, hasattr, setattr, delattr exist for manipulating attributes as well
- built in:
__dict__, __doc__, __name__, __module__, __bases__
- Overloadable:
__init__, __del__, __repr__, __str__, __cmp__
- dir(), type(), isinstance() are built in functions
Creating an Instance in a Different File
from MyClass import MyClass
x = MyClass(name = "Iron Man")
print x.getName()
Composition vs Inheritance
- Best advice is composition over inheritance, but use inheritance when needed.
- Inheritance can complete things (especially multiple inheritance) and make larger projects confusing
- Namespace collisions are a major problem in inheritance
- Time must be given to design to effectively use inheritance, which could be time used used to stand up composition quicker.
Inheritance Example
Parent Class
class Person(object):
def __init__(self, name):
self.__name = name
self.__age = None
try:
firstBlank = self.__name.rindex(' ')
self.__lastName = self.__name[firstBlank+1:]
except:
self.__lastName = None
def getLastName(self):
return self.__lastName
def setAge(self, age):
self.__age = age
def getAge(self):
if age == None:
return "N/A"
else:
return self.__age
Child Class
from Person import Person
class USResident(Person):
"""A person who resides in the US"""
def __init__(self, name, status):
Person.__init__(self, name)
if status.lower() != 'citizen' and /
status.lower() != 'legal_resident' and /
status.lower() != 'illegal_resident':
raise ValueError()
else:
self.__status = status
def getStatus(self):
"""
Returns the status
"""
return self.__status
Example Call
from USResident import USResident
resident = USResident("Joe Smo", "citizen")
resident.setAge(23)
print "{} is a {} and is {} years of age.".format(resident.getLastName(), resident.getStatus(), resident.getAge())
Composition Example
class Engine:
def __init__(self, size, amount):
self.size = size
self.amount = amount
def calculatePower(self):
return self.size * self.amount
class Payload:
def __init__(self, name, typeOf, weight):
self.name = name
self.typeOf = typeOf
self.weight = weight
def neededPower(self):
return self.weight * .25
class AtlasRocket:
def __init__(self, size, amount, name, typeOf, weight):
self.Engine = Engine(size, amount)
self.Payload = Payload(name, typeOf, weight)
def missionCapable(self):
power = self.Engine.calculatePower()
neededPower = self.Payload.neededPower()
if power > neededPower:
return True
else:
return False
def printMissionStats(self):
print "Avaliable power: {}".format(self.Engine.calculatePower())
print "Needed Power: {}".format(self.Payload.neededPower())
atlasV = AtlasRocket(200, 4, "DSCS", "COMM", 2000)
if atlasV.missionCapable() == True:
print "Mission is a go"
atlasV.printMissionStats()
else:
print "Mission is not a go"
atlasV.printMissionStats()
Function vs Method
A function is a piece of code that is called by name. It can be passed data to operate on (i.e., the parameters) and can optionally return data (the return value). All data that is passed to a function is explicitly passed.
def sum(num1, num2):
return num1 + num2
A method is a piece of code that is called by name that is associated with an object. In most respects it is identical to a function except for two key differences.
- It is implicitly passed for the object for which it was called.
- It is able to operate on data that is contained within the class (remembering that an object is an instance of a class - the class is the definition, the object is an instance of that data).
class Dog:
def my_method(self):
print "I am a Dog"
dog = Dog()
dog.my_method() # Prints "I am a Dog"
More Material
Continue to Performance Lab 5C