TypeError with objects


Since methods are functions in an object I can assume that they have the same behavior as what I tested in the functions project.


preview

I have these tests by the end of the chapter

questions about TypeError with objects


open the project

  • I open a terminal

  • I change directory to the type_error folder in the pumping_python folder

    terminal
    cd type_error
    
  • I open test_type_error.py from the tests folder

  • I use pytest-watcher to run the tests automatically

    terminal
    uv run pytest-watcher . --now --patterns "**/*.py"
    

    the terminal shows

    test_type_error.py ...                              [100%]
    
    =================== 3 passed in G.HIs ====================
    

test_type_error_w_object_methods

RED: make it fail


I add a test with a call to AnObject.method from tests/test_type_error.py

83    src.type_error.function_08(
84        'positional',
85        argument='keyword',
86    )
87
88
89def test_type_error_w_object_methods():
90    src.type_error.AnObject.method_00()
91
92
93# Exceptions seen

the terminal is my friend, and shows AttributeError

AttributeError: module 'src.type_error'
                has no attribute 'AnObject'

because AnObject is not defined in src/type_error/__init__.py.


GREEN: make it pass



REFACTOR: make it better


  • I remove the commented lines from src/type_error/__init__.py

  • I add a call to src.type_error.AnObject().method_01 from tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_01'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_01 to AnObject in src/type_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_01() takes
               0 positional arguments but 1 was given
    

    because a method of an instance takes the instance of the class (self) it belongs to as the first argument.

  • I add @staticmethod to method_01

    terminal
    class AnObject(object):
    
        def method_00(): return None
    
        @staticmethod
        def method_01(): return None
    

    the test passes because I can use the staticmethod decorator if I do not want to add self to the method definition when it does not use anything that belongs to the object.

    Both methods look the same. The difference is in how I call them AnObject.method_00() vs AnObject().method_01().

  • I add a call to src.type_error.AnObject().method_02 from tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_02'.
                    Did you mean: 'method_00'?
    
  • I add a definition for method_02 to AnObject in src/type_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_02() takes
               0 positional arguments but 1 was given
    

    because a method of an instance takes the instance of the class (self) it belongs to as the first argument.

  • I add @staticmethod to method_02

    the terminal is my friend, and shows NameError

    NameError: name 'self' is not defined
    
  • I add self to the parentheses of method_02

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_02() missing
               1 required positional argument: 'self'
    
  • I comment out the staticmethod decorator

    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 object.

  • I add a call to src.type_error.AnObject.method_03 from tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AnObject'
                    has no attribute 'method_03'.
                    Did you mean: 'method_00'?
    
  • I add a definition for method_03 to AnObject in src/type_error/__init__.py

    the terminal is my friend, and shows NameError

    NameError: name 'method_02' is not defined
    

    because there is nothing named method_02 inside method_03 or at the module level of src/type_error/__init__.py.

  • I add AnObject. before method_02

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_02() missing
               1 required positional argument: 'self'
    

    because

  • I use an instance of the class to call the method

    the test passes. This is a silly example because I used AnObject() inside a method of AnObject. I could just use self. I would only need this if I was calling a method of a different object.

  • Here is another silly example. I add a call to src.type_error.AnObject.method_04 from tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AnObject'
                    has no attribute 'method_04'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_04 to AnObject in src/type_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_02() missing
               1 required positional argument: 'self'
    

    because

  • I pass AnObject as input in the call to method_02

    the test passes. I called a method of AnObject and passed AnObject as input. I can use self.

  • I add a call to src.type_error.AnObject().method_05 from tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_05'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_05 to AnObject in src/type_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_05() takes
               0 positional arguments but 1 was given
    

    because a method of an instance takes the instance of the class (self) it belongs to as the first argument.

  • I add self to the parentheses of method_05

    the terminal is my friend, and shows NameError

    NameError: name 'method_02' is not defined
    

    because there is no method_02 at the module level of src/type_error/__init__.py. It is inside AnObject in src/type_error/__init__.py, I have to be specific.

  • I add self. before method_02

    the test passes.

  • I add a call to src.type_error.AnObject().method_06 from tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_06'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_06 to AnObject in src/type_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_06() takes
               0 positional arguments but 1 was given
    

    because a method of an instance takes the instance of the class (self) it belongs to as the first argument.

  • I add self to the parentheses of method_06

    the test passes.

  • I add a call to src.type_error.AnObject().method_07 from tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AnObject'
                    has no attribute 'method_07'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_07 to AnObject in src/type_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_07() missing
               1 required positional argument: 'self'
    

    because

  • I use an instance of the class to call the method from tests/test_type_error.py

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_00() takes
               0 positional arguments but 1 was given
    

    because

    • method_00 takes no input (the parentheses are empty).

    • I called it with an instance of the class (AnObject()) which passes the instance as input.

  • I add the staticmethod decorator to method_00 of AnObject in src/type_error/__init__.py

    the test passes. I can use the staticmethod decorator if I do not want to add self to the method definition when it does not use anything that belongs to the object.

  • I add a call to src.type_error.AnObject.method_08() from tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: type object 'AnObject'
                    has no attribute 'method_08'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_08 to AnObject in src/type_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_08() missing
               1 required positional argument: 'self'
    

    because I called method_08 like a staticmethod and it is defined as an instance method (It expects self as input).

  • I use an instance of the class to call the method from tests/test_type_error.py

    the terminal shows TypeError

    TypeError: AnObject.method_04() takes
               0 positional arguments but 1 was given
    

    because

    • method_04 takes no input (the parentheses are empty).

    • I called it with an instance of the class (AnObject()) which passes the instance as input.

  • I add the staticmethod decorator to method_04 of AnObject in src/type_error/__init__.py

    the test passes.

  • I add a call to src.type_error.AnObject().method_09() from tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: 'AnObject' object
                    has no attribute 'method_09'.
                    Did you mean: 'method_00'?
    
  • I add a method definition for method_09 to AnObject in src/type_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: AnObject.method_03() takes
               0 positional arguments but 1 was given
    

    because

    • method_03 takes no input (the parentheses are empty).

    • I called it with an instance of the class (AnObject()) which passes the instance as input.

  • I add the @staticmethod to method_03 of AnObject in src/type_error/__init__.py

    the test passes.

  • I remove the commented lines from src/type_error/__init__.py

  • I remove the commented lines from tests/test_type_error.py

  • I open a new terminal then make sure I am in the type_error folder

    terminal
    cd type_error
    
  • I add a git commit message in the other terminal

    terminal
    git commit --all --message \
    'add test_type_error_w_object_methods'
    

