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

I have done similar thing to myself in Python, sabotaging my own little project. The following is not a rare thing. Imagine this were initializing random key in TLS... But since Python syntax is arguably cleaner and more readable, it's easier to catch. But that's a bet we have to put up with...

    >>> def f(a,b=[]):
    ...     b.append(a)
    ...     return b
    ...
    >>> print f(1)
    [1]
    >>> print f(1)
    [1, 1]
    >>> print f(1)
    [1, 1, 1]


    >>> import random
    >>> def key():
    ...     return random.randint(1,10000)
    ...

    >>> def f2(a, b=key):
    ...     return b()
    ...
    >>> def f3(a, b=key()):
    ....    return b
    >>> f2(1)
    3974
    >>> f2(1)
    8684
    >>> f3(1)
    2867
    >>> f3(1)
    2867


Well, any Python developer worth his salt knows that initializing default parameters that way is a big no-no. I actually use code with those exact mistakes in interviews, as it is a good way to tell Python beginners from more enlightened users.


It's easy to make mistakes, especially when the compiler/interpreter gives no assistance/warnings.


Pylint catches this, pylint categorizes this as a warning.

If your language has a lint tool and your code is remotely important, please run the lint tool as part of your build.


Correct

Unfortunately a lot of people still use it

(and it's actually correct, IF you don't modify it)

It's a risk not worth taking (to me, at least)


That's the only way of creating function with state without introducing closure or making an object with __call__. It's very handy for accumulators and other bits of state which are inherent to the function you write. It's essentially a `static` variable declared inside a function in C and believe it or not it has it's uses.

Depending on a problem it can be worthwhile to use other techniques of creating stateful callables, but that doesn't mean you should never create a function with mutable default argument. It's there in the language - learn about it, understand how it works and why it works like this, then understand where to use it and use it where it makes sense. That's a pretty generic advice, valid for almost any language feature.


> That's the only way of creating function with state without introducing closure or making an object with __call__

What about this?

  def foo():
      if not hasattr(foo, 'static_list'):
          foo.static_list = []
At least it's a bit easier to see that something funky is going on.


The "No True Scotsman" helps out for essentially every language though.


    > But since Python syntax is arguably cleaner
    > and more readable, it's easier to catch.
I've seen nasty bugs in Python code having to do with the end of blocks losing their indentation due to someone's merge/editor mistake.

Having braces or other explicit start/end markers for blocks would have prevented those issues. So Python's syntax can in some cases encourage these sorts of mistakes.


Yeah, that's an excellent point. I remember arguing with friends about this vs braces. Mis-indent error is also a hard-to-detect bug in general. Also, a joke from Python-dev:

>>> from __future__ import braces


Python with braces ... aka Javascript

And I'm actually being serious. I program in both quite regularly. The Python ecosystem is amazing, but the web defaults to Javascript.


The __future__ may not be far off: Python with Braces (http://www.pythonb.org/).


This certainly is an underdog. Not that many people, probably just me, haven't heard of this yet. Interesting!




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

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

Search: