Logging oddity: handlers mandatory in every single logger?

2010-02-01 Thread Masklinn
When trying to load the following config file, I get an error 
``ConfigParser.NoOptionError: No option 'handlers' in section: 'logger_0'`` (in 
both Python 2.6.4 and  Python 3.1.1 on OSX, obviously ConfigParser is spelled 
configparser in 3.1):

[loggers]
keys=root,0
[handlers]
keys=console
[formatters]
keys=simple
[logger_root]
handlers=console
[logger_0]
level=DEBUG
qualname=0
[handler_console]
class=StreamHandler
formatter=simple
args=()
[formatter_simple]
format=%(asctime)s:%(levelname)-8s:%(name)s::%(message)s

the goal is simply to have a logging level different on ``0`` than it is on 
``root``, but to get it I have to include a handler on ``0`` and stop 
propagation (or messages are displayed on both root and 0).

Do note that this behavior (of mandating handlers) does *not* happen when 
loggers are configured programmatically.

Should this be considered a bug? Worthy of opening a request on the tracker?

And while I'm at it, a few other oddities/annoyances I noticed in logging:

* have to specify the `root` logger in loggers/keys, even though it's mandatory 
to configure the root logger, or I get the following error::

Traceback (most recent call last):
  File "test.py", line 6, in 
logging.config.fileConfig('logging.conf')
  File 
"/opt/local/Library/Frameworks/Python.framework/Versions/3.1/lib/python3.1/logging/config.py",
 line 82, in fileConfig
_install_loggers(cp, handlers, disable_existing_loggers)
  File 
"/opt/local/Library/Frameworks/Python.framework/Versions/3.1/lib/python3.1/logging/config.py",
 line 183, in _install_loggers
llist.remove("root")
ValueError: list.remove(x): x not in list

* the ``args`` option is required when defining a handler, even in the example 
above where the handler doesn't take any argument (mandatory ones, anyway)

* Logger.log() doesn't take level names, only numerical levels, even after 
having called ``addLevelName``. This makes logging with custom levels much less 
clear as one has to write something along the lines of ``logging.log(100, 
'Houston, we have a problem')`` instead of the clearer 
``logging.log('PANTS_ON_FIRE', 'Houston, we have a problem')``. Note that since 
the introduction of _checkLevel fixing that is trivial:

diff -r dafc54104884 Lib/logging/__init__.py
--- a/Lib/logging/__init__.py   Sun Jan 31 14:17:25 2010 +0100
+++ b/Lib/logging/__init__.py   Mon Feb 01 22:21:03 2010 +0100
@@ -1146,13 +1146,14 @@
 
 logger.log(level, "We have a %s", "mysterious problem", exc_info=1)
 """
-if not isinstance(level, int):
+try:
+rv = _checkLevel(level)
+except (TypeError, ValueError):
 if raiseExceptions:
-raise TypeError("level must be an integer")
-else:
-return
-if self.isEnabledFor(level):
-self._log(level, msg, args, **kwargs)
+raise
+
+if self.isEnabledFor(rv):
+self._log(rv, msg, args, **kwargs)
 
 def findCaller(self):
 """

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


Re: Logging oddity: handlers mandatory in every single logger?

2010-02-02 Thread Masklinn
Jean-Michel Pichavant wrote:
>To add a custom level, I would proceed that way:
>
>logging.ALERT = 45
>logging.addLevelName(logging.ALERT, 'ALERT !!')
>logging.getLogger().log(logging.ALERT, 'test')
>
>Passing a string to the log method as you did is incorrect.

I know it's currently incorrect. My point was more along the line that there 
was *no reason* for it to be incorrect. logging already contains all the tools 
for log('PANTS_ON_FIRE') to be allowed

>Regarding your first point, I guess it's anti pattern. One way to do it:
>1/ Configure the root logger with the lowest value 0, so the root logger 
>does not filter any level.
>2/ Configure each of your logger with the correct level
>
>That way you can configure your '0' logger as you (badly :o)) named it 
>with one level, and configure a potential '1' logger with another level. 
>Don't bother with propagation. That way you won't need to duplicate your 
>handlers on every logger.

re logger 0, no need for complex name for a test case (and it allowed me to 
create easy-to-remember 0.1 and 0.1.2 if needed)

Re your answer, from what I understand you want the root logger to NOTSET and 
then each child logger with its correct level? But that's not a solution, each 
and every level will *still* require a handler explicitly configured on it. 
That's in fact very much my issue: logging refuses that a logger be 
handler-less in a config file, it's mandatory to configure a handler any time a 
logger is configured.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Logging oddity: handlers mandatory in every single logger?

2010-02-03 Thread Masklinn
On 2 Feb 2010, at 17:52 , Jean-Michel Pichavant wrote:
> 
> Masklinn wrote:
>> Jean-Michel Pichavant wrote:
>>  
>>> To add a custom level, I would proceed that way:
>>> 
>>> logging.ALERT = 45
>>> logging.addLevelName(logging.ALERT, 'ALERT !!')
>>> logging.getLogger().log(logging.ALERT, 'test')
>>> 
>>> Passing a string to the log method as you did is incorrect.
>>>
>> 
>> I know it's currently incorrect. My point was more along the line that there 
>> was *no reason* for it to be incorrect. logging already contains all the 
>> tools for log('PANTS_ON_FIRE') to be allowed
>>  
> The reason is that log takes an *int* as first argument that defines the 
> logging level. You gave a string. So There is definitely a reason for it to 
> be incorrect.
That's not a reason, that's just what currently happens. I know it doesn't 
work, and I know why, I went and checked the code. But there's no fundamental 
reason why you couldn't use a level *name* instead of a level code. And indeed, 
in most parts of logging you can (including but not limited to the 
configuration of handlers and loggers)

