Search code examples
pythonlistviewtkinterlistbox

Python equivalent for C#'s generic List<T>


I am creating a simple GUI program to manage priorities.

Priorities

I have successfully managed to add functionality to add an item to the listbox. Now I want to add the item to the something what is known as List<> in C#. Does such a thing exist in Python?

For instance, in C#, to add an item to the listview I would first create:

List<Priority> priorities = new List<Priority>();

...and then create the following method:

void Add()
{
    if (listView1.SelectedItems.Count > 0)
    {
        MessageBox.Show("Please make sure you have no priorities selected!", "Notification", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    else if (txt_Priority.ReadOnly == true) { MessageBox.Show("Please make sure you refresh fields first!", "Notification", MessageBoxButtons.OK, MessageBoxIcon.Information); }
    else
    {
        if ((txt_Priority.Text.Trim().Length == 0)) { MessageBox.Show("Please enter the word!", "Notification", MessageBoxButtons.OK, MessageBoxIcon.Information); }
        else
        {
            Priority p = new Priority();
            p.Subject = txt_Priority.Text;

            if (priorities.Find(x => x.Subject == p.Subject) == null)
            {
                priorities.Add(p);
                listView1.Items.Add(p.Subject);
            }
            else
            {
                MessageBox.Show("That priority already exists in your program!");
            }
            ClearAll();
            Sync();
            Count();
        }
    }
    SaveAll();

}

Solution

  • Type hints

    Since Python 3.5, it's possible to add type hints. Coupled with dataclasses (Python 3.7+), and generic collections (Python 3.9+), you can write:

    from dataclasses import dataclass
    
    
    @dataclass
    class Priority:
        """Basic example class"""
        name: str
        level: int = 1
    
    
    foo = Priority("foo")
    bar = Priority("bar", 2)
    
    priorities: list[Priority] = [foo, bar]
    
    print(priorities)
    # [Priority(name='foo', level=1), Priority(name='bar', level=2)]
    print(sorted(priorities, key= lambda p: p.name))
    # [Priority(name='bar', level=2), Priority(name='foo', level=1)]
    
    baz = "Not a priority"
    priorities.append(baz) # <- Your IDE will probably complain
    
    print(priorities)
    # [Priority(name='foo', level=1), Priority(name='bar', level=2), 'Not a priority']
    

    In Python 3.5, the code would look like:

    from typing import List
    
    
    class Priority:
        """Basic example class"""
        def __init__(self, name: str, level: int = 1):
            self.name = name
            self.level = level
    
        def __str__(self):
            return '%s (%d)' % (self.name, self.level)
    
        def __repr__(self):
            return str(self)
    
    
    foo = Priority("foo")
    bar = Priority("bar", 2)
    
    priorities: List[Priority] = [foo, bar]
    
    print(priorities)
    # [foo (1), bar (2)]
    print(sorted(priorities, key=lambda p: p.name))
    # [bar (2), foo (1)]
    
    baz = "Not a priority"
    priorities.append(baz) # <- Your IDE will probably complain
    
    print(priorities)
    # [foo (1), bar (2), 'Not a priority']
    

    Note that type hints are optional, and the above code will run fine, even if there's a type mismatch when appending baz.

    You can explicitly check for errors with mypy:

    ❯ mypy priorities.py
    priorities.py:22: error: Argument 1 to "append" of "list" has incompatible type "str"; expected "Priority"
    Found 1 error in 1 file (checked 1 source file)
    

    Dynamic language

    Even if it now has type hints, Python stays dynamic, and type hints are completely optional:

    >>> my_generic_list = []
    >>> my_generic_list.append(3)
    >>> my_generic_list.append("string")
    >>> my_generic_list.append(['another list'])
    >>> my_generic_list
    [3, 'string', ['another list']]
    

    You don't have to define anything before appending any object to an existing list.

    Python uses duck-typing. If you iterate on a list and call a method on each one of the elements, you need to make sure that the elements understand the method.

    So if you want the equivalent of :

    List<Priority> priorities
    

    you just need to initialize a list and make sure you only add Priority instances to it. That's it!