Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

python sucks because: default parameters are only evaluated once.


Yes, weirdly missing.

Also omitted:

  my_dict.get('existing_key', foo())
does not short-circuits foo(). That always felt like a bug to me.


Functions in most popular languages behave this way. `get` is just a method; its arguments will never be short-circuited. If you wanted short-circuiting, use the ternary operator:

  my_dict['existing_key'] if 'existing_key' in my_dict else foo()
You could also define a `get_lazy` method that does the above, taking a nullary function as its key and evaluating it if the key is missing. But then you would need to wrap your default values in a lambda, which would look absurd for the common use case of calling `get` with some constant default value. Seems unnecessary when the ternary operator works fine.


If I know my_dict doesn't hold values that that are false-like, e.g. 0 or [], I use `or` to lazily alternate between options. This works because in python, `or` returns the first value that has a truthy value. In this case it would be

    my_dict.get('existing_key') or foo()
This would also easily let you do multiple alternations (much more annoying with the ternary operator).


This is dangerous because sometimes you have legitimate values that are not truthy.

  print(player_data['score'] or 'does not exist')
This will print "does not exist" when the score is zero.


gp's approach works best when you know that the argument is a list or tuple (something which can be empty). Of course, due to python's lack of typing, you should only use that approach when the function is being used in well-understood contexts.


You can fix that/cheat around that by cleverly using a lambda as kwarg, I think... (Real hacky though)


The common-sense approach would be not to introduce such defaults.

  def foo(bazzes=None):
    _baz = bazzes or []
    ...


Then why doesn't the language prohibit having a default of anything mutable?


Python is generally terrible at providing immutable types and workflows. No such thing as a constant, class variables are mutable by default, no built-in immutable dictionary class, etc.

I use a linter to catch this sort of thing and subclass `collections.namedtuple(...)` whenever I need to at least try to abolish mutability. It's one of the worst things about the language.

[edit] You can argue that there would be use cases for mutable defaults, and as with any edge use case you'd be right in asserting its existence. Unfortunately, I can't think of any solution (typing, changing function argument evaluation rules, etc) that wouldn't fundamentally change the language and break just about every sizable python library in existence. This looseness is baked deep into the language as far as I can see.


- how does the language know a thing is (not) mutable?

- how does it know you're not doing that on purpose?


1) aren't there specific immutable pass-by-value forms in python? If you pass a default integer, for example, and change the value of that variable in the function body, the next call will respect the default parameter and not the mutated parameter.

2) good point.


The mutable default is sometimes useful as a quick way to memoize a function


I would argue that that is an edge case that should be done with decorators. The whole mutable default thing bites everyone at least once, and at best it just means more code to do the same thing.


This is the idiomatic way to add mutable defaults.




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

Search: