classes: test_classes_w_initializers¶
requirements¶
So far I have gone over how to define classes, attributes and methods. I now expand on this to show how to use classes.
When making a new class, we can define an initializer which is a method that can receive inputs to be used to customize instances/copies of the class
red: make it fail¶
I add a failing test to test_classes.py
def test_classes_w_initializers(self):
self.assertEqual(classes.Boy().sex, 'M')
the terminal shows AttributeError
green: make it pass¶
I add a definition for the
Boy
classclass Boy(object): pass
the terminal shows another AttributeError
I make the
Boy
class with an attribute calledsex
class Boy(object): sex
the terminal produces NameError
I add a definition for the
sex
attributeclass Boy(object): sex = 'M'
the terminal shows passing tests
refactor: make it better¶
I add another assertion to
test_classes_w_initializers
this time for aGirl
class but with a difference, I provide the value for thesex
attribute when I call the classdef test_classes_w_initializers(self): self.assertEqual(classes.Boy().sex, 'M') self.assertEqual(classes.Girl(sex='F').sex, 'F')
the terminal shows AttributeError
I try the same solution I used for the
Boy
class then add a definition for theGirl
class toclasses.py
class Girl(object): sex = 'M'
and the terminal shows TypeError
TypeError: Girl() takes no arguments
I add the initializer method called
__init__
to theGirl
classclass Girl(object): sex = 'F' def __init__(self): pass
and the terminal shows TypeError
TypeError: __init__() got an unexpected keyword argument 'sex'
I make the signature of the
__init__
method take a keyword argumentdef __init__(self, sex=None): pass
and the terminal shows passing tests
I add another assertion
def test_classes_w_initializers(self): self.assertEqual(classes.Boy().sex, 'M') self.assertEqual(classes.Girl(sex='F').sex, 'F') self.assertEqual(classes.Other(sex='?').sex, '?')
and the terminal shows AttributeError
I add a class definition to
classes.py
class Other(object): sex = '?' def __init__(self, sex=None): pass
the terminal shows passing tests
Wait a minute, I just repeated the same thing twice.
I am going to make it a third repetition by redefining the
Boy
class to match theGirl
andOther
class because it is fun to do bad thingsclass Boy(object): sex = 'M' def __init__(self, sex=None): pass
the terminal shows all tests still passing and I have now written the same thing 3 times. Earlier on I mentioned inheritance, and will now try to use it to remove this duplication so I do not repeat myself
I add a new class called
Human
toclasses.py
before the definition forBoy
with the same attribute and method of the classes I am trying to abstractclass Human(object): sex = 'M' def __init__(self, sex='M'): pass
the terminal still shows passing tests
I change the definitions for
Boy
to inherit from theHuman
class and all tests are still passingclass Boy(Human): sex = 'M' def __init__(self, sex=None): pass
I remove the
sex
attribute from theBoy
class and the tests continue to passI remove the
__init__
method, then add the pass placeholderclass Boy(Human): pass
all tests are still passing. Lovely
What if I try the same thing with the
Girl
class and change its definition to inherit from theHuman
class?class Girl(Human): sex = 'F' def __init__(self): pass
I remove the
sex
attribute and the terminal shows AssertionErrorI make the
Human
class to set thesex
attribute in the parent initializer instead of at the child levelclass Human(object): sex = 'M' def __init__(self, sex='M'): self.sex = sex
the terminal still shows AssertionError
when I remove the
__init__
method from theGirl
classclass Girl(Human): pass
the terminal shows passing tests. Lovely
I wonder if I can do the same with the
Other
class? I change the definition to inherit from theHuman
classclass Other(Human): pass
the terminal shows passing tests
One More Thing! I remove the
sex
attribute from theHuman
classclass Human(object): def __init__(self, sex='M'): self.sex = sex
all tests are passing, I have successfully refactored the 3 classes and abstracted a
Human
class from them
review¶
Why did that work?
the
Boy
,Girl
andOther
class now inherit from theHuman
class which means they all get the same methods and attributes that theHuman
class has, including the__init__
methodself.sex
in each class is thesex
attribute in the class, allowing its definition from inside the__init__
methodsince
self.sex
is defined as a class attribute, it is accessible from outside the class as I do in the tests i.eclasses.Girl(sex='F').sex
andclasses.Other(sex='?').sex