'Python 3.10 Type Hinting causes Syntax Error

I have defined two classes. A Bookshelf class and a Book class and have defined each with its own methods and type hints. When I run the below code in VS Code using python 3.10 it comes up with the following error:

class Bookshelf: 
SyntaxError: Invalid syntax

Which is referring to the init of the BookShelf class below. Can any of you spot the issue?

class Bookshelf:

    def __init__(self, books: list[Book]):
        self.books = books

    def __str__(self) -> str:
        return f"Bookshelf with {len(self.books)}"


class Book:
    def __init__(self, name: str, page_count: int):
        self.name=name
        self.page_count = page_count


Solution 1:[1]

It is not a SyntaxError, It is a NameError because Book class is not defined yet when you are using it in your type hints.

1. First solution is moving the definition of Book class before the BookShelf.

2. Second solution is use the string instead of the book itself:

def __init__(self, books: list["Book"]):

I think in Python 3.11, They will allow to use it as it is. Evaluation of type annotations are gonna be postponed:

https://peps.python.org/pep-0563/

3. third solution: If you want to have this now, you can import:

from __future__ import annotations

then your code is going to work.

Solution 2:[2]

Using the code in your question, I'm actually getting a NameError because Book is used in the type hint before it's defined. Moving the Book class above Bookshelf took care of it.

class Book:
    def __init__(self, name: str, page_count: int):
        self.name = name
        self.page_count = page_count


class Bookshelf:
    def __init__(self, books: list[Book]):
        self.books = books

    def __str__(self) -> str:
        return f"Bookshelf with {len(self.books)} books."

atlas = Book("Atlas", 100)
dictionary = Book("Dictionary", 1000)
print(atlas)
print(Bookshelf([atlas, dictionary]))

Output:

<__main__.Book object at 0x7f61af441fd0>
Bookshelf with 2 books.

Solution 3:[3]

Try switching:

list[Book]

with:

'list[Book]'

Solution 4:[4]

  1. You have defined the Book class after you referred to it in books: list[Book]
  2. You can't use list[Book] as a parameter as the type list is already defined in Python

Try this:

from typing import List #Using typing's List instead of list

class Book:
    def __init__(self, name: str, page_count: int):
        self.name=name
        self.page_count = page_count
#Defined book class before its use
        
list_of_books = List[Book] #Using a type alias to solve the problem so you can use it as a parameter

class Bookshelf:

    def __init__(self, books: list_of_books):
        self.books = books

    def __str__(self) -> str:
        return f"Bookshelf with {len(self.books)}"

Use type aliases to define the complex type of parameter you want. See Using List/Tuple/etc. from typing vs directly referring type as list/tuple/etc

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Tim
Solution 3 Ofirfr
Solution 4