Re: [Python-Dev] PEP 246, redux
The volume of these discussions is (as expected) growing beyond any reasonable bounds; I hope the BDFL can find time to read them but I'm starting to doubt he will. Since obviously we're not going to convince each other, and it seems to me we're at least getting close to pinpointing our differences, maybe we should try to jointly develop an "executive summary" of our differences and briefly stated pros and cons -- a PEP is _supposed_ to have such a section, after all. Anyway, for now, here goes another LONG mail...: On 2005 Jan 10, at 22:38, Phillip J. Eby wrote: ... If interfaces can ensure against Liskov violations in instances of their subclasses, then they can follow the "case (a)" fast path, sure. Inheriting from an interface (in Guido's current proposal, as per his Artima blog) is a serious commitment from the inheritor's part; inheriting from an ordinary type, in real-world current practice, need not be -- too many cases of assumed covariance, for example, are around in the wild, to leave NO recourse in such cases and just assume compliance. I understand that, sure. But I don't understand why we should add complexity to PEP 246 to support not one but *two* bad practices: 1) implementing Liskov violations and 2) adapting to concrete classes. It is only if you are doing *both* of these that this extra feature is needed. s/support/deal with/ . If I was designing a "greenfield" system, I'd love nothing better than making a serious split between concrete classes (directly instantiable), abstract classes (subclassable), and protocols (adaptable-to). Scott Meyer's suggestion, in one of his Effective C++ books, to never subclass a concrete class, has much to recommend itself, in particular. But in the real world people do want to subclass concrete classes, just as much as they want covariance AND, I'll bet, adapting to classes, too, not just to interfaces seen as a separate category from classes. I think PEP 246 should deal with the real world. If the BDFL thinks otherwise, and believes that in this case Python should impose best practices rather than pragmatically deal with the way people's minds (as opposed to type-system maths) appear to work, I'll be glad to recast the PEP in that light. Contrary to what you state, adapting to concrete (instantiable) classes rather than abstract (not directly instantiable) one is not necessary to make the mechanism required, by the way. Consider an abstract class such as: class Abstract(object): def tp1(self): ''' template method 1 (calls hook method 1) ''' def tp2(self): ''' template method 2 (calls hook method 2) ''' def hook1(self): raise NotImplementedError def hook2(self): raise NotImplementedError One could subclass it just to get tp1...: class Dubious(Abstract): def hook1(self): ''' implementing just hook1 ''' Now, instantiating d=Dubious() is dubious practice, but, absent specific checks, it "works", as long as only d.hook1() and d.tp1() are ever called -- never d.hook2() nor d.tp2(). I would like adapt(d, Abstract) to fail. I'm not claiming that the ability to have a __conform__ method in Dubious to specifically block this adaptation is anywhere like a perfect solution, mind you -- it does require some change to the source of Dubious, for example. I'm just saying that I think it's better than nothing, and that is where we seem to disagree. If it were to support some kind of backward compatibility, that would be understandable. However, in practice, I don't know of anybody using adapt(x,ConcreteClass), and even if they did, the person subclassing ConcreteClass will need to change their subclass to raise LiskovViolation, so why not just switch to delegation? Because delegation doesn't give you _easy_ access to Template Method design patterns which may well be the one reason you're subclassing Abstract in the first place. TP hinges on a method calling some self.dothis(), self.dothat() hook methods; to get it via delegation rather than inheritance requires a more complicated arrangement where that 'self' actually belongs to a "private" concrete class which delegates some things back to the "real" class. In practice, inheritance as a means of code reuse (rather than as a pristine Liskovian assertion of purity) is quite popular because of that. C++ essentially acknowledges this fact by allowing _private_ inheritance, essentially meaning "I'm reusing that code but don't really mean to assert IS-A"; the effects of private inheritance could be simulated by delegation to a private auxiliary class, but the extra indirections and complications aren't negligible costs in terms of code complexity and maintainability. In Python, we don't distinguish between private inheritance (to just reuse code) and ordinary inheritance (assumed to imply Liskov sub.), but that doesn't make the need go away. The __conform__ raising LiskovViolation could be seen as a way
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 10, at 23:19, Phillip J. Eby wrote: ... As I said, after more thought, I'm actually less concerned about the performance than I am about even remotely encouraging the combination of Liskov violation *and* concrete adaptation As per other msg, abstract classes have just the same issues as concrete ones. If Ka-Ping Yee's idea (per Artima cmts on BDFL blog) of having interfaces supply template methods too ever flies, the issue would arise there, too (a BDFL comment with a -1 suggests it won't fly, though). targets. But, if "after the dust settles" it turns out this is going to be supported after all, then we can worry about the performance if need be. Note, however, that your statements actually support the idea of *not* adding a special case for Liskov violators. If newer code uses interfaces, the Liskov-violation mechanism is useless. If older code doesn't have __conform__, it cannot possibly *use* the Liskov-violation mechanism. Adding __conform__ to a class to raise a LiskovViolation when needed is a TINY change compared to the refactoring needed to use template-methods without subclassing. Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 10, at 23:15, Thomas Heller wrote: Alex Martelli <[EMAIL PROTECTED]> writes: PEP: 246 Title: Object Adaptation Minor nit (or not?): You could provide a pointer to the Liskov substitution principle, for those reader that aren't too familiar with that term. Excellent idea, thanks. Besides, the text mentions three times that LiskovViolation is a subclass of AdaptionError (plus once in the ref impl section). Always hard to strike a balance between what's repeated and what isn't, I'll try to get a better one on this point on the next edit. Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 10, at 19:34, Phillip J. Eby wrote: ... IMO it's more desirable to support abstract base classes than to allow classes to "opt out" of inheritance when testing conformance to a base class. If you don't have an "is-a" relationship to your base class, you should be using delegation, not inheritance. (E.g. 'set' has-a 'dict', not 'set' is-a 'dict', so 'adapt(set,dict)' should fail, at least on the basis of isinstance checking.) C++'s private inheritance explicitly acknowledges how HANDY subclassing can be for pure implementation purposes; we don't have private inheritance but that doesn't mean subclassing becomes any less handy;-) The other problem with a Liskov opt-out is that you have to explicitly do a fair amount of work to create a LiskovViolation-raising subclass; A TINY amount of work. Specifically, starting from: class X(Abstract): """ most of X omitted """ def hook1(self): """ implement hook1 so as to get tm1 from Abstract """ if self.foo() > self.bar(): self.baz() else: self.fie = self.flup - self.flum return self.zap() all you have to do is ADD def __conform__(self, protocol): if issubclass(protocol, Abstract): raise LiskovViolation that's all. (See my big post about what Abstract is, with template methods tm1 and tm2 respectively using hook methods hook1 and hook2: X doesn't implement hook2). that work would be better spent migrating to use delegation instead of inheritance, which would also be cleaner and more comprehensible code than writing a __conform__ hack to announce your bad style in having chosen to use inheritance where delegation is more appropriate. ;) The amount of effort is MUCH vaster. Essentially RECODE everything so s/thing like: class X(object): """ most of X omitted """ class PrivateAuxiliaryClass(Abstract): def __init__(self, x): self.x = x def hook1(self): return self.x.hook1() def __init__(self): self.pac = self.PrivateAuxiliaryClass(self) # rest of X.__init__ omitted def tm1(self): return self.pac.tm1() this isn't just a tiny band-aid to say "I really wish the language had private inheritance because I'm using Abstract as a base just for code reuse" -- it's a rich and complex restructuring, and in fact it's just the beginning; now you have a deuced reference loop between each instance x of X, and its x.pac, so you'll probably want to pull in weakref, too, to avoid giving too much work to the cyclical garbage collector. Basically, rephrasing private inheritance with containment and delegation is a lot of messy work, and results in far more complicated structures. And instead of paying the tiny price of a __conform__ call at adaptation time, you pay the price of delegating calls over and over at each x.tm1() call, so it's unlikely performance will improve. By pushing Liskov conformance without supporting "private inheritance" or its equivalent, you're really pushing people to use much more complicated and sophisticated structures of objects than "private inheritance" affords when properly used... and the LAST thing OO programmers need is any encouragement towards more complicated structures!-) Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 10, at 18:59, Phillip J. Eby wrote: At 12:43 PM 1/10/05 -0500, Phillip J. Eby wrote: As a practical matter, all of the existing interface systems (Zope, PyProtocols, and even the defunct Twisted implementation) treat interface inheritance as guaranteeing substitutability for the base interface, and do so transitively. An additional data point, by the way: the Eclipse Java IDE has an adaptation system that works very much like PEP 246 does, and it appears that in a future release they intend to support automatic adapter transitivity, so as to avoid requiring each provider of an interface to "provide O(n^2) adapters when writing the nth version of an interface." IOW, their current release is transitive only for interface inheritance ala Zope or Twisted; their future release will be transitive for adapter chains ala PyProtocols. This is definitely relevant prior art, so thanks for pointing it out. If interfaces change so often that 'n' can become worryingly high, this is a valid concern. In my world, though, published interfaces do NOT change as often as to require such remedies;-). Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 11, at 11:01, Alex Martelli wrote: On 2005 Jan 10, at 18:59, Phillip J. Eby wrote: At 12:43 PM 1/10/05 -0500, Phillip J. Eby wrote: As a practical matter, all of the existing interface systems (Zope, PyProtocols, and even the defunct Twisted implementation) treat interface inheritance as guaranteeing substitutability for the base interface, and do so transitively. An additional data point, by the way: the Eclipse Java IDE has an adaptation system that works very much like PEP 246 does, and it appears that in a future release they intend to support automatic adapter transitivity, so as to avoid requiring each provider of an interface to "provide O(n^2) adapters when writing the nth version of an interface." IOW, their current release is transitive only for interface inheritance ala Zope or Twisted; their future release will be transitive for adapter chains ala PyProtocols. This is definitely relevant prior art, so thanks for pointing it out. If interfaces change so often that 'n' can become worryingly high, this is a valid concern. In my world, though, published interfaces do NOT change as often as to require such remedies;-). ...that was a bit too flippant -- I apologize. It DOES happen that interfaces keep changing, and other situations where "adapter-chain transitivity" is quite handy do, absolutely!, occur, too. Reflecting on Microsoft's QI (QueryInterface), based on a very strong injunction against changing interfaces and yet mandating transitivity, points that out -- that's prior art, too, and a LOT more of it than Eclipse can accumulate any time soon, considering how long COM has been at the heart of Microsoft's components strategy, how many millions of programmers have used or abused it. Still, QI's set of constraints, amounting to a full-fledged equivalence relationship among all the "adapters" for a single underlying "object", is, I fear, stronger than we can impose (so it may be that Eclipse is a better parallel, but I know little of it while COM is in my bones, so that's what I keep thinking of;-). So, I see transitivity as a nice thing to have _IF_ it's something that gets explicitly asserted for a certain adapter -- if the adapter has to explicitly state to the system that it "isn't lossy" (maybe), or "isn't noisy" (perhaps more useful), or something like that... some amount of reassurance about the adapter that makes it fully safe to use in such a chain. Maybe it might suffice to let an adapter which IS 'lossy' (or, more likely, one that is 'noisy') state the fact. I'm always reluctant by instinct to default to convenient but risky behavior, trusting programmers to explicitly assert otherwise when needed; but in many ways this kind of design is a part of Python and works fine (_with_ the BDFL's fine nose/instinct for making the right compromise between convenience and safety in each case, of course). I'm still pondering the "don't adapt an adapter" suggestion, which seems a sound one, and yet also seems to be, intrinsically, what transitivity-by-chaining does. Note that QI does not suffer from this, because it lets you get the underlying object identity (IUnknown) from any interface adapter. Maybe, just maybe, we should also consider that -- a distinguished protocol bereft of any real substance but acting as a flag for "real unadapted object identity". Perhaps we could use 'object' for that, at least if the flow of logic in 'adapt' stays as in the current PEP 246 draft (i.e., __conform__ is given a chance before isinstance triggers -- so, all adapters could __conform__ to object by returning the underlying object being adapted, while other objects without such a feature in __conform__ would end up with 'adapt(x, object) is x'). Or, if object in this role turns out to be confusing, IDentity (;-) or some other specially designed protocol. If we had this ability to "get at the underlying object" we could at least write clearer axioms about what transitivity must mean, as well as, help out with the "adapting an adapter" problems. E.g., imagine: def f(x: IFoo, y: IFoo): if x is y: ... that wouldn't work if adapt(x, IFoo) returns a separate adapter each time, which is the most likely situation (think, again, of str->file adaptation by StringIO wrapping); but recovering underlying identities by "adapt(x, object) is adapt(y, object)" would work. I don't think that IUnknown or an equivalent, per se, can do *instead* of the need to have an adapter explicitly state it's non-noisy (or VV). Besides the need to check for object identity, which is pretty rare except when writing axioms, invariants or pre/post-conds;-), the IUnknown equivalent would perhaps be more of a conceptual/philosophical 'prop' than a practically useful feature -- while I see the ability to block unintended consequences of inheritance and transitivity (or even better, state explicitly when those consequences are wanted, even if that shoul
Re: [Python-Dev] PEP 246, redux
Hi Phillip, On Mon, Jan 10, 2005 at 04:38:55PM -0500, Phillip J. Eby wrote: > Your new proposal does not actually fix this problem in the absence of > tp_conform/tp_adapt slots; it merely substitutes possible confusion at the > metaclass/class level for confusion at the class/instance level. I think that what Alex has in mind is that the __adapt__() and __conform__() methods should work just like all other special methods for new-style classes. The confusion comes from the fact that the reference implementation doesn't do that. It should be fixed by replacing: conform = getattr(type(obj), '__conform__', None) with: for basecls in type(obj).__mro__: if '__conform__' in basecls.__dict__: conform = basecls.__dict__['__conform__'] break else: # not found and the same for '__adapt__'. The point about tp_xxx slots is that when implemented in C with slots, you get the latter (correct) effect for free. This is how metaconfusion is avoided in post-2.2 Python. Using getattr() for that is essentially broken. Trying to call the method and catching TypeErrors seems pretty fragile -- e.g. if you are calling a __conform__() which is implemented in C you won't get a Python frame in the traceback either. A bientot, Armin ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PATCH/RFC for AF_NETLINK support
On Tue, 11 Jan 2005 08:54:42 +0100, "\"Martin v. Löwis\"" <[EMAIL PROTECTED]> wrote: >Philippe Biondi wrote: > > I've done a small patch to use linux AF_NETLINK sockets (see below). > > Please comment! > > I have a high-level comment - python-dev is normally the wrong place > for patches; please submit them to sf.net/projects/python instead. > > Apart from that, the patch looks fine. > > > Is there a reason for recvmsg() and sendmsg() not to be implemented > > yet in socketmodule ? > > I'm not sure what you mean by "implemented": these functions are > implemented by the operating system, not in the socketmodule. > > If you ask "why are they not exposed to Python yet?": There has been no > need to do so, so far. What do I get with recvmsg that I cannot get with > recv/recvfrom just as well? Everything that recvmsg() does. recv() and recvfrom() give you "regular" bytes - data sent to the socket using send() or sendto(). recvmsg() gives you messages - data sent to the socket using sendmsg(). There is no way to receive messages by using recv() or recvfrom() (and no way to send them using send() or sendto()). Inversely, I believe send() and recv() can be implemented in terms of sendmsg() and recvmsg(). Perhaps we should get rid of socket.send() and socket.recv()? Other things that sendmsg() and recvmsg() can do include passing file descriptors, receiving notice of OOB TCP data, peek at bytes from the kernel's buffer without actually reading them, and implement scatter/gather IO functions (although you'd probably just want to wrap and use writev() and readv() instead). Jp ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PATCH/RFC for AF_NETLINK support
On Tue, 11 Jan 2005 01:32:52 +, David Wilson <[EMAIL PROTECTED]> wrote: >On Mon, Jan 10, 2005 at 05:17:49PM +0100, Philippe Biondi wrote: > > > I've done a small patch to use linux AF_NETLINK sockets (see below). > > Please comment! > > As of 2.6.10, a very useful new netlink family was merged - > NETLINK_KOBJECT_UEVENT. I'd imagine quite a lot of interest from Python > developers for NETLINK support will come from this new interface in the > coming years. > > [snip] > > I would like to see (optional?) support for this before your patch is > merged. I have a long-term interest in a Python-based service control / > init replacement / system management application, for use in specialised > environments. I could definately use this. :) Useful indeed, but I'm not sure why basic NETLINK support should be held up for it? Jp ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PATCH/RFC for AF_NETLINK support
On Tue, 11 Jan 2005, [ISO-8859-1] "Martin v. Löwis" wrote: > Philippe Biondi wrote: > > I've done a small patch to use linux AF_NETLINK sockets (see below). > > Please comment! > > I have a high-level comment - python-dev is normally the wrong place > for patches; please submit them to sf.net/projects/python instead. OK, I'll post it here. > > Apart from that, the patch looks fine. Fine! > > > Is there a reason for recvmsg() and sendmsg() not to be implemented > > yet in socketmodule ? > > I'm not sure what you mean by "implemented": these functions are > implemented by the operating system, not in the socketmodule. > > If you ask "why are they not exposed to Python yet?": There has been no > need to do so, so far. What do I get with recvmsg that I cannot get with > recv/recvfrom just as well? You can have access to ancillary messages. You can, for example transmit credentials or file descriptors through unix sockets, which is very interesting for privilege separation. -- Philippe Biondi SecDev.org Security Consultant/R&D http://www.secdev.org PGP KeyID:3D9A43E2 FingerPrint:C40A772533730E39330DC0985EE8FF5F3D9A43E2 ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
At 12:41 PM 1/11/05 +, Armin Rigo wrote: The point about tp_xxx slots is that when implemented in C with slots, you get the latter (correct) effect for free. This is how metaconfusion is avoided in post-2.2 Python. Using getattr() for that is essentially broken. Trying to call the method and catching TypeErrors seems pretty fragile -- e.g. if you are calling a __conform__() which is implemented in C you won't get a Python frame in the traceback either. An excellent point. The issue hasn't come up before now, though, because there aren't any __conform__ methods written in C in the field that I know of. Presumably, if there are any added to CPython in future, it will be because there's a tp_conform slot and it's needed for built-in types, in which case the problem is again moot for the implementation. (FYI, C methods implemented in Pyrex add a dummy frame to the traceback such that you see the file and line number of the original Pyrex source code. Very handy for debugging.) Anyway, I agree that your version of the code should be used to form the reference implementation, since the purpose of the reference implementation is to show the complete required semantics. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 11, at 16:34, Phillip J. Eby wrote: ... Anyway, I agree that your version of the code should be used to form the reference implementation, since the purpose of the reference implementation is to show the complete required semantics. Great, one point at last on which we fully agree -- thanks Armin!-) I was waiting for BDFL feedback before editing the PEP again, but if none is forthcoming I guess at some point I'll go ahead and at least to the edits that are apparently not controversial, like this one. I'd like to have a summary of controversial points and short pro and con args, too, but I'm not unbiased enough to write it all by myself...;-) Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] PEP 246, redux
Phillip: I think you must inhabit a far more perfect world than I do. You say, for instance, that: > ...-1 if this introduces a performance penalty [...] just to > support people who want to create deliberate Liskov violations. > I personally don't think that we should pander to Liskov > violators ... but in my world, people violate Liskov all the time, even in languages that attempt (unsuccessfully) to enforce it. [1] You say that: > I think one should adapt primarily to interfaces, and > interface-to-interface adaptation should be reserved for > non-lossy, non-noisy adapters. ... but in my world, half the time I'm using adaptation to correct for the fact that someone else's poorly-written code requests some class where it should have just used an interface. You seem to inhabit a world in which transitivity of adaptation can be enforced. But in my world, people occasionally misuse adaptation because they think they know what they're doing or because they're in a big hurry and it's the most convenient tool at hand. I wish I lived in your world, but I don't. -- Michael Chermside [1] - Except for Eiffel. Eiffel seems to do a pretty good job of enforcing it. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] logging class submission
Dear people on the dev list!
I hope that this is the right environment to post my submission request
(I'm new to the scene).
I have modified the RotatingFileHandler of the logging module to create
a daily rolling file handler.
As it works quite good, I would like to suggest inclusion into the
standard logging module of Python. I know that the code is quite trivial
but the class solves the problem of the RotatingFileHandler that you
don't know where to find a certain log entry. By using dates within the
log file name, one can exactly determine which log file to observe when
searching for specific errors.
I hope you like to code and/ or point to improvements on it and finally
move it into the logging module.
cheers,
Stephan
Here comes the code:
# Copyright 2004-2005 by Stephan Stapel <[EMAIL PROTECTED]>. All
Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and that
# both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of Stephan Stapel
# not be used in advertising or publicity pertaining to distribution
# of the software without specific, written prior permission.
#
# STEPHAN STAPEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# STEPHAN STAPEL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER
# IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
OUT
# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import logging
from datetime import date
import string
class DailyRollingFileHandler(logging.FileHandler):
"""
The class is based on the standard RotatingFileHandler class from the
official logging module.
It rolls over each day, thus one log file per day is created in the
form
myapp-2005-01-07.log, myapp-2005-01-08.log etc.
"""
def __init__(self, filename, mode="a"):
"""
Open the specified file and use it as the stream for logging.
Rollover occurs whenever the day changes.
The names of the log files each contain the date when they were
created. Thus if the filename "myapp.log" was used, the log files
each have look like myapp-2005-01-07.log etc.
The date is inserted at the position of the last '.' in the
filename
if any or simply appended to the given name if no dot was present.
"""
self.currentDay = date.today()
# create the logfile name parts (base part and extension)
nameparts = string.split(string.strip(filename), ".")
self.filestub = ""
self.fileext = ""
# remove empty items
while nameparts.count("") > 0:
nameparts.remove("")
if len(nameparts) < 2:
self.filestub = nameparts[0]
else:
# construct the filename
for part in nameparts[0:-2]:
self.filestub += part + "."
self.filestub += nameparts[-2]
self.fileext = "." + nameparts[-1]
logging.FileHandler.__init__(self, self.getFilename(), mode)
def getFilename(self):
return self.filestub + "-" + self.currentDay.isoformat() +
self.fileext
def doRollover(self):
"""
Do a rollover, as described in __init__().
"""
self.stream.close()
self.currentDay = date.today()
self.baseFilename = self.getFilename()
self.stream = open(self.baseFilename, "w")
def emit(self, record):
"""
Emit a record.
Output the record to the file, catering for rollover as described
in doRollover().
"""
msg = "%s\n" % self.format(record)
self.stream.seek(0, 2) #due to non-posix-compliant Windows
feature
if date.today() != self.currentDay:
self.doRollover()
logging.FileHandler.emit(self, record)
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] logging class submission
Title: RE: [Python-Dev] logging class submission [Stephan Stapel] #- # Copyright 2004-2005 by Stephan Stapel <[EMAIL PROTECTED]>. All #- Rights Reserved. #- # #- # Permission to use, copy, modify, and distribute this #- software and its #- # documentation for any purpose and without fee is hereby granted, #- # provided that the above copyright notice appear in all #- copies and that #- # both that copyright notice and this permission notice appear in #- # supporting documentation, and that the name of Stephan Stapel #- # not be used in advertising or publicity pertaining to distribution #- # of the software without specific, written prior permission. There's a license issue here? . Facundo Bitácora De Vuelo: http://www.taniquetil.com.ar/plog PyAr - Python Argentina: http://pyar.decode.com.ar/ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ADVERTENCIA. La información contenida en este mensaje y cualquier archivo anexo al mismo, son para uso exclusivo del destinatario y pueden contener información confidencial o propietaria, cuya divulgación es sancionada por la ley. Si Ud. No es uno de los destinatarios consignados o la persona responsable de hacer llegar este mensaje a los destinatarios consignados, no está autorizado a divulgar, copiar, distribuir o retener información (o parte de ella) contenida en este mensaje. Por favor notifíquenos respondiendo al remitente, borre el mensaje original y borre las copias (impresas o grabadas en cualquier medio magnético) que pueda haber realizado del mismo. Todas las opiniones contenidas en este mail son propias del autor del mensaje y no necesariamente coinciden con las de Telefónica Comunicaciones Personales S.A. o alguna empresa asociada. Los mensajes electrónicos pueden ser alterados, motivo por el cual Telefónica Comunicaciones Personales S.A. no aceptará ninguna obligación cualquiera sea el resultante de este mensaje. Muchas Gracias. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 11, at 18:27, Michael Chermside wrote: ... ... but in my world, people violate Liskov all the time, even in languages that attempt (unsuccessfully) to enforce it. [1] ... [1] - Except for Eiffel. Eiffel seems to do a pretty good job of enforcing it. ...has Eiffel stopped its heroic efforts to support covariance...? It's been years since I last looked seriously into Eiffel (it was one of the languages we considered as a successor to Fortran and C as main application language, at my previous employer), but at that time that was one of the main differences between Eiffel (then commercial-only) and its imitator (freeware) Sather: Sather succumbed to mathematical type-theory and enforced contravariance, Effel still tried to pander for how the human mind works by allowing covariance (which implies a Liskov violation and is probably the main serious reason for it) and striving horrendously to shoehorn it in. So what's the score now...? Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
At 10:34 AM 1/11/05 +0100, Alex Martelli wrote:
The volume of these discussions is (as expected) growing beyond any
reasonable bounds; I hope the BDFL can find time to read them but I'm
starting to doubt he will. Since obviously we're not going to convince
each other, and it seems to me we're at least getting close to pinpointing
our differences, maybe we should try to jointly develop an "executive
summary" of our differences and briefly stated pros and cons -- a PEP is
_supposed_ to have such a section, after all.
Yes, hopefully we will have sufficient convergence to do that soon. For
example, I'm going to stop arguing against the use case for Liskov
violation, and try looking at alternative implementations. If those don't
work out, I'll stop objecting to that item altogether.
the effects of private inheritance could be simulated by delegation to a
private auxiliary class, but the extra indirections and complications
aren't negligible costs in terms of code complexity and maintainability.
Ah. Well, in PEAK, delegation of methods or even read-only attributes is
trivial:
class SomeObj(object):
meth1 = meth2 = meth3 = binding.Delegate('_delegatee')
_delegatee = binding.Make(OtherClass)
This class will create a private instance of OtherClass for a given SomeObj
instance the first time meth1, meth2, or meth3 are retrieved from that
instance.
I bring this up not to say that people should use PEAK for this, just
explaining why my perspective was biased; I'm so used to doing this that I
tend to forget it's nontrivial if you don't already have these sorts of
descriptors available.
Maybe the ability to ``fake'' __class__ can help, but right now I don't
see how, because setting __class__ isn't fake at all -- it really affects
object behavior and type:
...
So, it doesn't seem to offer a way to fake out isinstance only, without
otherwise affecting behavior.
Python 2.3.4 (#53, May 25 2004, 21:17:02) [MSC v.1200 32 bit (Intel)] on
win32
Type "copyright", "credits" or "license()" for more information.
>>> class Phony(object):
def getClass(self): return Dummy
__class__ = property(getClass)
>>> class Dummy: pass
>>> Phony().__class__
>>> isinstance(Phony(),Dummy)
True
Unfortunately, this still doesn't really help, because isinstance() seems
to apply to a union of __class__ and type:
>>> isinstance(Phony(),Phony)
True
So, lying about __class__ doesn't fix the issue because you're still
considered isinstance, unless adapt() just uses __class__ and doesn't use
isinstance().
I can give no example at all in which adapting to a concrete class is a
_good_ idea, and I tried to indicate that in the PEP. I just believe that
if adaptation does not offer the possibility of using concrete classes as
protocols, but rather requires the usage as protocols of some specially
blessed 'interface' objects or whatever, then PEP 246 will never fly, (a)
because it would then require waiting for the interface thingies to
appear, and (b) because people will find it pragmatically useful to just
reuse the same classes as protocols too, and too limiting to have to
design protocols specifically instead.
Okay, I strongly disagree on this point, because there are people using
zope.interface and PyProtocols today, and they are *not* using concrete
classes. If PEP 246 were to go into Python 2.5 without interface types,
all that would change is that Zope and PyProtocols would check to see if
there is an adapt() in builtins and, if not, install their own version.
PEP 246 would certainly be more useful *with* some kind of interface type,
but Guido has strongly implied that PEP 246 won't be going in *without*
some kind of interface type, so it seems to me academic to say that PEP 246
needs adaptation to concrete types based on isinstance().
In fact, maybe we should drop isinstance() from PEP 246 altogether, and
only use __conform__ and __adapt__ to implement adaptation. Thus, to say
that you conform to a concrete type, you have to implement __conform__. If
this is done, then an abstract base used as an interface can have a
__conform__ that answers 'self' for the abstract base used as a protocol,
and a Liskov-violating subclass can return 'None' for the abstract
base. Inheritance of __conform__ will do the rest.
This approach allows concrete classes and Liskov violations, but simplifies
adapt() since it drops the need for isinstance and for the Liskov
exception. Further, we could have a default object.__conform__ that does
the isinstance check. Then, a Liskov-violating subclass just overrides
that __conform__ to block the inheritance it wants to block.
This approach can't work with a separately-distributed PEP 246
implementation, but it should work quite well for a built-in implementation
and it's backward compatible with the semantics expected by "old" PEP 246
implementations. It means that all objects will have a tp_conform slot
that will hav
RE: [Python-Dev] logging class submission
Title: RE: [Python-Dev] logging class submission [Stephan Stapel] #- > There's a license issue here? #- #- I was given the advise to use this license. If this license #- prohibts inclusion into Python, how should I re-license the code? I just was asking. Who gave you the advise? . Facundo Bitácora De Vuelo: http://www.taniquetil.com.ar/plog PyAr - Python Argentina: http://pyar.decode.com.ar/ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ADVERTENCIA. La información contenida en este mensaje y cualquier archivo anexo al mismo, son para uso exclusivo del destinatario y pueden contener información confidencial o propietaria, cuya divulgación es sancionada por la ley. Si Ud. No es uno de los destinatarios consignados o la persona responsable de hacer llegar este mensaje a los destinatarios consignados, no está autorizado a divulgar, copiar, distribuir o retener información (o parte de ella) contenida en este mensaje. Por favor notifíquenos respondiendo al remitente, borre el mensaje original y borre las copias (impresas o grabadas en cualquier medio magnético) que pueda haber realizado del mismo. Todas las opiniones contenidas en este mail son propias del autor del mensaje y no necesariamente coinciden con las de Telefónica Comunicaciones Personales S.A. o alguna empresa asociada. Los mensajes electrónicos pueden ser alterados, motivo por el cual Telefónica Comunicaciones Personales S.A. no aceptará ninguna obligación cualquiera sea el resultante de este mensaje. Muchas Gracias. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
At 10:59 AM 1/11/05 +0100, Alex Martelli wrote: all you have to do is ADD def __conform__(self, protocol): if issubclass(protocol, Abstract): raise LiskovViolation that's all. That will raise a TypeError if protocol is not a class or type, so this could probably serve as an example of how difficult it is to write a good Liskov-violating __conform__. :) Actually, there's another problem with it; if you do this: class Y(X): pass class Z(Y): pass then 'adapt(Z(),Y)' will now fail because of a Liskov violation. It should really check for 'protocol is Abstract' or 'protocol in (Abstract,..)' in order to avoid this issue. Basically, rephrasing private inheritance with containment and delegation is a lot of messy work, and results in far more complicated structures. And instead of paying the tiny price of a __conform__ call at adaptation time, you pay the price of delegating calls over and over at each x.tm1() call, so it's unlikely performance will improve. Well, as I mentioned in my other post, such inheritance is a lot simpler with PEAK, so I've probably forgotten how hard it is if you're not using PEAK. :) PEAK also caches the delegated methods in the instance's __dict__, so there's virtually no performance penalty after the first access. Again, not an argument that others should use PEAK, just an explanation as to why I missed this point; I've been using PEAK's delegation features for quite some time and so tend to think of delegation as something relatively trivial. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] logging class submission
On Tue, 2005-01-11 at 12:58, Batista, Facundo wrote: > [Stephan Stapel] > > #- > There's a license issue here? > #- > #- I was given the advise to use this license. If this license > #- prohibts inclusion into Python, how should I re-license the code? > > I just was asking. Who gave you the advise? Here's a link to the PSF contribution form: http://www.python.org/psf/contrib.html This contains links to the recommended licenses for software that might be included in Python. -Barry signature.asc Description: This is a digitally signed message part ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] logging class submission
> I just was asking. Who gave you the advise? someon in a german python forum. I'll change the license asap. I'm just curious, but do I really have to use the contributor agreement etc.? I mean I'm just trying to submit a small class, no big framework. cheers, Stephan Verschicken Sie romantische, coole und witzige Bilder per SMS! Jetzt neu bei WEB.DE FreeMail: http://freemail.web.de/?mc=021193 ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] PEP 246, redux
At 09:27 AM 1/11/05 -0800, Michael Chermside wrote: Phillip: I think you must inhabit a far more perfect world than I do. You say, for instance, that: > ...-1 if this introduces a performance penalty [...] just to > support people who want to create deliberate Liskov violations. > I personally don't think that we should pander to Liskov > violators I've since dropped both the performance objection and the objection to supporting Liskov violation; in a more recent post I've proposed an alternative algorithm for allowing it, that has a simpler implementation. You say that: > I think one should adapt primarily to interfaces, and > interface-to-interface adaptation should be reserved for > non-lossy, non-noisy adapters. ... but in my world, half the time I'm using adaptation to correct for the fact that someone else's poorly-written code requests some class where it should have just used an interface. PEP 246 adaptation? Or are you talking about some other language? (I ask out of curiosity.) I agree that if it's possible to adapt to concrete types, people will do so. However, I think we all agree that this isn't a great idea and should still be considered bad style. That's not the same thing as saying it should be forbidden, and I haven't said it should be forbidden. You seem to inhabit a world in which transitivity of adaptation can be enforced. But in my world, people occasionally misuse adaptation because they think they know what they're doing or because they're in a big hurry and it's the most convenient tool at hand. How is this different from abuse of *any* language feature that you're then forced to work around? Are you saying we should not provide a feature because *some* people will abuse the feature? I don't understand. If you allow interface inheritance, you're just as susceptible to an invalid adaptation path, and in my experience this is more likely to bite you unintentionally, mainly because interface inheritance works differently than class inheritance (which of course is used more often). Do you want to prohibit interface inheritance, too? ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
At 11:59 AM 1/11/05 +0100, Alex Martelli wrote: On 2005 Jan 11, at 11:01, Alex Martelli wrote: On 2005 Jan 10, at 18:59, Phillip J. Eby wrote: At 12:43 PM 1/10/05 -0500, Phillip J. Eby wrote: As a practical matter, all of the existing interface systems (Zope, PyProtocols, and even the defunct Twisted implementation) treat interface inheritance as guaranteeing substitutability for the base interface, and do so transitively. An additional data point, by the way: the Eclipse Java IDE has an adaptation system that works very much like PEP 246 does, and it appears that in a future release they intend to support automatic adapter transitivity, so as to avoid requiring each provider of an interface to "provide O(n^2) adapters when writing the nth version of an interface." IOW, their current release is transitive only for interface inheritance ala Zope or Twisted; their future release will be transitive for adapter chains ala PyProtocols. This is definitely relevant prior art, so thanks for pointing it out. If interfaces change so often that 'n' can become worryingly high, this is a valid concern. In my world, though, published interfaces do NOT change as often as to require such remedies;-). FWIW, I don't believe that by "nth version" the original author wasn't referring to changed versions of the same interface, but was instead maybe trying to say that N interfaces that adapt to IFoo, when IFoo has M interfaces that it can be adapted to, means that N*M adapters are required in all, if adapter composition isn't possible. "adapters" for a single underlying "object", is, I fear, stronger than we can impose (so it may be that Eclipse is a better parallel, but I know little of it while COM is in my bones, so that's what I keep thinking of;-). Fair enough. I think Eclipse's *implementation* maps fairly directly onto PEP 246, except that __conform__ is replaced by a 'getAdapter()' method, and an AdapterManager is used to look up adapters in place of both __adapt__ and the PEP 246 registry. So, it is much closer to PEP 246 than COM, in that COM all adaptation is managed by the object, and it cannot be externally adapted. (At least, the last I looked at COM many years ago it was the case; maybe that has changed now?) So, I see transitivity as a nice thing to have _IF_ it's something that gets explicitly asserted for a certain adapter -- if the adapter has to explicitly state to the system that it "isn't lossy" (maybe), or "isn't noisy" (perhaps more useful), or something like that... some amount of reassurance about the adapter that makes it fully safe to use in such a chain. Maybe, although I think in our other thread we may be converging on definitions of lossy and noisy that are such we can agree that it's not really a problem. (I hope.) Maybe it might suffice to let an adapter which IS 'lossy' (or, more likely, one that is 'noisy') state the fact. I don't see a valid use case for implementing such a thing as an automatically-invoked adapter. I'm always reluctant by instinct to default to convenient but risky behavior, trusting programmers to explicitly assert otherwise when needed; but in many ways this kind of design is a part of Python and works fine (_with_ the BDFL's fine nose/instinct for making the right compromise between convenience and safety in each case, of course). Proposal: let adaptation implemented via __conform__ be nontransitive, and adaptation via __adapt__ or the adapter registry be transitive. This would mean that lossy or noisy adapters could be implemented as an implicitly-executed explicit conversion, but only directly on a particular concrete class and its subclasses, thereby further limiting the scope and impact of a lossy or noisy adapter. Also, think about this: technically, if you implement lossy or noisy adaptation in __conform__, it *isn't* lossy or noisy, because you have to do it in the class -- which means that as the class' author, you have decreed it to have such semantics. However, if you are a third party, you will have to explicitly invoke the lossy or noisy adapter. IOW, if you globally register an adapter (with either the interface or the global registry), you are guaranteeing that your adaptation is not lossy or noisy. Otherwise, you need to put it in __conform__ or use it explicitly. I'm still pondering the "don't adapt an adapter" suggestion, which seems a sound one, and yet also seems to be, intrinsically, what transitivity-by-chaining does. Note that QI does not suffer from this, because it lets you get the underlying object identity (IUnknown) from any interface adapter. Maybe, just maybe, we should also consider that -- a distinguished protocol bereft of any real substance but acting as a flag for "real unadapted object identity". Perhaps we could use 'object' for that, at least if the flow of logic in 'adapt' stays as in the current PEP 246 draft (i.e., __conform__ is given a chance before i
RE: [Python-Dev] PEP 246, redux
I wrote: > >... but in my world, half the time I'm using adaptation to > >correct for the fact that someone else's poorly-written > >code requests some class where it should have just used > >an interface. Phillip replies: > PEP 246 adaptation? Or are you talking about some other language? > (I ask out of curiosity.) Well, it's partly just a rhetorical device here. I mean PEP 246 adaption, but (unlike you!) I'm not actually using it yet (aside from playing around to try things out), really I'm just guessing how I WOULD be using it if it were part of core python. > I agree that if it's possible to adapt to concrete types, people will do > so. However, I think we all agree that this isn't a great idea and should > still be considered bad style. I'd agree except for the case where I am trying to pass an object into code which is misbehaving. If we do add type declarations that trigger an adapt() call, then people WILL write poor code which declares concrete types, and I will find myself writing __conform__ methods to work around it. In this case, I'm the one making use of adaption (the original author was just expecting a TypeError), but what I'm doing isn't (IMO) bad style. > >You seem to inhabit a world in which transitivity of adaptation > >can be enforced. But in my world, people occasionally misuse > >adaptation because they think they know what they're doing > >or because they're in a big hurry and it's the most convenient > >tool at hand. > > How is this different from abuse of *any* language feature that you're > then forced to work around? Are you saying we should not provide a > feature because *some* people will abuse the feature? I don't > understand. If we're just recomending that people design for transitivity, then I don't have a problem (although see Alex's fairly good point illustrated with LotsOfInfo, PersonName, and FullName -- I found it convincing). But I was under the impression that the point of transitivity was to make it "required", then automatically walk chains of adaptions. Then I fear one case of mis-used adaption could "poison" my entire adaption mechanism. The N^2 explosion of pairwise-only adapters scares me less, because I think in most real situations N will be small. > If you allow interface inheritance, you're just as susceptible to an > invalid adaptation path, and in my experience this is more likely to > bite you unintentionally, mainly because interface inheritance works > differently than class inheritance (which of course is used more > often). Do you want to prohibit interface inheritance, too? Hmm. Sounds like you're making a point here that's important, but which I don't quite get. Can you elaborate? I certainly hadn't intended to prohibit interface inheritance... how exactly does it "bite" one? -- Michael Chermside ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On Tue, Jan 11, 2005 at 12:54:36PM -0500, Phillip J. Eby wrote: | * Replacing LiskovViolation is possible by dropping type/isinstance | checks from adapt(), and adding an isinstance check to | object.__conform__; Liskov violators then override __conform__ in their | class to return None when asked to conform to a protocol they wish to | reject, and return super().__conform__ for all other cases. This | achieves your use case while simplifying both the implementation and the | usage. I'd rather not assume that class inheritance implies substitutability, unless the class is "marked" as an interface (assuming that one doesn't have interfaces). I'd like it to be explicit -- a bit of a nudge to remind a developer to verify substitutability is a good thing. In this scenerio, a LiskovViolation exception isn't needed (aside, I don't see the rationale for the exception: to prevent third party adapters?). Could we make a boilerplate __conform__ which enables class-based substitutability a well-known decorator? | * In my experience, incorrectly deriving an interface from another is the | most common source of unintended adaptation side-effects, not adapter | composition It'd be nice if interfaces had a way to specify a test-suite that could be run against a component which claims to be compliant. For example, it could provide invalid inputs and assert that the proper errors are returned, etc. Best, Clark -- Clark C. Evans Prometheus Research, LLC. http://www.prometheusresearch.com/ o office: +1.203.777.2550 ~/ , mobile: +1.203.444.0557 // (( Prometheus Research: Transforming Data Into Knowledge \\ , \/- Research Exchange Database /\- Survey & Assessment Technologies ` \ - Software Tools for Researchers ~ * ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
Alex Martelli wrote: On 2005 Jan 10, at 23:15, Thomas Heller wrote: Alex Martelli <[EMAIL PROTECTED]> writes: PEP: 246 Title: Object Adaptation Minor nit (or not?): You could provide a pointer to the Liskov substitution principle, for those reader that aren't too familiar with that term. Excellent idea, thanks. Terminology point: I know that LiskovViolation is technically correct, but I'd really prefer it if exception names (which are sometimes all users get to see) were more informative for people w/o deep technical background. Would that be possible? --david ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
David Ascher writes: > Terminology point: I know that LiskovViolation is technically correct, > but I'd really prefer it if exception names (which are sometimes all > users get to see) were more informative for people w/o deep technical > background. Would that be possible? I don't see how. Googling on Liskov immediately brings up clear and understandable descriptions of the principle that's being violated. I can't imagine summarizing the issue more concisely than that! What would you suggest? Including better explanations in the documentation is a must, but "LiskovViolation" in the exception name seems unbeatably clear and concise. -- Michael Chermside ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] PEP 246, redux
At 10:47 AM 1/11/05 -0800, Michael Chermside wrote: I'd agree except for the case where I am trying to pass an object into code which is misbehaving. If we do add type declarations that trigger an adapt() call, then people WILL write poor code which declares concrete types, and I will find myself writing __conform__ methods to work around it. In this case, I'm the one making use of adaption (the original author was just expecting a TypeError), but what I'm doing isn't (IMO) bad style. Agreed. However, assuming that you're declaring a "clean" adaptation, perhaps it should be registered with the global registry rather than implemented in __conform__, which would be less work for you. If we're just recomending that people design for transitivity, then I don't have a problem (although see Alex's fairly good point illustrated with LotsOfInfo, PersonName, and FullName -- I found it convincing). It's a bit misleading, however; if the target protocol allows for "nulls", then it's allowed to have nulls. If it doesn't allow nulls, then the adaptation is broken. Either way, it seems to me to work out, you just have to decide which way you want it. But I was under the impression that the point of transitivity was to make it "required", then automatically walk chains of adaptions. I don't have a problem with making some part of the adaptation process avoid transitivity, such as hand-implemented __conform__ methods. Then I fear one case of mis-used adaption could "poison" my entire adaption mechanism. The N^2 explosion of pairwise-only adapters scares me less, because I think in most real situations N will be small. Well, Eclipse is a pretty good example of a large N, and I know that both Twisted and Zope developers have occasionally felt the need to do "double-dip" adaptation in order to work around the absence of transitive adapter composition in their adaptation systems. > If you allow interface inheritance, you're just as susceptible to an > invalid adaptation path, and in my experience this is more likely to > bite you unintentionally, mainly because interface inheritance works > differently than class inheritance (which of course is used more > often). Do you want to prohibit interface inheritance, too? Hmm. Sounds like you're making a point here that's important, but which I don't quite get. Can you elaborate? I certainly hadn't intended to prohibit interface inheritance... how exactly does it "bite" one? If you derive an interface from another interface, this is supposed to mean that your derived interface promises to uphold all the promises of the base interface. That is, your derived interface is always usable where the base interface is required. However, oftentimes one mistakenly derives an interface from another while meaning that the base interface is *required* by the derived interface, which is similar in meaning but subtly different. Here, you mean to say, "IDerived has all of the requirements of IBase", but you have instead said, "You can use IDerived wherever IBase is desired". But now, suppose that you have class Foo, which has an adapter defined to IDerived, and which is looked up for you by IDerived.__adapt__ and IBase.__adapt__. Then, if you pass a Foo instance to a function that expects an *IBase*, then the function will end up with an IDerived. Sometimes this is not at all what you want, at which point I normally go back and copy the relevant methods from IBase to IDerived and remove the inheritance relationship. This problem exists in Zope's adaptation system as well as in PyProtocols. I have found that I am far less likely to have an adaptation problem from defining a questionable adapter, than I am to have one from wrongly-used inheritance. I am now more careful about the inheritance, but it's difficult because intuitively an interface defines a *requirement*, so it seems logical to inherit from an interface in order to add requirements! Now, in the case where both an IBase and an IDerived adapter exist, Zope and PyProtocols prefer to use the IBase adapter when an IBase is requested. But this doesn't address the problem case, which is where there is no IBase-only adaptation. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
At 01:50 PM 1/11/05 -0500, Clark C. Evans wrote: On Tue, Jan 11, 2005 at 12:54:36PM -0500, Phillip J. Eby wrote: | * Replacing LiskovViolation is possible by dropping type/isinstance | checks from adapt(), and adding an isinstance check to | object.__conform__; Liskov violators then override __conform__ in their | class to return None when asked to conform to a protocol they wish to | reject, and return super().__conform__ for all other cases. This | achieves your use case while simplifying both the implementation and the | usage. I'd rather not assume that class inheritance implies substitutability, Hm, you should take that up with Alex then, since that is what his current PEP 246 draft does. :) Actually, the earlier drafts did that too, so I'm not sure why you want to change this now. What I've actually suggested here actually allows for inheritance=substitutability as the default, but also makes it trivially changeable for any given inheritance hierarchy by overriding __conform__ at the base of that hierarchy, and without introducing a special exception class to do it. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Concrete proposals for PEP 246
To save everyone from having to wade through the lengthy discussions between Alex and I, and to avoid putting all the summarization burden on Alex, I thought I would start a new thread listing my concrete proposals for PEP 246 changes, and summarizing my understanding of the current agreements and disagreements we have. (Alex, please correct me if I have misrepresented your position in any respects.) First, I propose to allow explicitly-declared Liskov violations, but using a different mechanism than the one Alex has proposed. Specifically, I wish to remove all type or isinstance checking from the 'adapt()' function. But, the 'object' type should have a default __conform__ that is equivalent to: class object: def __conform__(self,protocol): if isinstance(protocol,ClassTypes) and isinstance(self,protocol): return self return None and is inherited by all object types, including types defined by extension modules, unless overridden. This approach provides solid backward compatibility with the previous version of PEP 246, as long as any user-implemented __conform__ methods call their superclass __conform__. But, it also allows Liskov-violating classes to simply return 'None' to indicate their refusal to conform to a base class interface, instead of having to raise a special exception. I think that, all else being equal, this is a simpler implementation approach to providing the feature, which Alex and others have convinced me is a valid (if personally somewhat distasteful) use case. Second: Alex has agreed to drop the "cast" terminology, since its meanings in various languages are too diverse to be illuminating. We have instead begun creeping towards agreement on some concepts such as "lossy" or "noisy" conversions. I think we can also drop my original "lossy" term, because "noisy" can also imply information loss and better explains the real issue anyway. A "noisy" conversion, then, is one where the conversion "makes up" information that was not implicitly present in the original, or drops information that *alters the semantics of the information that is retained*. (This phrasing gets around Alex's LotsOfInfo example/objection, while still covering loss of numeric precision; mere narrowing and renaming of attributes/methods does not alter the semantics of the retained information.) Adaptation is not recommended as a mechanism for noisy conversions, because implicit changes to semantics are a bad idea. Note that this is actually independent of any transitivity issues -- implicit noisy conversion is just a bad idea to start with, which is why 'someList[1.2]' raises a TypeError rather than implicitly converting 1.2 to an integer! If you *mean* to drop the .2, you should say so, by explicitly converting to an integer. (However, it *might* be acceptable to implicitly convert 1.0 to an integer; I don't currently have a strong opinion either way on that issue, other than to note that the conversion is not "noisy" in that case.) Anyway, I think that the current level of consensus between Alex and myself on the above is now such that his comparison to casting could now be replaced by some discussion of noisy vs. non-noisy (faithful? high-fidelity?) conversion, and the fact that adaptation is suitable only for the latter, supplemented by some examples of noisy conversion use cases and how to transform them into non-noisy constructs. The string->file vs. string->file_factory example is a particularly good one, I think, because it shows how to address a common, practical issue. Third: (Proposed) The PEP should explicitly support classic classes, or else there is no way to adapt exception instances. (Yes, I have actually done this; peak.web adapts exception instances to obtain appropriate handlers, for example.) Fourth: The principal issue from the original discussion that remains open at this time is determining specific policies or recommendations for addressing various forms of transitivity, which we have delved into a little bit. (By "open" I jut mean that there is no proposal for this issue currently on the table, not to imply that my proposals are not also "open" in the sense of awaiting consensus.) Anyway, the kinds of transitivity we're discussing are: 1. interface inheritance transitivity (i.e. adapt(x,IBase) if adapt(x,IDerived) and IDerived inherits from IBase) 2. adapter composition transitivity (i.e. adapt(x,ISome) if adapt(x,IOther) and there is a general-purpose ISome->IOther adapter available. These are mostly issues for the design of an interface system (implementing __adapt__) and for the design of a global adapter registry. I don't think it's practical to implement either kind of transitivity on the __conform__ side, at least not for hand-written __conform__ methods. To summarize current PEP 246 implementations' choices on this issue, Zope implements type 1 transiti
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 11, at 20:44, Phillip J. Eby wrote: ... If we're just recomending that people design for transitivity, then I don't have a problem (although see Alex's fairly good point illustrated with LotsOfInfo, PersonName, and FullName -- I found it convincing). It's a bit misleading, however; if the target protocol allows for "nulls", then it's allowed to have nulls. If it doesn't allow nulls, then the adaptation is broken. Either way, it seems to me to work out, you just have to decide which way you want it. NULLs are allowed, but *PRAGMATICALLY* they shouldn't be used except where there's no alternative. Is the concept of *PRAGMATICS* so deucedly HARD for all of your eggheads?! Maybe a full-credits course in linguistics should be mandatory for CS major or wherever you got your sheepskin[s]. In terms of syntax and semantics, a TCP/IP stack which just dropped all packet instantly would be compliant with the standards. No GUARANTEE that any given packet will be delivered is ever written down anywhere, after all. The reason such a TCP/IP stack would NOT be a SENSIBLE implementation of the standards is PRAGMATICS. The stack is supposed to do a best-effort ATTEMPT to deliver packets, dammit! That may be hard to formalize mathematically, but it makes all the difference in the world between a silly joke and a real-world tool. My best example of pragmatics in linguistics: if I state...: """ I never strangle python-dev posters with the initials PJE in months with an "R" in them """ I am saying nothing that is false or incorrect or misleading, in terms of syntax and semantics. This assertion is grammatically correct and semantically true. Does this mean you should worry come May...? Not necessarily, because the assertion is _pragmatically_ dubious. *PRAGMATICALLY*, in all natural languages, when I state "I never do X under condition Y" there's an implication that "condition Y" DOES have something to do with the case -- that if condition Y DOESN'T hold then my assurance about not doing X weakens. If condition Y has nothing to do with my doing or not doing X, then by the PRAGMATICS of natural language I'm NOT supposed to juxtapose the two things -- even though both syntactically and semantically it's perfectly correct to do so. Network protocol specs, programming language, libraries, etc, have pragmatics, too. They're way harder to formalize, but that doesn't mean they can be blithely ignored in the real world. Yes, you're ALLOWED to stuff with NULL any field that isn't explicitly specified as NOT NULL. But you should ONLY do so when the information is REALLY missing, NOT when you've lost it along the way because you've implemented adapter-chain transitivity: dropping information which you COULD have preserved with a bit more care (==without transitivity) is a violation of PRAGMATICS, of the BEST-EFFORT implication, just as it would be to drop packets once in a while in a TCP/IP stack due to some silly programming bug which was passed silently. Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 11, at 20:48, Phillip J. Eby wrote: ... I'd rather not assume that class inheritance implies substitutability, Hm, you should take that up with Alex then, since that is what his current PEP 246 draft does. :) Actually, the earlier drafts did that too, so I'm not sure why you want to change this now. What I've actually suggested here actually allows for inheritance=substitutability as the default, but also makes it trivially changeable for any given inheritance hierarchy by overriding __conform__ at the base of that hierarchy, and without introducing a special exception class to do it. The base of the hierarchy has no idea of which subclasses follow or break Liskov subtitutability. It's just silly to site the check there. Moreover, having to change the base class is more invasive than being able to do it in the derived class: typically the author of the derived class is taking the base class from some library and does not want to change that library -- changing the derived class is not ideal, but still way better. Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
At 09:23 PM 1/11/05 +0100, Alex Martelli wrote: Is the concept of *PRAGMATICS* so deucedly HARD for all of your eggheads?! Hmm. Pot, meet kettle. :) Yes, you're ALLOWED to stuff with NULL any field that isn't explicitly specified as NOT NULL. But you should ONLY do so when the information is REALLY missing, NOT when you've lost it along the way because you've implemented adapter-chain transitivity: dropping information which you COULD have preserved with a bit more care (==without transitivity) is a violation of PRAGMATICS, of the BEST-EFFORT implication, just as it would be to drop packets once in a while in a TCP/IP stack due to some silly programming bug which was passed silently. This is again a misleading analogy. You are comparing end-to-end with point-to-point. I am saying that if you have a point-to-point connection that drops all packets of a particular kind, you should not put it into your network, unless you know that an alternate route exists that can ensure those packets get through. Otherwise, you are breaking the network. Thus, I am saying that PRAGMATICALLY, it is silly to create a cable that drops all ACK packets, for example, and then plug it into your network. And especially, it's silly to turn around that as a reason that one should only use end-to-end leased lines, because that packet forwarding business is dangerously unreliable! As far as I can tell, you are arguing that you should never use packet forwarding for communication, because somebody might have a router somewhere that drops packets. While I am arguing that if a router is known to drop packets incorrectly, the router is broken and should be removed from the network, or else bypassed via another route. And, in the cases where you have a "leased line" direct from point A to point B, your routers should be smart enough to use that route in place of forwarding from A to C to D to B, or whatever. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
At 09:10 PM 1/11/05 +0100, Alex Martelli wrote: On 2005 Jan 11, at 20:48, Phillip J. Eby wrote: ... I'd rather not assume that class inheritance implies substitutability, Hm, you should take that up with Alex then, since that is what his current PEP 246 draft does. :) Actually, the earlier drafts did that too, so I'm not sure why you want to change this now. What I've actually suggested here actually allows for inheritance=substitutability as the default, but also makes it trivially changeable for any given inheritance hierarchy by overriding __conform__ at the base of that hierarchy, and without introducing a special exception class to do it. The base of the hierarchy has no idea of which subclasses follow or break Liskov subtitutability. It's just silly to site the check there. Moreover, having to change the base class is more invasive than being able to do it in the derived class: typically the author of the derived class is taking the base class from some library and does not want to change that library -- changing the derived class is not ideal, but still way better. Stop; you're responding to something I didn't propose! (Maybe you're reading these posts in reverse order, and haven't seen the actual proposal yet?) Clark said he didn't want to assume substitutability; I was pointing out that he could choose to not assume that, if he wished, by implementing an appropriate __conform__ at the base of his hierarchy. This is entirely unrelated to deliberate Liskov violation, and is in any case not possible with your original proposal. I don't agree with Clark's use case, but my proposal supports it as a possibility, and yours does not. To implement a Liskov violation with my proposal, you do exactly the same as with your proposal, *except* that you can simply return None instead of raising an exception, and the logic for adapt() is more straightforward. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] copy confusion
On 2005 Jan 11, at 23:20, Fredrik Lundh wrote: back in Python 2.1 (and before), an object could define how copy.copy should work simply by definining a __copy__ method. here's the relevant portion: ... try: copierfunction = _copy_dispatch[type(x)] except KeyError: try: copier = x.__copy__ except AttributeError: raise error, \ "un(shallow)copyable object of type %s" % type(x) y = copier() ... I recently discovered that this feature has disappeared in 2.3 and 2.4. in- stead of looking for an instance method, the code now looks at the object's type: Hmmm, yes, we were discussing this general issue as part of the huge recent thread about pep 246. In the new-style object model, special methods are supposed to be looked up on the type, not on the object; otherwise, having a class with special methods would be a problem -- are the methods meant to apply to the class object itself, or to its instances? However, apparently, the code you quote is doing it wrong: cls = type(x) copier = _copy_dispatch.get(cls) if copier: return copier(x) copier = getattr(cls, "__copy__", None) if copier: return copier(x) ...because getattr is apparently the wrong way to go about it (e.g., it could get the '__copy__' from type(cls), which would be mistaken). Please see Armin Rigo's only recent post to Python-Dev for the way it should apparently be done instead -- assuming Armin is right (he generally is), there should be plenty of bugs in copy.py (ones that emerge when you're using custom metaclasses &c -- are you doing that?). Still, if you're using an instance of an old-style class, the lookup in _copy_dispatch should be on types.InstanceType -- is that what you're trying to copy, an instance of an old-style class? (copy.deepcopy still seems to be able to use __deepcopy__ hooks, though) It starts with a peek into a dispatch dictionary for the type of the object, too, just like shallow copy does. What's the type of what you're trying to copy? is this a bug, or a feature of the revised copy/pickle design? (the code in copy_reg/copy/pickle might be among the more convoluted pieces of python coding that I ever seen... and what's that smiley doing in copy.py?) and if it's a bug, does the fact that nobody reported this for 2.3 indicate that I'm the only one using this feature? is there a better way to control copying that I should use instead? When I can, I use __getstate__ and __setstate__, simply because they seem clear and flexible to be (usable for copying, deep copying, pickling). But that doesn't mean __copy__ or __deepcopy__ should be left broken, of course. Although there are features of design intent here, it does appear to me there may be bugs too (if the getattr on the type is wrong); in this case it's worrisome, not just that nobody else reported problems, but also that the unit tests didn't catch them...:-( Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] copy confusion
On 2005 Jan 11, at 23:39, Phillip J. Eby wrote: ... cls = type(x) copier = _copy_dispatch.get(cls) if copier: return copier(x) ... this a bug, or a feature of the revised copy/pickle design? Looks like a bug to me; it breaks the behavior of classic classes, since type(classicInstance) returns InstanceType. It doesn't, because types.InstanceType is a key in _copy_dispatch and gets a function that implements old-style classe behavior. However, it also looks like it might have been introduced to fix the possibility that calling '__copy__' on a new-style class with a custom metaclass would result in ending up with an unbound method. (Similar to the "metaconfusion" issue being recently discussed for PEP 246.) ISTM the way to fix both issues is to switch to using x.__class__ in preference to type(x) to retrieve the __copy__ method from, although this still allows for metaconfusion at higher metaclass levels. What "both issues"? There's only one issue, it seems to me -- one of metaconfusion. Besides, getattr(x.__class__, '__copy__') would not give backwards compatibility if x is an old-style instance -- it would miss the per-instance x.__copy__ if any. Fortunately, _copy_dispatch deals with that. So changing from type(x) to x.__class__ seems useless. Maybe we need a getclassattr to deal with this issue, since I gather from Armin's post that this problem has popped up other places besides here and PEP 246. Apparently we do: a bug in a reference implementation in a draft PEP is one thing, one that lives so long in a key module of the standard library is quite another. (Follow-up: Guido's checkin comment for the change suggests it was actually done as a performance enhancement while adding a related feature (copy_reg integration), rather than as a fix for possible metaconfusion, even though it also has that effect.) OK, but if Armin is correct about the code in the reference implementation of pep 246, and I think he is, this is still a bug in copy.py (though probably not the specific one that bit /f). Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] copy confusion
On 2005 Jan 11, at 23:58, Guido van Rossum wrote: ... cls = type(x) copier = _copy_dispatch.get(cls) if copier: return copier(x) ... is this a bug, or a feature of the revised copy/pickle design? [Phillip] Looks like a bug to me; it breaks the behavior of classic classes, since type(classicInstance) returns InstanceType. I'm not so sure. I can't seem to break this for classic classes. You can't, _copy_dispatch deals with those. The only thing this intends to break, and then only for new-style classes, is the ability to have __copy__ be an instance variable (whose value should be a callable without arguments) -- it must be a method on the class. This is the same thing that I've done for all built-in operations (__add__, __getitem__ etc.). And a wonderful idea it is. However, it also looks like it might have been introduced to fix the possibility that calling '__copy__' on a new-style class with a custom metaclass would result in ending up with an unbound method. (Similar to the "metaconfusion" issue being recently discussed for PEP 246.) Sorry, my head just exploded. :-( I think I did this change (for all slots) to make the operations more efficient by avoiding dict lookups. It does have the desirable property of not confusing a class's attributes with its metaclass's attributes, but only as long as you use the operation's native syntax (e.g. x[y]) rather than the nominally "equivalent" method call (e.g. x.__getitem__(y)). Unfortunately, we do have a problem with the code in copy.py: class MetaCopyableClass(type): def __copy__(cls): """ code to copy CLASSES of this metaclass """ # etc, etc, snipped class CopyableClass: __metaclass__ = MetaCopyableClass # rest of class snipped x = CopyableClass() import copy y = copy.copy(x) kallisti:/tmp alex$ python x.py Traceback (most recent call last): File "x.py", line 14, in ? y = copy.copy(x) File "/usr/local/lib/python2.4/copy.py", line 79, in copy return copier(x) TypeError: __copy__() takes exactly 1 argument (2 given) kallisti:/tmp alex$ See? copy.copy(x) ends up using MetaCopyableClass.__copy__ -- because of a getattr on CopyableClass for '__copy__', which gets the BOUND-METHOD defined in the metaclass, with im_self being CopyableClass. I had exactly the same metabug in the pep 246 reference implementation, Armin Rigo showed how to fix it in his only recent post. Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Re: PEP 246: LiskovViolation as a name
Michael Chermside wrote: David Ascher writes: Terminology point: I know that LiskovViolation is technically correct, but I'd really prefer it if exception names (which are sometimes all users get to see) were more informative for people w/o deep technical background. Would that be possible? I don't see how. Googling on Liskov immediately brings up clear and understandable descriptions of the principle that's being violated. I can't imagine summarizing the issue more concisely than that! What would you suggest? Including better explanations in the documentation is a must, but "LiskovViolation" in the exception name seems unbeatably clear and concise. Clearly, I disagree. My point is that it'd be nice if we could come up with an exception name which could be grokkable without requiring 1) Google, 2) relatively high-level understanding of type theory. Googling on Liskov brings up things like: http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple """What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T." - BarbaraLiskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23,5 (May, 1988).""" If you think that that is clear and understandable to the majority of the Python community, you clearly have a different perspective on that community. I have (almost) no doubt that all Python-dev'ers understand it, but maybe we should ask someone like Anna Ravenscroft or Mark Lutz if they thinks it'd be appropriate from a novice user's POV. I'm quite sure that the experts could understand a more pedestrian name, and quite sure that the reverse isn't true. I also think that the term "violation" isn't necessarily the best word to add to the Python namespace, when error or exception would do just fine. In addition, to say that it's unbeatably clear without a discussion of alternatives (or if I've missed it, please let me know) seems weird. The point is broader, though -- when I get my turn in the time machine, I'll lobby for replacing NameError with UndefinedVariable or something similar (or more useful still). The former is confusing to novices, and while it can be learned, that's yet another bit of learning which is, IMO, unnecessary, even though it may be technically more correct. --david ascher ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Re: PEP 246: LiskovViolation as a name
> My point is that it'd be nice if we could come up with an exception name > which could be grokkable without requiring 1) Google, 2) relatively > high-level understanding of type theory. How about SubstitutabilityError? > The point is broader, though -- when I get my turn in the time machine, > I'll lobby for replacing NameError with UndefinedVariable or something > similar (or more useful still). The former is confusing to novices, and > while it can be learned, that's yet another bit of learning which is, > IMO, unnecessary, even though it may be technically more correct. We did that for UnboundLocalError, which subclasses NameError. Perhaps we can rename NameError to UnboundVariableError (and add NameError as an alias for b/w compat). -- --Guido van Rossum (home page: http://www.python.org/~guido/) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Re: PEP 246: LiskovViolation as a name
Guido van Rossum wrote: My point is that it'd be nice if we could come up with an exception name which could be grokkable without requiring 1) Google, 2) relatively high-level understanding of type theory. How about SubstitutabilityError? That would be far, far better, yes. We did that for UnboundLocalError, which subclasses NameError. Perhaps we can rename NameError to UnboundVariableError (and add NameError as an alias for b/w compat). Sure, although (and here I'm pushing it, I know, and I should have argued it way back then), the notion of 'unbound' is possibly too low-level still. 'Unknown' would probably carry much more meaning to those people who most need it. But yes, you're catching my drift. --david ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] copy confusion
At 11:56 PM 1/11/05 +0100, Alex Martelli wrote: What "both issues"? There's only one issue, it seems to me -- one of metaconfusion. I was relying on Fredrik's report of a problem with the code; that is the other "issue" I referred to. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] copy confusion
At 11:20 PM 1/11/05 +0100, Fredrik Lundh wrote: I recently discovered that this feature has disappeared in 2.3 and 2.4. in- stead of looking for an instance method, the code now looks at the object's type: ... cls = type(x) copier = _copy_dispatch.get(cls) if copier: return copier(x) copier = getattr(cls, "__copy__", None) if copier: return copier(x) ... (copy.deepcopy still seems to be able to use __deepcopy__ hooks, though) is this a bug, or a feature of the revised copy/pickle design? Looks like a bug to me; it breaks the behavior of classic classes, since type(classicInstance) returns InstanceType. However, it also looks like it might have been introduced to fix the possibility that calling '__copy__' on a new-style class with a custom metaclass would result in ending up with an unbound method. (Similar to the "metaconfusion" issue being recently discussed for PEP 246.) ISTM the way to fix both issues is to switch to using x.__class__ in preference to type(x) to retrieve the __copy__ method from, although this still allows for metaconfusion at higher metaclass levels. Maybe we need a getclassattr to deal with this issue, since I gather from Armin's post that this problem has popped up other places besides here and PEP 246. (Follow-up: Guido's checkin comment for the change suggests it was actually done as a performance enhancement while adding a related feature (copy_reg integration), rather than as a fix for possible metaconfusion, even though it also has that effect.) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On 2005 Jan 11, at 22:08, Phillip J. Eby wrote: ... Yes, you're ALLOWED to stuff with NULL any field that isn't explicitly specified as NOT NULL. But you should ONLY do so when the information is REALLY missing, NOT when you've lost it along the way because you've implemented adapter-chain transitivity: dropping information which you COULD have preserved with a bit more care (==without transitivity) is a violation of PRAGMATICS, of the BEST-EFFORT implication, just as it would be to drop packets once in a while in a TCP/IP stack due to some silly programming bug which was passed silently. This is again a misleading analogy. You are comparing end-to-end with point-to-point. I am saying that if you have a point-to-point connection that drops all packets of a particular kind, you should not put it into your network, unless you know that an alternate route exists that can ensure those packets get through. Otherwise, you are breaking the network. But adaptation is not transmission! It's PERFECTLY acceptable for an adapter to facade: to show LESS information in the adapted object than was in the original. It's PERFECTLY acceptable for an adapter to say "this piece information is not known" when it's adapting an object for which that information, indeed, is not known. It's only CONJOINING the two perfectly acceptable adapters, as transitivity by adapter chain would do automatically, that you end up with a situation that is pragmatically undesirable: asserting that some piece of information is not known, when the information IS indeed available -- just not by the route automatically taken by the transitivity-system. What happened here is not that either of the adapters registered is wrong: each does its job in the best way it can. The programming error, which transitivity hides (degrading the quality of information resulting from the system -- a subtle kind of degradation that will be VERY hard to unearth), is simply that the programmer forgot to register the direct adapter. Without transitivity, the programmer's mistake emerges easily and immediately; transitivity hides the mistake. By imposing transitivity, you're essentially asserting that, if a programmer forgets to code and register an A -> C direct adapter, this is never a problem, as long as A -> B and B -> C adapters are registered, because A -> B -> C will give results just as good as the direct A -> C would have, so there's absolutely no reason to trouble the programmer about the trivial detail that transitivity is being used. At the same time, if I understand correctly, you're ALSO saying that if two other adapters exist, A -> Z and Z -> C, *THEN* it's an error, because you don't know when adapting A -> C whether to go via B or via Z. Well, if you consistently believe what I state in the previous paragraph, then this is just weird: since you're implicitly asserting that any old A->?->C transitive adaptation is just as good as a direct A->C, why should you worry about there being more than one such 2-step adaptation available? Roll the dice to pick one and just proceed. Please note that in the last paragraph I'm mostly trying to "reason by absurd": I do NOT believe one can sensibly assert in the general case that A->?->C is just as good as A->C, without imposing FAR stronger constraints on adaptation that we possibly can (QI gets away with it because, designed from scratch, it can and does impose such constraints, essentially that all interfaces "belong" to ONE single object -- no independent 3rd party adaptation, which may be a bigger loss than the constraints gain, actually). I'm willing to compromise to the extent of letting any given adaptation somehow STATE, EXPLICITLY, "this adaptation is lossless and perfect, and can be used as a part of transitive chains of adaptation without any cost whatsoever". If we do that, though, the adaptation system should trust this assertion, so if there are two possibilities of equal minimal length, such as A->B->C or A->Z->C, with all the steps being declared lossless and perfect, then it SHOULD just pick one by whatever criterion, since both will be equally perfect anyway -- so maybe my reasoning by absurd wasn't totally absurd after all;-). Would this compromise be acceptable to you? Alex ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] copy confusion
[Fredrik] > >I recently discovered that this feature has disappeared in 2.3 and 2.4. in- > >stead of looking for an instance method, the code now looks at the object's > >type: > > > > ... > > > > cls = type(x) > > > > copier = _copy_dispatch.get(cls) > > if copier: > > return copier(x) > > > > copier = getattr(cls, "__copy__", None) > > if copier: > > return copier(x) > > > > ... > > > >(copy.deepcopy still seems to be able to use __deepcopy__ hooks, though) > > > >is this a bug, or a feature of the revised copy/pickle design? [Phillip] > Looks like a bug to me; it breaks the behavior of classic classes, since > type(classicInstance) returns InstanceType. I'm not so sure. I can't seem to break this for classic classes. The only thing this intends to break, and then only for new-style classes, is the ability to have __copy__ be an instance variable (whose value should be a callable without arguments) -- it must be a method on the class. This is the same thing that I've done for all built-in operations (__add__, __getitem__ etc.). > However, it also looks like it might have been introduced to fix the > possibility that calling '__copy__' on a new-style class with a custom > metaclass would result in ending up with an unbound method. (Similar to > the "metaconfusion" issue being recently discussed for PEP 246.) Sorry, my head just exploded. :-( I think I did this change (for all slots) to make the operations more efficient by avoiding dict lookups. It does have the desirable property of not confusing a class's attributes with its metaclass's attributes, but only as long as you use the operation's native syntax (e.g. x[y]) rather than the nominally "equivalent" method call (e.g. x.__getitem__(y)). -- --Guido van Rossum (home page: http://www.python.org/~guido/) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
On Tue, Jan 11, 2005 at 03:30:19PM -0500, Phillip J. Eby wrote: | Clark said he didn't want to assume substitutability; I was pointing out | that he could choose to not assume that, if he wished, by implementing an | appropriate __conform__ at the base of his hierarchy. Oh, that's sufficient. If someone making a base class wants to assert that derived classes should check compliance (rather than having it automagic), then they can do this. Good enough! | I don't agree with Clark's use case, but my | proposal supports it as a possibility, and yours does not. It was a straw-man; and I admit, not a particularly compelling one. | To implement a Liskov violation with my proposal, you do exactly the same | as with your proposal, *except* that you can simply return None instead | of raising an exception, and the logic for adapt() is more | straightforward. I think I prefer just returning None rather than raising a specific exception. The semantics are different: None implies that other adaptation mechanisms (like a registry) could be tried, while LiskovException implies that processing halts and no further adaptation techniques are to be used. In this case, None is the better choice for this particular case since it would enable third-parties to register a wrapper. Overall, I think both you and Alex are now proposing essentially the same thing... no? Best, Clark -- Clark C. Evans Prometheus Research, LLC. http://www.prometheusresearch.com/ o office: +1.203.777.2550 ~/ , mobile: +1.203.444.0557 // (( Prometheus Research: Transforming Data Into Knowledge \\ , \/- Research Exchange Database /\- Survey & Assessment Technologies ` \ - Software Tools for Researchers ~ * ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] copy confusion
At 02:58 PM 1/11/05 -0800, Guido van Rossum wrote: [Phillip] > Looks like a bug to me; it breaks the behavior of classic classes, since > type(classicInstance) returns InstanceType. I'm not so sure. I can't seem to break this for classic classes. Sorry; I was extrapolating from what I thought was Fredrik's description of this behavior as a bug, and examining of the history of the code that he referenced. I saw that the current version of that code had evolved directly from a version that was retrieving instance.__copy__; I therefore assumed that the loss-of-feature Fredrik was reporting was that. That is, I thought that the problem he was experiencing was that classic classes no longer supported __copy__ because this code had changed. I guess I should have looked at other lines of code besides the ones he pointed out; sorry about that. :( The only thing this intends to break, and then only for new-style classes, is the ability to have __copy__ be an instance variable (whose value should be a callable without arguments) -- it must be a method on the class. This is the same thing that I've done for all built-in operations (__add__, __getitem__ etc.). Presumably, this is the actual feature loss that Fredrik's describing; i.e. lack of per-instance __copy__ on new-style classes. That would make more sense. > However, it also looks like it might have been introduced to fix the > possibility that calling '__copy__' on a new-style class with a custom > metaclass would result in ending up with an unbound method. (Similar to > the "metaconfusion" issue being recently discussed for PEP 246.) Sorry, my head just exploded. :-( The issue is that for special attributes (like __copy__, __conform__, etc.) that do not have a corresponding type slot, using getattr() is not sufficient to obtain slot-like behavior. This is because 'aType.__special__' may refer to a __special__ intended for *instances* of 'aType', instead of the __special__ for aType. As Armin points out, the only way to fully emulate type slot behavior for unslotted special attributes is to perform a search of the __dict__ of each type in the MRO of the type of the object for which you wish to obtain the special attribute. So, in this specific case, __copy__ does not have a type slot, so it is impossible using getattr (or simple attribute access) to guarantee that you are retrieving the correct version of __copy__ in the presence of metaclasses. This is what Alex and I dubbed "metaconfusion" in discussion of the same issue for PEP 246's __adapt__ and __conform__ methods; until they have tp_adapt and tp_conform slots, they can have this same problem. Alex and I also just speculated that perhaps the stdlib should include a function that can do this, so that stdlib modules that define unslotted special attributes (such as __copy__) can ensure they work correctly in the presence of metaclasses. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Re: PEP 246: LiskovViolation as a name
Guido van Rossum wrote: The point is broader, though -- when I get my turn in the time machine, I'll lobby for replacing NameError with UndefinedVariable or something Strange, my blog reading just hit upon http://blogs.zdnet.com/open-source/index.php?p=93 ... "Perhaps as open source developers are making their resolutions for 2005, they could add human-readable error codes to their list? " :-) --david ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
At 06:38 PM 1/11/05 -0500, Clark C. Evans wrote: | To implement a Liskov violation with my proposal, you do exactly the same | as with your proposal, *except* that you can simply return None instead | of raising an exception, and the logic for adapt() is more | straightforward. I think I prefer just returning None rather than raising a specific exception. The semantics are different: None implies that other adaptation mechanisms (like a registry) could be tried, while LiskovException implies that processing halts and no further adaptation techniques are to be used. In this case, None is the better choice for this particular case since it would enable third-parties to register a wrapper. Overall, I think both you and Alex are now proposing essentially the same thing... no? Yes; I'm just proposing shuffling the invocation of things around a bit in order to avoid the need for an exception, and in the process increasing the number of possible customizations a bit. Not that I care about those customizations as such; I just would like to simplify the protocol. I suppose there's some educational benefit in making somebody explicitly declare that they're a Liskov violator, but it seems that if we're going to support it, it should be simple. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] Re: [Csv] csv module TODO list
Would the csv module be a good place to add a DBF reader and writer? Dbase's dbf file format is one of the oldest, simplest and more common database interchange formats. It can be a good alternative to CSV as a means of sharing data with pre-existing, non-python apps. On the plus side, it has a precise spec, can preserve numeric and date types, has guaranteed round-trip equivalence, and does not have weird escape rules. On the minus side, strings are limited to ASCII without NULs and the fields are fixed length. I've posted a draft on ASPN. It interoperates well with the rest of the CSV module because it also accepts/returns a list of fieldnames and a sequence of records. http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/362715 Raymond Hettinger ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] copy confusion
back in Python 2.1 (and before), an object could define how copy.copy should work simply by definining a __copy__ method. here's the relevant portion: ... try: copierfunction = _copy_dispatch[type(x)] except KeyError: try: copier = x.__copy__ except AttributeError: raise error, \ "un(shallow)copyable object of type %s" % type(x) y = copier() ... I recently discovered that this feature has disappeared in 2.3 and 2.4. in- stead of looking for an instance method, the code now looks at the object's type: ... cls = type(x) copier = _copy_dispatch.get(cls) if copier: return copier(x) copier = getattr(cls, "__copy__", None) if copier: return copier(x) ... (copy.deepcopy still seems to be able to use __deepcopy__ hooks, though) is this a bug, or a feature of the revised copy/pickle design? (the code in copy_reg/copy/pickle might be among the more convoluted pieces of python coding that I ever seen... and what's that smiley doing in copy.py?) and if it's a bug, does the fact that nobody reported this for 2.3 indicate that I'm the only one using this feature? is there a better way to control copying that I should use instead? ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] Re: copy confusion
Guido van Rossum wrote:
> The only thing this intends to break /.../
it breaks classic C types:
>>> import cElementTree
>>> x = cElementTree.Element("tag")
>>> x
>>> x.__copy__
>>> x.__copy__()
>>> import copy
>>> y = copy.copy(x)
Traceback (most recent call last):
File "", line 1, in ?
File "C:\python24\lib\copy.py", line 93, in copy
raise Error("un(shallow)copyable object of type %s" % cls)
copy.Error: un(shallow)copyable object of type
>>> dir(x)
['__copy__', '__deepcopy__', 'append', 'clear', 'find', 'findall', 'findtext',
'get', 'getchildren', 'getiterator', 'insert', 'items', 'keys', 'makeelement',
'set']
>>> dir(type(x))
['__class__', '__delattr__', '__delitem__', '__delslice__', '__doc__',
'__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__',
'__len__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__setitem__', '__setslice__', '__str__']
(and of course, custom C types is the only case where I've ever used
__copy__; the default behavior has worked just fine for all other cases)
for cElementTree, I've worked around this with an ugly __reduce__ hack,
but that doesn't feel right...
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] PEP 246, redux
> Thus, my argument is that an adapter like this should never be made part > of > the adapter system, even if there's no transitivity. However, if you > agree > that such an adapter shouldn't be implicit, then it logically follows that > there is no problem with allowing transitivity, except of course that > people may sometimes break the rule. At some point, the PEP should be extended to include a list of best practices and anti-patterns for using adapters. I don't find issues of transitivity and implicit conversion to be immediately obvious. Also, it is not clear to me how or if existing manual adaption practices should change. For example, if I need a file-like interface to a string, I currently wrap it with StringIO. How will that change it the future? By an explicit adapt/conform pair? Or by strings knowing how to conform to file-like requests? Raymond Hettinger ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Re: [Csv] csv module TODO list
>Would the csv module be a good place to add a DBF reader and writer? I would have thought it would make sense as it's own module (in the same way that we have separate modules that present a common interface for the different databases), or am I missing something? I'd certainly like to see a DBF parser in python - reading and writing odd file formats is bread-and-butter for us contractors... 8-) -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] PEP 246, redux
At 12:33 AM 1/12/05 +0100, Alex Martelli wrote: But adaptation is not transmission! It's PERFECTLY acceptable for an adapter to facade: to show LESS information in the adapted object than was in the original. It's also true that it's acceptable for a router to choose not to forward packets, e.g. for security reasons, QoS, etc. My point was that you seem to be using this to conclude that multihop packet forwarding is a bad idea in the general case, and that's what doesn't make any sense to me. More to the point, the error in your example isn't the filtering-out of information, it's the adding of a NULL back in. If NULLs are questionable for the target interface, this is not in general a candidate for implicit adaptation IMO -- *whether or not transitivity is involved*. Let's look at the reverse of the float-to-int case for a better example. Should I be able to implicitly adapt a float to a Decimal? No, because I might be making up precision that isn't there. May I explicitly convert a float to a decimal, if I know what I'm doing? Yes, of course. Just don't expect Python to guess for you. This is very much like your example; adding a NULL middle name seems to me almost exactly like going from float to Decimal with spurious precision. If you know what you're doing, it's certainly allowable to do it explicitly, but Python should not do it implicitly. Thus, my argument is that an adapter like this should never be made part of the adapter system, even if there's no transitivity. However, if you agree that such an adapter shouldn't be implicit, then it logically follows that there is no problem with allowing transitivity, except of course that people may sometimes break the rule. However, I think we actually have an opportunity now to actually codify sensible adaptation practices, such that the violations will be infrequent. It's also possible that we may be able to define some sort of restricted implicitness so that somebody making a noisy adapter can implicitly adapt in a limited context. What happened here is not that either of the adapters registered is wrong: each does its job in the best way it can. The programming error, which transitivity hides (degrading the quality of information resulting from the system -- a subtle kind of degradation that will be VERY hard to unearth), is simply that the programmer forgot to register the direct adapter. Without transitivity, the programmer's mistake emerges easily and immediately; transitivity hides the mistake. Where we differ is that I believe that if the signal degradation over a path isn't acceptable, it shouldn't be made an implicit part of the network; it should be an explicitly forced route instead. Note by the way, that the signal degradation in your example comes from a broken adapter: it isn't valid to make up data if you want real data. It's PRAGMATIC, as you say, to make up the data when you don't have a choice, but this does not mean it should be AUTOMATIC. So, we both believe in restricting the automatic and implicit nature of adaptation. The difference is that I'm saying you should be explicit when you do something questionable, and you are saying you should be explicit when you're doing something that is *not*. Perhaps as you previously suggested, this really is the aspect where we need the BDFL to be the tiebreaker. At the same time, if I understand correctly, you're ALSO saying that if two other adapters exist, A -> Z and Z -> C, *THEN* it's an error, because you don't know when adapting A -> C whether to go via B or via Z. Well, if you consistently believe what I state in the previous paragraph, then this is just weird: since you're implicitly asserting that any old A->?->C transitive adaptation is just as good as a direct A->C, why should you worry about there being more than one such 2-step adaptation available? Because such ambiguities are usually an indication of some *other* error, often in the area of interface inheritance transitivity; they rarely occur as a direct result of implementing two versions of the same adapter (at least in my experience). I'm willing to compromise to the extent of letting any given adaptation somehow STATE, EXPLICITLY, "this adaptation is lossless and perfect, and can be used as a part of transitive chains of adaptation without any cost whatsoever". If we do that, though, the adaptation system should trust this assertion, so if there are two possibilities of equal minimal length, such as A->B->C or A->Z->C, with all the steps being declared lossless and perfect, then it SHOULD just pick one by whatever criterion, since both will be equally perfect anyway -- so maybe my reasoning by absurd wasn't totally absurd after all;-). Here's the part I don't think you're seeing: interface inheritance transitivity has this *exact* same problem, and it's *far* easier to stumble into it, assuming you don't start out by declaring adapters tha
[Python-Dev] PEP 246, redux
I'm trying to understand the relation between Guido's posts on optional static typing and PEP 245 (interfaces) and 246 (adaptation). I have a couple of questions PEP 245 proposes to introduce a fundamental distinction between type and interface. However, 245 only introduces a syntax for interfaces, and says very little about the semantics of interfaces. (Basically only that if X implements Y then implements(X, Y) will return True). The semantics of interfaces are currently only implied by PEP 246, and by Guido's posts referring to 246. Unfortunately PEP 246 explicitly refuses to decide that protocols are 245-style interfaces. Therefore, it is not clear to me how acceptance of 245 would impact on 246? Specifically, what would be the difference between: x = adapt(obj, a_245_style_interface) x = adapt(obj, a_protocol_type) and, if there is no difference, what would the use-case of interfaces be? Put another way: explicit interfaces and adaptation based typing seem to be about introducing rigor (dynamic, not static) to Python. Yet, PEP 245 and 246 seems to go out of their way to give interfaces and adaptation as little baggage as possible. So, where is the rigor going to come from? On the one hand this seems very Pythonic - introduce a new feature with as little baggage as possible, and see where it evolves from there. Let the rigor flow, not from the restrictions of the language, but from the expressive power of the language. On the other hand: why not, at least: - explore in 245 how the semantics of interfaces might introduce rigor into the language. It would be particularly illuminating to find out in what way implementing an interface differs from deriving from an ABC and in what way an interface hierarchy differs semantically from a hierarchy of ABCs - rewrite 246 under the assumption that 245 (including semantics) has been accepted I would volunteer, but, for those of you who hadn't noticed yet, I don't know what I'm talking about. Cheers, Roeland Rengelink ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
RE: [Python-Dev] PEP 246, redux
At 07:52 PM 1/11/05 -0500, Raymond Hettinger wrote: Also, it is not clear to me how or if existing manual adaption practices should change. For example, if I need a file-like interface to a string, I currently wrap it with StringIO. How will that change it the future? By an explicit adapt/conform pair? Or by strings knowing how to conform to file-like requests? The goal here is to be able to specify that a function parameter takes, e.g. a "readable stream", and that you should be able to either explicitly wrap in a StringIO to satisfy this, or *possibly* that you be able to just pass a string and have it work automatically. If the latter is the case, there are a variety of possible ways it might work. str.__conform__ might recognize the "readable stream" interface, or the __adapt__ method of the "readable stream" interface could recognize 'str'. Or, Alex's new proposed global type registry might contain an entry for 'str,readableStream'. Which of these is the preferred scenario very much depends on a lot of things, like who defined the "readable stream" interface, and whether anybody has registered an adapter for it! PyProtocols tries to answer this question by allowing you to register adapters with interfaces, and then the interface's __adapt__ method will do the actual adaptation. Zope does something similar, at least in that it uses the interface's __adapt__ method, but that method actually uses a global registry. Neither PyProtocols nor Zope make much use of actually implementing hand-coded __conform__ or __adapt__ methods, as it's too much trouble for something that's so inherently declarative anyway, and only the creator of the object class or the interface's type have any ability to define adapters that way. Given that built-in types are often handy sources of adaptation (e.g. str-to-StringIO in your example), it isn't practical in present-day Python to add a __conform__ method to the str type! Thus, in the general case it just seems easier to use a per-interface or global registry for most normal adaptation, rather than using __conform__. However, having __conform__ exist is a nice "out" for implementing unusual custom requirements (like easy dynamic conformance), so I don't think it should be removed. ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] copy confusion
> Unfortunately, we do have a problem with the code in copy.py: > > class MetaCopyableClass(type): > def __copy__(cls): > """ code to copy CLASSES of this metaclass """ > # etc, etc, snipped > > class CopyableClass: > __metaclass__ = MetaCopyableClass > # rest of class snipped > > x = CopyableClass() > > import copy > y = copy.copy(x) > > kallisti:/tmp alex$ python x.py > Traceback (most recent call last): >File "x.py", line 14, in ? > y = copy.copy(x) >File "/usr/local/lib/python2.4/copy.py", line 79, in copy > return copier(x) > TypeError: __copy__() takes exactly 1 argument (2 given) > kallisti:/tmp alex$ > > See? copy.copy(x) ends up using MetaCopyableClass.__copy__ -- because > of a getattr on CopyableClass for '__copy__', which gets the > BOUND-METHOD defined in the metaclass, with im_self being > CopyableClass. > > I had exactly the same metabug in the pep 246 reference implementation, > Armin Rigo showed how to fix it in his only recent post. Don't recall seeing that, but if you or he can fix this without breaking other stuff, it's clear you should go ahead. (This worked in 2.2, FWIW; it broke in 2.3.) -- --Guido van Rossum (home page: http://www.python.org/~guido/) ___ Python-Dev mailing list [email protected] http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
