TypeError with classes
Since methods are functions in a class I can assume that they have the same behavior as what I tested in test_type_error_w_positional_arguments, test_type_error_w_keyword_arguments and test_type_error_w_args_and_kwargs.
The difference is that how I call a method is affected by if I do it with a class or an instance.
preview
I have these tests by the end of the chapter
1import src.type_error
2
3
4def test_type_error_w_positional_arguments():
5 src.type_error.function_00('a')
6 src.type_error.function_01('a', 'b')
7 src.type_error.function_02('a', 'b', 'c')
8 src.type_error.function_03('a', 'b', 'c', 'd')
9 src.type_error.function_04('a')
10 src.type_error.function_05('a', 'b')
11 src.type_error.function_06('a', 'b', 'c')
12 src.type_error.function_07('a', 'b', 'c', 'd')
13 src.type_error.function_08('last', 'one')
14
15
16def test_type_error_w_keyword_arguments():
17 src.type_error.function_00(the_input=0)
18 src.type_error.function_01(
19 first='first',
20 second={'key': 'value'},
21 )
22 src.type_error.function_02(
23 third=(0, 1, 2, 'n'),
24 second=[0, 1, 2, 'n'],
25 first={0, 1, 2, 'n'},
26 )
27 src.type_error.function_03(
28 first=None,
29 second=False,
30 third=True,
31 fourth=4,
32 )
33 src.type_error.function_04(argument='value')
34 src.type_error.function_05(
35 argument_0='value1',
36 argument_1=(0, 1, 2, 'n'),
37 )
38 src.type_error.function_06(
39 argument_0='value1',
40 argument_1=(0, 1, 2, 'n'),
41 argument_2=[0, 1, 2, 'n'],
42 )
43 src.type_error.function_07(
44 argument_0=(0, 1, 2, 'n'),
45 argument_1=[0, 1, 2, 'n'],
46 argument_2={0, 1, 2, 'n'},
47 argument_n={'key': 'value'},
48 )
49 src.type_error.function_08(
50 argument='positional', name='keyword'
51 )
52
53
54def test_type_error_w_args_and_kwargs():
55 src.type_error.function_00('argument')
56 src.type_error.function_01(1, 0)
57 src.type_error.function_02(
58 third=True, second=False, first=None
59 )
60 src.type_error.function_03(
61 second=[0, 1, 2, 'n'],
62 first=(0, 1, 2, 'n'),
63 third={0, 1, 2, 'n'},
64 fourth={'key': 'value'}
65 )
66 src.type_error.function_04('value')
67 src.type_error.function_05(
68 (0, 1, 2, 'n'),
69 [0, 1, 2, 'n'],
70 )
71 src.type_error.function_06(
72 (0, 1, 2, 'n'),
73 [0, 1, 2, 'n'],
74 argument_2={0, 1, 2, 'n'},
75 )
76 src.type_error.function_07(
77 argument_n={'key': 'value'},
78 argument_2={0, 1, 2, 'n'},
79 argument_0=(0, 1, 2, 'n'),
80 argument_1=[0, 1, 2, 'n'],
81 )
82 src.type_error.function_08(
83 'positional', argument='keyword'
84 )
85
86
87def test_type_error_w_class_methods():
88 src.type_error.AClass.method_00()
89 src.type_error.AClass().method_01()
90 src.type_error.AClass().method_02()
91 src.type_error.AClass.method_03()
92 src.type_error.AClass.method_04()
93 src.type_error.AClass().method_05()
94 src.type_error.AClass().method_06()
95 src.type_error.AClass().method_07()
96 src.type_error.AClass().method_08()
97 src.type_error.AClass().method_09()
98
99
100# Exceptions seen
101# AssertionError
102# NameError
103# TypeError
104# ModuleNotFoundError
105# AttributeError
open the project
I open a terminal
I change directory to the type_error folder in the
pumping_pythonfoldercd type_errorI open
test_type_error.pyI use pytest-watcher to run the tests automatically
uv run pytest-watcher . --nowthe terminal shows
test_type_error.py ... [100%] =================== 3 passed in G.HIs ====================
test_type_error_w_class_methods
RED: make it fail
I add a test with a call to AClass.method from test_type_error.py
82 src.type_error.function_08(
83 'positional', argument='keyword'
84 )
85
86
87def test_type_error_w_class_methods():
88 src.type_error.AClass.method_00()
89
90
91# Exceptions seen
the terminal is my friend, and shows AttributeError
AttributeError: module 'src.type_error'
has no attribute 'AClass'
because AClass is not defined in type_error.py.
GREEN: make it pass
I open
type_error.pyI add a class definition for
AClasstotype_error.py40def function_08(name, argument): 41 return None 42 43 44class AClass(object): 45 46 passthe terminal is my friend, and shows AttributeError
AttributeError: type object 'AClass' has no attribute 'method_00'because there is nothing named
method_00inAClass.I add the name to the class definition
44class AClass(object): 45 46 # pass 47 method_00the terminal is my friend, and shows NameError
NameError: name 'method_00' is not definedI define
method_00by pointing it to None44class AClass(object): 45 46 # pass 47 # method_00 48 method_00 = Nonethe terminal is my friend, and shows TypeError
TypeError: 'NoneType' object is not callablebecause
method_00points to None and I cannot call None like a function.I change
method_00to a method44class AClass(object): 45 46 # pass 47 # method_00 48 # method_00 = None 49 def method_00(): return Nonethe test passes.
REFACTOR: make it better
I remove the commented lines
44class AClass(object): 45 46 def method_00(): return NoneI add a call to
src.type_error.AClass().method_01fromtest_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 91 92# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: 'AClass' object has no attribute 'method_01'. Did you mean: 'method_00'?I add a method definition for
method_01toAClassintype_error.py44class AClass(object): 45 46 def method_00(): return None 47 def method_01(): return Nonethe terminal is my friend, and shows TypeError
TypeError: AClass.method_01() takes 0 positional arguments but 1 was givenbecause a method of an instance takes the instance of the class (
self) it belongs to as the first argument.I add @staticmethod to
method_01class AClass(object): def method_00(): return None @staticmethod def method_01(): return Nonethe test passes because I can use the staticmethod decorator if I do not want to add
selfto the method definition when it does not use anything in the class.Both methods look the same. The difference is in how I call them
AClass.method_00()vsAClass().method_01().I add a call to
src.type_error.AClass().method_02fromtest_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 92 93# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: 'AClass' object has no attribute 'method_02'. Did you mean: 'method_00'?I add a definition for
method_02toAClassintype_error.py44class AClass(object): 45 46 def method_00(): return None 47 48 @staticmethod 49 def method_01(): return None 50 51 def method_02(): return self.method_01()the terminal is my friend, and shows TypeError
TypeError: AClass.method_02() takes 0 positional arguments but 1 was givenbecause a method of an instance takes the instance of the class (
self) it belongs to as the first argument.I add @staticmethod to
method_0248 @staticmethod 49 def method_01(): return None 50 51 @staticmethod 52 def method_02(): return self.method_01()the terminal is my friend, and shows NameError
NameError: name 'self' is not definedI add
selfto the parentheses ofmethod_0251 @staticmethod 52 # def method_02(): return self.method_01() 53 def method_02(self): 54 return self.method_01()the terminal is my friend, and shows TypeError
TypeError: AClass.method_02() missing 1 required positional argument: 'self'I comment out the staticmethod decorator
51 # @staticmethod 52 # def method_02(): return self.method_01() 53 def method_02(self): 54 return self.method_01()the test passes because a method of an instance takes the instance of the class (
self) it belongs to as the first argument which allows it to use things that belong to the class.I add a call to
src.type_error.AClass.method_03fromtest_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 93 94# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: type object 'AClass' has no attribute 'method_03'. Did you mean: 'method_00'?I add a definition for
method_03toAClassintype_error.py51 # @staticmethod 52 # def method_02(): return self.method_01() 53 def method_02(self): 54 return self.method_01() 55 56 def method_03(): 57 return method_02()the terminal is my friend, and shows NameError
NameError: name 'method_02' is not definedI add
AClass.beforemethod_0256 def method_03(): 57 # return method_02() 58 return AClass.method_02()the terminal is my friend, and shows TypeError
TypeError: AClass.method_02() missing 1 required positional argument: 'self'because
method_02takes an instance of the class it belongs to as input.I called the method with the class not an instance of the class.
I use an instance of the class to call the method
56 def method_03(): 57 # return method_02() 58 # return AClass.method_02() 59 return AClass().method_02()the test passes. This is a silly example because I used
AClass()inside a method ofAClass. I could just useself. I would only need this if I was calling a method of a different class.Here is another silly example. I add a call to
src.type_error.AClass.method_04fromtest_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 src.type_error.AClass.method_04() 93 94 95# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: type object 'AClass' has no attribute 'method_04'. Did you mean: 'method_00'?I add method definition for
method_04toAClassintype_error.py56 def method_03(): 57 # return method_02() 58 # return AClass.method_02() 59 return AClass().method_02() 60 61 def method_04(): 62 return AClass.method_02()the terminal is my friend, and shows TypeError
TypeError: AClass.method_02() missing 1 required positional argument: 'selfbecause
method_02takes an instance of the class it belongs to as input.I called the method with the class not an instance of the class.
I pass
AClassas input in the call tomethod_0261 def method_04(): 62 # return AClass.method_02() 63 return AClass.method_02(AClass)the test passes. I called a method of
AClassand passedAClassas input. I can useself.I add a call to
src.type_error.AClass().method_05fromtest_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 src.type_error.AClass.method_04() 93 src.type_error.AClass().method_05() 94 95 96# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: 'AClass' object has no attribute 'method_05'. Did you mean: 'method_00'?I add a method definition for
method_05toAClassintype_error.py61 def method_04(): 62 # return AClass.method_02() 63 return AClass.method_02(AClass) 64 65 def method_05(): 66 return method_02()because a method of an instance takes the instance of the class (
self) it belongs to as the first argument.I add
selfto the parentheses ofmethod_0565 # def method_05(): 66 def method_05(self): 67 return method_02()the terminal is my friend, and shows NameError
NameError: name 'method_02' is not definedI add
self.beforemethod_0265 # def method_05(): 66 def method_05(self): 67 # return method_02() 68 return self.method_02()the test passes.
I add a call to
src.type_error.AClass().method_06fromtest_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 src.type_error.AClass.method_04() 93 src.type_error.AClass().method_05() 94 src.type_error.AClass().method_06() 95 96 97# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: 'AClass' object has no attribute 'method_06'. Did you mean: 'method_00'?I add a method definition for
method_06toAClass65 # def method_05(): 66 def method_05(self): 67 # return method_02() 68 return self.method_02() 69 70 def method_06(): 71 return self.method_01()the terminal is my friend, and shows TypeError
TypeError: AClass.method_06() takes 0 positional arguments but 1 was givenbecause a method of an instance takes the instance of the class (
self) it belongs to as the first argument.I add
selfto the parentheses ofmethod_0670 # def method_06(): 71 def method_06(self): 72 return self.method_01()the test passes.
I add a call to
src.type_error.AClass().method_07fromtest_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 src.type_error.AClass.method_04() 93 src.type_error.AClass().method_05() 94 src.type_error.AClass().method_06() 95 src.type_error.AClass.method_07() 96 97 98# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: 'AClass' object has no attribute 'method_07'. Did you mean: 'method_00'?I add a method definition for
method_07toAClassintype_error.py70 # def method_06(): 71 def method_06(self): 72 return self.method_01() 73 74 def method_07(self): 75 return self.method_00()the terminal is my friend, and shows TypeError
TypeError: AClass.method_07() missing 1 required positional argument: 'self'because
method_07takes an instance of the class it belongs to as input.I called the method with the class not an instance of the class.
I use an instance of the class to call the method from
test_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 src.type_error.AClass.method_04() 93 src.type_error.AClass().method_05() 94 src.type_error.AClass().method_06() 95 # src.type_error.AClass.method_07() 96 src.type_error.AClass().method_07() 97 98 99# Exceptions seenthe terminal is my friend, and shows TypeError
TypeError: AClass.method_00() takes 0 positional arguments but 1 was givenbecause
method_00takes no input (the parentheses are empty).I called it with an instance of the class (
self) which passes the instance as input.
I add the staticmethod decorator to
method_00ofAClassintype_error.py44class AClass(object): 45 46 @staticmethod 47 def method_00(): return Nonethe test passes. I can use the staticmethod decorator if I do not want to add
selfto the method definition when it does not use anything in the class.I add a call to
src.type_error.AClass.method_08()fromtest_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 src.type_error.AClass.method_04() 93 src.type_error.AClass().method_05() 94 src.type_error.AClass().method_06() 95 # src.type_error.AClass.method_07() 96 src.type_error.AClass().method_07() 97 src.type_error.AClass.method_08() 98 99 100# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: type object 'AClass' has no attribute 'method_08'. Did you mean: 'method_00'?I add a method definition for
method_08toAClassintype_error.py75 def method_07(self): 76 return self.method_00() 77 78 def method_08(self): 79 return self.method_04()the terminal is my friend, and shows TypeError
TypeError: AClass.method_08() missing 1 required positional argument: 'self'because I called
method_08like a staticmethod and it is defined as an instance method (It expectsselfas input).I use an instance of the class to call the method from
test_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 src.type_error.AClass.method_04() 93 src.type_error.AClass().method_05() 94 src.type_error.AClass().method_06() 95 # src.type_error.AClass.method_07() 96 src.type_error.AClass().method_07() 97 # src.type_error.AClass.method_08() 98 src.type_error.AClass().method_08() 99 100 101# Exceptions seenTypeError: AClass.method_04() takes 0 positional arguments but 1 was givenbecause
method_04takes no input (the parentheses are empty).I called it with an instance of the class (
self) which passes the instance as input.
I add the staticmethod decorator to
method_04ofAClassintype_error.py57 def method_03(): 58 # return method_02() 59 # return AClass.method_02() 60 return AClass().method_02() 61 62 @staticmethod 63 def method_04(): 64 # return AClass.method_02() 65 return AClass.method_02(AClass) 66 67 # def method_05(): 68 def method_05(self): 69 # return method_02() 70 return self.method_02()the test passes.
I add a call to
src.type_error.AClass.method_09()fromtest_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 src.type_error.AClass.method_04() 93 src.type_error.AClass().method_05() 94 src.type_error.AClass().method_06() 95 # src.type_error.AClass.method_07() 96 src.type_error.AClass().method_07() 97 # src.type_error.AClass.method_08() 98 src.type_error.AClass().method_08() 99 src.type_error.AClass().method_09() 100 101 102# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: type object 'AClass' has no attribute 'method_09'. Did you mean: 'method_00'?I add a method definition for
method_09toAClassintype_error.py79 def method_08(self): 80 return self.method_04() 81 82 def method_09(self): 83 return self.method_03()the terminal is my friend, and shows TypeError
TypeError: AClass.method_03() takes 0 positional arguments but 1 was givenbecause
method_03takes no input (the parentheses are empty).I called it with an instance of the class (
self) which passes the instance as input.
I add the @staticmethod to
method_03ofAClassintype_error.py52 # @staticmethod 53 # def method_02(): return self.method_01() 54 def method_02(self): 55 return self.method_01() 56 57 @staticmethod 58 def method_03(): 59 # return method_02() 60 # return AClass.method_02() 61 return AClass().method_02() 62 63 @staticmethod 64 def method_04(): 65 # return AClass.method_02() 66 return AClass.method_02(AClass)the test passes.
I remove the commented lines from
type_error.py44class AClass(object): 45 46 @staticmethod 47 def method_00(): return None 48 49 @staticmethod 50 def method_01(): return None 51 52 def method_02(self): 53 return self.method_01() 54 55 @staticmethod 56 def method_03(): 57 return AClass().method_02() 58 59 @staticmethod 60 def method_04(): 61 return AClass.method_02(AClass) 62 63 def method_05(self): 64 return self.method_02() 65 66 def method_06(self): 67 return self.method_01() 68 69 def method_07(self): 70 return self.method_00() 71 72 def method_08(self): 73 return self.method_04() 74 75 def method_09(self): 76 return self.method_03()I remove the commented lines from
test_type_error.py87def test_type_error_w_class_methods(): 88 src.type_error.AClass.method_00() 89 src.type_error.AClass().method_01() 90 src.type_error.AClass().method_02() 91 src.type_error.AClass.method_03() 92 src.type_error.AClass.method_04() 93 src.type_error.AClass().method_05() 94 src.type_error.AClass().method_06() 95 src.type_error.AClass().method_07() 96 src.type_error.AClass().method_08() 97 src.type_error.AClass().method_09() 98 99 100# Exceptions seen 101# AssertionError 102# NameError 103# TypeError 104# ModuleNotFoundError 105# AttributeErrorI open a new terminal then make sure I am in the
type_errorfoldercd type_errorI add a git commit message in the other terminal
git commit --all --message \ 'add test_type_error_w_class_methods'
review
The tests show that
If I call a method with an instance, it takes the instance as the first argument (
self)I can use the staticmethod decorator if the method does not use anything that belongs to the class it is part of.
All the tests so far show that I get TypeError when I call a function/method in a way that is different from its definition.
code from the chapter
what is next?
so far you 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.