>>  
>>> Regarding your first point, I guess it's anti pattern. One way to do it:
>>> 1/ Configure the root logger with the lowest value 0, so the root logger 
>>> does not filter any level.
>>> 2/ Configure each of your logger with the correct level
>>> 
>>> That way you can configure your '0' logger as you (badly :o)) named it with 
>>> one level, and configure a potential '1' logger with another level. Don't 
>>> bother with propagation. That way you won't need to duplicate your handlers 
>>> on every logger.
>>>
>> 
>> re logger 0, no need for complex name for a test case (and it allowed me to 
>> create easy-to-remember 0.1 and 0.1.2 if needed)
>> 
>> Re your answer, from what I understand you want the root logger to NOTSET 
>> and then each child logger with its correct level? But that's not a 
>> solution, each and every level will *still* require a handler explicitly 
>> configured on it. That's in fact very much my issue: logging refuses that a 
>> logger be handler-less in a config file, it's mandatory to configure a 
>> handler any time a logger is configured.
>>  
> the field handlers must be defined even if empty.
Ah, interesting, I didn't think it could be defined as empty.

Which makes the requirement to have an empty ``handler`` completely 
nonsensical, doesn't it?

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


Re: Logging oddity: handlers mandatory in every single logger?

2010-02-03 Thread Masklinn
On 3 Feb 2010, at 11:50 , Jean-Michel Pichavant wrote:
> 
> 
>>> The reason is that log takes an *int* as first argument that defines the 
>>> logging level. You gave a string. So There is definitely a reason for it to 
>>> be incorrect.
>>>
>> That's not a reason, that's just what currently happens. I know it doesn't 
>> work, and I know why, I went and checked the code. But there's no 
>> fundamental reason why you couldn't use a level *name* instead of a level 
>> code. And indeed, in most parts of logging you can (including but not 
>> limited to the configuration of handlers and loggers)
>> 
> You don't neeed to check the code for that ! It is written in the 
> documentation. The logging module designer choose to ask for a level, not a 
> level name, possibly because 2 different levels can have the same name.
> 
Nope, 2 different levels cannot have the same name: levels are currently stored 
in a dict of string:level and level:string, so you can't have 2 names for the 
same level, and you can't have 2 levels with the same name either.

>>> 
>>> the field handlers must be defined even if empty.
>>>
>> Ah, interesting, I didn't think it could be defined as empty.
>> 
>> Which makes the requirement to have an empty ``handler`` completely 
>> nonsensical, doesn't it?
> 'completeley nonsensical' is overstating.  It make sense to state that your 
> handler list is empty, when it is empty.
Programmatically, that's implied in the fact that you aren't specifying it. Why 
wouldn't it be in the config file? Why the asymetry here?

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


Re: beautiful soup

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 09:30 , Diez B. Roggisch wrote:

xubin.cz schrieb:

hi, everyone
Is there any pakage or module handling html document like beautiful
soup?


why don't you *use* beautiful soup? It is a module...
Or lxml, which works a bit better than BF 3.1 (post parser change)  
nowadays.

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


Re: Confessions of a Python fanboy

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 06:04 , alex23 wrote:

On Jul 30, 1:06 pm, r  wrote:

1.) No need to use "()" to call a function with no arguments.
Python --> "obj.m2().m3()" --ugly
  Ruby --> "obj.m1.m2.m3"  -- sweeet!
Man, i must admit i really like this, and your code will look so much
cleaner.


How do you distinguish between calling a method with no arguments, and
getting access to the method object itself (because it _is_ an object,
y'know, it's OO all the way down...)?

As chris pointed out, there's a method for that, to which a symbol is  
provided: `Object#method(methodname)`, which is basically equivalent  
to `getattr(object, methodname)` in Python.



2.) the .each method
container.each{|localVar| block}
This method can really cleanup some ugly for loops, although i really
like the readability of for loops.


map(lambda localVar: , sequence)

or:

def usefully_named_func(var):
   
   return var

transformed = [usefully_named_func(v) for v in sequence]

The issue here is of course that `map` and comprehensions are  
transformations. `#each` exists for effectful iterations (Ruby has  
`#map` for the map operation). So the intent expressed by `#each` and  
`map` isn't the same. Furthermore and this is the most problematic  
limitation of Python here, `lambda` doesn't allow complex  
transformations due to its restrictions, so one has to switch to named  
functions which works but isn't sexy (and tends to lower readability  
imo).



3.) true OOP
Now before you go and get all "huffy" over this statement, hear me
out. Python is the best language in the world. But it damn sure has
some warts! "len(this)" instead of "obj.length" max(that) instead of
[1,2,3,4,5].max().


As the Zen says: '[P]racticality beats purity'. Personally, I'm not
sure how a handful of convenient built-in functions make a language in
which _everything is an object_ somehow "false" OO.

That's an interesting point, but not relevant at the end of the day:  
`foo.length` and `length(foo)` have the same "practicality". On the  
other hand Ruby can be praised for the coherence: everything's a  
method period end of the story; while Python does have a dichotomy  
between methods and functions/generic methods (whether or not that  
dichotomy bothers users is another issue).



With max(), this is a built-in that takes _any_ iterable and an
optional key function, and returns the highest value as per the key.
This means that _every_ iterable object - as _well_ as every object
that supports enough of the iterator protocol - can be handed to max()
and a result obtained. So at best, I just need to make sure my new
sequence-type provides the iterator protocol and viola, it works with
max() without me having to hand-code a .max() that's specialised for
my new type, and without Python forcing me to have a complex
inheritance chain just to make sure I include the right
MaxableSequence ancestor to inherit the right .max().

Well interestingly, Ruby works pretty much the same way. Where Python  
asks that you implement the iterator protocol to have `max` work, Ruby  
asks that you implement the `each` method (also called the Enumerable  
protocol) and mixin `Enumerable` (http://ruby-doc.org/core/classes/Enumerable.html 
). Then you get max (and min, map, etc…) "for free". Of course you're  
free to re-implement all of them manually if you wish to do so (or if  
you need those operations to return your custom collection rather than  
arrays). Enumerable is merely a convenience mixin. So there's no big  
difference here (and note that mixins aren't necessarily part of the  
inheritance chain, though they're implemented that way in Ruby).


Also, it's "voilà" not "viola" (a viola is a bowed string instrument,  
slightly bigger than a violin, whereas voilà is a french interjection  
used to call attention or suggest the appearance of something, as if  
by magic).



