Hacker News new | past | comments | ask | show | jobs | submit login

Python's not really built for that AFAIK, though. In languages built for it, you can type your dicts/hashes/maps/whatever and its easier to see what they are/know where the functions that operate on them live. I'm most familiar with Elixir which has structs which are simply specialized map (analogous to dict in Python) where their "type" is the name of the module they belong to. There can only be one struct per module, In this sense is easy to know exactly where its functions live and is almost like a class with the very key difference that modules are not stateful.



> In languages built for it, you can type your dicts/hashes/maps/whatever and its easier to see what they are/know where the functions that operate on them live.

I think I must be misunderstanding what you mean by that, because I can very much do that in Python.


I think I misunderstand OP's problem then.


Their problem stems from the scenario where you don't type them. You just leave them as generic lists & dicts.


That's what I thought. I obviously don't know Python well enough and didn't know you can name dicts (like, beyond setting them to a variable). I guess you can export from a module so they are prefixed! Didn't think of that one earlier.


I'm not sure what you mean by naming dicts, but Python has TypedDict, where you can define the names and types of specific keys. They only exist for type checking and behave exactly as a normal dict at runtime.

In modern typed Python, you can instead use dataclasses, NamedTuples (both in the standard library), attrs or Pydantic (both third-party) to represent structs/records, the latter also providing validation. Still, TypedDicts are helpful when interfacing with older code that uses dicts for heterogeneous data.

My main gripe with them is that different TypedDicts are not compatible with each other. For example, it would be very helpful if a dict with x:str and y:str fields were considered superclasses of dicts with x:str, y:str and z:str like they are in TypeScript, but they aren't. They are considered different types, limiting their usability in some contexts.

When using homogenous dicts, you can still use dict[str, T], and T can be Any if you don't want to type the whole thing. You can use any hashable type instead of str for keys. I often do that when reading JSON from dynamically typed dict[str, Any] to dataclasses.


    class X(TypedDict):
        x: str

    class Y(TypedDict):
        y: str

    class XYZ(X, Y):
        z: str
That should get you the class/superclass relationship that you want, no?


That needs to be explicit for any interacting types. You must define separate classes and explicitly define their hierarchy. This is fine if you control all the types, but it breaks down quickly. The best example is having two TypedDicts with the same members; in Python, you cannot use one instead of the other.

    from typing import TypedDict

    class A(TypedDict):
        a: int
        b: str
        

    class B(TypedDict):
        a: int
        b: str
        
    def f(a: A) -> None: pass

    b = B(a=1, b='b')
    f(B) # mypy error: Argument 1 to "f" has incompatible type "type[B]"; expected "A"  [arg-type]
On the other hand, this is legal in Typescript:

    interface A {
      a: number;
      b: string;
    }

    interface B {
      a: number;
      b: string;
    }  

    function f(a: A) {}

    const b: B = {a: 1, b: 'b'};
    f(b);
This is most useful when A has a subset of B's attributes, like this (which also doesn't work in Python):

    interface A {
      a: number;
    }

    interface B {
      a: number;
      b: string;
    }  

    function f(a: A) {}

    const b: B = {a: 1, b: 'b'};
    f(b);


That seems a lot like duck typing to me.


Yes, it is. Typed Python supports duck typing to some extent; see typing.Protocol and stuff like Sequence, Iterable, Mapping, etc.


I'd argue non-typed Python supports duck typing pretty well too, so you don't necessarily need Typed Python to support it.


Awesome, thanks for the clarification.


Python classes are basically dictionaries that have a distinct type bound to them. Alternatively you can subclass from dictionary to give yourself a distinct type but still be a dictionary. Slotted classes are basically named tuples (and of course, Python has actual named tuples and dataclasses), so there's a lot of ways to "tag" a collection with a specific type in mind.


A typed dict is more like what I mean. Obviously I know about classes as I'm no stranger to OO.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: