Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-15 Thread Steven D'Aprano
On Mon, Feb 13, 2017 at 06:14:34PM -0800, David Mertz wrote:
> On Mon, Feb 13, 2017 at 5:48 PM, Steven D'Aprano 
> wrote:
> 
> > # the clean proposed way:
> > def instance.method(self):  # or MyClass.method
> > ...
> >
> > But I don't think that we can reasonably argue that the suggested syntax
> > isn't a clear, non-trivial win over the status quo, not unless we're
> > also going to argue that introducing decorator syntax was a waste of
> > time.
> >
> 
> I argue it's not a win specifically because we HAVE decorators already.

I wouldn't word it quite like that, but I'll certainly agree that a 
decorator may be able to (almost) solve the method-injection use-case. 
Being able to write:

@inject(Class)
def method ...


is almost as nice as 

def Class.method ...


The one thing a decorator can't do is clean up after itself and avoid 
leaving an unneeded and unnecessary 'method' name in the current 
namespace.


[...]
> Moreover, I think your spelling of what it is sugar for is slightly off.
> The `del method` at the end feels wrong to me.  Specifically, in the
> example I repeated of attaching callbacks, the reason I'd want a function
> defined outside any particular class (or instance) scope is because I might
> want to use the same function as a method of various classes.

The existing syntax won't be going away, so anything you can do now, you 
will still be able to do :-)


My gut feeling is that `def Class.method` should avoid polluting the 
current namespace. If you need access to the method again, you can 
always grab it from `Class.method`.


-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-15 Thread Steven D'Aprano
On Tue, Feb 14, 2017 at 04:34:09PM -0500, Barry Warsaw wrote:
> On Feb 14, 2017, at 12:48 PM, Steven D'Aprano wrote:
> 
> >On Fri, Feb 10, 2017 at 09:05:49PM -0500, Terry Reedy wrote:
> >> Saving about 10 keystrokes is close to trivial.  
> >
> >The same argument can be made for @decorator syntax.
> >
> >And, if I understand correctly, the same argument *was* made against
> >decorator syntax: that it was trivial, unnecessary and confusing.
> 
> Well, not exactly.  Remember that the semantics, and common decorators like
> property, existed well before the decorator syntax was added.  We had a lot of
> experience writing post-definition "decorators", which taught us that the
> behavior was useful but the syntax was painful.  And adding the syntax made a
> huge improvement in readability.

Your memory of the discussion may be more accurate than mine, but the 
PEP does suggest that general unfamiliarity with the concept was still a 
large issue:

https://www.python.org/dev/peps/pep-0318/#why-is-this-so-hard


-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-14 Thread Barry Warsaw
On Feb 14, 2017, at 12:48 PM, Steven D'Aprano wrote:

>On Fri, Feb 10, 2017 at 09:05:49PM -0500, Terry Reedy wrote:
>> Saving about 10 keystrokes is close to trivial.  
>
>The same argument can be made for @decorator syntax.
>
>And, if I understand correctly, the same argument *was* made against
>decorator syntax: that it was trivial, unnecessary and confusing.

Well, not exactly.  Remember that the semantics, and common decorators like
property, existed well before the decorator syntax was added.  We had a lot of
experience writing post-definition "decorators", which taught us that the
behavior was useful but the syntax was painful.  And adding the syntax made a
huge improvement in readability.

Cheers,
-Barry


pgpIpdsRZULwq.pgp
Description: OpenPGP digital signature
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-13 Thread Steven D'Aprano
On Fri, Feb 10, 2017 at 09:05:49PM -0500, Terry Reedy wrote:

> >def foo(self):
> >pass
> >Foo.foo = foo
> >
> >Becomes:
> >
> >def Foo.foo(self):
> >pass
> 
> Saving about 10 keystrokes is close to trivial.

The same argument can be made for @decorator syntax.

And, if I understand correctly, the same argument *was* made against 
decorator syntax: that it was trivial, unnecessary and confusing.

In a realistic example, the function definition line:

def method(self, arg):

and the line which actually injects it into the class:

MyClass.method = method

may be separated by *many lines of code*. Yes, short methods are better 
than long methods, but even so, sometimes you have a long method. 
Arguably the most important part of the definition of this method (that 
it belongs to MyClass) may be lost way down the end, past the 
implementation.

Just as with decorators, the current idiom for method injecting repeats 
the method name too many times:

# the bad old way of using decorators
def function():
...
...
...
...
function = decorator(function)

# the nice clean way
@decorator
def function():
...
...
...
...


Likewise this proposal:

# the bad current way repeats the method name at least three times:
def method(self):
...
...
...
...
MyClass.method = method
del method

# and for injecting into an instance, the instance twice:
def method(self):
...
...
...
...
instance.method = types.MethodType(method, instance)
del method


# the clean proposed way:
def instance.method(self):  # or MyClass.method
...
...
...
...