PS stay tuned for more from this series


Is this going to be more of you telling us - without any apparent
irony whatsoever - how Ruby has some valid points after all your
vilification last year when we said the same to you?  If so, where can
I sign up?!

I fear I'll have to agree with that sentiment.
--
http://mail.python.org/mailman/listinfo/python-list


Re: Confessions of a Python fanboy

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 14:03 , superpollo wrote:

Masklinn wrote:
...
That's an interesting point, but not relevant at the end of the  
day:  `foo.length` and `length(foo)` have the same "practicality".  
On the other hand Ruby can be praised for the coherence:  
everything's a  method period end of the story; while Python does  
have a dichotomy  between methods and functions/generic methods  
(whether or not that  dichotomy bothers users is another issue).

...
how would you correct a newbie (like me) who says:

"well, the main difference between a function and a method (from the  
caller's pow) is a syntactic one:


fun(obj, arguments)

as opposed to:

obj.met(arguments)

but the effect is just about the same."

?
Depending on the way things are implemented, it can be very similar  
(see CLOS' generic functions, which have the same look as functions  
but dispatch based on parameter types).


In Python, the difference would be that functions don't automatically  
dispatch (you have a function for everybody, and any dispatch you  
perform based on argument types or other qualifiers has to be done  
manually) whereas methods do dispatch on the first [implied] argument  
(you execute a precise method corresponding to the object it's being  
called on).


So fun(obj, *arguments) will call the same `fun` whether `obj` is an  
int, a string or an HTTPFactory whereas obj.met(*arguments) will call  
a different `met` each time (they all have the same "unqualified" name  
[and signature if it's part of a protocol], but might very well be  
implemented completely differently). Therefore -- in python -- the  
effect isn't anywhere "just about the same".


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


Re: Confessions of a Python fanboy

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 18:31 , Falcolas wrote:

On Jul 29, 9:06 pm, r  wrote:


1.) No need to use "()" to call a function with no arguments.
Python --> "obj.m2().m3()" --ugly
  Ruby --> "obj.m1.m2.m3"  -- sweeet!
Man, i must admit i really like this, and your code will look so much
cleaner.


I personally would not prefer this, and would likely continue to use
(), precisely for code clarity - let me explain:

foo.nextval
foo.val
foo.previousval

Which of the calls above referenced instance variables
Well, that's very simple: none of them. In Ruby (as in Smalltalk),  
public instance variables simply don't exist.


and which ones called functions which changed the internal state of  
foo?
That you can't say, but neither can you say in Python as they could  
all be properties. And of course just because it's a method doesn't  
mean it mutates the object.



I would have
trouble saying, just based on the calls above. I would have to go back
to the definition or documentation of foo to identify which is doing
what. On the other hand, the following gives a better clue as to what
is happening (granted not perfect, but better):

Well... it doesn't give much of a clue no really.
--
http://mail.python.org/mailman/listinfo/python-list


Re: Confessions of a Python fanboy

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 19:01 , Inky 788 wrote:

On Jul 30, 12:04 am, alex23  wrote:

On Jul 30, 1:06 pm, r  wrote:


1.) No need to use "()" to call a function with no arguments.
Python --> "obj.m2().m3()" --ugly
  Ruby --> "obj.m1.m2.m3"  -- sweeet!
Man, i must admit i really like this, and your code will look so  
much

cleaner.


How do you distinguish between calling a method with no arguments,  
and
getting access to the method object itself (because it _is_ an  
object,

y'know, it's OO all the way down...)?


I agree with alex here. Will take the explicit syntax over the extra
cognitive load of figuring out exactly what's going on with
`obj.m1.m2.m3`.
There's no cognitive load whatsoever: it's calling methods. Always.  
Ruby simply gives you no other option. Now it could be very simple  
methods to instance attributes, akin to a java getter, but it's still  
only methods.


Furthermore Ruby has a pretty nice convention (sadly not used enough I  
think) taken from Scheme where it's possible to postfix a method name  
with "!" (note: the "!" is part of the name, there's no magic) to  
indicate that this method modifies the object it's called on rather  
than simply returning stuff.


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


Re: Confessions of a Python fanboy

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 19:37 , Jean-Michel Pichavant wrote:

r wrote:

On Jul 30, 11:31 am, Falcolas  wrote:


On Jul 29, 9:06 pm, r  wrote:



1.) No need to use "()" to call a function with no arguments.
Python --> "obj.m2().m3()" --ugly
 Ruby --> "obj.m1.m2.m3"  -- sweeet!
Man, i must admit i really like this, and your code will look so  
much

cleaner.


I personally would not prefer this, and would likely continue to use
(), precisely for code clarity - let me explain:

foo.nextval
foo.val
foo.previousval

Which of the calls above referenced instance variables, and which  
ones
called functions which changed the internal state of foo? I would  
have
trouble saying, just based on the calls above. I would have to go  
back

to the definition or documentation of foo to identify which is doing
what. On the other hand, the following gives a better clue as to  
what

is happening (granted not perfect, but better):

foo.nextval()
foo.val
foo.previousval()

~G



I held your exact same view before i learned the Ruby language. And
your veiw makes some good points, however, naming conventions with
eliminate this problem all together. All "method names" should use  
the

underscore to separate words, "variable names" should use camelCase,
"constants" in all caps, and "class defs" in titlecase.

def go_and_do_this_for_me_now(self, *args)
self.variableNameHere
MyClassNameHere
THISISACONSTANT -or- THIS_IS_A_CONSTANT


in your example i would have used the following

