News for hackers. Stuff that matters.
Re:Anti-Patterns in Python Programming by jcampbell1 on Wednesday July 09, 2014 @10:26AM (#8009760)
Can you clarify?

    def foo(default_arg = []):
Why can't that just be shorthand for:

    def foo(default_arg = ParamNone):
        if default_arg == ParamNone:
            default_arg = []
How would that break first class functions?
Re:Anti-Patterns in Python Programming by dalke on Wednesday July 09, 2014 @11:08AM (#8010006)
As a minor point, use "default_arg is ParamNone", since "==" probably won't do the right thing.

What breaks is something like:

  def foo(default_arg = slow_f()):
    pass
Under the shorthand gets turned into:

  ParamNone = object()

  def foo(default_arg = ParamNone):
    if default_arg is ParamNone:
        default_arg = slow_f()
    pass
This is fine, since everyone would know that the shorthand means to not put slow code there. Instead, people will start writing it as:

  _foo_arg = slow_f()
  def foo(default_arg = _foo_arg):
    pass
Of course, then what happens with:

  _foo_arg = slow_f()
  def foo(default_arg = _foo_arg):
    _foo_arg = 5
? Under expansion it becomes:

  _foo_arg = slow_f()
  def foo(default_arg = ParamNone):
    if default_arg is ParamNone:
        default_arg = _foo_arg
    _foo_arg.add(5)
This violates Python's scoping rules, because _foo_arg is now being used in local scope instead of global scope. Eg:

  >>> def f(x=None):
  ...   if x is None:
  ...     x = spam
  ...   spam = 3
  ... 
  >>> spam = 9
  >>> 
  >>> f()
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 3, in f
  UnboundLocalError: local variable 'spam' referenced before assignment
Which means you now need a new scoping rule, just to handle default parameters without making things more confusing.

It also turns what was a simple O(1) offset into a precomputed list into a globals() lookup for many cases.

Re:Anti-Patterns in Python Programming by syllogism on Wednesday July 09, 2014 @05:08PM (#8012247)
In Python 3 there's the nonlocal keyword to deal with the scoping thing.

The default arguments thing is worse than a lot of the stuff Python 3 corrected.

Re:Anti-Patterns in Python Programming by dalke on Wednesday July 09, 2014 @10:54PM (#8013337)
I don't see how nonlocal could fix this. Could you explain?

More specifically, given a better 'default arguments thing', how would you interpret:

    x = [2]
    def f(x=x*5):
        x.append(4)
With the earlier conversion it's:

    x = [2]
    def f(x=DefaultArg):
        if x is DefaultArg:
            x = x*5
        x.append(4)
This isn't going to work because the x inside of f() is different than the outside x, and you'll get the error message I mentioned.

If you add a nonlocal, as in:

    x = [2]
    def f(x=DefaultArg):
        nonlocal x
        if x is DefaultArg:
            x = x*5
        x.append(4)
then you'll get "SyntaxError: name 'x' is parameter and nonlocal".

What other solution are you thinking of?

Re:Anti-Patterns in Python Programming by syllogism on Friday July 11, 2014 @03:44PM (#8022012)
Ah I see. Yeah nonlocal can't fix that.
Re:Anti-Patterns in Python Programming by ollysb on Thursday July 10, 2014 @10:37AM (#8015093)
Why not just memoize the result of the slow function?
Re:Anti-Patterns in Python Programming by dalke on Thursday July 10, 2014 @12:28PM (#8015535)
I think by your use of "just memoize" that I didn't explain myself well enough. I don't mean to focus on the slow aspect, nor even the function aspect. It could be

   def foo(default_arg = [0]*(256*256)):
     ...
and still get the same namespace issues.

Memoization is not always going to be an available solution. For example, it may be that slow_f() returns a stateless object, so can be reused, while slow_f(x) returns something stateful. You can think of my examples as either using default arguments as a single element memo, or using a module variable for the same. Both premised on the idea that the developer knows enough to make the right decision.

Re:Anti-Patterns in Python Programming by bkeroack on Wednesday July 09, 2014 @10:46AM (#8009862)
How would the above work for duck-typed lists, for example? How would the language "know" which types are mutable?