We can reasonably argue that the benefit is not worth the cost; we can 
even reasonably argue that we don't wish to encourage the Interceptor 
design pattern, method swizzling, extension methods or method 
injection, whatever name you want to call it. Even monkey-patching.

But I don't think that we can reasonably argue that the suggested syntax 
isn't a clear, non-trivial win over the status quo, not unless we're 
also going to argue that introducing decorator syntax was a waste of 
time.


> I am not enthusiastic about enablin the following style of 
> class definition.
> 
> class Foo: "Object that implement the Foo protocol.
> 
> def Foo.__init__(self, x):
> self.x = s
> 
> def Foo.__getitem__(self, key):
> return vars(Foo)[key]

Neither am I, but why would anyone write classes that way? Do you have 
evidence that people in the C#, VB, Objective-C, Swift or Lua 
communities routinely do that?


> The problem with two-phase initialization is that one temporarily has a 
> partially initialized and likely useless object.  I am not enthusiastic 
> about encouraging this.

Indeed. But in practice, I don't believe that two-phase initialization 
is the usual reason for using method injection. It seems to be more 
commonly used for "introspection, overriding default behavior, or maybe 
even dynamic method loading".

https://blog.newrelic.com/2014/04/16/right-way-to-swizzle/



-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-10 Thread Terry Reedy

On 2/10/2017 4:13 AM, Markus Meskanen wrote:

I'm suggesting the addition of support to using a dot notation when
defining a function to be a method of a class, or a callback attribute.


My default starting position for every proposed syntax addition is -1.

1. Additions usually make Python more complicated and harder to learn. 
(This can be argued in particular cases.)


2. Syntax changes, when used, cut code off from past versions.

Consequently, to me, there should be a non-trivial gain to compensate 
for the above.



For example:

def foo(self):
pass
Foo.foo = foo

Becomes:

def Foo.foo(self):
pass


Saving about 10 keystrokes is close to trivial.  If Foo is defined in 
the same file, then putting the def in the class statement would save 
even more.  I am not enthusiastic about enablin the following style of 
class definition.


class Foo: "Object that implement the Foo protocol.

def Foo.__init__(self, x):
self.x = s

def Foo.__getitem__(self, key):
return vars(Foo)[key]

...


And when an object needs a callback as an attribute:

class Menu:
def __init__(self, items=None, select_callback=None):
self.items = items if items is not None else []
self.select_callback = select_callback

my_menu = Menu([item1, item2])

def my_menu.select_callback(self, item_index):
print(self.items[item_index])


A function with a 'self' parameter is normally an instance method (a 
function attribute of the class).  As an instance attribute, it will 
have be called as inst.select_callback(inst, index).  But I suppose you 
could find an example function that I like better as an instance attribute.



As opposed to:

my_menu = Menu([item1, item2])

def select_callback(self, item_index):
print(self.items[item_index])
my_menu.select_callback = select_callback


or
my_menu.select_callback = (lambda self, item_index:
print(self.items[item_index]))

The problem with two-phase initialization is that one temporarily has a 
partially initialized and likely useless object.  I am not enthusiastic 
about encouraging this.



Or defining them in "unnatural" order:


To me, this is the natural and proper order: create all the objects 
needed to initialize an instance before creating it.  When __init__ 
returns, the instance is ready to go.


In tkinter programming, callbacks must be defined
before they are used in a bind or after call, which passes them on to 
tk, where they are not directly accessible as attributes.



def select_callback(self, item_index):
print(self.items[item_index])

my_menu = Menu([item1, item2], select_callback)


Looks good to me ;-)

--
Terry Jan Reedy

___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator.

2017-02-10 Thread Gerald Britton
This is looking familiar. .Net extension methods anyone?
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-10 Thread Kyle Lahnakoski

On 2017-02-10 05:44, Markus Meskanen wrote:
>
>
> On Fri, Feb 10, 2017 at 12:29 PM, Stephan Houben  > wrote:
>
> What about using a simple decorator instead?
>
> def monkey_patch(cls):
> return lambda func: setattr(cls, func.__name__, func)
>

I suggest naming the decorator with something less generic than
"monkey_patch", like "extension_method".





___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-10 Thread Markus Meskanen
On Fri, Feb 10, 2017 at 12:29 PM, Stephan Houben 
wrote:

> What about using a simple decorator instead?
>
> def monkey_patch(cls):
> return lambda func: setattr(cls, func.__name__, func)
>
> class Foo:
>pass
>
> @monkey_patch(Foo)
> def bar(self):
> return 42
>
> Foo().bar()
> # gives 42
>

This would work, but I still believe the proposed method is much shorter
and easier to follow. Decorator approach is no different from doing
`Foo.bar = bar` under the function definition I think, except it requires
one to figure out what the decorator does first.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-10 Thread Stephan Houben
What about using a simple decorator instead?