foo.next_value
foo.value
foo.prev_value

good naming conventions will make your life (and everybody else's)
much easier when debugging code.

How do I know if foo.value is an attribute or if it is a method that  
returns the foo value ?
It cannot be an attribute. Ruby doesn't give access to attributes,  
they're always solely private (as in Smalltalk). Also you shouldn't  
reply to r, he has no idea about what he's talking about.


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


Re: Confessions of a Python fanboy

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 19:42 , Carsten Haese wrote:

r wrote:

Of course in python you would do...
 vector.reverse --> in-place
 vector.reversed --> in-place


You do know that only one of those works in-place, right?

Well mostly because the other one doesn't exist (as python has  
`lst.reverse()` but `reversed(lst)`) but he was probably talking  
hypothetically. Or something.

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


Re: Confessions of a Python fanboy

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 20:05 , superpollo wrote:

r wrote:

On Jul 30, 12:15 pm, Masklinn  wrote:
[snip]
Furthermore Ruby has a pretty nice convention (sadly not used  
enough I  think) taken from Scheme where it's possible to postfix  
a method name  with "!" (note: the "!" is part of the name,  
there's no magic) to  indicate that this method modifies the  
object it's called on rather  than simply returning stuff.
Another oddity i did not like at first but must admit is growing on  
me

 vector.reverse --> returns a new reversed vector
 vector.reverse! --> modifies the instance vector in-place
Of course in python you would do...
 vector.reverse --> in-place
 vector.reversed --> in-place


how to reverse a string in python? must i usa a temp? like:

>>> s = "ciccio"
>>> l = list(s)
>>> l.reverse()
>>> s = "".join(l)
>>> s
'oiccic'
>>>

???

bye


s = s[::-1]
--
http://mail.python.org/mailman/listinfo/python-list


Re: Confessions of a Python fanboy

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 20:06 , Falcolas wrote:

On Jul 30, 11:56 am, Masklinn  wrote:

On 30 Jul 2009, at 19:37 , Jean-Michel Pichavant wrote:


r wrote:



How do I know if foo.value is an attribute or if it is a method that
returns the foo value ?


It cannot be an attribute. Ruby doesn't give access to attributes,
they're always solely private (as in Smalltalk). Also you shouldn't
reply to r, he has no idea about what he's talking about.


That doesn't sound like a feature I would appreciate much, though I am
a big fan of "we're all adults here" programming. Though if they are
all functions, then adding parentheses wouldn't make much difference,
so offering the option of getting rid of them makes sense.


That's pretty much it.


I would have
trouble saying, just based on the calls above. I would have to go  
back

to the definition or documentation of foo to identify which is doing
what. On the other hand, the following gives a better clue as to  
what

is happening (granted not perfect, but better):



Well... it doesn't give much of a clue no really.


It, with few exceptions, tells me that fetching the value foo.val will
not modify the state of foo. Important stuff, at least to me.
But because of those few exceptions, it really tells you that foo.val  
*probably* doesn't modify the state of foo. Unless you go source- 
diving, you can't know for sure. Only Haskell gives you that kind of  
guarantees (and even then, the code you call could have an unsafe*  
somewhere)

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


Re: Confessions of a Python fanboy

2009-07-30 Thread Masklinn

On 30 Jul 2009, at 22:23 , Jan Kaliszewski wrote:

30-07-2009 o 13:36:49 Masklinn  wrote:


On 30 Jul 2009, at 06:04 , alex23 wrote:

On Jul 30, 1:06 pm, r  wrote:

2.) the .each method
container.each{|localVar| block}
This method can really cleanup some ugly for loops, although i  
really

like the readability of for loops.


map(lambda localVar: , sequence)

or:

def usefully_named_func(var):
  
  return var

transformed = [usefully_named_func(v) for v in sequence]

The issue here is of course that `map` and comprehensions are  
transformations. `#each` exists for effectful iterations (Ruby has  
`#map` for the map operation). So the intent expressed by `#each`  
and `map` isn't the same. Furthermore and this is the most  
problematic limitation of Python here, `lambda` doesn't allow  
complex transformations due to its restrictions, so one has to  
switch to named functions which works but isn't sexy (and tends to  
lower readability imo).


I don't see any real limitation. What's wrong in:

for localVar in container:
   block

Well what's wrong with using that rather than `map`, `filter` or a  
list comprehension? (and if you don't see what the limitations of  
`lambda` are, you probably very rarely use it)



And ruby's container.each is very similar to Python's iter()


Uh… not at all…

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


Re: Confessions of a Python fanboy

2009-07-31 Thread Masklinn

On 30 Jul 2009, at 23:52 , Jan Kaliszewski wrote:
Dnia 30-07-2009 o 22:41:57 Masklinn   
napisał(a):

On 30 Jul 2009, at 22:23 , Jan Kaliszewski wrote:

30-07-2009 o 13:36:49 Masklinn  wrote:

On 30 Jul 2009, at 06:04 , alex23 wrote:

On Jul 30, 1:06 pm, r  wrote:

2.) the .each method
container.each{|localVar| block}
This method can really cleanup some ugly for loops, although i  
really

like the readability of for loops.


map(lambda localVar: , sequence)

or:

def usefully_named_func(var):
 
 return var

transformed = [usefully_named_func(v) for v in sequence]

The issue here is of course that `map` and comprehensions are  
transformations. `#each` exists for effectful iterations (Ruby  
has `#map` for the map operation). So the intent expressed by  
`#each` and `map` isn't the same. Furthermore and this is the  
most problematic limitation of Python here, `lambda` doesn't  
allow complex transformations due to its restrictions, so one has  
to switch to named functions which works but isn't sexy (and  
tends to lower readability imo).


I don't see any real limitation. What's wrong in:

for localVar in container:
  block

Well what's wrong with using that rather than `map`, `filter` or a  
list comprehension? (and if you don't see what the limitations of  
`lambda` are, you probably very rarely use it)


