Search code examples
pythonpython-3.xdictionarypython-dataclasses

Correct way to initialize an Optional Dict with type hint in Python3?


I want to initialize a dataclass dictionary with type hint(key should be string, the value should be another dataclass's instances) called usr_orders that does NOT require user init upon initializing instances. Based on my understanding Optional is the union(.., None), so I went with:

@dataclass
class User:
    usr_orders: Optional[Dict[str, BookOrder]] = Dict

But when I try to modify it using key-value I got the following error: TypeError: '_GenericAlias' object does not support item assignment

def update_usr_orders(self, book_order:BookOrder):
    self.usr_orders[book_order.order_id] = book_order # book_order: BookOrder is a dataclass instance

This error seems to be caused by the optional Dict definition. But I don't know how to solve this. Does anyone know why I cannot update the usr_orders? Thanks!


Solution

  • You'll need to import a field and use a default_factory:

    from dataclasses import dataclass, field
    from typing import Optional, Dict
    
    @dataclass
    class BookOrder():
        id: str
    
    @dataclass
    class User:
        usr_orders: Optional[Dict[str, BookOrder]] = field(default_factory=dict)
    
        def update_usr_orders(self, book_order:BookOrder):
            self.usr_orders[book_order.id] = book_order
    
    a = BookOrder('1')
    u = User()
    u.update_usr_orders(a)
    print(u.usr_orders)
    

    Part of the issue is that you were using Dict as a default field for the data class. Dict is a type hint; I think you were meaning to use dict() or {} - however, this would not work. Try it and see for yourself! You'll end up with this error: ValueError: mutable default <class 'dict'> for field usr_orders is not allowed: use default_factory. This is a dataclass thing where it prevents you from using 1 dictionary for multiple instances.

    Further reading