Hacker News new | ask | show | jobs
by oroul 1559 days ago
It's hard to completely get away from objects in Python, but I don't think that needs to be an objective to get away from OOP patterns. My suggestions would be:

- Don't use classes for information. Use regular data structures (dict, list, tuple, set) and use functions to manipulate them. If you really want/need something like a struct, use a dataclass.

- The itertools module has a bunch of useful constructs for creating and combining iterators. Take advantage of Python's iterators and construct your own when necessary.

- List comprehensions and generator expressions are great for clear and concise data transformations

- You're going to have to deal with state somewhere in your program. That's fine, some state is necessary to do real work. Don't feel bad about creating classes for things like context managers (e.g. for a database connection) so you can use it in a with statement and it will handle the setup and teardown logic for you. That way your business logic stays concise and Pythonic since those classes can be in separate modules and imported as necessary. I've found this 'functions in the front, classes in the back' approach to writing Python useful as it lets me think about what my program does in a functional manner without denying myself the ergonomics of Python's class-based ecosystem.

3 comments

> Don't use classes for information. Use regular data structures (dict, list, tuple, set) and use functions to manipulate them.

I've written a lot of functionalish Python, and I've found that this is a consistent way to breed code that's hard to understand. Instead, I would default to (usually frozen) dataclasses to represent data—they're functional records that also let your code reflect the concepts that make sense for whatever you're doing. A list of dictionaries of strings looks like any other list of dictionaries of strings; a sequence of User objects has clear semantics and, as a benefit, is harder to mutate in unexpected ways.

Wouldn't TypedDict come in handy here? This way we can kinda mimick a structural typing system. The only disadvantage I ran across here is that TypedDict can't handle recursive fields, unlike dataclasses. Otherwise, it seems to me like a more Pythonic choice, reminding of Clojure
> Don't use classes for information. Use regular data structures (dict, list, tuple, set) and use functions to manipulate them.

One problem is many of these datastructures are easy to mutate. When I need to ensure immutability to a dictionary, for instance - quite often - I can't avoid wrapping it in a class and setting up an interface to lock down mutation.

If Python had a way to declare immutable datastructure, similarly to Clojure, it would make life a lot easier...

Frozen dataclass instances (https://docs.python.org/3/library/dataclasses.html#frozen-in...) might be of help.
Wasn't aware of this feature in dataclasses, that can be helpful in a few cases, thanks for pointing out
> class types.MappingProxyType(mapping)

> Read-only proxy of a mapping. It provides a dynamic view on the mapping’s entries, which means that when the mapping changes, the view reflects these changes.

https://docs.python.org/3/library/types.html#types.MappingPr...

This can be helpful in some cases, but it's precisely what I sometimes need to avoid, which is protecting a dictionary and having changes affecting only its own scope.

If function A passes a dict to function B, I would like:

1) Function A to keep the dict intact while function B can manipulate its content;

2) Function A can change the dict after passing to B, and B still keep the original copy, unaware of A's later changes.

One way of doing this is by deep copying dictionaries around, but it can easily become a big performance issue.

It sounds like what you really want is an efficient way of copying dictionaries, perhaps copy on write, something like the cowdict [1] project.

[1]: https://pypi.org/project/cowdict/

Can you point to any public codebases which illustrate this approach in Python? I would love to see some of these principles in action.