I know well about the expression-only-limitation of lambda, fortnately
there is the 'for' loop construct (or, alternatively, you can define
a named function).

And then, what's wrong with using 'for' rather than 'map', 'filter'  
etc.?

Nothing, but then again nothing's wrong using C's for either.

But I do think that using higher-order functions:
* tends to be terser while not going overly terse, it only removes  
boilerplate
* is more composable (it's pretty easy to tack another transformer in  
your chain, the same way defining iterator/generator transformers and  
chaining them is simpler than doing the same thing using explicit  
`for…in`)
* it clearly spells the intent of the programmer, while `for` can be  
anything and everything, and one has to dive into the code to know  
even the high-level operations performed (is it a basic  
transformation? A filtering or partitioning? A reduction? An  
application of side effects?)

Agree, that 'anonymous block syntax' would be nice in some cases, but
I don't see any real limitation caused by lack of it i.e. something  
you

can't (all you can only with unreasonable effort).

There are no limitations, but once again there never are. There are no  
actual limitations to using conditional jumps over iterators either.



And ruby's container.each is very similar to Python's iter()



Uh… not at all…


OK, .each is like Python's iter() + some form of iterating over it
('for' loop or '[i]map'...).
Well of course Enumerable#each is similar to map/imap, it's the same  
core principle.

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


Re: Confessions of a Python fanboy

2009-07-31 Thread Masklinn

On 30 Jul 2009, at 23:57 , Luis Zarrabeitia wrote:
I'd like to ask, what "container.each" is, exactly? It looks like a  
function
call (as I've learned a few posts ago), but, what are its arguments?  
How the
looping "works"? Does it receive a "code" object that it has to  
execute?
Is .each some kind of magic keyword? (This has little to do with  
python or

the current thread, so feel free to reply off-list if you want to...)


#each is simply a method that takes a function (called blocks in  
ruby). One could call it a higher-order method I guess.


It's an implementation of the concept of internal iteration: instead  
of collections yielding iterator objects, and programmers using those  
through specially-built iteration constructs (e.g. `for…in`),  
collections control iteration over themselves (the iteration is  
performed "inside" the collection, thus the "internal" part) and the  
programmer provides the operations to perform at each iterative step  
through (usually) a function.


In Python (assuming we had anonymous defs and an each method on  
lists), the following loop:


for item in some_list:
do_something(item)
do_something_else(item)

some_list.each((def (item):
do_something(item)
do_something_else(item)
))

There's absolutely nothing magic there, it's simply using anonymous  
functions and method calls (SmallTalk initiated this approach in the  
70s, and actually went much, much further than Ruby as it did away not  
only with `for…in` but also with `if…else` and `while` and a bunch of  
other stuff).


Now as IV pointed out, #each isn't the most interesting usage of  
blocks/anonymous functions (though I do like it, because it gets rid  
of no less than two keywords… even if Ruby reintroduced them as  
syntactic sugar), higher-order functions (functions which act on other  
functions) are (among other things) ways to create new control  
structures without having to extend the core language (so are lisp- 
style macros, by the way).


Of course Python does have higher-order functions (functions are first- 
class objects, so it's possible and frequent to have functions act on  
other functions), but since Python doesn't have anonymous functions  
that usage tends to be a bit too verbose beyond simple cases (also, of  
course, this kind of usages is neither in the "genes" nor in the  
stdlib).


In closing, IV has an example of how blocks make `with` unnecessary in  
Ruby (the functionality can be implemented at the library level rather  
than the language one). Generally, anonymous functions in OO languages  
are a way to inject behavior into third-party methods/objects. Kind-of  
a first-class Visitor support.


-m

PS: there's actually a bit of syntactic magic in Ruby's blocks, and  
it's one of the things I hate in the language, but it's not relevant  
to the role of blocks, and unnecessary to it: SmallTalk has no magical  
syntax).

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


Re: Confessions of a Python fanboy

2009-07-31 Thread Masklinn

On 31 Jul 2009, at 10:25 , Chris Rebert wrote:
On Fri, Jul 31, 2009 at 1:21 AM, Xavier Ho  
wrote:
On Fri, Jul 31, 2009 at 6:08 PM, Masklinn   
wrote:


... but since Python doesn't have anonymous functions that  
usage

tends to be a bit too verbose ... 


Sorry to interrupt, but wouldn't lambda in Python be considered as
'anonymous functions'?


I believe "full" anonymous functions was intended by the author.
lambdas are limited to a single expression.
Yes, and they're limited to a single *expression*, so before Python 3,  
lambda: print "foo" is out. Likewise, it isn't possible to have an if/ 
else statement within a lambda (though a ternary is ok), or a with, …  
since Python statements aren't expressions.

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


Re: Confessions of a Python fanboy

2009-07-31 Thread Masklinn

On 31 Jul 2009, at 11:54 , Iain King wrote:

On Jul 31, 8:28 am, Steven D'Aprano  wrote:

On Thu, 30 Jul 2009 18:06:31 -0500, Robert Kern wrote:

On 2009-07-30 16:44, r wrote:
On Jul 30, 4:29 pm, Emmanuel Surleau  
wrote:
1.) No need to use "()" to call a function with no arguments.  
Python

-->  "obj.m2().m3()" --ugly
   Ruby -->  "obj.m1.m2.m3"  -- sweeet!
Man, i must admit i really like this, and your code will look  
so much

cleaner.
It has benefits - code does look better. It has also significant  
cons

- it is ambiguous.
For instance:



a = b



Is b a variable or a method called without parameter?



Hello Emanuel,
Again, who so ever names a method with such a non-descriptive  
name will

get whats coming to him. And if you did for some reason use such a
cryptic name as "b", do yourself (and everyone else) a favor and  
follow

it with "()" to denote the method call. Remember when something is
optional that means you have an option to use it OR not use it.


I believe his point is that it is ambiguous to the compiler, not  
humans
reading the code. Python functions and methods are first class  
objects.
They can be passed around. If they were auto-called, then you  
could not

