family ties
In test_attributes_and_methods_of_classes I saw the methods I added to the Person class and also saw a lot of attributes and methods that I did not add, which led to the question of where they came from.
In object oriented programming there is a concept called Inheritance, it allows me to define new objects that inherit from other objects.
Making new objects is easier with Inheritance because I do not have to rewrite things that have already been written, I can inherit them instead and change the new objects for what I need
To use inheritance I specify the “parent” in parentheses when I define the new object (the child) to make the relationship
preview
These are the tests I have by the end of the chapter
1import unittest
2import src.classes
3import src.person
4
5
6class TestClasses(unittest.TestCase):
7
8 def test_making_a_class_w_pass(self):
9 self.assertIsInstance(src.classes.WPass(), object)
10
11 def test_making_a_class_w_parentheses(self):
12 self.assertIsInstance(src.classes.WParentheses(), object)
13
14 def test_making_a_class_w_object(self):
15 self.assertIsInstance(src.classes.WObject(), object)
16
17 def test_attributes_and_methods_of_objects(self):
18 self.assertEqual(
19 dir(object),
20 [
21 '__class__',
22 '__delattr__',
23 '__dir__',
24 '__doc__',
25 '__eq__',
26 '__format__',
27 '__ge__',
28 '__getattribute__',
29 '__getstate__',
30 '__gt__',
31 '__hash__',
32 '__init__',
33 '__init_subclass__',
34 '__le__',
35 '__lt__',
36 '__ne__',
37 '__new__',
38 '__reduce__',
39 '__reduce_ex__',
40 '__repr__',
41 '__setattr__',
42 '__sizeof__',
43 '__str__',
44 '__subclasshook__'
45 ]
46 )
47
48 def test_making_classes_w_inheritance(self):
49 self.assertIsInstance(
50 src.classes.Doe('doe'),
51 src.person.Person
52 )
53 self.assertEqual(
54 dir(src.classes.Doe),
55 dir(src.person.Person)
56 )
57
58 def test_family_ties(self):
59 doe = src.classes.Doe('doe')
60 jane = src.classes.Doe('jane')
61 john = src.classes.Doe('john')
62 mary = src.classes.Smith('mary')
63 joe = src.classes.Blow('joe')
64 baby = src.classes.Baby('baby')
65 lil = src.classes.Lil('lil')
66
67 self.assertEqual(doe.last_name, 'doe')
68 self.assertEqual(jane.last_name, 'doe')
69 self.assertEqual(john.last_name, 'doe')
70 self.assertEqual(mary.last_name, 'smith')
71 self.assertEqual(joe.last_name, 'blow')
72 self.assertEqual(baby.last_name, 'blow')
73 self.assertEqual(lil.last_name, 'doe')
74
75
76# Exceptions seen
77# AssertionError
requirements
open the project
I change directory to the
personfoldercd personthe terminal shows I am in the
personfolder.../pumping_python/personI activate the virtual environment
source .venv/bin/activateAttention
on Windows without Windows Subsystem for Linux use
.venv/bin/activate.ps1NOTsource .venv/bin/activate.venv/scripts/activate.ps1the terminal shows
(.venv) .../pumping_python/personI use
pytest-watchto run the testspytest-watchthe terminal shows
rootdir: .../pumping_python/person collected 2 items tests/test_person.py .. [100%] ============================ 2 passed in X.YZs =============================I hold ctrl on the keyboard and click on
tests/test_person.pyto open it in the editorI make another file in the
srcfolder namedclasses.py
test_making_a_class_w_pass
to review, I can make a class with the class keyword, use CapWords format for the name and use a name that tells what the group of attributes and methods do
RED: make it fail
I add an import statement for the
classesmodule1import unittest 2import src.classes 3 4 5class TestClasses(unittest.TestCase):I change
test_failuretotest_making_a_class_w_pass5class TestClasses(unittest.TestCase): 6 7 def test_making_a_class_w_pass(self): 8 self.assertIsInstance(src.classes.WPass(), object) 9 10 11# Exceptions seenthe terminal shows AttributeError
AttributeError: module 'src.classes' has no attribute 'WPass'there is no definition for
WPassinclasses.py
GREEN: make it pass
then I add a class definition to
classes.py1class WPass: 2 3 passthe test passes
pass is a placeholder, it makes sure I am following Python rules and I can make a class with pass
test_making_a_class_w_parentheses
I can also make a class with parentheses.
RED: make it red
I add another test in test_classes.py
7 def test_making_a_class_w_pass(self):
8 self.assertIsInstance(src.classes.WPass(), object)
9
10 def test_making_a_class_w_parentheses(self):
11 self.assertIsInstance(src.classes.WParentheses(), object)
12
13
14# Exceptions seen
the terminal shows AttributeError
E AttributeError: module 'src.classes' has no attribute 'WParentheses'
GREEN: make it pass
I add a class definition like WPass to classes.py
1class WPass:
2
3 pass
4
5
6class WParentheses:
7
8 pass
the test passes
REFACTOR: make it better
I add parentheses to the definition
6class WParentheses(): 7 8 passthe terminal shows all tests are still passing.
pass is a placeholder, it makes sure I am following Python rules, I can make a class with
test_making_a_class_w_object
RED: make it fail
I add another test to TestClasses in test_classes.py
7 def test_making_a_class_w_parentheses(self):
8 self.assertIsInstance(src.classes.WParentheses(), object)
9
10 def test_making_a_class_w_object(self):
11 self.assertIsInstance(src.classes.WObject(), object)
12
13
14# Exceptions seen
the terminal shows AttributeError
AttributeError: module 'src.classes' has no attribute 'WObject'
GREEN: make it pass
I add a class definition to classes.py
6class WParentheses():
7
8 pass
9
10
11class WObject():
12
13 pass
the test passes
REFACTOR: make it better
The last two tests pass because everything in Python is an object also known as a class. object is the mother class of all classes. I can use anything in the assertIsInstance method and the test would pass.
I use the examples to show different ways to make a class. I can also say who the parent of a class is when I define it. I add object to the definition
11class WObject(object):
12
13 pass
the test is still green. pass is a placeholder, it makes sure I am following Python rules, I can make a class with
test_attributes_and_methods_of_objects
I add a test to show the attributes and methods of object
RED: make it fail
I add a test to test_classes.py
13 def test_making_a_class_w_object(self):
14 self.assertIsInstance(src.classes.WObject(), object)
15
16 def test_attributes_and_methods_of_objects(self):
17 self.assertEqual(
18 dir(object),
19 []
20 )
21
22
23# Exceptions seen
the terminal shows AssertionError
AssertionError: Lists differ: ['__class__', '__delattr__', '__dir__', '_[272 chars]k__'] != []
GREEN: make it pass
I copy and paste the values from the terminal as the expectation and use the Find and Replace feature of the Integrated Development Environment (IDE) to remove the extra characters
16 def test_attributes_and_methods_of_objects(self):
17 self.assertEqual(
18 dir(object),
19 [
20 '__class__',
21 '__delattr__',
22 '__dir__',
23 '__doc__',
24 '__eq__',
25 '__format__',
26 '__ge__',
27 '__getattribute__',
28 '__getstate__',
29 '__gt__',
30 '__hash__',
31 '__init__',
32 '__init_subclass__',
33 '__le__',
34 '__lt__',
35 '__ne__',
36 '__new__',
37 '__reduce__',
38 '__reduce_ex__',
39 '__repr__',
40 '__setattr__',
41 '__sizeof__',
42 '__str__',
43 '__subclasshook__'
44 ]
45 )
46
47
48# Exceptions seen
and it passes. All classes automatically get these attributes, they inherit them
test_making_classes_w_inheritance
RED: make it fail
I add a new test
43 '__subclasshook__'
44 ]
45 )
46
47 def test_making_classes_w_inheritance(self):
48 self.assertIsInstance(
49 src.classes.Doe('doe'),
50 src.person.Person
51 )
52
53
54# Exceptions seen
the terminal shows AttributeError
AttributeError: module 'src.classes' has no attribute 'Doe'
GREEN: make it pass
I add a class definition to
classes.py11class WObject(object): 12 13 pass 14 15 16class Doe(object): 17 18 passTypeError: Doe() takes no argumentsI add the
__init__method16class Doe(object): 17 18 def __init__(self): 19 return NoneTypeError: Doe.__init__() takes 1 positional argument but 2 were givenI add a parameter to the method
16class Doe(object): 17 18 def __init__(self, first_name): 19 return Nonethe terminal shows AssertionError
AssertionError: <src.classes.Doe object at 0xffff01a2bc34> is not an instance of <class 'src.person.Person'>I add an import statement at the top of
classes.py1import src.person 2 3 4class WPass:the terminal still shows AssertionError
I change the “parent” of
Doe19class Doe(src.person.Person): 20 21 def __init__(self, first_name): 22 return Nonethe test passes
REFACTOR: make it better
I add a test for the attributes and methods of the
Doeclass47 def test_making_classes_w_inheritance(self): 48 self.assertIsInstance( 49 src.classes.Doe('doe'), 50 src.person.Person 51 ) 52 self.assertEqual( 53 dir(src.classes.Doe), 54 [] 55 ) 56 57 58# Exceptions seenthe terminal shows AssertionError
AssertionError: Lists differ: ['__class__', '__delattr__', '__dict__', '[377 chars]llo'] != []I change the expectation
47 def test_making_classes_w_inheritance(self): 48 self.assertIsInstance( 49 src.classes.Doe('doe'), 50 src.person.Person 51 ) 52 self.assertEqual( 53 dir(src.classes.Doe), 54 dir(src.person.Person) 55 ) 56 57 58# Exceptions seenthe test passes. I do not need to add an import statement because
classes.pyimportssrc.personand I importsrc.classesat the beginning oftest_person.pyI add the import statement to be clearer
1import unittest 2import src.classes 3import src.person 4 5 6class TestClasses(unittest.TestCase):the test is still green
I can remove the
__init__method from theDoeclass19class Doe(src.person.Person): passthe test is still green
test_family_ties
RED: make it fail
I add a new test for Inheritance
53 self.assertEqual( 54 dir(src.classes.Doe), 55 dir(src.person.Person) 56 ) 57 58 def test_family_ties(self): 59 doe = src.classes.Doe('doe') 60 jane = src.classes.Doe('jane') 61 john = src.classes.Doe('john') 62 63 64# Exceptions seenI add an assertion for the last name of
doe61 john = src.classes.Doe('john') 62 63 self.assertEqual(doe.last_name, '') 64 65 66# Exceptions seenthe terminal shows AssertionError
AssertionError: 'doe' != ''
GREEN: make it pass
I change the expectation
63 self.assertEqual(doe.last_name, 'doe')
REFACTOR: make it better
I add another assertion
61 john = src.classes.Doe('john') 62 63 self.assertEqual(doe.last_name, 'doe') 64 self.assertEqual(jane.last_name, '') 65 66 67# Exceptions seenthe terminal shows AssertionError
AssertionError: 'doe' != ''I change the expectation
64 self.assertEqual(jane.last_name, 'doe')the test passes
I add one more assertion
64 self.assertEqual(jane.last_name, 'doe') 65 self.assertEqual(john.last_name, '') 66 67 68# Exceptions seenthe terminal shows AssertionError
AssertionError: 'doe' != ''I change the expectation
65 self.assertEqual(john.last_name, 'doe')the test passes. All 3 people made with the
Doeclass have the same last name, they are related.I add a person from another family
58 def test_family_ties(self): 59 doe = src.classes.Doe('doe') 60 jane = src.classes.Doe('jane') 61 john = src.classes.Doe('john') 62 mary = src.classes.Smith('mary') 63 64 self.assertEqual(doe.last_name, 'doe')the terminal shows AttributeError
AttributeError: module 'src.classes' has no attribute 'Smith'I add a class to
classes.py19class Doe(src.person.Person): pass 20class Smith(src.person.Person): passthe test passes
I add an assertion for the
last_nameofmary66 self.assertEqual(john.last_name, 'doe') 67 self.assertEqual(mary.last_name, '') 68 69 70# Exceptions seenthe terminal shows AssertionError
AssertionError: 'doe' != ''maryshould have a last name ofsmithnotdoe. I change the expectation67 self.assertEqual(mary.last_name, 'smith')the terminal shows AssertionError
AssertionError: 'doe' != 'smith'I add a value for
last_nameto theSmithclass inclasses.py21class Smith(src.person.Person): 22 23 def __init__(self, first_name, last_name='smith'): 24 passthe terminal shows AttributeError
AttributeError: 'Smith' object has no attribute 'last_name'I need to add the class attributes. I can do that by calling the
__init__method of thePersonclass. Python has a way for me to do that, I add it21class Smith(src.person.Person): 22 23 def __init__(self, first_name, last_name='smith'): 24 super().__init__(first_name, last_name)the test passes.
the super built-in function calls the
__init__method of the parent class with the values I pass in parentheses.In this case it calls the
Personclass with values forfirst_nameandlast_nameI add another person to
test_classes.py61 john = src.classes.Doe('john') 62 mary = src.classes.Smith('mary') 63 joe = src.classes.Blow('joe') 64 65 self.assertEqual(doe.last_name, 'doe')the terminal shows AttributeError
AttributeError: module 'src.classes' has no attribute 'Blow'I add the class to
classes.py21class Smith(src.person.Person): 22 23 def __init__(self, first_name, last_name='smith'): 24 super().__init__(first_name, last_name) 25 26class Blow(src.person.Person): passthe test passes
I add an assertion for the last name of
joe67 self.assertEqual(john.last_name, 'doe') 68 self.assertEqual(mary.last_name, 'smith') 69 self.assertEqual(joe.last_name, 'blow') 70 71 72# Exceptions seenthe terminal shows AssertionError
AssertionError: 'doe' != 'blow'I add the
__init__method to the class26class Blow(src.person.Person): 27 28 def __init__(self, first_name, last_name='blow'): 29 passthe terminal shows AttributeError
AttributeError: 'Blow' object has no attribute 'last_name'I use the super built-in function
28class Blow(src.person.Person): 29 30 def __init__(self, first_name, last_name='blow'): 31 super().__init__(first_name, last_name)the test passes
I add a new person who is a child of
janenamedbabyintest_classes.py63 joe = src.classes.Blow('joe') 64 baby = src.classes.Baby('baby') 65 66 self.assertEqual(doe.last_name, 'doe')the terminal shows AttributeError
AttributeError: module 'src.classes' has no attribute 'Baby'I add a class for
babyinclasses.py27class Blow(src.person.Person): 28 29 def __init__(self, first_name, last_name='blow'): 30 super().__init__(first_name, last_name) 31 32 33class Baby(Doe): passthe test passes
babyis also the child ofjoe. I add an assertion for the last name ofbabyintest_classes.py69 self.assertEqual(mary.last_name, 'smith') 70 self.assertEqual(joe.last_name, 'blow') 71 self.assertEqual(baby.last_name, 'blow') 72 73 74# Exceptions seenthe terminal shows AssertionError
AssertionError: 'doe' != 'blow'I add another parent to the
Babyclass inclasses.py33class Baby(Blow, Doe): passthe test passes
I add another person, a child of
johnintest_classes.py63 joe = src.classes.Blow('joe') 64 baby = src.classes.Baby('baby') 65 lil = src.classes.Lil('lil') 66 67 self.assertEqual(doe.last_name, 'doe')the terminal shows AttributError
AttributeError: module 'src.classes' has no attribute 'Lil'I add a class for
liltoclasses.py33class Baby(Blow, Doe): pass 34 35 36class Lil(Doe): passthe test passes
lilis also the child ofmary. I add an assertion for the last name oflil71 self.assertEqual(joe.last_name, 'blow') 72 self.assertEqual(baby.last_name, 'blow') 73 self.assertEqual(lil.last_name, '') 74 75 76# Exceptions seenthe terminal shows AssertionError
AssertionError: 'doe' != ''I add another parent to show that
lilis a child ofDoeandSmithinclasses.py37class Lil(Doe, Smith): passthe terminal shows AssertionError
AssertionError: 'smith' != ''this is a problem. When I made
Baby, it took the last name of the first parent, and when I try the same thing withLilit has the last name of the second parentI add a call to the super built-in function in the
Doeclass19class Doe(src.person.Person): 20 21 def __init__(self, first_name): 22 super().__init__(first_name) 23 24 25class Smith(src.person.Person):TypeError: Doe.__init__() takes 2 positional arguments but 3 were givenbecause the
Babyclass passes a value forlast_nameI add
last_nameto the call to__init__method19class Doe(src.person.Person): 20 21 def __init__(self, first_name, last_name='doe'): 22 super().__init__(first_name, last_name)the terminal shows AssertionError
AssertionError: 'doe' != ''I change the expectation in
test_classes.pyself.assertEqual(lil.last_name, 'doe')the test passes
review
I can make a class with
close the project
I close the file(s) I have open in the editor(s)
I click in the terminal and exit the tests with ctrl+c on the keyboard
I deactivate the virtual environment
deactivatethe terminal goes back to the command line,
(.venv)is no longer on the left side.../pumping_python/personI change directory to the parent of
personcd ..the terminal shows
.../pumping_pythonI am back in the
pumping_pythondirectory
code from the chapter
what is next?
you have gone through a lot of things and know
rate pumping python
If this has been a 7 star experience for you, please CLICK HERE to leave a 5 star review of pumping python. It helps other people get into the book too