test_type_error_w_the_uncallables

Is every object callable?


RED: make it fail


  • I go back to the terminal that is running the tests.

  • I add a test to tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.type_error' has no attribute 'none'
    

    there is nothing named none in src/type_error/__init__.py in the src folder, yet.


GREEN: make it pass


  • I add none and point it to None

    1none = None
    

    the terminal is my friend, and shows TypeError

    TypeError: 'NoneType' object is not callable
    
    • the () to the right of src.type_error.none makes it a call

    • the name none points to None which is NOT callable. Using substitution

      none = None   # point the name to the object
      none()        # call the name
      None()        # substitute the value for the name
      

      None() raises TypeError because I cannot call None like a function.

  • I make none a function in src/type_error/__init__.py to make it callable

    1# none = None
    2def none(): return None
    3
    4
    5def function_00(the_input):
    6    return None
    

    the test passes.

I can call a function, I cannot call None.


REFACTOR: make it better


  • I add a call to false in tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.type_error'
                    has no attribute 'false'
    

    false is not in src/type_error/__init__.py.

  • I add false to src/type_error/__init__.py and point it to False

    1# none = None
    2def none(): return None
    3false = False
    4
    5
    6def function_00(the_input):
    7    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: 'bool' object is not callable
    

    false points to False which is NOT callable. Using substitution

    false = False
    false()
    False()
    

    False() raises TypeError because I cannot call a boolean like a function.

  • I change false from a variable to a function to make it callable

    1# none = None
    2def none(): return None
    3# false = False
    4def false(): return False
    5
    6
    7def function_00(the_input):
    8    return None
    

    the test is green again.

  • I add a call to the other boolean in tests/test_type_error.py

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.type_error'
                    has no attribute 'true'
    

    there is nothing named true in src/type_error/__init__.py.

  • I add true and point it to True in src/type_error/__init__.py

    the terminal is my friend, and shows TypeError

    TypeError: 'bool' object is not callable
    
  • I change true from a variable to a function to make it callable

    the test passes. I can call a function, I cannot call a boolean or None.



close the project

  • I close tests/test_type_error.py and src/type_error/__init__.py

  • I click in the terminal where the tests are running

  • I use q on the keyboard to leave the tests. The terminal goes back to the command line.

  • I change directory to the parent of type_error

    terminal
    cd ..
    

    the terminal shows

    .../pumping_python
    

    I am back in the pumping_python directory.


review

The tests show that

All the tests so far show that I get TypeError when I call an object in a way that is different from its definition.

How many questions can you answer about TypeError with objects?


code from the chapter

Do you want to see all the CODE I typed in this chapter?


what is next?

Would you like to see another way to write tests?


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.