do this.


Oh my, "r" is still around is he??? And now he's singing the  
praises of
Ruby, the language which he treated as the Devil's Spawn when he  
first

arrived. That's hilarious.

But back on topic... "r" has missed the point. It's not that a=b is  
hard

to understand because b is a poor name. The example could have been:

def factory_function():
magic = time.time()  # or whatever
def inner():
return magic
return inner

my_function = factory_function

It's still ambiguous. Does the programmer intend my_function to  
become

factory_function itself, or the output of factory_function?


Not only that - does 'return inner' return the function inner or the
result of function inner?

How does ruby pass a function as an object?
Ruby doesn't have functions as such. It has methods and blocks (which  
would be anonymous functions). `def` always creates methods.


To get a (bound) method object, you simply call `method` on an  
instance e.g. `foo.method(:bar)` is equivalent to `foo.bar` in Python  
(it returns a bound method object without calling it).


Blocks are usually created as part of the calls: `foo.bar  
{do_something}` the part between braces (braces included) is a block,  
which will be passed to the method `bar`. Sadly, Ruby's blocks are  
magical syntax (doesn't mean they have to be, in Smalltalk there's  
nothing magical about blocks for instance) so you can't just do `foo =  
{do_something}`, you have to turn them into `Proc` objects with the  
`proc` constructor (or `lambda`, it's equivalent and looks better so  
I'll use that): `foo = lambda {do_something}`. If you use the magical  
syntax previously shown, Ruby handles the turning of a block into an  
actual `Proc` instance.


And since Ruby doesn't have a `()` operator, it uses a method instead  
(`#call`), so you simply do `foo.call` to execute the proc and get its  
value.


All in all, much like Smalltalk, Ruby tends not to favor raw functions  
the way Python does, so a direct translation of the Python code  
doesn't make much sense.

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


Re: Confessions of a Python fanboy

2009-07-31 Thread Masklinn

On 31 Jul 2009, at 13:38 , Bruno Desthuilliers wrote:

Steven D'Aprano a écrit :

On Thu, 30 Jul 2009 18:47:04 +0100, Tim Rowe wrote:
That and the fact that I couldn't stop laughing for long enough to  
learn

any more when I read in the Pragmatic Programmer's Guide that "Ruby,
unlike less flexible languages, lets you alter the value of a  
constant."

Yep, as they say "Bug" = "Undocumented feature"!

That's no different from Python's "constant by convention".
Ruby's code blocks come from Smalltalk, where they are an absolute  
necessity since message passing (which code blocks are part of) is  
the *only* builtin control flow in Smalltalk - so you just *need*  
this construction to provide branching and iterations.


I'm not so sure about the way you say it. I'm pretty sure  
"traditional" flow control structures preceded Smalltalk by a pair of  
decades so it's not that Smalltalk's designers found it necessary to  
use blocks & messages, but that they understood blocks & messages  
could trivially replace most control structures (making *those*  
unnecessary), making the core language simpler and more flexible.


In other words, I see it the other way around.

Wether it makes sense to have code blocks in Ruby is another  
question since Ruby does provide traditional control flow features
Well it does at least allow for the creation of new flow control  
structures in library land when the existing ones aren't enough (e.g.  
allows Ruby not to require the introduction of a `with` statement).  
Though Ruby's blocks are nowhere near as flexible as Smalltalk's.

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


Re: Confessions of a Python fanboy

2009-07-31 Thread Masklinn

On 31 Jul 2009, at 15:12 , Bruno Desthuilliers wrote:

Masklinn a écrit :

On 31 Jul 2009, at 13:38 , Bruno Desthuilliers wrote:

Steven D'Aprano a écrit :

On Thu, 30 Jul 2009 18:47:04 +0100, Tim Rowe wrote:
That and the fact that I couldn't stop laughing for long enough  
to learn
any more when I read in the Pragmatic Programmer's Guide that  
"Ruby,
unlike less flexible languages, lets you alter the value of a  
constant."

Yep, as they say "Bug" = "Undocumented feature"!

That's no different from Python's "constant by convention".
Ruby's code blocks come from Smalltalk, where they are an absolute  
necessity since message passing (which code blocks are part of) is  
the *only* builtin control flow in Smalltalk - so you just *need*  
this construction to provide branching and iterations.



[misunderstandings on my part/clarifications on yours]
Well it does at least allow for the creation of new flow control  
structures in library land when the existing ones aren't enough  
(e.g. allows Ruby not to require the introduction of a `with`  
statement).


Yeps. But then other "traditionnal" control flow features become  
redundant.
They can be anyway: Ruby doesn't deprecate most control flows as the  
actual usages of blocks are a bit restricted (cannot be used for  
`while` as it would require the serialization to a Proc, and Ruby's  
syntax doesn't allow sending multiple blocks to a method so `if…else`  
is out as well). And I assume they reintroduced the for…in sugar to  
ease the transition from more traditional languages (using #each and  
others seems the suggested collection iterators across the community).

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


Re: Confessions of a Python fanboy

2009-07-31 Thread Masklinn

On 31 Jul 2009, at 17:55 , Steven D'Aprano wrote:
But seriously, while I admit that I have very little Ruby  
experience, and
so aren't in a great position to judge, it seems to me that Ruby  
doesn't
have anything like Python's over-riding design principles (the Zen).  
If

there is a design principle to Ruby, I can't see what it is.

As far as I know, Ruby doesn't have anything like the Zen no. But then  
again, I don't know any language other than Python with such a document.



Ruby just seems to be far more complicated than Python: things which
Python does at runtime, with a function call, Ruby has special  
syntax for:


"a bunch of words".split()
%w(a bunch of words)

ord('a')
?a


That's the Perl heritage. And since it inherits from Perl, TIMTOWTDI:
>> "a bunch of words".split
=> ["a", "bunch", "of", "words"]
>> "a"[0]
=> 97
(yes, the indexing operator returns a character code if provided a  
single index. With two, it returns as string slice)


