Re: Curious function argument

2014-11-27 Thread Akira Li
ast nom...@invalid.com writes:

 Hello

 I saw in a code from a previous message in this forum
 a curious function argument.

 def test(x=[0]):
   print(x[0])   ## Poor man's object
   x[0] += 1

 test()
 0
 test()
 1
 test()
 2


 I understand that the author wants to implement a global
 variable x . It would be better to write 'global x' inside the
 function.

 At first test() function call, it prints 0, that's OK.
 But at the second call, since we dont pass any argument to test(),
 x should be equal to its default value [0] (a single item list). But
 it seems that Python keeps the original object whose content has
 been changed to 1.

 Is it a usual way to implement a global variable ?

It is not a global, a global would be easily available (visible) to
other functions. You can get it if you try but Python also allows you to
get private attributes, replace builtins and other things that you
should not normally do.

*# Poor man's object* in this context suggests that I'm the
author. The code is meant as a part of a short Python script that is
executed directly. Imagine the *test()* definition is put inside main()
function that is called when the script is run.

`def test(*, _x=[0]):..` attaches some state (_x list) to the function
*test*. It could be used as a way to emulate *nonlocal* keyword:

  def counter():
  count = 0
  def increment():
  nonlocal count
  count += 1
  return count
  return increment
  
  c = counter()
  print(c(), c()) # 0, 1
  c = counter()
  print(c(), c()) # 0, 1

an alternative is to create an object using class:

  class Counter:
  def __init__(self):
  self.count = 0
  def __call__(self):
  self.count += 1
  return self.count

  c = Counter()
  print(c(), c())
  
For this specific case, you could use `itertools.count`:

  c = itertools.count()
  print(next(c), next(c))

which could be implemented here as a generator:

  def count():
  count = 0
  while True:
 count += 1  
 yield count

  c = count()
  print(next(c), next(c))

Objects are data with methods attached, closures are functions with data
attached. [1]

Sometimes you need to define a class to create objects, in other cases a
function is enough (and of course functions are objects too in Python).

[1]
http://stackoverflow.com/questions/13857/can-you-explain-closures-as-they-relate-to-python


--
Akira


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Curious function argument

2014-11-15 Thread Steven D'Aprano
ast wrote:

 Hello
 
 I saw in a code from a previous message in this forum
 a curious function argument.
 
 def test(x=[0]):
print(x[0])   ## Poor man's object
x[0] += 1
 
 test()
 0
 test()
 1
 test()
 2
 
 
 I understand that the author wants to implement a global
 variable x . It would be better to write 'global x' inside the
 function.

No, it's not a global. A better description is that it is a way of faking
static storage for a function: the function test has a static variable x
which is independent of any other function's x, but it can remember its
value from one function call to another.


 At first test() function call, it prints 0, that's OK.
 But at the second call, since we dont pass any argument to test(),
 x should be equal to its default value [0] (a single item list). But
 it seems that Python keeps the original object whose content has
 been changed to 1.
 
 Is it a usual way to implement a global variable ?

No, it's unusual. If you actually want a global, use the global keyword.
Otherwise, there are often better ways to get a similar effect, such as
using a generator:

def gen():
x = 0
while True:
yield x
x += 1

it = gen()
next(it)  # returns 0
next(it)  # returns 1
next(it)  # returns 2

You can turn that into functional form like this:

import functools
func = functools.partial(next, gen())
func()  # returns 0
func()  # returns 1
func()  # returns 2



-- 
Steven

-- 
https://mail.python.org/mailman/listinfo/python-list


Curious function argument

2014-11-12 Thread ast

Hello

I saw in a code from a previous message in this forum
a curious function argument.

def test(x=[0]):
  print(x[0])   ## Poor man's object
  x[0] += 1


test()

0

test()

1

test()

2




I understand that the author wants to implement a global
variable x . It would be better to write 'global x' inside the
function.

At first test() function call, it prints 0, that's OK.
But at the second call, since we dont pass any argument to test(),
x should be equal to its default value [0] (a single item list). But
it seems that Python keeps the original object whose content has
been changed to 1.

Is it a usual way to implement a global variable ?

thx





--
https://mail.python.org/mailman/listinfo/python-list


Re: Curious function argument

2014-11-12 Thread Denis McMahon
On Wed, 12 Nov 2014 14:07:14 +0100, ast wrote:

[function def with mutable default parameter]

 I understand that the author wants to implement a global variable x . It
 would be better to write 'global x' inside the function.

It may not be the case that the purpose was to implement a global 
variable, but rather to illustrate what happens when you use a mutable 
default parameter.

 At first test() function call, it prints 0, that's OK.
 But at the second call, since we dont pass any argument to test(), x
 should be equal to its default value [0] (a single item list). But it
 seems that Python keeps the original object whose content has been
 changed to 1.

This is explained in the docs:

https://docs.python.org/3/reference/compound_stmts.html#function-
definitions

Default parameter values are evaluated from left to right *when the 
function definition is executed*[1]. This means that the expression is 
evaluated once, when the function is defined, and that the same “pre-
computed” value is used for each call. This is especially important to 
understand when a default parameter is a mutable object, such as a list 
or a dictionary: if the function modifies the object (e.g. by appending 
an item to a list), the default value is in effect modified.

[1] ie when the function is 'compiled', not each time it executes.

-- 
Denis McMahon, denismfmcma...@gmail.com
-- 
https://mail.python.org/mailman/listinfo/python-list