my $0.02 on MEP13

Hi,

I saw that a discussion started on transitioning to the use of properties instead of explicit getters and setters, which seems like a very good idea to me… so I thought this would be a good idea to get involved in matplotlib-devel :slight_smile:

Right now an issue raised is what to do with set_* that take multiple arguments. Taking set_title, which takes both positional and keyword arguments, as an example, my idea would be to do

ax.title = “A title”

ax.title.fontdict = fontdict

Basically, a property “foo” (in the matplotlib meaning of the word) becomes a descriptor with get => get_foo and set => set_foo, and keyword arguments to the old property setter become themselves descriptors on that descriptor.

Antony

Unfortunately descriptors don't really work like that, because when
you do `.title` on an instance that doesn't return the descriptor
itself, it just returns the result of `__get__` on the descriptor. So
in your example `.fontdict` would have to be an attribute on any
string assigned as the title. So what you really have to do for this
to work is to wrap every value returned by the descriptor in some kind
of proxy that adds the appropriate extra attributes. It also has to
do so in a way that the proxy can behave transparently like the
wrapped object, and that none of the wrapped objects attributes are
overshadowed. And it has to hypothetically work with instances any
any arbitrary type or class.

While this is somewhat doable for a limited set cases it's really more
of a can of worms than it's worth. Believe me, I've tried to solve
similar problems to this one before. A couple easier solutions: Allow
the `.title` (and other such attributes) to be assigned to with a
(value, options) tuple where the value is the title itself, and the
options is a dictionary or tuple of supported options for the title.
Another solution is to just keep set_title() for cases like this if
one wishes to set the title with additional options (while still
allowing `.title = 'foo'` for the simple case).

···

On Thu, Feb 7, 2013 at 8:40 PM, Antony Lee <antony.lee@...453...> wrote:

Hi,

I saw that a discussion started on transitioning to the use of properties
instead of explicit getters and setters, which seems like a very good idea
to me... so I thought this would be a good idea to get involved in
matplotlib-devel :slight_smile:

Right now an issue raised is what to do with set_* that take multiple
arguments. Taking set_title, which takes both positional and keyword
arguments, as an example, my idea would be to do

ax.title = "A title"
ax.title.fontdict = fontdict

Basically, a property "foo" (in the matplotlib meaning of the word) becomes
a descriptor with __get__ => get_foo and __set__ => set_foo, and keyword
arguments to the old property setter become themselves descriptors on that
descriptor.

Interesting. Just brainstorming here...then

ax.title += (None, moreoptions)

could set more options (without changing the title text or already set options), or

ax.title -= (None, deleteoptions)

could reset just certain options to default values.

Thanks,

Jason

···

On 2/7/13 8:08 PM, Erik Bray wrote:

A couple easier solutions: Allow
the `.title` (and other such attributes) to be assigned to with a
(value, options) tuple where the value is the title itself, and the
options is a dictionary or tuple of supported options for the title.

Indeed, good catch. But another issue comes to my mind: should ax1.title (that is, “ax1…title.get(ax1)” where “…” means no descriptor invoked) return a string (like now) or something that contains all the properties of the title? Returning a string copies the current behavior of get_title, but “ax2.title = ax1.title” would not do what I expect (I would expect every property related to the title to be copied). Now, if we want “ax2.title = ax1.title” to work as I expect (what do other people think here?), then there is no choice but to wrap the return value of set.

Antony

2013/2/7 Erik Bray <erik.m.bray@…149…>

···

On Thu, Feb 7, 2013 at 8:40 PM, Antony Lee <antony.lee@…453…> wrote:

Hi,

I saw that a discussion started on transitioning to the use of properties

instead of explicit getters and setters, which seems like a very good idea

to me… so I thought this would be a good idea to get involved in

matplotlib-devel :slight_smile:

Right now an issue raised is what to do with set_* that take multiple

arguments. Taking set_title, which takes both positional and keyword

arguments, as an example, my idea would be to do

ax.title = “A title”

ax.title.fontdict = fontdict

Basically, a property “foo” (in the matplotlib meaning of the word) becomes

a descriptor with get => get_foo and set => set_foo, and keyword

arguments to the old property setter become themselves descriptors on that

descriptor.

Unfortunately descriptors don’t really work like that, because when

you do .title on an instance that doesn’t return the descriptor

itself, it just returns the result of __get__ on the descriptor. So

in your example .fontdict would have to be an attribute on any

string assigned as the title. So what you really have to do for this

to work is to wrap every value returned by the descriptor in some kind