Oh and %w() isn't really equivalent to split(): you don't use it to  
split a string but to create a list of strings, so the equivalent  
expression in Python would be `["a", "bunch", "of", "words"]`.



That makes the barrier to entry far higher: it's easier to leverage
existing knowledge to interpret unfamiliar Python code than unfamiliar
Ruby code. Or so it seems to me.


That's probable.

Although I'm sure Ruby has its good points. I'm not convinced  
anonymous

code blocks are one of them though.


Ruby's code blocks come from Smalltalk, where they are an absolute
necessity since message passing (which code blocks are part of) is  
the

*only* builtin control flow in Smalltalk - so you just *need* this
construction to provide branching and iterations.


Just because Smalltalk had a particular (mis?)feature doesn't mean  
that

other languages should copy it. I know, I know, Ruby people swear by
anonymous code blocks, and I've read Paul Graham too. But I'm really  
not

so sure that the benefits of anonymous code blocks are great enough to
overcome the disadvantages of anonymous code blocks.


What are the disadvantages of anonymous functions?

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


Re: Confessions of a Python fanboy

2009-07-31 Thread Masklinn

On 31 Jul 2009, at 18:24 , Terry Reedy wrote:

Masklinn wrote:

#each is simply a method that takes a function (called blocks in  
ruby). One could call it a higher-order method I guess.
It's an implementation of the concept of internal iteration:  
instead of collections yielding iterator objects, and programmers  
using those through specially-built iteration constructs (e.g. `for… 
in`), collections control iteration over themselves (the iteration  
is performed "inside" the collection, thus the "internal" part) and  
the programmer provides the operations to perform at each iterative  
step through (usually) a function.


Python's iterator protocol was developed in part to avoid the  
(inside-out) callback style of programming. Writing virtual  
collections as generator functions instead of iterator or iterable  
classes saves a lot of boilerplate code. The itertools modules shows  
how nicely iterators can be composed in a way that is much more  
awkward with callbacks.


In Python (assuming we had anonymous defs and an each method on  
lists), the following loop:

   for item in some_list:
   do_something(item)
   do_something_else(item)
   some_list.each((def (item):
   do_something(item)
   do_something_else(item)
   ))


And how does Ruby do the equivalent of

def double(it):
 for i in it:
   yield 2*i

for i,j in zip(double(some_list), some_gen_func(args)):
 print(do_something(i+j,i-j))



Somethign along the lines of

some_list.map{|e| 2*e}.zip(some_gen_func(args)).each {|i, j|
puts(do_something(i+j, i-j))
}

