Re: [Python-Dev] PEP 309: Partial method application
Martin v. Löwis wrote: Steven Bethard wrote: I thought that: operator.attrgetter() was for obj.attr operator.itemgetter() was for obj[integer_index] My point exactly. If we're sticking to the same style, I would expect that for obj.method(*args, **kwargs) we would have something like: operator.methodcaller('method', *args, **kwargs) You might be missing one aspect of attrgetter, though. I can have f = operator.attrgetter('name', 'age') and then f(person) gives me (person.name, person.age). Likewise for itemgetter(1,2,3). [snip] I don't know what the common use for attrgetter is: one or more attributes? Well, in current Python code, I'd be willing to wager that it's one, no more, since Python 2.4 only supports a single argument to itemgetter and attrgetter. Of course, when Python 2.5 comes out, it's certainly possible that the multi-argument forms will become commonplace. I agree that an operator.methodcaller() shouldn't try to support multiple methods. OTOH, the syntax methodcall.method(*args, **kwargs) doesn't really lend itself to multiple methods either. STeVe -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Steven Bethard [EMAIL PROTECTED] wrote: I agree that an operator.methodcaller() shouldn't try to support multiple methods. OTOH, the syntax methodcall.method(*args, **kwargs) doesn't really lend itself to multiple methods either. But that's OK, we don't want to be calling multiple methods anyways, do we? I'd personally like to see an example it makes sense if someone says that we do. - Josiah ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
[Steven Bethard] I agree that an operator.methodcaller() shouldn't try to support multiple methods. OTOH, the syntax methodcall.method(*args, **kwargs) doesn't really lend itself to multiple methods either. [Josiah Carlson] But that's OK, we don't want to be calling multiple methods anyways, do we? I'd personally like to see an example it makes sense if someone says that we do. If an obvious syntax doesn't emerge, don't fret. The most obvious approach is to define a regular Python function and supply that function to the key= argument for list.sort() or sorted(). A virtue of the key= argument was reducing O(n log n) calls to just O(n). Further speed-ups are a false economy. So there's no need to twist syntax into knots just to get a C based method calling function. Likewise with map(), if a new function doesn't fit neatly, take that as a cue to be writing a plain for-loop. Raymond ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Josiah Carlson wrote: Steven Bethard [EMAIL PROTECTED] wrote: I agree that an operator.methodcaller() shouldn't try to support multiple methods. OTOH, the syntax methodcall.method(*args, **kwargs) doesn't really lend itself to multiple methods either. But that's OK, we don't want to be calling multiple methods anyways, do we? I'd personally like to see an example it makes sense if someone says that we do. Several people argued that the version with a string method name should be added for consistency. I only pointed out that doing so would not be completely consistent. Regards, Martin ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
[Python-Dev] PEP 309: Partial method application
I missed the discussion on this (http://www.python.org/peps/pep-0309.html), but then 2.5 isn't out yet. I think partial() misses an important use case of method getting, for instance: lst = ['A', 'b', 'C'] lst.sort(key=partialmethod('lower')) Which sorts by lower-case. Of course you can use str.lower, except you'll have unnecessarily enforced a type (and excluded Unicode). So you are left with lambda x: x.lower(). Here's an implementation: def partialmethod(method, *args, **kw): def call(obj, *more_args, **more_kw): call_kw = kw.copy() call_kw.update(more_kw) return getattr(obj, method)(*(arg+more_args), **call_kw) return call This is obviously related to partial(). Maybe this implementation should be a classmethod or function attribute, partial.method(). -- Ian Bicking / [EMAIL PROTECTED] / http://blog.ianbicking.org ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
[Ian Bicking] I think partial() misses an important use case of method getting, for instance: lst = ['A', 'b', 'C'] lst.sort(key=partialmethod('lower')) We've already got one: lst.sort(key=operator.attrgetter('lower')) Raymond ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Raymond Hettinger wrote: [Ian Bicking] I think partial() misses an important use case of method getting, for instance: lst = ['A', 'b', 'C'] lst.sort(key=partialmethod('lower')) We've already got one: lst.sort(key=operator.attrgetter('lower')) Doesn't that just sort on the str.lower or unicode.lower method object? py sorted(['A', u'b', 'C'], key=operator.attrgetter('lower')) [u'b', 'C', 'A'] py sorted(['A', u'b', 'C'], key=partialmethod('lower')) # after fixing arg - args bug ['A', u'b', 'C'] STeVe -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
[Ian Bicking] I think partial() misses an important use case of method getting, for instance: lst = ['A', 'b', 'C'] lst.sort(key=partialmethod('lower')) We've already got one: lst.sort(key=operator.attrgetter('lower')) Doesn't that just sort on the str.lower or unicode.lower method object? My mistake. It sorts on the bound method rather than the results of applying that method. Raymond ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Raymond Hettinger wrote: instance: lst = ['A', 'b', 'C'] lst.sort(key=partialmethod('lower')) We've already got one: lst.sort(key=operator.attrgetter('lower')) Doesn't that just sort on the str.lower or unicode.lower method object? My mistake. It sorts on the bound method rather than the results of applying that method. Then I thought it might be right to do partial(operator.attrgetter('lower')). This, however, accomplishes exactly nothing. I only decided this after actually trying it, though upon reflection partial(function) always accomplishes nothing. I don't have any conclusion from this, but only mention it to demonstrate that callables on top of callables are likely to confuse. -- Ian Bicking / [EMAIL PROTECTED] / http://blog.ianbicking.org ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Ian Bicking wrote: lst = ['A', 'b', 'C'] lst.sort(key=partialmethod('lower')) Which sorts by lower-case. Of course you can use str.lower, except you'll have unnecessarily enforced a type (and excluded Unicode). So you are left with lambda x: x.lower(). For this specific case, you can use string.lower (which is exactly what the lambda function does). As for the more general proposal: -1 on more places to pass strings to denote method/function/class names. These are ugly to type. What I think you want is not a partial method, instead, you want to turn a method into a standard function, and in a 'virtual' way. So I would propose the syntax lst.sort(key=virtual.lower) # where virtual is functional.virtual As for extending PEP 309: This PEP deliberately abstained from other ways of currying, and instead only introduced the functional module. If you want to see lazy functions in the standard library, you should write a new PEP (unless there is an easy agreement about a single right way to do this, which I don't see). Regards, Martin P.S. It's not even clear that this should be added to functional, as attrgetter and itemgetter are already in operator. But, perhaps, they should be in functional. ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Martin v. Löwis wrote: So I would propose the syntax lst.sort(key=virtual.lower) # where virtual is functional.virtual Ooh, may I say that idea is interesting! It's easy to implement, too: class virtual: def __getattr__(self, name): return lambda obj: getattr(obj, name)() virtual = virtual() Shane ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
On 8/18/05, Martin v. Löwis [EMAIL PROTECTED] wrote: As for the more general proposal: -1 on more places to pass strings to denote method/function/class names. These are ugly to type. Agreed. What I think you want is not a partial method, instead, you want to turn a method into a standard function, and in a 'virtual' way. So I would propose the syntax lst.sort(key=virtual.lower) # where virtual is functional.virtual I like this, but would hope for a different name -- the poor word 'virtual' has been abused enough by C++. P.S. It's not even clear that this should be added to functional, as attrgetter and itemgetter are already in operator. But, perhaps, they should be in functional. They feel related to attrgetter more than to partial. -- --Guido van Rossum (home page: http://www.python.org/~guido/) ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
On 8/18/05, Guido van Rossum [EMAIL PROTECTED] wrote: On 8/18/05, Martin v. Löwis [EMAIL PROTECTED] wrote: As for the more general proposal: -1 on more places to pass strings to denote method/function/class names. These are ugly to type. Agreed. What I think you want is not a partial method, instead, you want to turn a method into a standard function, and in a 'virtual' way. So I would propose the syntax lst.sort(key=virtual.lower) # where virtual is functional.virtual I like this, but would hope for a different name -- the poor word 'virtual' has been abused enough by C++. Yeah, me too. Possible name are 'delayed', 'lazyattr', or just plain 'lazy' since it reminds me of Haskell. P.S. It's not even clear that this should be added to functional, as attrgetter and itemgetter are already in operator. But, perhaps, they should be in functional. They feel related to attrgetter more than to partial. True, but the idea of lazy evaluation, at least for me, reminds me more of functional languages and thus the functional module. Oh, when should we think of putting reduce into functional? I remember this was discussed when it was realized reduce was the only functional built-in that is not covered by itertools or listcomps. -Brett ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
[Guido] They feel related to attrgetter more than to partial. That suggests operator.methodcall() ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Brett Cannon wrote: What I think you want is not a partial method, instead, you want to turn a method into a standard function, and in a 'virtual' way. So I would propose the syntax lst.sort(key=virtual.lower) # where virtual is functional.virtual I like this, but would hope for a different name -- the poor word 'virtual' has been abused enough by C++. Yeah, me too. Possible name are 'delayed', 'lazyattr', or just plain 'lazy' since it reminds me of Haskell. I don't think there's anything particularly lazy about it. It's like a compliment of attrgetter. Where attrgetter is an inversion of getattr, partialmethod is an inversion of... well, of something that currently has no name. There's kind of an implicit operation in obj.method() -- people will generally read that as a method call, not as the retrieval of a bound method and later invocation of that method. I think that is why it's so hard to figure out how to represent this in terms of something like attrgetter -- we try to invert something (a method call) that doesn't exist in the language. -- Ian Bicking / [EMAIL PROTECTED] / http://blog.ianbicking.org ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Brett Cannon wrote: What I think you want is not a partial method, instead, you want to turn a method into a standard function, and in a 'virtual' way. So I would propose the syntax lst.sort(key=virtual.lower) # where virtual is functional.virtual I like this, but would hope for a different name -- the poor word 'virtual' has been abused enough by C++. Yeah, me too. Possible name are 'delayed', 'lazyattr', or just plain 'lazy' since it reminds me of Haskell. Hmm, methodcall? As in: lst.sort(key=methodcall.lower) Where methodcall is something like what Shane described: class methodcall: def __getattr__(self, name): def delayedcall(*args, **kwds): return getattr(args[0], name)(*args[1:], **kwds) return delayedcall methodcall = methodcall() Oh, when should we think of putting reduce into functional? I remember this was discussed when it was realized reduce was the only functional built-in that is not covered by itertools or listcomps. I expected functional.map, functional.filter and functional.reduce to all exist in 2.5. Cheers, Nick. -- Nick Coghlan | [EMAIL PROTECTED] | Brisbane, Australia --- http://boredomandlaziness.blogspot.com ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
On 8/18/05, Nick Coghlan [EMAIL PROTECTED] wrote: Brett Cannon wrote: Oh, when should we think of putting reduce into functional? I remember this was discussed when it was realized reduce was the only functional built-in that is not covered by itertools or listcomps. I expected functional.map, functional.filter and functional.reduce to all exist in 2.5. Itertools covers map, filter is covered by genexps. 'reduce' is the only one that does not have an equivalent anywhere. I guess we could cross-link itertools.map into functional.map, but I would rather just mention in the docs of one that it is located in the other module. And filter is just not worth it; that can definitely be covered in the docs of the module. -Brett ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Steven Bethard [EMAIL PROTECTED] wrote: Martin v. Löwis wrote: So I would propose the syntax lst.sort(key=virtual.lower) # where virtual is functional.virtual Shane Hathaway wrote: class virtual: def __getattr__(self, name): return lambda obj: getattr(obj, name)() virtual = virtual() I think (perhaps because of the name) that this could be confusing. I don't have any intuition that virtual.lower would return a function that calls the lower attribute instead of returning a function that simply accesses that attribute. If we're going to move away from the itemgetter() and attrgetter() style, then we should be consistent about it and provide a solution (or solutions) that answers all of these problems: obj.attr obj.attr(*args, **kwargs) obj[key] I'm not sure that there is a clean/obvious way to do this. I thought that: operator.attrgetter() was for obj.attr operator.itemgetter() was for obj[integer_index] That's almost all the way there. All that remains is to have something that gets any key (not just integers) and which handles function calls. In terms of the function call semantics, what about: class methodcall: def __getattr__(self, name, *args, **kwds): def delayedcall(obj): return getattr(obj, name)(*args, **kwds) return delayedcall methodcall = methodcall() - Josiah ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Josiah Carlson wrote: Steven Bethard [EMAIL PROTECTED] wrote: If we're going to move away from the itemgetter() and attrgetter() style, then we should be consistent about it and provide a solution (or solutions) that answers all of these problems: obj.attr obj.attr(*args, **kwargs) obj[key] I'm not sure that there is a clean/obvious way to do this. I thought that: operator.attrgetter() was for obj.attr operator.itemgetter() was for obj[integer_index] My point exactly. If we're sticking to the same style, I would expect that for obj.method(*args, **kwargs) we would have something like: operator.methodcaller('method', *args, **kwargs) The proposal by Martin v. Löwis is that this should instead look something like: methodcall.method(*args, **kwargs) which is a departure from the current attrgetter() and itemgetter() idiom. I'm not objecting to this approach, by the way. I think with the right name, it would probably read well. I just think that we should try to be consistent one way or the other. If we go with Martin v. Löwis's suggestion, I would then expect that the corrolates to attrgetter() and itemgetter() would also be included, e.g.: attrget.attr (for obj.attr) itemget[key] (for obj[key]) STeVe -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy ___ Python-Dev mailing list Python-Dev@python.org 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 309: Partial method application
Steven Bethard wrote: I thought that: operator.attrgetter() was for obj.attr operator.itemgetter() was for obj[integer_index] My point exactly. If we're sticking to the same style, I would expect that for obj.method(*args, **kwargs) we would have something like: operator.methodcaller('method', *args, **kwargs) You might be missing one aspect of attrgetter, though. I can have f = operator.attrgetter('name', 'age') and then f(person) gives me (person.name, person.age). Likewise for itemgetter(1,2,3). Extending this to methodcaller is not natural; you would have x=methodcaller(('open',['foo','r'],{}),('read',[100],{}), ('close',[],{})) and then x(somestorage) (I know this is not the typical open/read/close pattern, where you would normally call read on what open returns) It might be that there is no use case for a multi-call methodgetter; I just point out that a single-call methodgetter would *not* be in the same style as attrgetter and itemgetter. attrget.attr (for obj.attr) itemget[key] (for obj[key]) I agree that would be consistent. These also wouldn't allow to get multiple items and indices. I don't know what the common use for attrgetter is: one or more attributes? Regards, Martin ___ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com