of proxy that adds the appropriate extra attributes. It also has to

do so in a way that the proxy can behave transparently like the

wrapped object, and that none of the wrapped objects attributes are

overshadowed. And it has to hypothetically work with instances any

any arbitrary type or class.

While this is somewhat doable for a limited set cases it’s really more

of a can of worms than it’s worth. Believe me, I’ve tried to solve

similar problems to this one before. A couple easier solutions: Allow

the .title (and other such attributes) to be assigned to with a

(value, options) tuple where the value is the title itself, and the

options is a dictionary or tuple of supported options for the title.

Another solution is to just keep set_title() for cases like this if

one wishes to set the title with additional options (while still

allowing .title = 'foo' for the simple case).

I think you are trying to make this too smart for its own good. I think
things should work in a simple, consistent manner. If the property is set
using a string, then it should return a string. If you assign a string to
something, it should assign a string only. If you want to start copying
other properties, we can use a separate property that accepts and returns a
different object, which I am pretty sure was part of my proposal. This
should be described in the documentation.

So if you want the title fontdict, you get something like
ax1.titletext.fontdict (where titletext is the property for a text object).

Currently ax1.get_title returns a string, so ax2.set_title(ax1.get_title())
will only copy the string. If we want to change the defaults, so that the
title-related methods work with text objects instead of strings, that is
possible (although would be a major backwards-incompatible API break). But
that is a separate discussion from MEP13, which only deals with the
transition to properties. In all cases, under this proposal, I think
properties should be kept as similar as possible to their setters and
getters. API breaks should be a separate issue.

···

On Fri, Feb 8, 2013 at 10:04 AM, Antony Lee <antony.lee@...453...> wrote:

2013/2/7 Erik Bray <erik.m.bray@...149...>

On Thu, Feb 7, 2013 at 8:40 PM, Antony Lee <antony.lee@...453...> >> wrote:
> Hi,
>
> I saw that a discussion started on transitioning to the use of
properties
> instead of explicit getters and setters, which seems like a very good
idea
> to me... so I thought this would be a good idea to get involved in
> matplotlib-devel :slight_smile:
>
> Right now an issue raised is what to do with set_* that take multiple
> arguments. Taking set_title, which takes both positional and keyword
> arguments, as an example, my idea would be to do
>
> ax.title = "A title"
> ax.title.fontdict = fontdict
>
> Basically, a property "foo" (in the matplotlib meaning of the word)
becomes
> a descriptor with __get__ => get_foo and __set__ => set_foo, and keyword
> arguments to the old property setter become themselves descriptors on
that
> descriptor.

Unfortunately descriptors don't really work like that, because when
you do `.title` on an instance that doesn't return the descriptor
itself, it just returns the result of `__get__` on the descriptor. So
in your example `.fontdict` would have to be an attribute on any
string assigned as the title. So what you really have to do for this
to work is to wrap every value returned by the descriptor in some kind
of proxy that adds the appropriate extra attributes. It also has to
do so in a way that the proxy can behave transparently like the
wrapped object, and that none of the wrapped objects attributes are
overshadowed. And it has to hypothetically work with instances any
any arbitrary type or class.

While this is somewhat doable for a limited set cases it's really more
of a can of worms than it's worth. Believe me, I've tried to solve
similar problems to this one before. A couple easier solutions: Allow
the `.title` (and other such attributes) to be assigned to with a
(value, options) tuple where the value is the title itself, and the
options is a dictionary or tuple of supported options for the title.
Another solution is to just keep set_title() for cases like this if
one wishes to set the title with additional options (while still
allowing `.title = 'foo'` for the simple case).

Indeed, good catch. But another issue comes to my mind: should ax1.title
(that is, "ax1..title.__get__(ax1)" where ".." means no descriptor invoked)
return a string (like now) or something that contains all the properties of
the title? Returning a string copies the current behavior of get_title,
but "ax2.title = ax1.title" would not do what I expect (I would expect
every property related to the title to be copied). Now, if we want
"ax2.title = ax1.title" to work as I expect (what do other people think
here?), then there is no choice but to wrap the return value of __set__.

Antony

I am not a fan of this approach. It seems to be trying to force a property
to behave like a function when it isn't meant to behave like a function.
In my mind a property is just that, a single aspect of an object. If you
want to change another aspect, you need to change another property. So
these "moreoptions" need to have their own properties, either in the axes
object or, better yet, since they are properties of the title text, have
them as properties of a text object.

···