The `#each` call after `#zip` is not actually necessary, but I find it  
clearer. Oh, and some_gen_func and do_something probably wouldn't work  
that way (as I said above, Ruby isn't big on named functions and  
doesn't actually have them)

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


Re: Confessions of a Python fanboy

2009-07-31 Thread Masklinn

On 31 Jul 2009, at 20:17 , Steven D'Aprano wrote:

On Fri, 31 Jul 2009 18:15:15 +0200, Masklinn wrote:


I know, I know, Ruby people swear by
anonymous code blocks, and I've read Paul Graham too. But I'm really
not so sure that the benefits of anonymous code blocks are great
enough to overcome the disadvantages of anonymous code blocks.


What are the disadvantages of anonymous functions?


In no particular order, and not necessarily exhaustive:

* The risk of obfuscation in your code. That's fairly minimal for
lambdas, because they're just a single expression, but for a large
anonymous code block (ACB) defined inside a named function, it may be
difficult for the reader to easily distinguish which bits are the  
outer

function and which are the ACB.


I believe that one's unadulterated BS.


* Loss of useful debugging information. Take this example from Python:


def main(f):

... return f(3)
...

main(lambda n: 2/(n-3))

Traceback (most recent call last):
 File "", line 1, in 
 File "", line 2, in main
 File "", line 1, in 
ZeroDivisionError: integer division or modulo by zero


def my_special_function(n):

... return 2/(n-3)
...

main(my_special_function)

Traceback (most recent call last):
 File "", line 1, in 
 File "", line 2, in main
 File "", line 2, in my_special_function
ZeroDivisionError: integer division or modulo by zero

If your code has only one anonymous function (whether a lambda or a  
full

multi-line block), then it's easy to identify which lambda raised the
exception: there is only one it could be. But if your code uses lots  
of

lambdas, the lack of a function name makes it hard to distinguish one
 from another . Anonymity makes identification harder.

The traceback gives you the line of the anonymous function (even in  
python) so unless you have several anonymous functions on the same  
line, there's no reason why that would be much of an issue.  
Furthermore, Python doesn't provide any more information when the  
error happens out of a function (in a `for` or a `with`), so it's not  
like there's much of a difference here between Ruby's block-based  
approach and Python's statements-based approach.



* Risk of code-duplication and breaking the principle of Once And Only
Once. Anonymous functions are generally created, used, then  
immediately
thrown away -- or at least made more-or-less inaccessible for reuse.  
An
anonymous function stored in a callback still exists, but the coder  
isn't
able to easily re-use it for another callback somewhere else in the  
code.

Consequently, there's a temptation for the coder to write the same
function multiple times:

add_button("Parrot", colour=blue, callback=lambda x: x.stuff('a'))
add_button("Cheese", flavour=tasty, callback=lambda x: x.thing('b'))
add_button("Canary", colour=yellow, callback=lambda x: x.stuff('a'))

instead of:

def bird_callback(x):
   return x.stuff('a')

add_button("Parrot", colour=blue, callback=bird_callback)
add_button("Cheese", flavour=tasty, callback=lambda x: x.thing('b'))
add_button("Canary", colour=yellow, callback=bird_callback)

Yes, that one I can give you though I don't think that's a big issue.  
And it's not like it's hard to extract the anonymous function into a  
named one and then use that on the third strike, so I really don't  
believe that point holds much water.



* Recursion is more or less impossible without fragile tricks.

(At least for Python. I don't know how recursion operates in Ruby.)
Code blocks are rarely if ever used recursively. If an operation is  
using anonymous functions recursively, then there's often something  
very wrong with the idea leading to that code. So I find this  
objection irrelevant.

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


Re: Help understanding the decisions *behind* python?

2009-07-31 Thread Masklinn

On 31 Jul 2009, at 20:48 , Emmanuel Surleau wrote:

On Friday 31 July 2009 19:49:04 Raymond Hettinger wrote:
On Jul 20, 9:27 am, Phillip B Oldham   
wrote:

Specifically the "differences" between lists and tuples have us
confused and have caused many "discussions" in the office. We
understand that lists are mutable and tuples are not, but we're a
little lost as to why the two were kept separate from the start.  
They

both perform a very similar job as far as we can tell.


The underlying C code for the two is substantially the same.  In  
terms

of code, tuples are in effect just immutable lists that have the
added
feature of being hashable (and therefore usable as dictionary keys or
elements of sets).

Beyond the mutable/hashable distinction, there is an important
philosophical distinction articulated by Guido.  He deems tuples
to be useful for struct like groupings of non-homogenous fields
and lists to be useful for sequences of homogenous data suitable
for looping.

While nothing in the list/tuple code requires you to make that
distinction,
it is important because that philosophy pervades the language.  If  
you

follow Guido's direction, you'll find that the various parts of the
language fit together better.  Do otherwise and you'll be going
against
the grain.


I might be wrong, but I get the impression that many people don't  
indeed "get
it" and use tuples as static arrays and lists when the array needs  
to be

dynamically resized. This is certainly how I use them as well.

This would tend to show that Guido's notion here was not particularly
intuitive.
It's intuitive if you come to Python knowing other languages with  
tuples (which are mostly functional, and in which tuples are *never*  
sequences/iterables). At the end of the day, and if Guido's intention  
truly was what Raymond says, implementing tuples as immutable sequence  
was a mistake. And the documentation is to blame as well: in it,  
tuples are clearly described as a *sequence* type, not a *structure*  
type. 
--

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


Re: Python docs disappointing

2009-07-31 Thread Masklinn

On 31 Jul 2009, at 22:34 , Emmanuel Surleau wrote:

You have first-grade documentation on the Python website:
http://docs.python.org/library/urllib.html
I'm not really using pydoc, but I'd wager it's more used as a quick  
lookup

than anything else.
Another important documentary resource for the stdlib is Doug  
Hellmann's awesome Python Module of the Day series (http://www.doughellmann.com/PyMOTW/ 
)

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


Re: Help understanding the decisions *behind* python?

2009-08-04 Thread Masklinn

On 3 Aug 2009, at 18:57 , John Nagle wrote:

Dave Angel wrote:

sturlamolden wrote:

On 20 Jul, 18:27, Phillip B Oldham  wrote:
Tuples are used for passing arguments to and from a function. Common
use of tuples include multiple return values and optional arguments
(*args).


  That's from Mesa, the Xerox PARC language of the 1970s.

  Mesa used tuples for subroutine arguments in a very straightforward
way.  Every function took one tuple as an argument, written as  
parameters

in parentheses separated by commas.
Most statically typed functional languages seem to do pretty much the  
same: uncurried functions really take a tuple as single argument  
rather than multiple arguments, using pattern matching to make it look  
like multiple arguments. Then again, most of them seem to default to  
curried functions these days, which is nice.

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


Re: Confessions of a Python fanboy

2009-08-04 Thread Masklinn

On 4 Aug 2009, at 11:28 , Steven D'Aprano wrote:

So I'd ask, does Smalltalk's message passing model match the way human
beings think?

Yes.

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


Re: Parsing Binary Structures; Is there a better way / What is your way?

2009-08-05 Thread Masklinn

On 5 Aug 2009, at 16:46 , Martin P. Hellwig wrote:

Hi List,

On several occasions I have needed (and build) a parser that reads a  
binary piece of data with custom structure. For example (bogus one):


BE
+-+-+-+-+--++
| Version | Command | Instruction | Data Length | Data | Filler |
+-+-+-+-+--++
Version: 6 bits
Command: 4 bits
Instruction: 5 bits
Data Length: 5 bits
Data: 0-31 bits
Filler: filling 0 bits to make the packet dividable by 8

what I usually do is read the packet in binary mode, convert the  
output to a concatenated 'binary string'(i.e. '0101011000110') and  
then use slice indeces to get the right data portions.
Depending on what I need to do with these portions I convert them to  
whatever is handy (usually an integer).


This works out fine for me. Most of the time I also put the ASCII  
art diagram of this 'protocol' as a comment in the code, making it  
more readable/understandable.


Though there are a couple of things that bothers me with my approach:
- This seems such a general problem that I think that there must be  
already a general pythonic solution.
- Using a string for binary representation takes at least 8 times  
more memory for the packet than strictly necessary.

- Seems to need a lot of prep work before doing the actual parsing.

Any suggestion is greatly appreciated.
The gold standard for binary parsing (and serialization) is probably  
Erlang's bit syntax, but as far as Python goes you might be interested  
by Hachoir (http://hachoir.org/ but it seems down right now).


It's not going to match your second point, but it can probably help  
with the rest (caveat: I haven't used hachoir personally).

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


Re: Parsing Binary Structures; Is there a better way / What is your way?

2009-08-05 Thread Masklinn

On 5 Aug 2009, at 19:17 , Bearophile wrote:

Have you tried Hachoir? (I think its name may be changed to Fusil, I
don't know).
Name hasn't been changed (I think fusil is a subproject, something  
like that) on the other hand the hachoir.org site is dead.


But apparently Hachoir was moved to bitbucket (http://bitbucket.org/haypo/hachoir/wiki/Home 
) just in time so…

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