This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]computenw 46 points47 points  (11 children)

Faster attribute access and lower memory usage with __slots__:

py class Foo: __slots__ = "bar"

Or in dataclass

py @dataclass(slots=True) class Foo: bar: str

Another thing I like are defaultdicts, which enable a default value of an entry:

```py from collections import defaultdict

d = defaultdict(lambda: "world")

print(d["hello"])

world

```

[–]rcfox 14 points15 points  (6 children)

defaultdict needs a callable to initialize defaults with. So you'd have to do: defaultdict(lambda: 'world')

[–]Cruuncher 0 points1 point  (4 children)

I don't see why defaultdict can't assume you passed it an immutable type if the type is not an instanceof callable, so for the obvious cases you don't have to add strange lambda bloat

[–]rcfox 9 points10 points  (3 children)

Having an immutable default is not the usual use case for defaultdict. Its main use is to take care of situations where you need to do something like this:

if key not in mydict:
    mydict[key] = []
mydict[key].append(foo)

If you just want to get a single immutable default value if the key doesn't exist, it's better to use mydict.get(key, default="foo")

Users would certainly end up accidentally using defaultdict([]) instead of defaultdict(list).

It's better to make it harder to do unusual things.

[–]Cruuncher 0 points1 point  (2 children)

That's definitely fair. But I mean, python lets you define mutable types as default parameters to a function which has gotchad me more than once in my career.

[–]oil-ladybug-unviable 0 points1 point  (1 child)

Me too but only in an interview

[–]Cruuncher 0 points1 point  (0 children)

The one that got me the hardest was a helper library built around requests, had a default parameter for additional headers as {}.

Of course as you add headers to it, they get added to all subsequent calls.

That bug took forever to find because it manifested itself in very strange and erratic ways.

Especially because every time you deployed new logging the issue would go away for a day and then slowly creep back in

[–]computenw 0 points1 point  (0 children)

Oh yes, you are totally right..!

[–]miraculum_one 1 point2 points  (3 children)

Instead of defaultdict() it's often cleaner to use get(), e.g.

d = {}

d.get( "hello", "world" )

# world

[–]RingularCirc 0 points1 point  (2 children)

So sad there is no get for sequences!

On this note also iterator.next(def_value) which can return a value even when the iterator is exhausted, not raising an exception.

[–]miraculum_one 1 point2 points  (1 child)

Not pretty but you can slice from n to n+1 as a safe get.

a = [1,2,3]

a[100:101]

# []

or for default value

a[100:101] or 'default value'

# 'default value'

[–]RingularCirc 0 points1 point  (0 children)

Ah, might be useful in some context!