On Fri, Feb 8, 2013 at 3:38 AM, Jason Grout <jason-sage@...691...>wrote:

On 2/7/13 8:08 PM, Erik Bray wrote:
> A couple easier solutions: Allow
> the `.title` (and other such attributes) to be assigned to with a
> (value, options) tuple where the value is the title itself, and the
> options is a dictionary or tuple of supported options for the title.

Interesting. Just brainstorming here...then

ax.title += (None, moreoptions)

could set more options (without changing the title text or already set
options), or

ax.title -= (None, deleteoptions)

could reset just certain options to default values.

Thanks,

Jason

I think this makes it over-complicated. It is much simpler, more explicit,
and more consistent to have two properties here, one that only deals with a
string, and a second that only deals with a text object. Then you can do
something like (where titletext returns the text object):

ax.titletext.fontdict

That way we automatically get what you want without any additional work or
fancy tricks in a much cleaner, more explicit, and more predictable manner.

···

On Fri, Feb 8, 2013 at 2:40 AM, Antony Lee <antony.lee@...453...> wrote:

Hi,

I saw that a discussion started on transitioning to the use of properties
instead of explicit getters and setters, which seems like a very good idea
to me... so I thought this would be a good idea to get involved in
matplotlib-devel :slight_smile:

Right now an issue raised is what to do with set_* that take multiple
arguments. Taking set_title, which takes both positional and keyword
arguments, as an example, my idea would be to do

ax.title = "A title"
ax.title.fontdict = fontdict

Basically, a property "foo" (in the matplotlib meaning of the word)
becomes a descriptor with __get__ => get_foo and __set__ => set_foo, and
keyword arguments to the old property setter become themselves descriptors
on that descriptor.

Antony

Just a crazy thought, but why are we trying to treat “title” and such as properties? When I think of properties for matplotlib, I think of edgecolors, fontsize, and linestyles. Why don’t we solve that problem first?

Cheers!
Ben Root

Yes, I realize that this (or the += approach) was overdoing it. Separating the stuff in two different properties is probably more the way to go (at least, it’s less crazy).

Even the ax.title += (string, options) approach has the problem that this would imply ax.title (in the sense of ax.dict[“title”].get(ax)) cannot be a string anymore, so this would involve some wrapper object. Ugh.

Antony

2013/2/8 Todd <toddrjen@…149…>

···

On Fri, Feb 8, 2013 at 2:40 AM, Antony Lee <antony.lee@…453…> wrote:

Hi,

I saw that a discussion started on transitioning to the use of properties instead of explicit getters and setters, which seems like a very good idea to me… so I thought this would be a good idea to get involved in matplotlib-devel :slight_smile:

Right now an issue raised is what to do with set_* that take multiple arguments. Taking set_title, which takes both positional and keyword arguments, as an example, my idea would be to do

ax.title = “A title”

ax.title.fontdict = fontdict

Basically, a property “foo” (in the matplotlib meaning of the word) becomes a descriptor with get => get_foo and set => set_foo, and keyword arguments to the old property setter become themselves descriptors on that descriptor.

Antony

I think this makes it over-complicated. It is much simpler, more explicit, and more consistent to have two properties here, one that only deals with a string, and a second that only deals with a text object. Then you can do something like (where titletext returns the text object):

ax.titletext.fontdict

That way we automatically get what you want without any additional work or fancy tricks in a much cleaner, more explicit, and more predictable manner.

In my mind there are several reasons.
First, I personally see things like “title” as properties as well. I can see why not everyone would, but that would seem to me a reason to keep the setter functions at least in some cases rather than a reason to not implement properties.

Second, it is more consistent. Users wouldn’t need to remember on a case-by-basis whether to use a setter or a property.

Third, it would require making sure the API is clan and consistent behind the scenes. The more complex setters like title would just be wrappers around the properties or property functions, so there would need to be ways to access the individual arguments on their own.

That being said, it would be possible to implement properties in stages, with simpler ones done first and more complex ones done later.

However, there are three reasons I did not include this in my proposed plan. First, it would mean we lose consistency, perhaps for a few releases. Second, it could lead to the API breakage being split over several releases rather than happening all at once. Third, if we do the behind-the-scenes cleanups first then this isn’t an issue to begin with since complexities will already be dealt with.

···

On Feb 8, 2013 11:14 PM, “Benjamin Root” <ben.root@…553…> wrote:

Just a crazy thought, but why are we trying to treat “title” and such as properties? When I think of properties for matplotlib, I think of edgecolors, fontsize, and linestyles. Why don’t we solve that problem first?