Logging oddity: handlers mandatory in every single logger?
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?
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?
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?
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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?
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
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?
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
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?
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?
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