Re: bad recursion, still works

2008-07-15 Thread mdsherry
On Jul 15, 2:59 pm, iu2 <[EMAIL PROTECTED]> wrote:
> Hi,
>
> I wrote this wrong recursive function that flattens a list:
>
> def flatten(lst, acc=[]):
>     #print 'acc =', acc, 'lst =', lst
>     if type(lst) != list:
>         acc.append(lst)
>     else:
>         for item in lst:
>             flatten(item)
>     return acc
>
> a = [1, 2, [3, 4, 5], [6, [7, 8, [9, 10], 11], 12], 13, 14]
> b = flatten(a)
> print b
>
> I was amazed to realize that it flattens the list alright. Why? 'acc'
> should be an empty list on each invocation of flatten, but is seems to
> accumulate anyway...

When you say acc=[] in the function declaration, it binds acc to a
particular list object, rather than to a concept of an empty list.
Thus, all operations being performed on acc are being performed on the
same list. If, after the sample code you provided, were to call

c = flatten([15,16,17,[18,19]])
print c

you would get back the list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19].

Mark Sherry
--
http://mail.python.org/mailman/listinfo/python-list


Re: bad recursion, still works

2008-07-15 Thread mdsherry
On Jul 15, 4:12 pm, iu2 <[EMAIL PROTECTED]> wrote:
> On Jul 15, 9:30 pm, [EMAIL PROTECTED] wrote:
>
>
>
> > On Jul 15, 2:59 pm, iu2 <[EMAIL PROTECTED]> wrote:
>
> > > Hi,
>
> > > I wrote this wrong recursive function that flattens a list:
>
> > > def flatten(lst, acc=[]):
> > >     #print 'acc =', acc, 'lst =', lst
> > >     if type(lst) != list:
> > >         acc.append(lst)
> > >     else:
> > >         for item in lst:
> > >             flatten(item)
> > >     return acc
>
> > > a = [1, 2, [3, 4, 5], [6, [7, 8, [9, 10], 11], 12], 13, 14]
> > > b = flatten(a)
> > > print b
>
> > > I was amazed to realize that it flattens the list alright. Why? 'acc'
> > > should be an empty list on each invocation of flatten, but is seems to
> > > accumulate anyway...
>
> > When you say acc=[] in the function declaration, it binds acc to a
> > particular list object, rather than to a concept of an empty list.
> > Thus, all operations being performed on acc are being performed on the
> > same list. If, after the sample code you provided, were to call
>
> > c = flatten([15,16,17,[18,19]])
> > print c
>
> > you would get back the list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
> > 13, 14, 15, 16, 17, 18, 19].
>
> > Mark Sherry
>
> I still don't understand: In each recursive call to flatten, acc
> should be bound to a new [], shouldn't it? Why does the binding happen
> only on the first call to flatten?

Default values are bound when the function is defined, not when it's
called. For example,

>>> import random
>>> def foo(bar = random.random()):
... print bar
...
>>> foo()
0.632312549821312
>>> foo()
0.632312549821312

If you view [...] just as shorthand for list(...), it might make a bit
more sense. For immutable values, one can't change the value bound to
the name, only what the name is bound to, so this behaviour is less
obvious. But still there.

As to why default values are evaluated at define time vs. call time,
I'd argue reasons of scope and speed - if the default value is a
computed constant, it makes little sense to recompute it every time
the function is called.

Mark Sherry
--
http://mail.python.org/mailman/listinfo/python-list


Re: bad recursion, still works

2008-07-17 Thread mdsherry
On Jul 17, 8:27 am, Jeff <[EMAIL PROTECTED]> wrote:
> Thanks, that made things very clear.  I like that technique for adding
> memoization via the parameter.  That is clever.  It would be nice if
> there were a way to have multiple functions close over a shared local
> variable in Python, like let-binding in lisp.

Is this something like what you're looking for?

>>> def functionmaker():
... shared = []
... def addnumber():
... shared.append(3)
... return shared
... def addletter():
... shared.append('f')
... return shared
... return addnumber, addletter
...
>>> addnumber, addletter = functionmaker()
>>> addnumber()
[3]
>>> addletter()
[3, 'f']
--
http://mail.python.org/mailman/listinfo/python-list


Re: Making small executive file for distribution

2008-09-24 Thread mdsherry
On Sep 24, 9:17 am, Marin Brkic <[EMAIL PROTECTED]> wrote:
> Not commercial distribution, but an academic kind of sorts - giving
> the exe file to coleagues, so they can use it in their work. Giving
> .py file is not an option, since due to centralized computer
> maintenance, they don't (and cannot) have installed python (except the
> ones that bring their own computer at work, but those are an
> exception).
>
> As far as I know py2exe is the only option which can do such a thing
> (make exe files from scripts). Is there a way to make those exe files
> a little smaller (for a small script they easily go up to 5-10 mb).
>
> Has anyone had a situation like this ? All your inputs and suggestions
> are more then welcomed.
>
> --
> Marin

If you don't create a monolithic EXE, then most of the extra files
(that make up the bulk of the size) can be shared between other
converted scripts. That is, if you convert foo.py, and send the bundle
to your colleague, then convert bar.py, you only need to send bar.exe,
and it will run fine if they execute it in the same directory that has
all the DLLs you sent with foo.exe.

Another option might be to encourage them to download Portable Python,
which doesn't need to be installed.

Mark Sherry
--
http://mail.python.org/mailman/listinfo/python-list


Re: TypeError: can't pickle HASH objects?

2008-10-01 Thread mdsherry
On Oct 1, 3:50 pm, est <[EMAIL PROTECTED]> wrote:
> >>> import md5
> >>> a=md5.md5()
> >>> import pickle
> >>> pickle.dumps(a)
>
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "C:\Python25\lib\pickle.py", line 1366, in dumps
>     Pickler(file, protocol).dump(obj)
>   File "C:\Python25\lib\pickle.py", line 224, in dump
>     self.save(obj)
>   File "C:\Python25\lib\pickle.py", line 306, in save
>     rv = reduce(self.proto)
>   File "C:\Python25\lib\copy_reg.py", line 69, in _reduce_ex
>     raise TypeError, "can't pickle %s objects" % base.__name__
> TypeError: can't pickle HASH objects
>
> Why can't I pickle a md5 object? Is it because md5 algorithm needs to
> read 512-bits at a time?
>
> I need to md5() some stream, pause(python.exe quits), and resume
> later.  It seems that the md5 and hashlib in  std module could not be
> serialized?
>
> Do I have to implement md5 algorithm again for this special occasion?
>
> Or is there anyway to assige a digest when creating md5 objects?

I'm sure some of the regulars can correct me if I'm wrong, but looking
at the source code, it seems that this is the error that you'll see if
the object doesn't explicitly support pickling, or possibly isn't
composed of objects that do.

Examining the md5 and hashlib source files, it seems that they rely on
C implementations, and so have internal states opaque to Python. If
you feel confident, you could write your own MD5 class that would have
methods to dump and restore state, but I think you're out of luck when
it comes to the official module.

Mark Sherry
--
http://mail.python.org/mailman/listinfo/python-list