def monkey_patch(cls):
return lambda func: setattr(cls, func.__name__, func)

class Foo:
   pass

@monkey_patch(Foo)
def bar(self):
return 42

Foo().bar()
# gives 42

2017-02-10 11:15 GMT+01:00 Matthias welp :

> Hi Markus,
>
> Thanks for writing this up, as I've had this same very valid problem
> before.
>
> On 10 February 2017 at 10:13, Markus Meskanen 
> wrote:
> > I'm suggesting the addition of support to using a dot notation when
> defining
> > a function to be a method of a class, or a callback attribute.
>
> Your solution to me seems like a 'hack': class monkey-patching during
> runtime
> is already available if you really need it, and your proposal only
> makes it easier,
> which I don't really like.
>
> > This functionality would be useful in the few rare cases where the class
> > itself needs to be accessed in the function's definition (decorator,
> typing,
> > etc
>
> This problem could just as well be solved by allowing access to a
> scope-level
> variable (__class__? __type__?) which is available in the class body at
> construction time, which points to the (eventual) class type object,
> or evaluating
> the type hints in a class only after the class is created, which then
> allows for that
> class to be pointed to in the type annotations.
>
> E.G. this does not work right now:
>
> class A:
> def foo(self: A):
> pass
>
> as it fails with NameError: A is not defined, whereas you'd expect it to
> work.
>
> The problem is very annoying when you're trying to work with the dunder
> methods for e.g. numerical objects, as you cannot say '+ is only allowed
> for
> these types', but it is not limited to this scope only.
>
>
> -Matthias
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Re: [Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-10 Thread Steven D'Aprano
On Fri, Feb 10, 2017 at 11:13:47AM +0200, Markus Meskanen wrote:
> I'm suggesting the addition of support to using a dot notation when
> defining a function to be a method of a class, or a callback attribute. For
> example:
> 
> def foo(self):
> pass
> Foo.foo = foo
> 
> Becomes:
> 
> def Foo.foo(self):
> pass

That saves one line, at the cost of introducing even more complexity to 
the language.

Are these use-cases common enough to justify the extra syntax?


> Other syntaxes can also be used if the dot itself is an issue, although I
> dislike these:
> 
> def Foo:foo(self):
> def foo@Foo(self):
> def Foo>foo(self):
> def Foo(self):

That's just putting arbitrary symbols into the statement.

I know that *ultimately* all symbols are arbitrary, but . dot means 
attribute access in Python, so Foo.foo at least has some connection to 
creating an attribute of Foo called foo. In what way does "Foo greater 
than foo" suggest to the reader that foo ends up as an attribute of Foo?


> This functionality would be useful in the few rare cases where the class
> itself needs to be accessed in the function's definition (decorator,
> typing, etc.):

I'm sure that there are a number of use-cases for injecting a method 
into an existing class. But we already have a way of doing that:

def method(self): ...
Spam.method = method

What advantage does this proposed syntax have?

Since that's not actually a rhetorical question, I'll answer it myself:

def Spam.method(self) not only saves the line

Spam.method = method

but it also avoids leaving a global name "method" in the namespace (no 
need to follow with `del method`); it makes it explicit from the 
beginning that the function is an attribute of Spam.

If the implementation is clever enough, it can avoid clashing with a 
global of the same name:

eggs = "something"

def Spam.eggs(self):
...

def Cheese.eggs(self):
...

assert eggs == "something"


So the idea isn't without merit; but the question in my mind is whether 
the advantages outweigh the extra complexity.


-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] Define a method or function attribute outside of a class with the dot operator

2017-02-10 Thread Markus Meskanen
I'm suggesting the addition of support to using a dot notation when
defining a function to be a method of a class, or a callback attribute. For
example:

def foo(self):
pass
Foo.foo = foo

Becomes:

def Foo.foo(self):
pass

Other syntaxes can also be used if the dot itself is an issue, although I
dislike these:

def Foo:foo(self):
def foo@Foo(self):
def Foo>foo(self):
def Foo(self):

This functionality would be useful in the few rare cases where the class
itself needs to be accessed in the function's definition (decorator,
typing, etc.):

@barify(Foo)
def Foo.method(self, other: Foo) -> Foo:
pass

And when an object needs a callback as an attribute:

class Menu:
def __init__(self, items=None, select_callback=None):
self.items = items if items is not None else []
self.select_callback = select_callback

my_menu = Menu([item1, item2])

def my_menu.select_callback(self, item_index):
print(self.items[item_index])

As opposed to:

my_menu = Menu([item1, item2])

def select_callback(self, item_index):
print(self.items[item_index])
my_menu.select_callback = select_callback

Or defining them in "unnatural" order:

def select_callback(self, item_index):
print(self.items[item_index])

my_menu = Menu([item1, item2], select_callback)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/