I have seen some people prefer to create a list of strings by using thing = list[str]() instead of thing: list[str] = []. I think it looks kinda weird, but maybe that’s just because I have never seen that syntax before. Does that have any downsides?

It is also possible to use this for dicts: thing = dict[str, SomeClass](). Looks equally weird to me. Is that widely used? Would you use it? Would you point it out in a code review?

  • chemacortes
    link
    fedilink
    English
    arrow-up
    13
    ·
    1 year ago

    The first one, has a implicit call to the constructor that need infer the type annotation of the result. BTW, the second form is a direct statement with a explicit type annotation, more recommended. When you see the AST of both statements, you can see the overload of calling the constructor and the use of AnnAssign (assign with type annotation) vs Assign:


    thing = list[str]()

    Module(
        body=[
            Assign(
                targets=[
                    Name(id='thing', ctx=Store())],
                value=Call(
                    func=Subscript(
                        value=Name(id='list', ctx=Load()),
                        slice=Name(id='str', ctx=Load()),
                        ctx=Load()),
                    args=[],
                    keywords=[]))],
        type_ignores=[])
    

    thing: list[str] = []

    Module(
        body=[
            AnnAssign(
                target=Name(id='thing', ctx=Store()),
                annotation=Subscript(
                    value=Name(id='list', ctx=Load()),
                    slice=Name(id='str', ctx=Load()),
                    ctx=Load()),
                value=List(elts=[], ctx=Load()),
                simple=1)],
        type_ignores=[])
    
      • chemacortes
        link
        fedilink
        arrow-up
        8
        ·
        1 year ago

        With the dump function:

        from ast import dump, parse
        
        st = parse("thing = list[str]()")
        print(dump(st, indent=4))
        
        st = parse("thing: list[str] = []")
        print(dump(st, indent=4))
        
  • amanaftermidnight@lemmy.world
    link
    fedilink
    English
    arrow-up
    12
    ·
    1 year ago

    You’d always want to use varname: type_description = initial_value pattern. It’s readable, is the same pattern you use in method params, and linters and IDEs recognize this pattern. And it makes sense for the type description be on the left side of the assignment operator, together with the variable it’s describing.

    • qwop
      link
      fedilink
      arrow-up
      1
      ·
      1 year ago

      I’m pretty sure most type checkers recognise both forms.

  • lascapi@jlai.lu
    link
    fedilink
    English
    arrow-up
    7
    arrow-down
    2
    ·
    1 year ago

    I find like you that the first one is strange.

    But I think that both are useless because you can put what you want in a list in python.

    thing = List[str]()
    type(thing)
    # 
    stuff: List[str] = []
    type(stuff)
    # 
    

    But in other hand it’s helpful in IDE to get some warning like Expected type 'str' (matched generic type '_T'), got 'int' instead.

    Soooo, in the end I say that I choose this one thing: list[str] = [] because it looks more widely used and easily readable.

    • UlrikHDA
      link
      fedilink
      arrow-up
      11
      ·
      1 year ago

      But I think that both are useless because you can put what you want in a list in python.

      You can say that about all type hinting, but assuming you actually adhere to the type hints, it’s a great tool to make python projects manageable.

  • InsecureSignpost@kbin.social
    link
    fedilink
    arrow-up
    3
    ·
    1 year ago

    In addition to what others have said, collection literals are also faster. list[str]() performs a function call that technically might not be the built-in list. Where [] is always an empty list and it can be created with less overhead.