Re: Is this pythonic?
Chris Angelico : > On Thu, Nov 24, 2016 at 10:14 PM, Marko Rauhamaa wrote: >> When you use threads, you call read(2) in the blocking mode. Then the >> read(2) operation will block "for ever." There's no clean way to >> cancel the system call. > > Signals will usually interrupt system calls, causing them to return > EINTR. There are exceptions (the aforementioned uninterruptible calls, > but they're not available in nonblocking form, so they're the same for > threads and coroutines), but the bulk of system calls will halt > cleanly on receipt of a signal. And yes, you CAN send signals to > specific threads; there are limitations, but for a language like > Python, there's no difficulty in having a single disposition for (say) > SIGINT, and then using thread signalling to figure out which thread > should have KeyboardInterrupt raised in it. Yes, pthread_kill(3) has been made available in Python-3.3, I'm noticing. Also: Changed in version 3.5: Python now retries system calls when a syscall is interrupted by a signal, except if the signal handler raises an exception (see PEP 475 for the rationale), instead of raising InterruptedError. https://docs.python.org/3/library/exceptions.html#Interrupt edError> Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Thu, Nov 24, 2016 at 10:14 PM, Marko Rauhamaa wrote: > When you use threads, you call read(2) in the blocking mode. Then the > read(2) operation will block "for ever." There's no clean way to cancel > the system call. Signals will usually interrupt system calls, causing them to return EINTR. There are exceptions (the aforementioned uninterruptible calls, but they're not available in nonblocking form, so they're the same for threads and coroutines), but the bulk of system calls will halt cleanly on receipt of a signal. And yes, you CAN send signals to specific threads; there are limitations, but for a language like Python, there's no difficulty in having a single disposition for (say) SIGINT, and then using thread signalling to figure out which thread should have KeyboardInterrupt raised in it. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
Chris Angelico : > On Thu, Nov 24, 2016 at 9:59 PM, Marko Rauhamaa wrote: >> Chris Angelico : >>> A coroutine can be abandoned at an await point, but the >>> currently-executed call is still going to complete (usually); >> >> I don't quite understand. Say you are awaiting on receiving bytes from a >> socket. That means there has been a nonblocking call to read(2), >> recvmsg(2) or equivalent that has returned EAGAIN. If you now abandon >> the coroutine, there is no resumption of the system call but the >> coroutine can finish instantaneously. > > Is the read(2) still going to consume data from the pipe/socket? Only if the kernel has already buffered data it has received previously. If there isn't yet any data available in the kernel, read(2) returns with errno=EAGAIN, and the control is returned to the main loop. The main loop then goes to sleep in epoll_wait(2) or equivalent. > If so, the operation is still going to continue, whether you use > coroutines or threads. If not, it would have been cancelled whether > you use coroutines or threads. When you use threads, you call read(2) in the blocking mode. Then the read(2) operation will block "for ever." There's no clean way to cancel the system call. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Thu, Nov 24, 2016 at 9:59 PM, Marko Rauhamaa wrote: > Chris Angelico : > >> On Thu, Nov 24, 2016 at 7:39 PM, Marko Rauhamaa wrote: >>> * Coroutines can be killed, threads cannot. >> >> Not strictly true. A coroutine can be abandoned at an await point, but >> the currently-executed call is still going to complete (usually); > > I don't quite understand. Say you are awaiting on receiving bytes from a > socket. That means there has been a nonblocking call to read(2), > recvmsg(2) or equivalent that has returned EAGAIN. If you now abandon > the coroutine, there is no resumption of the system call but the > coroutine can finish instantaneously. Is the read(2) still going to consume data from the pipe/socket? If so, the operation is still going to continue, whether you use coroutines or threads. If not, it would have been cancelled whether you use coroutines or threads. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
Chris Angelico : > On Thu, Nov 24, 2016 at 7:39 PM, Marko Rauhamaa wrote: >> * Coroutines can be killed, threads cannot. > > Not strictly true. A coroutine can be abandoned at an await point, but > the currently-executed call is still going to complete (usually); I don't quite understand. Say you are awaiting on receiving bytes from a socket. That means there has been a nonblocking call to read(2), recvmsg(2) or equivalent that has returned EAGAIN. If you now abandon the coroutine, there is no resumption of the system call but the coroutine can finish instantaneously. > a thread can be killed, but certain non-interruptible operations will > delay the termination until after that operation. So either way, the > operation still runs to completion. There *could* be such noninterruptible operations (which would be a big shame). They would have to be implemented with the help of a separate thread. The surface coroutine can never sit in a blocking operation. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Thu, Nov 24, 2016 at 7:39 PM, Marko Rauhamaa wrote: > * Coroutines can be killed, threads cannot. > Not strictly true. A coroutine can be abandoned at an await point, but the currently-executed call is still going to complete (usually); a thread can be killed, but certain non-interruptible operations will delay the termination until after that operation. So either way, the operation still runs to completion. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
"Frank Millman" : > "Steven D'Aprano" wrote in message > news:58368358$0$1513$c3e8da3$54964...@news.astraweb.com... >> I'm a newbie to asyncio, but if I were doing this using threads, [...] > > To me, the beauty of asyncio (or I suppose async in general) is that I > don't have to worry about any of what you describe above. The programming model for threads and asyncio coroutines is identical. The differences for the programmer are smallish details: * In asyncio, all functions that can potentially block must be tagged with "async" and all calls to such functions must be tagged with "await". * Not all blocking functions have an equivalent coroutine. All functions are readily available to threads. * Coroutines can be killed, threads cannot. * Coroutines can be multiplexed, threads cannot. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
"Steven D'Aprano" wrote in message news:58368358$0$1513$c3e8da3$54964...@news.astraweb.com... On Thursday 24 November 2016 15:55, Frank Millman wrote: > "Steve D'Aprano" wrote in message > news:583653bb$0$1603$c3e8da3$54964...@news.astraweb.com... > >> Even if the computation of the memoised value is done asynchronously, >> you >> can easily split the computation off to a separate method (as you >> already >> talked about doing!) and make getval() block until it returns. > > Surely that defeats the whole purpose of asyncio. Anything that blocks > holds > up the entire process. I strenuously try to avoid blocking in any shape > or > form. Perhaps I'm not understanding your task correctly, but surely you have to wait for the computation to occur at some point? Even if that's just you hitting Refresh waiting for the value of the column to eventually show up. I'm a newbie to asyncio, but if I were doing this using threads, I'd have getval() set the self._cached_value to "pending..." (say), start the computation thread running, and then return. The computation thread will eventually write the true value to _cached_value, and in the meantime the getval() method (and hence __str__ will happily use the "pending..." value. The only tricky part is to make sure you only start the thread once. I am not really qualified to answer this - I *use* asyncio, but I don’t really understand what goes on under the covers. With that caveat, here goes. To me, the beauty of asyncio (or I suppose async in general) is that I don't have to worry about any of what you describe above. I just have to 'await' whatever I am waiting for. There could be a long chain of function calls (which I suppose I should call coroutine calls) but at some point one of them is actually going to wait for some I/O, and yield control back to the event loop. At that point, the entire chain is suspended, pending return of the value. Once received, control passes back down the chain to the originating coroutine, which can then carry on exactly where it left off. Frank -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Thursday 24 November 2016 15:55, Frank Millman wrote: > "Steve D'Aprano" wrote in message > news:583653bb$0$1603$c3e8da3$54964...@news.astraweb.com... > >> Even if the computation of the memoised value is done asynchronously, you >> can easily split the computation off to a separate method (as you already >> talked about doing!) and make getval() block until it returns. > > Surely that defeats the whole purpose of asyncio. Anything that blocks holds > up the entire process. I strenuously try to avoid blocking in any shape or > form. Perhaps I'm not understanding your task correctly, but surely you have to wait for the computation to occur at some point? Even if that's just you hitting Refresh waiting for the value of the column to eventually show up. I'm a newbie to asyncio, but if I were doing this using threads, I'd have getval() set the self._cached_value to "pending..." (say), start the computation thread running, and then return. The computation thread will eventually write the true value to _cached_value, and in the meantime the getval() method (and hence __str__ will happily use the "pending..." value. The only tricky part is to make sure you only start the thread once. -- Steven 299792.458 km/s — not just a good idea, it’s the law! -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
"Steve D'Aprano" wrote in message news:583653bb$0$1603$c3e8da3$54964...@news.astraweb.com... Even if the computation of the memoised value is done asynchronously, you can easily split the computation off to a separate method (as you already talked about doing!) and make getval() block until it returns. Surely that defeats the whole purpose of asyncio. Anything that blocks holds up the entire process. I strenuously try to avoid blocking in any shape or form. > I can say 'print(await obj.__str__())', and it works, but I lose the > ability to include it in a larger print statement. Any time you find yourself directly calling dunder methods, you're probably doing it wrong. This is one of those times. Yes. Having slept on it, I realise I over-reacted. The __str__() method is convenient for me, but I only use it for testing and debugging to see what is going on. It is not part of my app per se. I now realise that the solution is - 1. Keep the __str__ method, but replace calls to getval() with a direct reference to the underlying attribute. It means that any 'computable' objects that have not already been computed will return None, but that is ok for my purposes. 2. Write a separate method, retaining the calls to getval(), to be called independently using 'await' if I ever need to see the full result after computation. Frank -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Wed, 23 Nov 2016 10:11 pm, Frank Millman wrote: > Gah! The law of unintended consequences strikes again! > > As I mentioned, the class in question represents a database column. Yes, you mentioned that. > A > separate class represents a database row. I have a __str__() method on the > 'row' class that prints a nicely formatted representation of the object > with all of its column objects and their values. You didn't mention that, but it shouldn't matter. > With the above changes, I had to turn getval() into a coroutine. You what? I'm gobsmacked by this assertion. Nobody else seems to have commented on this, so perhaps I'm missing something, but this strikes me as astonishing. Nothing in your earlier post even hinted that you were using coroutines or async, and as sure as the day is long memoisation doesn't force you to start. Even if the computation of the memoised value is done asynchronously, you can easily split the computation off to a separate method (as you already talked about doing!) and make getval() block until it returns. [...] > I can say 'print(await obj.__str__())', and it works, but I lose the > ability to include it in a larger print statement. Any time you find yourself directly calling dunder methods, you're probably doing it wrong. This is one of those times. -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Wed, 23 Nov 2016 11:27 pm, Frank Millman wrote: > It is a bit like quantum theory. I have no way of telling whether the > computation has been carried out without looking at it, but the act of > looking at it triggers the computation. I can tell, of course, by looking > at the underlying attribute, but not by using the public methods. Then give it a public method (or better, a property) to tell. @property def needs_computation(self): return not hasattr(self, '_cached_value') -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
Frank Millman wrote: For the time being I will use 'print(await obj.__str__())', as this is a good compromise. It seems more like a very *bad* compromise to me. I can't see how this gains you anything over just doing print(await obj.getvalue()), and you lose the ability to do anything that calls __str__ implicitly. -- Greg -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On 2016-11-23 22:15, Steve D'Aprano wrote: > On Wed, 23 Nov 2016 08:10 pm, Frank Millman wrote: > > The class has a getval() method to return the current value. > > > > Usually the value is stored in the instance, and can be returned > > immediately, but sometimes it has to be computed, incurring > > further database lookups. > > This is called memoisation, or caching, and is a perfectly standard > programming technique. It's not without its traps though: there's a > famous quote that says there are only two hard problems in > computing, naming things and cache invalidation. Fortunately, you can offload some odd edge-cases to the standard library, no? from functools import lru_cache # ... @lru_cache(maxsize=1) def getval(...): return long_computation() It doesn't cache across multiple instances of the same class, but does cache multiple calls to the same instance's function: >>> from functools import lru_cache >>> class Foo: ... def __init__(self, name): ... self.name = name ... @lru_cache(maxsize=1) ... def getval(self): ... print("Long process") ... return self.name ... >>> f1 = Foo("f1") >>> f2 = Foo("f2") >>> f1.getval() Long process 'f1' >>> f1.getval() 'f1' >>> f2.getval() Long process 'f2' >>> f2.getval() 'f2' -tkc -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
"Chris Angelico" wrote in message news:CAPTjJmqGEwHPVyrR+Ti9bV=S5MsLt3nquF4TvE=xpees188...@mail.gmail.com... On Wed, Nov 23, 2016 at 11:27 PM, Frank Millman wrote: > > @Chris >> >> This strongly suggests that str(x) is the wrong way to get the >> information. You shouldn't be doing database requests inside __str__ >> or __repr__. > > > I guess you are right, but still it is a pity. __str__ has been working > for > me beautifully for a long time now. The only change is that, previously, > all > the values had been read in or computed before calling __str__(), now I > am > delaying the computation until requested. > > It is a bit like quantum theory. I have no way of telling whether the > computation has been carried out without looking at it, but the act of > looking at it triggers the computation. I can tell, of course, by > looking at > the underlying attribute, but not by using the public methods. That makes sense. What you could do is have __repr__ do something like this: def __repr__(self): if self.has_data: return "<%s: %r>" % (self.col_name, self.data) return "<%s: >" % self.col_name I'm not sure that that would be appropriate for __str__, though; maybe it could return the string of data if it exists, otherwise it could fall back on __repr__? Thanks for the ideas. I will have to experiment a bit. There is a certain irony in all this. When I started using asyncio, I just converted the networking functions into coroutines and waited for it to stabilise. Then I wanted to extend it, and found that coroutines can only be called by other coroutines, and I had some long chains of function calls, so I backed off. Then I eventually bit the bullet, converted everything in the chain to a coroutine, and let it settle down again. I have done this a few times, and each time I sensed an improvement in the way that my entire application was beginning to 'flow' in an async manner, which was good. However, I have managed to avoid turning getval() into a coroutine, until now. Now I am ready to embrace the change, but this time it is Python that is tripping me up. For the time being I will use 'print(await obj.__str__())', as this is a good compromise. Of course I don't have to use __str__, I can call it anything, so I will probably create a helper function to make it easy to call on any object. One of the things that was deterring me from turning getval() into a coroutine was the inability to use a coroutine inside a comprehension. I see that Python 3.6 now allows this, so I must download a beta version and try it out. Frank -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Wed, Nov 23, 2016 at 11:27 PM, Frank Millman wrote: > > @Chris >> >> This strongly suggests that str(x) is the wrong way to get the >> information. You shouldn't be doing database requests inside __str__ >> or __repr__. > > > I guess you are right, but still it is a pity. __str__ has been working for > me beautifully for a long time now. The only change is that, previously, all > the values had been read in or computed before calling __str__(), now I am > delaying the computation until requested. > > It is a bit like quantum theory. I have no way of telling whether the > computation has been carried out without looking at it, but the act of > looking at it triggers the computation. I can tell, of course, by looking at > the underlying attribute, but not by using the public methods. That makes sense. What you could do is have __repr__ do something like this: def __repr__(self): if self.has_data: return "<%s: %r>" % (self.col_name, self.data) return "<%s: >" % self.col_name I'm not sure that that would be appropriate for __str__, though; maybe it could return the string of data if it exists, otherwise it could fall back on __repr__? ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
"Frank Millman" wrote in message news:o13meh$p2g$1...@blaine.gmane.org... 3. When instantiating an object, check if it would need computation - if computation_required: self.getval = self._getval_with_comp else: self.getval = self._getval 4. In _getval_with_comp, perform the computation, then add the following - self.getval = self._getval return self._getval() What is the verdict? -1, 0, or +1? Thanks for the responses. I will reply to them all here - @Peter You can also have the method replace itself ... I like it. Thanks for the suggestion. @Steve So this check only happens once, on instantiation? And you're sure that once the instance is created, there will never be any circumstances where you want to re-calculate the value? Well, the process that I call 'computation' includes setting up some variables that will trigger a recalculation when certain values change. Part of my motivation was to avoid all of this if the value is never accessed. def __getval_with_comp(self): value = ... # long computation self._cached_value = value self.getval = self._getval # return value return self._getval() # why call the method when you already know the answer? How are subclasses supposed to override getval? Two questions there, but the answer is the same. I don't want subclasses to override the computation part of the process. I just want then to 'massage' the result before returning it. Therefore the answer to the first question is, to force the subclass to return the result, if it has its own _getval(). The answer to the second question is that they override _getval(), and therefore they will be invoked when getval() is called, provided getval has been set to be equal to _getval. Hope that makes sense. @Chris This strongly suggests that str(x) is the wrong way to get the information. You shouldn't be doing database requests inside __str__ or __repr__. I guess you are right, but still it is a pity. __str__ has been working for me beautifully for a long time now. The only change is that, previously, all the values had been read in or computed before calling __str__(), now I am delaying the computation until requested. It is a bit like quantum theory. I have no way of telling whether the computation has been carried out without looking at it, but the act of looking at it triggers the computation. I can tell, of course, by looking at the underlying attribute, but not by using the public methods. Frank -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
Frank Millman wrote: > Hi all > > Sometimes I write something that I think is quite clever, but later on I > look at it and ask 'What was I thinking?'. > > I have just come up with a 'clever' solution to a problem. Would this > cause raised eyebrows if you were reviewing this? > > I have a class that represents a single database column - there could be > hundreds of instances at any time. > > The class has a getval() method to return the current value. > > Usually the value is stored in the instance, and can be returned > immediately, but sometimes it has to be computed, incurring further > database lookups. > > In many cases the computed value is never actually requested, so I want to > delay the computation until the first call to getval(). > > I could add an 'if computation_required: ' block to getval(), but I am > trying to avoid that, partly because this would have to be checked for > every call to getval() but would only used in a small number of cases, and > partly because I have a few subclasses where getval() is over-ridden so I > would have to add the extra code to every one (or call the superclass on > every one). > > This is what I have come up with. > > 1. Rename all instances of 'getval()' to '_getval()'. > > 2. Add a new method '_getval_with_comp()'. > > 3. When instantiating an object, check if it would need computation - > if computation_required: > self.getval = self._getval_with_comp > else: > self.getval = self._getval You can also have the method replace itself: >>> class Foo: ... def get_val(self): ... print("computing...") ... val = self._val = 42 ... self.get_val = self.get_cached_val ... return val ... def get_cached_val(self): ... return self._val ... >>> foo = Foo() >>> foo.get_val() computing... 42 >>> foo.get_val() 42 > 4. In _getval_with_comp, perform the computation, then add the following - > self.getval = self._getval > return self._getval() > > What is the verdict? -1, 0, or +1? > > Frank Millman -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Wed, Nov 23, 2016 at 10:11 PM, Frank Millman wrote: > Gah! The law of unintended consequences strikes again! > > As I mentioned, the class in question represents a database column. A > separate class represents a database row. I have a __str__() method on the > 'row' class that prints a nicely formatted representation of the object with > all of its column objects and their values. > > With the above changes, I had to turn getval() into a coroutine. My > __str__() method uses getval() to obtain the values, so I had to prefix > getval() with 'await', but then I get a syntax error on __str__(). I can add > 'async' to remove the syntax error, but then print(obj) does not work - > TypeError: __str__ returned non-string (type coroutine) > > I don't think there is an answer to this, but any suggestions will be > appreciated. > > I can say 'print(await obj.__str__())', and it works, but I lose the ability > to include it in a larger print statement. > > Ah well :-( This strongly suggests that str(x) is the wrong way to get the information. You shouldn't be doing database requests inside __str__ or __repr__. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Wed, 23 Nov 2016 08:10 pm, Frank Millman wrote: [...] > The class has a getval() method to return the current value. > > Usually the value is stored in the instance, and can be returned > immediately, but sometimes it has to be computed, incurring further > database lookups. This is called memoisation, or caching, and is a perfectly standard programming technique. It's not without its traps though: there's a famous quote that says there are only two hard problems in computing, naming things and cache invalidation. But putting that aside: def getval(self): sentinel = object() value = getattr(self, '_cached_value', sentinel) if value is sentinel: # compute the value and store it value = ... self._cached_value = value return value To invalidate the cache and force a recalculation: del self._cached_value Now it's easy to override: class Subclass(ParentClass): def getval(self): value = super(Subclass, self).getval() return value + 1 > This is what I have come up with. > > 1. Rename all instances of 'getval()' to '_getval()'. > > 2. Add a new method '_getval_with_comp()'. > > 3. When instantiating an object, check if it would need computation - > if computation_required: > self.getval = self._getval_with_comp > else: > self.getval = self._getval So this check only happens once, on instantiation? And you're sure that once the instance is created, there will never be any circumstances where you want to re-calculate the value? > 4. In _getval_with_comp, perform the computation, then add the following - > self.getval = self._getval > return self._getval() So you have something like this? def _getval(self): return self._cached_value def __getval_with_comp(self): value = ... # long computation self._cached_value = value self.getval = self._getval # return value return self._getval() # why call the method when you already know the answer? How are subclasses supposed to override getval? -- Steve “Cheer up,” they said, “things could be worse.” So I cheered up, and sure enough, things got worse. -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
"Marko Rauhamaa" wrote in message news:87inrer0dl@elektro.pacujo.net... "Frank Millman" : > 3. When instantiating an object, check if it would need computation - >if computation_required: >self.getval = self._getval_with_comp >else: >self.getval = self._getval > > 4. In _getval_with_comp, perform the computation, then add the > following - >self.getval = self._getval >return self._getval() > > What is the verdict? -1, 0, or +1? Perfectly cromulent, run-of-the-mill Python code. Gah! The law of unintended consequences strikes again! As I mentioned, the class in question represents a database column. A separate class represents a database row. I have a __str__() method on the 'row' class that prints a nicely formatted representation of the object with all of its column objects and their values. With the above changes, I had to turn getval() into a coroutine. My __str__() method uses getval() to obtain the values, so I had to prefix getval() with 'await', but then I get a syntax error on __str__(). I can add 'async' to remove the syntax error, but then print(obj) does not work - TypeError: __str__ returned non-string (type coroutine) I don't think there is an answer to this, but any suggestions will be appreciated. I can say 'print(await obj.__str__())', and it works, but I lose the ability to include it in a larger print statement. Ah well :-( Frank -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
"Marko Rauhamaa" wrote in message news:87inrer0dl@elektro.pacujo.net... "Frank Millman" : > What is the verdict? -1, 0, or +1? Perfectly cromulent, run-of-the-mill Python code. A new word to add to my vocabulary - thanks :-) Frank -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
"Frank Millman" : > 3. When instantiating an object, check if it would need computation - >if computation_required: >self.getval = self._getval_with_comp >else: >self.getval = self._getval > > 4. In _getval_with_comp, perform the computation, then add the following - >self.getval = self._getval >return self._getval() > > What is the verdict? -1, 0, or +1? Perfectly cromulent, run-of-the-mill Python code. Marko -- https://mail.python.org/mailman/listinfo/python-list
Is this pythonic?
Hi all Sometimes I write something that I think is quite clever, but later on I look at it and ask 'What was I thinking?'. I have just come up with a 'clever' solution to a problem. Would this cause raised eyebrows if you were reviewing this? I have a class that represents a single database column - there could be hundreds of instances at any time. The class has a getval() method to return the current value. Usually the value is stored in the instance, and can be returned immediately, but sometimes it has to be computed, incurring further database lookups. In many cases the computed value is never actually requested, so I want to delay the computation until the first call to getval(). I could add an 'if computation_required: ' block to getval(), but I am trying to avoid that, partly because this would have to be checked for every call to getval() but would only used in a small number of cases, and partly because I have a few subclasses where getval() is over-ridden so I would have to add the extra code to every one (or call the superclass on every one). This is what I have come up with. 1. Rename all instances of 'getval()' to '_getval()'. 2. Add a new method '_getval_with_comp()'. 3. When instantiating an object, check if it would need computation - if computation_required: self.getval = self._getval_with_comp else: self.getval = self._getval 4. In _getval_with_comp, perform the computation, then add the following - self.getval = self._getval return self._getval() What is the verdict? -1, 0, or +1? Frank Millman -- https://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On 18 déc 2008, 13:51, Jason Scheirer wrote: > I'd say it's fine but breaking up the statement once or twice is a > good idea just because if one of the function calls in this nested > thing throws an exception, a smaller statement with fewer calls makes > for a far more readable traceback. And I hope that this whole > statement all lives inside of a method in the same x class, or is a > higher-level class that makes use of this behavior? If not, you may > want to consider doing so. > > class X(object): > @property > def todays_filepattern(self): > return self.match_filename( > self.determine_filename_pattern( > datetime.datetime.now())) > def validate_todays_files(self): > return self.validate_output(self.find_text > (self.todays_filepattern)) Thanks for this lesson in application design. Just what I was looking for. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Jan 21, 4:23 pm, Scott David Daniels wrote: > prueba...@latinmail.com wrote: > > ... If you have duplicates this will not work. You will have to do > > something like this instead: > > o=[] > i=0 > ln=len(l) > while i > if l[i]['title']=='ti': > > o.append(l.pop(i)) > > ln-=1 > > else: > > i+=1 > > Or the following: > indices = [i for i,d in enumerate(l) if d['title']=='ti'] > for i in reversed(indices): # so del doesn't affect later positions > del l[i] > > --Scott David Daniels > scott.dani...@acm.org Cool. How come I didn't think of that!. Now I can write my evil one liner >:-). o=[l.pop(i) for i in reversed(xrange(len(l))) if l[i]['title']=='ti'] -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Jan 21, 4:23 pm, Scott David Daniels wrote: > prueba...@latinmail.com wrote: > > ... If you have duplicates this will not work. You will have to do > > something like this instead: > > o=[] > i=0 > ln=len(l) > while i > if l[i]['title']=='ti': > > o.append(l.pop(i)) > > ln-=1 > > else: > > i+=1 > > Or the following: > indices = [i for i,d in enumerate(l) if d['title']=='ti'] > for i in reversed(indices): # so del doesn't affect later positions > del l[i] > > --Scott David Daniels > scott.dani...@acm.org Cool. How come I didn't think of that! That means I can create an evil one liner now >:-). replacecount=len([o.append(l.pop(i)) for i in reversed(xrange(len(l))) if l[i]['title']=='ti']) -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
Peter Otten wrote: > If you can change the rest of your program to work smoothly with a > dictionary I would suggest the following: [snip] >>> from collections import defaultdict [snip] Thanks a lot. I didn't know defaultdict. It is powerful. I begin to understand that people prefer using dictionaries than lists, so as to take advantage of their automatic lookup feature. -- python -c "print ''.join([chr(154 - ord(c)) for c in '*9(9&(18%.\ 9&1+,\'Z4(55l4('])" "When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong." (first law of AC Clarke) -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
TP wrote: > Hi, > > Is the following code pythonic: > l=[{"title":"to", "value":2},{"title":"ti","value":"coucou"}] dict = [ dict for dict in l if dict['title']=='ti'] l.remove(*dict) l > [{'title': 'to', 'value': 2}] > > Precision: I have stored data in the list of dictionaries l, because in my > application I am sure that "title" is unique for each record. But perhaps > it is better to imagine that someday it will not be anymore the case? And > rather use a data storage as the following? > > l = { '001':{"title":"to", "value":2}, '002' > {"title":"ti","value":"coucou"}} > > The problem with this storage is that it implies to manipulate some "ids" > that have not any meaning for a humain being (001, 002, etc). > > Thanks a lot for you opinion, If you can change the rest of your program to work smoothly with a dictionary I would suggest the following: >>> items = [{"title":"to", "value":2},{"title":"ti","value":"coucou"}] >>> lookup = dict((item["title"], item) for item in items) >>> lookup {'to': {'value': 2, 'title': 'to'}, 'ti': {'value': 'coucou', 'title': 'ti'}} >>> del lookup["ti"] >>> lookup {'to': {'value': 2, 'title': 'to'}} If you later have to accomodate for multiple dictionaries with the same title use lists of dictionaries as values: >> from collections import defaultdict >>> lookup = defaultdict(list) >>> for item in items: ... lookup[item["title"]].append(item) ... >>> lookup defaultdict(, {'to': [{'value': 2, 'title': 'to'}], 'ti': [{'value': 'coucou', 'title': 'ti'}]}) >>> del lookup["ti"] >>> lookup defaultdict(, {'to': [{'value': 2, 'title': 'to'}]}) Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
prueba...@latinmail.com wrote: ... If you have duplicates this will not work. You will have to do something like this instead: o=[] i=0 ln=len(l) while i if l[i]['title']=='ti': o.append(l.pop(i)) ln-=1 else: i+=1 Or the following: indices = [i for i,d in enumerate(l) if d['title']=='ti'] for i in reversed(indices): # so del doesn't affect later positions del l[i] --Scott David Daniels scott.dani...@acm.org -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Jan 21, 12:34 pm, TP wrote: > alex23 wrote: > > Try not to use 'dict' or the name of any of the other built-in types > > So my list is rather: > l=[{"title":"to", "color":"blue", "value":2} > {"title":"ti", "color":"red", "value":"coucou"}] > > So, I will rather use your solution: > > for index, record in enumerate(l): > if record['title'] == 'ti': > to_add_in_another_list = l.pop(index) > another_list.append(to_add_in_another_list ) > If you have duplicates this will not work. You will have to do something like this instead: >>> o=[] >>> i=0 >>> ln=len(l) >>> while i>> for index, record in enumerate(l): if record['title'] == 'ti': to_add_in_another_list = l.pop(index) break I don't know if these are more pythonic, they should be more efficient for longer lists though. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Jan 22, 3:56 am, MRAB wrote: > I was referring to the code: > > for index, record in enumerate(l): > if record['title'] == 'ti': > l.pop(index) > > where you are enumerating and iterating over 'l', but also modifying 'l' > with 'l.pop(index)'. Ack, you're absolutely correct. TP: my mistake, the for loop won't work at all. I'd really recommend using the dictionary-based solution. Apologies all around. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Jan 22, 3:34 am, TP wrote: > > for index, record in enumerate(l): > > if record['title'] == 'ti': > > l.pop(index) > > Ok, I will use this solution. But it is less pythonic than list > comprehensions. Are you asking if it's less pythonic, or asserting? Because you'll find a lot of disagreement here: list comprehensions are used for constructing lists, not manipulating them. > Perhaps you mean rather: > > l = [d for d in l if d['title'] != 'ti'] > ? You are correct. I should never post past 3am :) > In fact, in my case, in cannot use this simple solution, because there are > other fields in each dictionary, not only 2. I was not clear in my post. > So my list is rather: > l=[{"title":"to", "color":"blue", "value":2} > {"title":"ti", "color":"red", "value":"coucou"}] I still find this a lot simpler: records = {'to': {'color': 'blue', 'value': '2'}, 'ti': {'color': 'red', 'value': 'coucou'}} > > It's always better to design for what you know you need, not what you > > may possibly need in the future. > > Ok. Do all the programmers agree with this principle? Have you seen the size of some of the threads here? It's hard to get two programmers to agree on variable names... :) But it's a practice that has served me well and it even has a catchy name[1]. Getting what you -need- to work is effort enough, if you don't have a definite use case for a feature then how do you know you've implemented it correctly? Write it when you need it. 1: http://en.wikipedia.org/wiki/You_Ain%27t_Gonna_Need_It -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
alex23 wrote: On Jan 22, 3:27 am, MRAB wrote: FYI, you shouldn't modify a list you're iterating over. But I'm not. I'm building a new list and binding it to the same name as the original, which works perfectly fine (unless I'm missing something): [snip] I was referring to the code: for index, record in enumerate(l): if record['title'] == 'ti': l.pop(index) where you are enumerating and iterating over 'l', but also modifying 'l' with 'l.pop(index)'. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Jan 22, 3:27 am, MRAB wrote: > FYI, you shouldn't modify a list you're iterating over. But I'm not. I'm building a new list and binding it to the same name as the original, which works perfectly fine (unless I'm missing something): >>> l = range(100) >>> l = [d for d in l if not d % 5] >>> l [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95] > The for-loop was removing the item where there's a match, so the list > comprehension in this case should keep the item where there _isn't_ a match: > > l = [d for d in l if d['title'] != 'ti'] Now that's a mistake. Cheers for the catch. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
alex23 wrote: > Try not to use 'dict' or the name of any of the other built-in types > as labels. Ops... Moreover I know it... > You're stepping through an entire list just to pass another list to > l.remove to step through and remove items from...in fact, given that > list.remove deletes the -first- occurance of the item, you're asking > it to loop through -again- to find the matching element which you've - > already- detected. A better and cleaner approach would be to step > through the list -once- and remove the item when you find it: > > for index, record in enumerate(l): > if record['title'] == 'ti': > l.pop(index) Ok, I will use this solution. But it is less pythonic than list comprehensions. > Or you could just use a list comprehension: > > l = [d for d in l if d['title'] == 'ti'] Perhaps you mean rather: l = [d for d in l if d['title'] != 'ti'] ? In fact, I cannot use this solution, because I want to get back the dictionary with title 'ti', for another use (in fact, to add it to another list, see below). >> Precision: I have stored data in the list of dictionaries l, because in >> my application I am sure that "title" is unique for each record. But >> perhaps it is better to imagine that someday it will not be anymore the >> case? > > It's always better to design for what you know you need, not what you > may possibly need in the future. You say that you are sure that record > titles are unique, so why not use them as the dictionary keys, with > the values as the values: > > records = {'ti': 1, 'to': 2} > > This way your code can be replaced with: > > value = records.pop('ti') # if you want to know the value > del records['ti'] # if you just want to delete the entry > > It's a lot simpler to work with and extend. In fact, in my case, in cannot use this simple solution, because there are other fields in each dictionary, not only 2. I was not clear in my post. So my list is rather: l=[{"title":"to", "color":"blue", "value":2} {"title":"ti", "color":"red", "value":"coucou"}] So, I will rather use your solution: for index, record in enumerate(l): if record['title'] == 'ti': to_add_in_another_list = l.pop(index) another_list.append(to_add_in_another_list ) > It's always better to design for what you know you need, not what you > may possibly need in the future. Ok. Do all the programmers agree with this principle? -- python -c "print ''.join([chr(154 - ord(c)) for c in '*9(9&(18%.\ 9&1+,\'Z4(55l4('])" "When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong." (first law of AC Clarke) -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
alex23 wrote: On Jan 22, 1:16 am, TP wrote: Is the following code pythonic: l=[{"title":"to", "value":2},{"title":"ti","value":"coucou"}] dict = [ dict for dict in l if dict['title']=='ti'] l.remove(*dict) l [{'title': 'to', 'value': 2}] Try not to use 'dict' or the name of any of the other built-in types as labels. You're stepping through an entire list just to pass another list to l.remove to step through and remove items from...in fact, given that list.remove deletes the -first- occurance of the item, you're asking it to loop through -again- to find the matching element which you've - already- detected. A better and cleaner approach would be to step through the list -once- and remove the item when you find it: for index, record in enumerate(l): if record['title'] == 'ti': l.pop(index) [snip] FYI, you shouldn't modify a list you're iterating over. Or you could just use a list comprehension: l = [d for d in l if d['title'] == 'ti'] The for-loop was removing the item where there's a match, so the list comprehension in this case should keep the item where there _isn't_ a match: l = [d for d in l if d['title'] != 'ti'] [remainder snipped] -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Jan 22, 1:16 am, TP wrote: > Is the following code pythonic: > >>> l=[{"title":"to", "value":2},{"title":"ti","value":"coucou"}] > >>> dict = [ dict for dict in l if dict['title']=='ti'] > >>> l.remove(*dict) > >>> l > [{'title': 'to', 'value': 2}] Try not to use 'dict' or the name of any of the other built-in types as labels. You're stepping through an entire list just to pass another list to l.remove to step through and remove items from...in fact, given that list.remove deletes the -first- occurance of the item, you're asking it to loop through -again- to find the matching element which you've - already- detected. A better and cleaner approach would be to step through the list -once- and remove the item when you find it: for index, record in enumerate(l): if record['title'] == 'ti': l.pop(index) Or you could just use a list comprehension: l = [d for d in l if d['title'] == 'ti'] > Precision: I have stored data in the list of dictionaries l, because in my > application I am sure that "title" is unique for each record. But perhaps > it is better to imagine that someday it will not be anymore the case? It's always better to design for what you know you need, not what you may possibly need in the future. You say that you are sure that record titles are unique, so why not use them as the dictionary keys, with the values as the values: records = {'ti': 1, 'to': 2} This way your code can be replaced with: value = records.pop('ti') # if you want to know the value del records['ti'] # if you just want to delete the entry It's a lot simpler to work with and extend. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Wed, 21 Jan 2009 16:16:32 +0100, TP wrote: > > Is the following code pythonic: > l=[{"title":"to", "value":2},{"title":"ti","value":"coucou"}] dict = [ dict for dict in l if dict['title']=='ti'] l.remove(*dict) l > [{'title': 'to', 'value': 2}] > > Precision: I have stored data in the list of dictionaries l, because in my > application I am sure that "title" is unique for each record. But perhaps > it is better to imagine that someday it will not be anymore the case? [snip] 1. You probably don't want to use the name "dict". 2. I believe this code will fail if the number of dictionaries with title="ti" is not exactly 1. It that your intention? (You probably answered this question in the last paragraph quoted above, but I can't make it out.) -- To email me, substitute nowhere->spamcop, invalid->net. -- http://mail.python.org/mailman/listinfo/python-list
is this pythonic?
Hi, Is the following code pythonic: >>> l=[{"title":"to", "value":2},{"title":"ti","value":"coucou"}] >>> dict = [ dict for dict in l if dict['title']=='ti'] >>> l.remove(*dict) >>> l [{'title': 'to', 'value': 2}] Precision: I have stored data in the list of dictionaries l, because in my application I am sure that "title" is unique for each record. But perhaps it is better to imagine that someday it will not be anymore the case? And rather use a data storage as the following? l = { '001':{"title":"to", "value":2}, '002' {"title":"ti","value":"coucou"}} The problem with this storage is that it implies to manipulate some "ids" that have not any meaning for a humain being (001, 002, etc). Thanks a lot for you opinion, -- python -c "print ''.join([chr(154 - ord(c)) for c in '*9(9&(18%.\ 9&1+,\'Z4(55l4('])" "When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong." (first law of AC Clarke) -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
"Bruno Desthuilliers" wrote: >ipyt...@gmail.com a écrit : >> x.validate_output(x.find_text(x.match_filename >> (x.determine_filename_pattern(datetime.datetime.now() >> >> Is it even good programming form? > >functional programming addicts might say yes. But as far as I'm >concerned, I find it a bit too nested... > +1 I would call it onionskin programming. There is of course nothing technically wrong with it, and you can do the same kind of thing in C, but every time I see something like it, my reaction is WTF. - Hendrik -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Dec 18, 8:08 am, ipyt...@gmail.com wrote: > x.validate_output(x.find_text(x.match_filename > (x.determine_filename_pattern(datetime.datetime.now() > > Is it even good programming form? I hope you're kidding. -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Dec 18, 8:45 am, prueba...@latinmail.com wrote: > On Dec 18, 11:08 am, ipyt...@gmail.com wrote: > > > x.validate_output(x.find_text(x.match_filename > > (x.determine_filename_pattern(datetime.datetime.now() > > > Is it even good programming form? > > Lisp and Scheme programmers love that style. You can tell by the > number of parentheses :-). In Python people usually use an > intermediate variable to break things up a bit but the amount of > acceptable nesting is a matter of personal style. I'd say it's fine but breaking up the statement once or twice is a good idea just because if one of the function calls in this nested thing throws an exception, a smaller statement with fewer calls makes for a far more readable traceback. And I hope that this whole statement all lives inside of a method in the same x class, or is a higher-level class that makes use of this behavior? If not, you may want to consider doing so. class X(object): @property def todays_filepattern(self): return self.match_filename( self.determine_filename_pattern( datetime.datetime.now())) def validate_todays_files(self): return self.validate_output(self.find_text (self.todays_filepattern)) -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
On Dec 18, 11:08 am, ipyt...@gmail.com wrote: > x.validate_output(x.find_text(x.match_filename > (x.determine_filename_pattern(datetime.datetime.now() > > Is it even good programming form? Lisp and Scheme programmers love that style. You can tell by the number of parentheses :-). In Python people usually use an intermediate variable to break things up a bit but the amount of acceptable nesting is a matter of personal style. -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
ipyt...@gmail.com wrote: x.validate_output(x.find_text(x.match_filename (x.determine_filename_pattern(datetime.datetime.now() Is it even good programming form? You should try LISP. :-) -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this pythonic?
ipyt...@gmail.com a écrit : x.validate_output(x.find_text(x.match_filename (x.determine_filename_pattern(datetime.datetime.now() Is it even good programming form? functional programming addicts might say yes. But as far as I'm concerned, I find it a bit too nested... -- http://mail.python.org/mailman/listinfo/python-list
Is this pythonic?
x.validate_output(x.find_text(x.match_filename (x.determine_filename_pattern(datetime.datetime.now() Is it even good programming form? -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
[EMAIL PROTECTED] (phil hunt) writes: >>It would (possibly) be more Pythonic to >>define an interface instead, > > Does Python have the concept of an interface? When was that added? It doesn't have one included, but there are at least two implementations, zope.interface and PyProtocols (I'm sure google will find you more on both of these). -- ... with these conditions cam the realisation that ... nothing turned a perfectly normal healthy individual into a great political or military leader better than irreversible brain damage. -- The Hitch-Hikers Guide to the Galaxy, Episode 11 -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
On Tue, 02 Aug 2005 08:31:27 GMT, Michael Hudson <[EMAIL PROTECTED]> wrote: >[EMAIL PROTECTED] (phil hunt) writes: > >> Suppose I'm writing an abstract superclass which will have some >> concrete subclasses. I want to signal in my code that the subclasses >> will implement certan methods. Is this a Pythonic way of doing what >> I have in mind: >> >> class Foo: # abstract superclass >>def bar(self): >> raise Exception, "Implemented by subclass" >>def baz(self): >> raise Exception, "Implemented by subclass" >> >> class Concrete(Foo): >>def bar(self): >> #...actual implemtation... >>def baz(self): >> #...actual implemtation... > >Well, I guess you know this, but if Foo contains no implementation at >all, why inherit from it? (in fact the class I'm using/creating does contain some implementation) >It would (possibly) be more Pythonic to >define an interface instead, Does Python have the concept of an interface? When was that added? -- Email: zen19725 at zen dot co dot uk -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
[EMAIL PROTECTED] (phil hunt) writes: > Suppose I'm writing an abstract superclass which will have some > concrete subclasses. I want to signal in my code that the subclasses > will implement certan methods. Is this a Pythonic way of doing what > I have in mind: > > class Foo: # abstract superclass >def bar(self): > raise Exception, "Implemented by subclass" >def baz(self): > raise Exception, "Implemented by subclass" > > class Concrete(Foo): >def bar(self): > #...actual implemtation... >def baz(self): > #...actual implemtation... Well, I guess you know this, but if Foo contains no implementation at all, why inherit from it? It would (possibly) be more Pythonic to define an interface instead, or just use duck typing. Cheers, mwh -- nonono, while we're making wild conjectures about the behavior of completely irrelevant tasks, we must not also make serious mistakes, or the data might suddenly become statistically valid. -- Erik Naggum, comp.lang.lisp -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
Delaney, Timothy (Tim) wrote: > Peter Hansen wrote: > >> Change those to "raise NotImplementedError('blah')" instead and you'll >> be taking the more idiomatic approach. > > One thing I've noticed, which I may raise on python-dev ... > NotImplementedError does *not* play well with super() ... > > class A (object): > def test (self): > raise NotImplementedError > > class B (object): > def test (self): > print 'B' > super(B, self).test() > > class C (B, A): > def test (self): > print 'C' > super(C, self).test() > > It's actually worse than AttributeError, because the method actually > exists. In both cases though you need to know when you create the base > class how it's going to be used to work out whether a super() call is > needed. > > One option is to do a try: except (AttributeError, NotImplementedError). > Yuk - talk about hiding errors :( Hm... one could return NotImplemented from the abstract method. It won't raise an error immediately, but will certainly be discovered at some point. Not optimal though. Reinhold -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
phil hunt wrote: > That's a clever trick, but it's obvious from the code that the class > is intended to be abstract, so if people are stupid enough to shoot > themselves in the foot by creating an instance, I don't feel like > adding extra code to protect themselves from their stupidity. Right. But even if you're not worried about stupidity, it's useful to have it fail in an explicit way as early as possible, rather than later on. With that addition, the moment you try to create an instance of an abstract class, you get an exception. Even if it's just a typo, and not severe negligence, that helps the problem get fixed sooner, rather than later. -- Erik Max Francis && [EMAIL PROTECTED] && http://www.alcyone.com/max/ San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis Morality is a weakness of the mind. -- Arthur Rimbaud -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
On Mon, 01 Aug 2005 14:07:46 -0700, Erik Max Francis <[EMAIL PROTECTED]> wrote: > >Yes, but raise NotImplementedError instead of Exception. Another trick >you can use is to prevent people from instantiating the abstract class: > > class Foo: > def __init__(self): > if self.__class__ is Foo: > raise NotImplementedError > ... > > def bar(self): > raise NotImplementedError That's a clever trick, but it's obvious from the code that the class is intended to be abstract, so if people are stupid enough to shoot themselves in the foot by creating an instance, I don't feel like adding extra code to protect themselves from their stupidity. -- Email: zen19725 at zen dot co dot uk -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
On Mon, 01 Aug 2005 22:01:06 +0200, Caleb Hattingh <[EMAIL PROTECTED]> wrote: >Peter > >To my mind, this kind of setup (interface class, or abstact class) is more >usually used in static languages to benefit polymorphism - but python is >dynamically typed, so in which situations would this setup be useful in a >python program? You see, I expected your post to say that it wouldn't >even be necessary, but you didn't :) I realise it's not necessary. I just thought it would be nice to document the interfaces my concrete classes will be using. >I have spent a little effort training myself not to bother setting up >class hierarchies like this in python, due to the fact that I use Delphi a >lot at work (I do pretty much the code below to let myself know when an >inherited/abstract class method is being called in error). I started doing OO stuff with Smalltalk, where it isn't necessary, then moved to C++, where it is, and liked it. -- Email: zen19725 at zen dot co dot uk -- http://mail.python.org/mailman/listinfo/python-list
RE: Is this Pythonic?
Peter Hansen wrote: > Change those to "raise NotImplementedError('blah')" instead and you'll > be taking the more idiomatic approach. One thing I've noticed, which I may raise on python-dev ... NotImplementedError does *not* play well with super() ... class A (object): def test (self): raise NotImplementedError class B (object): def test (self): print 'B' super(B, self).test() class C (B, A): def test (self): print 'C' super(C, self).test() It's actually worse than AttributeError, because the method actually exists. In both cases though you need to know when you create the base class how it's going to be used to work out whether a super() call is needed. One option is to do a try: except (AttributeError, NotImplementedError). Yuk - talk about hiding errors :( Tim Delaney -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
On Mon, 01 Aug 2005 12:52:02 -0400, Peter Hansen <[EMAIL PROTECTED]> wrote: >phil hunt wrote: >> Suppose I'm writing an abstract superclass which will have some >> concrete subclasses. I want to signal in my code that the subclasses >> will implement certan methods. Is this a Pythonic way of doing what >> I have in mind: >> >> class Foo: # abstract superclass >>def bar(self): >> raise Exception, "Implemented by subclass" >>def baz(self): >> raise Exception, "Implemented by subclass" > >Change those to "raise NotImplementedError('blah')" instead and you'll >be taking the more idiomatic approach. Ta -- Email: zen19725 at zen dot co dot uk -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
phil hunt wrote: > Suppose I'm writing an abstract superclass which will have some > concrete subclasses. I want to signal in my code that the subclasses > will implement certan methods. Is this a Pythonic way of doing what > I have in mind: > > class Foo: # abstract superclass >def bar(self): > raise Exception, "Implemented by subclass" >def baz(self): > raise Exception, "Implemented by subclass" > > class Concrete(Foo): >def bar(self): > #...actual implemtation... >def baz(self): > #...actual implemtation... Yes, but raise NotImplementedError instead of Exception. Another trick you can use is to prevent people from instantiating the abstract class: class Foo: def __init__(self): if self.__class__ is Foo: raise NotImplementedError ... def bar(self): raise NotImplementedError -- Erik Max Francis && [EMAIL PROTECTED] && http://www.alcyone.com/max/ San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis Everything's gonna be all right / Everything's gonna be okay -- Sweetbox -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
Caleb Hattingh a écrit : > Peter > > To my mind, this kind of setup (interface class, or abstact class are two different things. >) is > more usually used in static languages True. >to benefit polymorphism This is a good reason to use an interface in Java. C++ has no notion of 'interface', so you have to use abstract classes to achieve the same result. > - but > python is dynamically typed, so in which situations would this setup be > useful in a python program? Abstract classes ? When you want to factor out common implementation in a base class and force derived class to implement specific parts. One common use case is the template method (aka "hollywood", aka "don't call us, we'll call you") pattern. > You see, I expected your post to say that > it wouldn't even be necessary, but you didn't :) Implementation inheritance is never "necessary". Nor are OO, modularity, structured programming, and human-readable programming languages !-) It's a fact that inheritence being "only" (err... should I say "mostly" ?) an implementation mechanism in dynamic languages, class hierarchies tends to be much more flat. But this doesn't mean that abstract base classes are useless. > I have spent a little effort training myself not to bother setting up > class hierarchies like this in python I had this pattern too. -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
Peter To my mind, this kind of setup (interface class, or abstact class) is more usually used in static languages to benefit polymorphism - but python is dynamically typed, so in which situations would this setup be useful in a python program? You see, I expected your post to say that it wouldn't even be necessary, but you didn't :) I have spent a little effort training myself not to bother setting up class hierarchies like this in python, due to the fact that I use Delphi a lot at work (I do pretty much the code below to let myself know when an inherited/abstract class method is being called in error). regards Caleb On Mon, 01 Aug 2005 18:52:02 +0200, Peter Hansen <[EMAIL PROTECTED]> wrote: > phil hunt wrote: >> Suppose I'm writing an abstract superclass which will have some >> concrete subclasses. I want to signal in my code that the subclasses >> will implement certan methods. Is this a Pythonic way of doing what I >> have in mind: >> class Foo: # abstract superclass >>def bar(self): >> raise Exception, "Implemented by subclass" >>def baz(self): >> raise Exception, "Implemented by subclass" > > Change those to "raise NotImplementedError('blah')" instead and you'll > be taking the more idiomatic approach. > > -Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
phil hunt wrote: > Suppose I'm writing an abstract superclass which will have some > concrete subclasses. I want to signal in my code that the subclasses > will implement certan methods. Is this a Pythonic way of doing what See http://docs.python.org/lib/module-exceptions.html#l2h-298 (NotImplementedError) -- Benji York -- http://mail.python.org/mailman/listinfo/python-list
Re: Is this Pythonic?
phil hunt wrote: > Suppose I'm writing an abstract superclass which will have some > concrete subclasses. I want to signal in my code that the subclasses > will implement certan methods. Is this a Pythonic way of doing what > I have in mind: > > class Foo: # abstract superclass >def bar(self): > raise Exception, "Implemented by subclass" >def baz(self): > raise Exception, "Implemented by subclass" Change those to "raise NotImplementedError('blah')" instead and you'll be taking the more idiomatic approach. -Peter -- http://mail.python.org/mailman/listinfo/python-list
Is this Pythonic?
Suppose I'm writing an abstract superclass which will have some concrete subclasses. I want to signal in my code that the subclasses will implement certan methods. Is this a Pythonic way of doing what I have in mind: class Foo: # abstract superclass def bar(self): raise Exception, "Implemented by subclass" def baz(self): raise Exception, "Implemented by subclass" class Concrete(Foo): def bar(self): #...actual implemtation... def baz(self): #...actual implemtation... -- Email: zen19725 at zen dot co dot uk -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
"Caleb Hattingh" <[EMAIL PROTECTED]> wrote: >In another > newsgroup, I could have been flamed for letting Simon know he helped > more > than just the OP with his post :) +1 OP asks, thousands are educated (perhaps). The group's generosity is greatly appreciated, even if that appreciation is under-expressed. -Anon (well, sort of) P.S. You mean this list isn't TFM? -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Thu, Jul 21, 2005 at 10:27:24AM -0400, Bill Mill wrote: > On 7/21/05, Steven D'Aprano <[EMAIL PROTECTED]> wrote: > > On Wed, 20 Jul 2005 16:30:10 -0400, Bill Mill wrote: > > > > > On 7/20/05, Simon Brunning <[EMAIL PROTECTED]> wrote: > > >> On 7/20/05, Mage <[EMAIL PROTECTED]> wrote: > > >> > Or is there better way? > > >> > > > >> > for (i, url) in [(i,links[i]) for i in range(len(links))]: > > >> > > >> for i, url in enumerate(links): > > >> > > > > > > +2 for creating seeing a need and crafting a reasonable solution, but > > > -1 for not reading the section on builtins to see if it existed > > > already. > > > > To see if *what* existed already? > > > > It is well and good to say RTFM, but there are 697 subsections to the > > Python Library reference, and if you don't know what you are looking for, > > and beginners rarely are, it isn't obvious which is the right section to > > read. And the Library Reference isn't even "the" manual: there is also the > > global module reference and language reference. > > > > If you already know what you are looking for, reading the manual is great > > advice. Browsing the manual looking for interesting tidbits can even be > > fun for a certain mindset. But if you don't know enough to know what to > > look for, where in the 2000-odd sections of the Python references will > > you find it? > > > > I said the *builtins* section. I think you learn pretty quick that > figuring out what functions are builtins is pretty important in every > language. There's a fair number of people out there giving the advice > to read chapter 2 of the library reference cover-to-cover for a good > starter on python. The quick reference guide is also a nice place to find all the most important information: http://rgruet.free.fr/PQR24/PQR2.4.html > > Furthermore, I wasn't being hard on the guy, he still added up to +1. > Lighten up, I was joking. > > > > > > > > (As for its pythonicity, I would have recommended isolating it into a > > > function and making it a generator: > > > > It is easy to take this to extremes. It isn't necessary to isolate > > everything into its own object, or class, or module. Too much > > encapsulation is just as bad as too little. > > > > agreed; his listcomp just looks awkward inside the for loop statement; > if it were my code, I would put it into a function. He asked if his > code was pythonic, and I think the (non-extreme) pythonic thing to do > would be to put his listcomp into a function. > > > > > > def my_enumerate(enumerable): > > > i = 0 > > > for elt in enumerable: > > > yield (i, elt) > > > i += 1 > > > > > > for i, url in my_enumerate(links): > > > > > > but it's not too bad as it is. Also, my function is completely > > > untested - it's close to right though.) > > > > What is the advantage of your function my_enumerate over the Python > > built-in enumerate? > > > > > > absolutely none; I just was saying how I would encapsulate it into a function. Except that enumerate was introduced in 2.3 so if you are working with an older version of Python it won't be there. > > Peace > Bill Mill > bill.mill at gmail.com > -- > http://mail.python.org/mailman/listinfo/python-list -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
Terry Yes, I must agree with you that it is something I should know. I do try to keep with things but there are always some things that slip through the cracks, like enumerate, in this case. That is why I am extremely grateful the for the activity, generosity and pure knowledge on this newsgroup to fill in the blanks for me. It is guys like you who are willing to take the time to give responses that make it what it is. In another newsgroup, I could have been flamed for letting Simon know he helped more than just the OP with his post :) Thanks Caleb On Wed, 20 Jul 2005 23:41:36 +0200, Terry Reedy <[EMAIL PROTECTED]> wrote: > >> Wow, I didn't know about enumerate. > > It is listed and explained in Lib Ref Manual, Chapter 2, on builtin > functions and types and their methods. Everyone should read at least > that > much of the Lib manual. > > Terry J. Reedy > > > -- http://mail.python.org/mailman/listinfo/python-list
Apology [was: is this pythonic]
It has been suggested to me off-list that my response(s) to Bill Mill in the "is this pythonic" thread were rude and hostile. If that is what people saw in my posts, then I apologise, because that wasn't my intention. In fact, my comments weren't especially even aimed at Bill -- they were intended as more general comments about finding a balance between dismissing questions by pointing to the Python references, and guiding the questioner to learn the skills to be able to use the references effectively. I know I'm not yet at that stage: I still hit road-blocks in knowing where to look at times, and I guess that made me over-sensitive. In hindsight, it would have been better for me to have cut Bill's comments from my reply, and just make allusions to a nebulous "they" who sometimes have a tendency towards using "RTFM" as an answer to anything, because Bill's specific was less dismissive and more supportive than what you can get on many newsgroups. I agree with his basic sentiments, although I might not have worded it in precisely the same way. (Given how I put my foot in it when I did reply, perhaps that's not a bad thing.) My apologies to Bill specifically, and [shameless brown-nosing here] thank you to the comp.lang.python community, which as a whole is far more tolerent than many other forums I've been on. -- Steven. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
"Steven D'Aprano" <[EMAIL PROTECTED]> wrote in message news:[EMAIL PROTECTED] > On Thu, 21 Jul 2005 10:27:24 -0400, Bill Mill wrote: > > [snip] > >> I said the *builtins* section. I think you learn pretty quick that >> figuring out what functions are builtins is pretty important in every >> language. There's a fair number of people out there giving the advice >> to read chapter 2 of the library reference cover-to-cover for a good >> starter on python. Including me. > > Sure. But for a beginner to start learning the language by reading the > language manual is a bit much to ask. Sure, but who is suggesting that. Suggesting that people specifically read chapter 2 of the Library manual (but only that to start -- I probably have still not read every chapter yet) is quite different. > There is no need to get defensive, I was merely commenting on the need to > understand that inexperienced programmers often don't know enough about > the language to know where to start looking for the answer. Which is precise why I try to help by telling them where to start. A large number of beginner queries posted here are answered in the builtins chapter. Terry J. Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Thu, 21 Jul 2005 10:27:24 -0400, Bill Mill wrote: [snip] > I said the *builtins* section. I think you learn pretty quick that > figuring out what functions are builtins is pretty important in every > language. There's a fair number of people out there giving the advice > to read chapter 2 of the library reference cover-to-cover for a good > starter on python. Sure. But for a beginner to start learning the language by reading the language manual is a bit much to ask. Some people can do it, but most learn best by doing, not by reading dry, abstract descriptions of what various functions do. In my experience, iterators and generators don't even make sense until you've spent some time playing with them. > Furthermore, I wasn't being hard on the guy, he still added up to +1. > Lighten up, I was joking. There is no need to get defensive, I was merely commenting on the need to understand that inexperienced programmers often don't know enough about the language to know where to start looking for the answer. In fact, it isn't just inexperienced programmers, but experienced programmers too. I'm sure Guido doesn't need to look up enumerate in the reference manual; but if he wanted to write a program to calculate the positions of the anti-nodes of vibratory modes of the bound-state of a muon and a proton/neutron pair, the odds are pretty good he wouldn't even know where to start looking either :-) The great thing about Usenet and the Internet is that we can pick each other's brains for answers, instead of flailing around blindly in manuals that don't understand the simplest natural language query. And isn't that why we're here? Regards, -- Steven. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Thu, 21 Jul 2005 16:43:00 +0100, Michael Hoffman wrote: > Personally, I feel my time is better served by answering questions that > would not be easy to find without assistance. I can't expect everyone to > know about or expect enumerate() from the beginning, so I don't have any > objections to it being asked here. > > If people were to ask what the function signature for enumerate() was > when that is easy to Google, then I would think they were wasting > everyone's time. And on that, I think we can agree! -- Steven. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
Steven D'Aprano wrote: > The great thing about Usenet and the Internet is that we can pick each > other's brains for answers, instead of flailing around blindly in manuals > that don't understand the simplest natural language query. And isn't that > why we're here? Personally, I feel my time is better served by answering questions that would not be easy to find without assistance. I can't expect everyone to know about or expect enumerate() from the beginning, so I don't have any objections to it being asked here. If people were to ask what the function signature for enumerate() was when that is easy to Google, then I would think they were wasting everyone's time. -- Michael Hoffman -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On 7/21/05, Steven D'Aprano <[EMAIL PROTECTED]> wrote: > On Wed, 20 Jul 2005 16:30:10 -0400, Bill Mill wrote: > > > On 7/20/05, Simon Brunning <[EMAIL PROTECTED]> wrote: > >> On 7/20/05, Mage <[EMAIL PROTECTED]> wrote: > >> > Or is there better way? > >> > > >> > for (i, url) in [(i,links[i]) for i in range(len(links))]: > >> > >> for i, url in enumerate(links): > >> > > > > +2 for creating seeing a need and crafting a reasonable solution, but > > -1 for not reading the section on builtins to see if it existed > > already. > > To see if *what* existed already? > > It is well and good to say RTFM, but there are 697 subsections to the > Python Library reference, and if you don't know what you are looking for, > and beginners rarely are, it isn't obvious which is the right section to > read. And the Library Reference isn't even "the" manual: there is also the > global module reference and language reference. > > If you already know what you are looking for, reading the manual is great > advice. Browsing the manual looking for interesting tidbits can even be > fun for a certain mindset. But if you don't know enough to know what to > look for, where in the 2000-odd sections of the Python references will > you find it? > I said the *builtins* section. I think you learn pretty quick that figuring out what functions are builtins is pretty important in every language. There's a fair number of people out there giving the advice to read chapter 2 of the library reference cover-to-cover for a good starter on python. Furthermore, I wasn't being hard on the guy, he still added up to +1. Lighten up, I was joking. > > > > (As for its pythonicity, I would have recommended isolating it into a > > function and making it a generator: > > It is easy to take this to extremes. It isn't necessary to isolate > everything into its own object, or class, or module. Too much > encapsulation is just as bad as too little. > agreed; his listcomp just looks awkward inside the for loop statement; if it were my code, I would put it into a function. He asked if his code was pythonic, and I think the (non-extreme) pythonic thing to do would be to put his listcomp into a function. > > > def my_enumerate(enumerable): > > i = 0 > > for elt in enumerable: > > yield (i, elt) > > i += 1 > > > > for i, url in my_enumerate(links): > > > > but it's not too bad as it is. Also, my function is completely > > untested - it's close to right though.) > > What is the advantage of your function my_enumerate over the Python > built-in enumerate? > > absolutely none; I just was saying how I would encapsulate it into a function. Peace Bill Mill bill.mill at gmail.com -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On Wed, 20 Jul 2005 16:30:10 -0400, Bill Mill wrote: > On 7/20/05, Simon Brunning <[EMAIL PROTECTED]> wrote: >> On 7/20/05, Mage <[EMAIL PROTECTED]> wrote: >> > Or is there better way? >> > >> > for (i, url) in [(i,links[i]) for i in range(len(links))]: >> >> for i, url in enumerate(links): >> > > +2 for creating seeing a need and crafting a reasonable solution, but > -1 for not reading the section on builtins to see if it existed > already. To see if *what* existed already? It is well and good to say RTFM, but there are 697 subsections to the Python Library reference, and if you don't know what you are looking for, and beginners rarely are, it isn't obvious which is the right section to read. And the Library Reference isn't even "the" manual: there is also the global module reference and language reference. If you already know what you are looking for, reading the manual is great advice. Browsing the manual looking for interesting tidbits can even be fun for a certain mindset. But if you don't know enough to know what to look for, where in the 2000-odd sections of the Python references will you find it? > (As for its pythonicity, I would have recommended isolating it into a > function and making it a generator: It is easy to take this to extremes. It isn't necessary to isolate everything into its own object, or class, or module. Too much encapsulation is just as bad as too little. > def my_enumerate(enumerable): > i = 0 > for elt in enumerable: > yield (i, elt) > i += 1 > > for i, url in my_enumerate(links): > > but it's not too bad as it is. Also, my function is completely > untested - it's close to right though.) What is the advantage of your function my_enumerate over the Python built-in enumerate? -- Steven. -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
Mage wrote: > Or is there better way? > > for (i, url) in [(i,links[i]) for i in range(len(links))]: > ... > > "links" is a list. for i, url in enumerate(links): -- Thomas -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
Terry Reedy wrote: >>Wow, I didn't know about enumerate. > > It is listed and explained in Lib Ref Manual, Chapter 2, on builtin > functions and types and their methods. Everyone should read at least that > much of the Lib manual. Or be sure to read the "What's New in Python X.Y" pages that are released with new versions of Python, to stay current. Then read them again a few months later. Then again when you finally get around to installing the new version (if you lag behind). And again a few months later... ;-) -Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
> Wow, I didn't know about enumerate. It is listed and explained in Lib Ref Manual, Chapter 2, on builtin functions and types and their methods. Everyone should read at least that much of the Lib manual. Terry J. Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On 7/20/05, Bill Mill <[EMAIL PROTECTED]> wrote: > On 7/20/05, Simon Brunning <[EMAIL PROTECTED]> wrote: > > On 7/20/05, Mage <[EMAIL PROTECTED]> wrote: > > > Or is there better way? > > > > > > for (i, url) in [(i,links[i]) for i in range(len(links))]: > > > > for i, url in enumerate(links): > > > > +2 for creating seeing a need and crafting a reasonable solution, but > -1 for not reading the section on builtins to see if it existed > already. > -1 for me for not reading over my email before sending. "creating seeing" should be "seeing". Peace Bill Mill bill.mill at gmail.com -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On 7/20/05, Simon Brunning <[EMAIL PROTECTED]> wrote: > On 7/20/05, Mage <[EMAIL PROTECTED]> wrote: > > Or is there better way? > > > > for (i, url) in [(i,links[i]) for i in range(len(links))]: > > for i, url in enumerate(links): > +2 for creating seeing a need and crafting a reasonable solution, but -1 for not reading the section on builtins to see if it existed already. (As for its pythonicity, I would have recommended isolating it into a function and making it a generator: def my_enumerate(enumerable): i = 0 for elt in enumerable: yield (i, elt) i += 1 for i, url in my_enumerate(links): but it's not too bad as it is. Also, my function is completely untested - it's close to right though.) Peace Bill Mill -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
Wow, I didn't know about enumerate. Many thanks Caleb On Wed, 20 Jul 2005 15:19:50 +0200, Simon Brunning <[EMAIL PROTECTED]> wrote: > On 7/20/05, Mage <[EMAIL PROTECTED]> wrote: >> Or is there better way? >> >> for (i, url) in [(i,links[i]) for i in range(len(links))]: > > for i, url in enumerate(links): > -- http://mail.python.org/mailman/listinfo/python-list
Re: is this pythonic?
On 7/20/05, Mage <[EMAIL PROTECTED]> wrote: > Or is there better way? > > for (i, url) in [(i,links[i]) for i in range(len(links))]: for i, url in enumerate(links): -- Cheers, Simon B, [EMAIL PROTECTED], http://www.brunningonline.net/simon/blog/ -- http://mail.python.org/mailman/listinfo/python-list
is this pythonic?
Or is there better way? for (i, url) in [(i,links[i]) for i in range(len(links))]: ... "links" is a list. Mage -- http://mail.python.org/mailman/listinfo/python-list