Saturday, 13 July 2024

Some Python Tricks 2024

This post is not much related to another post with a similar title from 2 years ago, but honestly I could not think of any other distintive title.

1) Overtime I've been using 3 different approches for a common, simple task. I've got a list of lines that I've read from a basic CSV file. To split these lines by separator and extract some of the columns (so obtaining a list of tuples) I was initially using this:


	lines: list[str] = Path(file_path).read_text().splitlines()
    
    pairs = [(items[0], items[2]) 
    	for items in
    	[line.split(separator) for line in lines]
    ]

Then I realized I could leverage the assignment expressions (aka walrus) feature like this:


    pairs = [((items := line.split(separator))[0], items[2])
        for line in lines
    ]

And recently I've learnt about the convenience of using operator.itemgetter


    pairs = [(operator.itemgetter(0, 2)(line.split(separator)))
        for line in lines
    ]

2) Nested list comprehensions can be confusing if written in a single line. Given this data:


# Nested list comprehensions
@dataclass
class City:
    name: str
    population: int

@dataclass
class Country:
    name: str
    population: int
    cities: list[City]

countries = [
    Country("France", 68_000_000, 
        cities = [
            City("Paris", 12_000_000),
            City("Marseille", 1_800_000),
        ]        
    ),
    Country("Portugal", 10_000_000, 
        cities = [
            City("Lisbon", 3_000_000),
            City("Porto", 1_000_000),
        ]        
    ),   
]

This list comprehension:


city_country_pairs = [(city.name, country.name) for country in countries for city in country.cities]

Is quite less evident than this one:


city_country_pairs = [
    (city.name, country.name)
    for country in countries
    for city in country.cities
]

That is equivalent to this:


city_country_pairs = []
for country in countries:
    for city in country.cities:
        city_country_pairs.append((city.name, country.name))

3) The other day I came across a nice trick for setting an attribute in objects of one list and returning it in just one sentence (so using a list comprehension)


cities = [
    City("Paris", 12_000_000),
    City("Marseille", 1_800_000),
]        
return [
    setattr(city, "population", None) or city
    for city in cities 
]


The trick there is that setattr returns None, so doing an or with the object itself where we've just set the attribute returns that object.

No comments:

Post a Comment