Re: [Python-ideas] Revisiting Immutable Mappings

2018-10-18 Thread Chris Barker via Python-ideas
On Thu, Oct 18, 2018 at 10:12 AM, Sven R. Kunze  wrote:

> On 18.10.18 18:49, Anders Hovmöller wrote:
>
>> If it's AND, shouldn't it be "hasinterfaces" (notice the s!)?
>
>
yeah, that would make sense.

Is someone proposing something here? The point I was making, is in the case
of ABCs:

issubclass(a_class, an_abc)

isn't "Really" testing a subclass, but really an interface. That is - the
ABC exists solely to define an interface, not provide any functionality
(though there is some in there), and you can, in fact, use ABCs to provide
a way to check a duck-typed class that isn't an actual subclass.

So do we need a new function that makes that clear? would it functionally
be an different than issubclass with an ABC?

I honestly don't know.

Though an easy way to get the "and" behaviour -- i.e. interfaceS would be
nice.

-CHB


To be sure, we are on the same page here: "interface" refers to a set of
> attributes of the object in question, does it?
>
> E.g. like the __iter__ iterface. I usually don't care about the actual
> inheritance hierarchy but care about functionality.
>
> One could also imagine that isinstance and issubclass taking a keyword
>> argument for the logical operator. Maybe just something as simple as
>> "isinstance(foo, (a, b), all=True)"
>>
>
> Does AND even make sense for isinstance/issubclass?
>
> Cheers,
> Sven
>
>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>



-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
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] Revisiting Immutable Mappings

2018-10-18 Thread Anders Hovmöller


> Does AND even make sense for isinstance/issubclass?

Why wouldn't it? Python supports multiple inheritance. 

/ Anders
___
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] Revisiting Immutable Mappings

2018-10-18 Thread Anders Hovmöller

>> Even though, it would be the same as issubclass() (though I'd like an AND 
>> relationship with the tuple of ABCs..)
> 
> When "hasinterface" ANDs the tuple, it's already different, isn't it?
> 

If it's AND, shouldn't it be "hasinterfaces" (notice the s!)?

One could also imagine that isinstance and issubclass taking a keyword argument 
for the logical operator. Maybe just something as simple as "isinstance(foo, 
(a, b), all=True)"

/ Anders___
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] Revisiting Immutable Mappings

2018-10-16 Thread Philip Martin
I think it could inherit from the Mapping abc?

class frozendict(Mapping):
def __new__(cls, *args, **kwargs):
d = dict(*args, **kwargs)
proxy = MappingProxyType(d)
instance = super().__new__(cls)
instance.__proxy = proxy

return instance

def __hash__(self):
return hash(tuple(self.items()))

def __getattr__(self, name):
return getattr(self.__proxy, name)

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

def __iter__(self):
return self.__proxy.__iter__()

def __len__(self):
return len(self.__proxy)

def __repr__(self):
return "%s(%r)" % (type(self).__name__, dict(self))


On Tue, Oct 16, 2018 at 4:29 AM Steven D'Aprano  wrote:

> On Tue, Oct 16, 2018 at 01:02:03AM -0700, George Leslie-Waksman wrote:
> > Would a frozendict require that keys and values be hashable?
>
> Keys, yes. Values, no.
>
> If the values were hashable, the frozendict itself would also be
> hashable. If not, then it would be like trying to hash a tuple with
> unhashable items:
>
> py> hash((1, 2, {}, 3))
> Traceback (most recent call last):
>   File "", line 1, in 
> TypeError: unhashable type: 'dict'
>
>
> > It seems to me that we would need this restriction to make a reasonably
> > universal frozendict that is, itself, hashable.
>
> When people talk about frozendicts being hashable, they mean it in the
> same sense that tuples are hashable.
>
>
> For what it is worth, here's an incomplete, quick and dirty proof of
> concept frozendict, using automatic delegation:
>
> # Not good enough for production, not tested, buyer beware, etc.
> class frozendict:
> def __new__(cls, *args, **kwargs):
> d = dict(*args, **kwargs)
> proxy = types.MappingProxyType(d)
> instance = super().__new__(cls)
> instance.__proxy = proxy
> return instance
> def __hash__(self):
> return hash(tuple(self.items()))
> def __getattr__(self, name):
> return getattr(self.__proxy, name)
> def __getitem__(self, key):
> return self.__proxy[key]
> def __repr__(self):
> return "%s(%r)" % (type(self).__name__, dict(self))
>
>
> --
> 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 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] Revisiting Immutable Mappings

2018-10-16 Thread Zaur Shibzukhov


вторник, 16 октября 2018 г., 12:29:55 UTC+3 пользователь Steven D'Aprano 
написал:
>
>
> > It seems to me that we would need this restriction to make a reasonably 
> > universal frozendict that is, itself, hashable. 
>
> When people talk about frozendicts being hashable, they mean it in the 
> same sense that tuples are hashable. 
>
>
> For what it is worth, here's an incomplete, quick and dirty proof of 
> concept frozendict, using automatic delegation: 
>
> # Not good enough for production, not tested, buyer beware, etc. 
> class frozendict: 
> def __new__(cls, *args, **kwargs): 
> d = dict(*args, **kwargs) 
> proxy = types.MappingProxyType(d) 
> instance = super().__new__(cls) 
> instance.__proxy = proxy 
> return instance 
> def __hash__(self): 
> return hash(tuple(self.items())) 
> def __getattr__(self, name): 
> return getattr(self.__proxy, name) 
> def __getitem__(self, key): 
> return self.__proxy[key] 
> def __repr__(self): 
> return "%s(%r)" % (type(self).__name__, dict(self)) 
>
> For those who need more performant variant (Cython compiled) of frozendict 
frozenmap  project can be offer.
___
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] Revisiting Immutable Mappings

2018-10-16 Thread Steven D'Aprano
On Tue, Oct 16, 2018 at 01:02:03AM -0700, George Leslie-Waksman wrote:
> Would a frozendict require that keys and values be hashable?

Keys, yes. Values, no.

If the values were hashable, the frozendict itself would also be 
hashable. If not, then it would be like trying to hash a tuple with 
unhashable items:

py> hash((1, 2, {}, 3))
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unhashable type: 'dict'


> It seems to me that we would need this restriction to make a reasonably
> universal frozendict that is, itself, hashable.

When people talk about frozendicts being hashable, they mean it in the 
same sense that tuples are hashable. 


For what it is worth, here's an incomplete, quick and dirty proof of 
concept frozendict, using automatic delegation:

# Not good enough for production, not tested, buyer beware, etc.
class frozendict:
def __new__(cls, *args, **kwargs):
d = dict(*args, **kwargs)
proxy = types.MappingProxyType(d)
instance = super().__new__(cls)
instance.__proxy = proxy
return instance
def __hash__(self):
return hash(tuple(self.items()))
def __getattr__(self, name):
return getattr(self.__proxy, name)
def __getitem__(self, key):
return self.__proxy[key]
def __repr__(self):
return "%s(%r)" % (type(self).__name__, dict(self))


-- 
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] Revisiting Immutable Mappings

2018-10-16 Thread Chris Angelico
On Tue, Oct 16, 2018 at 7:02 PM George Leslie-Waksman  wrote:
>
> Would a frozendict require that keys and values be hashable?

Keys would already have to be hashable - regular dicts demand this,
and there's no reason not to for frozendict.

Values? Not so sure. Personally I would say that no, they don't HAVE
to be hashable - but that the frozendict itself would then not be
hashable.

> It seems to me that we would need this restriction to make a reasonably 
> universal frozendict that is, itself, hashable.
>

The tuple provides a good precedent here:

>>> hash((1,2,3))
2528502973977326415
>>> hash((1,2,[]))
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unhashable type: 'list'
>>>

ChrisA
___
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] Revisiting Immutable Mappings

2018-10-16 Thread George Leslie-Waksman
Would a frozendict require that keys and values be hashable?

It seems to me that we would need this restriction to make a reasonably
universal frozendict that is, itself, hashable. With this restriction for
the general case, is there still sufficient value for everyone that is
asking for a frozendict?

Without this restriction and without frozendict being hashable, is there
still sufficient value for everyone that is asking for a frozendict?

On Fri, Oct 12, 2018 at 7:31 AM Greg Ewing 
wrote:

> Chris Barker - NOAA Federal via Python-ideas wrote:
>
> > Or maybe come up with a new name
>
> We should call it a birdseyedict, because of this:
>
>
> http://www.vulture.com/2016/12/unearthing-a-rare-1971-monty-python-film-all-about-peas.html
>
> --
> Greg
> ___
> 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] Revisiting Immutable Mappings

2018-10-12 Thread Greg Ewing

Chris Barker - NOAA Federal via Python-ideas wrote:


Or maybe come up with a new name


We should call it a birdseyedict, because of this:

http://www.vulture.com/2016/12/unearthing-a-rare-1971-monty-python-film-all-about-peas.html

--
Greg
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Chris Barker via Python-ideas
On Thu, Oct 11, 2018 at 3:35 PM, Steven D'Aprano 
wrote:

> On Thu, Oct 11, 2018 at 12:34:13PM -0700, Chris Barker via Python-ideas
> wrote:
>
> > I don't care what is or isn't a subclass of what -- I don't think that's
> a
> > Pythonic question. But I do think :
> >
> > issubclass(frozendict, abc.Mapping) and issubclass(frozendict,
> abc.Hashable)
> >
> > would be useful.
>
> So you do care about what is and isn't a subclass :-)
>

well, kinda -- I don't care whether dict and frozen dict have a subclassing
relationship, and I don't care what class a given object is that gets
passed to my code. What I *might* care about is what interface it presents,
which is what ABCs are for.

If Python had a way to check ABCs without issubclass, then I wouldn't care
about subclasses at all. I'd actually kind of like to have:

hasinterface(an_object, (ABC1, ABC2, ABC3))

Even though, it would be the same as issubclass() (though I'd like an AND
relationship with the tuple of ABCs..)

Maybe I'm making a distinction that isn't really there, but I see a
subclass of an ABC is quite different than a subclass of another concrete
class.


> It is 2018 and we've had isinstance and issubclass in the language since
> Python 2.2 in 2002, I really wish that we could get away from the idea
> that checking types is unPythonic and duck-typing is the One True Way to
> do things. The old, Python 1.5 form of type-checking:
>
> type(spam) is dict
>
> was not so great, since it tested only for a specific type by identity.
> But with ABCs and virtual subclasses and inheritance, isinstance is a
> great way to check that your duck both quacks and swims, rather than
> watching it sink and drown in the middle of your function :-)
>

yeah, I'm not so sure -- I"ve been watching Python go more and more in that
direction -- and I don't think I'm happy about it.

Personally, the only time I check a type is the darn list-of-strings vs
single-string issue -- ever since we got true_division, that's the only
type error I commonly see (that isn't trivial to debug). And I still wish
Python had a Character type, and then I wouldn't need to do that either :-)

And actually, if you're talking "modern" Python, isn't static type checking
the way to do it now ?

Now that I think about it - how does MyPy/Typeshed handle the
iterable_of_strings problem? Since a single string IS and iterable of
strings?

-CHB


-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Chris Angelico
On Fri, Oct 12, 2018 at 9:16 AM Steven D'Aprano  wrote:
>
> On Fri, Oct 12, 2018 at 02:45:30AM +1100, Chris Angelico wrote:
> > On Fri, Oct 12, 2018 at 2:41 AM Chris Barker - NOAA Federal via
> > Python-ideas  wrote:
> > >
> > > > This violates the Liskov Substitution Principle.
> > >
> > > If we REALLY had a time machine, then dict would subclass frozendict,
> > > and we’d be all set.
> >
> > Thanks to virtual subclassing, we can still do this. The question is, 
> > should we?
> >
> > Intuition tells me that a frozen dictionary is a form of dictionary
> > that adds restrictions, not that a dictionary is a frozen dictionary
> > that you left out to thaw.
>
> No offence Chris, but that's why we shouldn't program by intuition :-)
>
> > But as we see from [frozen]set, it's
> > probably best to treat them as completely independent classes, both
> > implementing the basic Mapping interface.
>
> Indeed.
>

Which was my point. They probably should NOT be in a direct hierarchy,
partly because people's intuition WILL lead them to a dangerous
expectation.

ChrisA
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Steven D'Aprano
On Thu, Oct 11, 2018 at 12:34:13PM -0700, Chris Barker via Python-ideas wrote:

> I don't care what is or isn't a subclass of what -- I don't think that's a
> Pythonic question. But I do think :
> 
> issubclass(frozendict, abc.Mapping) and issubclass(frozendict, abc.Hashable)
> 
> would be useful.

So you do care about what is and isn't a subclass :-)

It is 2018 and we've had isinstance and issubclass in the language since 
Python 2.2 in 2002, I really wish that we could get away from the idea 
that checking types is unPythonic and duck-typing is the One True Way to 
do things. The old, Python 1.5 form of type-checking:

type(spam) is dict

was not so great, since it tested only for a specific type by identity. 
But with ABCs and virtual subclasses and inheritance, isinstance is a 
great way to check that your duck both quacks and swims, rather than 
watching it sink and drown in the middle of your function :-)


-- 
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] Revisiting Immutable Mappings

2018-10-11 Thread Steven D'Aprano
On Fri, Oct 12, 2018 at 02:45:30AM +1100, Chris Angelico wrote:
> On Fri, Oct 12, 2018 at 2:41 AM Chris Barker - NOAA Federal via
> Python-ideas  wrote:
> >
> > > This violates the Liskov Substitution Principle.
> >
> > If we REALLY had a time machine, then dict would subclass frozendict,
> > and we’d be all set.
> 
> Thanks to virtual subclassing, we can still do this. The question is, should 
> we?
> 
> Intuition tells me that a frozen dictionary is a form of dictionary
> that adds restrictions, not that a dictionary is a frozen dictionary
> that you left out to thaw.

No offence Chris, but that's why we shouldn't program by intuition :-) 
We don't build Smart cars by starting with a Hummer and slicing off the 
bits that aren't needed.

We already have prior art demonstrating best practice in the form 
of the Mapping and MutableMapping ABCs, and frozenset versus set for 
concrete classes.

Best practice is not to subclass a type and restrict existing 
functionality, but to start with a restricted class and extend
functionality. Or not to subclass at all.

Subclassing is not the only way to DRY -- there are other ways for 
frozendict and dict to share code other than subclassing, although 
they're not necessarily efficient or easy if frozendict is written in 
pure Python. One way is delegation to a hidden dict (like the 
MappingProxyType, except we ensure the dict is private and not shared).


# Just a sketch, not a full implementation.
class frozendict(object):
def __new__(cls, *args, **kwargs):
instance = super().__new__(cls)
instance.__d = dict(*args, **kwargs)
return instance

# Define only the methods we want, delegating to the
# hidden dict.

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

def keys(self):
return self.__d.keys()

def items(self):
return self.__d.items()


The trickiest part is probably getting hashing right. I think this would 
work:

def __hash__(self):
return hash(tuple(self.items()))



> But as we see from [frozen]set, it's
> probably best to treat them as completely independent classes, both
> implementing the basic Mapping interface.

Indeed.


-- 
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] Revisiting Immutable Mappings

2018-10-11 Thread Chris Barker via Python-ideas
BTW:

In [7]: issubclass(set, frozenset)
Out[7]: False

In [8]: issubclass(frozenset, set)
Out[8]: False

no reason to do anything different here.

and:

In [13]: issubclass(MappingProxyType, abc.Hashable)
Out[13]: False

so yes, there is a need for something different

-CHB




On Thu, Oct 11, 2018 at 12:34 PM, Chris Barker 
wrote:

> On Thu, Oct 11, 2018 at 9:54 AM, Jonathan Fine 
> wrote:
>
>> Summary: Long post. Because of LSP, neither dict nor frozendict are a
>> subclass of the other.
>
>
> given Python's dynamic typing, these issues are kinda academic :-)
>
> > Intuition tells me that a frozen dictionary is a form of dictionary
>> > that adds restrictions, not that a dictionary is a frozen dictionary
>> > that you left out to thaw.
>>
>
> well, IIUC the Liskov principle correctly then a subclass is never a
> version of a class that does less, but rather always one that does more.
>
> Think you intuition may be driven by the choice of names and history: yes,
> a frozen dict sounds like a regular dict that has been altered
> (specifically frozen) -- but if we called them "hash_table" and
> "mutable_has_table", then your intuition may be different :-)
>
> As for subclassing or not, for most Python code is makes no difference --
> polymorphism is not achieved through subclassing. and the "Pythonic" way to
> test for type is through ABCs, and we already have Mapping and
> MutableMapping, which kind of surprised me, as there is no builtin Mapping
> that isn't also a MutableMapping.
>
> Notice that I said USEFUL property P. The negation Q of property P is
>> also a property.
>
>
> well, yeah, but I think the concept of "useful" is pretty vague.
>
> in this case, is "imutablilty" the "useful" property -- or is
> "hashability"?, which would want us to use abc.Hashable.
>
> So:
>
> I don't care what is or isn't a subclass of what -- I don't think that's a
> Pythonic question. But I do think :
>
> issubclass(frozendict, abc.Mapping) and issubclass(frozendict,
> abc.Hashable)
>
> would be useful.
>
> BTW, I just noticed that:
>
> A tuple, as in ``issubclass(x, (A, B, ...))``, may be given as the target
> to check against. This is equivalent to ``issubclass(x, A) or issubclass(x,
> B) or ...`` etc.
>
> which seems less useful than "and" -- at least for ABCs
>
> I suppose that API pre-dates ABCs
>
> One way to fix this in Python 4 would be to create a common ancestor,
>> which has only the shared methods of dict and frozendict.
>
>
> which would be an immutable, but not hashable, mapping ?!?
>
> Or do
>> something similar with abstract base classes.
>>
>
> already done -- see above.
>
> -CHB
>
>
> --
>
> Christopher Barker, Ph.D.
> Oceanographer
>
> Emergency Response Division
> NOAA/NOS/OR(206) 526-6959   voice
> 7600 Sand Point Way NE   (206) 526-6329   fax
> Seattle, WA  98115   (206) 526-6317   main reception
>
> chris.bar...@noaa.gov
>



-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Chris Barker via Python-ideas
On Thu, Oct 11, 2018 at 9:54 AM, Jonathan Fine  wrote:

> Summary: Long post. Because of LSP, neither dict nor frozendict are a
> subclass of the other.


given Python's dynamic typing, these issues are kinda academic :-)

> Intuition tells me that a frozen dictionary is a form of dictionary
> > that adds restrictions, not that a dictionary is a frozen dictionary
> > that you left out to thaw.
>

well, IIUC the Liskov principle correctly then a subclass is never a
version of a class that does less, but rather always one that does more.

Think you intuition may be driven by the choice of names and history: yes,
a frozen dict sounds like a regular dict that has been altered
(specifically frozen) -- but if we called them "hash_table" and
"mutable_has_table", then your intuition may be different :-)

As for subclassing or not, for most Python code is makes no difference --
polymorphism is not achieved through subclassing. and the "Pythonic" way to
test for type is through ABCs, and we already have Mapping and
MutableMapping, which kind of surprised me, as there is no builtin Mapping
that isn't also a MutableMapping.

Notice that I said USEFUL property P. The negation Q of property P is
> also a property.


well, yeah, but I think the concept of "useful" is pretty vague.

in this case, is "imutablilty" the "useful" property -- or is
"hashability"?, which would want us to use abc.Hashable.

So:

I don't care what is or isn't a subclass of what -- I don't think that's a
Pythonic question. But I do think :

issubclass(frozendict, abc.Mapping) and issubclass(frozendict, abc.Hashable)

would be useful.

BTW, I just noticed that:

A tuple, as in ``issubclass(x, (A, B, ...))``, may be given as the target
to check against. This is equivalent to ``issubclass(x, A) or issubclass(x,
B) or ...`` etc.

which seems less useful than "and" -- at least for ABCs

I suppose that API pre-dates ABCs

One way to fix this in Python 4 would be to create a common ancestor,
> which has only the shared methods of dict and frozendict.


which would be an immutable, but not hashable, mapping ?!?

Or do
> something similar with abstract base classes.
>

already done -- see above.

-CHB


-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Jonathan Fine
A link on https://en.wikipedia.org/wiki/Liskov_substitution_principle goes to
http://www.engr.mun.ca/~theo/Courses/sd/5895-downloads/sd-principles-3.ppt.pdf
which has a very nice example (slides 14 and 15).

Slide 14: Is immutable Square a behavioural subtype of immutable
Rectangle? And vice versa?
Slide 15: Is mutable Square a behavioural subtype of mutable
Rectangle? And vice versa? And relationship between mutable and
immutable Square (resp Rectangle).

-- 
Jonathan
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Jonathan Fine
Summary: Long post. Because of LSP, neither dict nor frozendict are a
subclass of the other.

Chris Barker wrote:
> If we REALLY had a time machine, then dict would subclass frozendict,
> and we’d be all set.

Prediction is difficult, particularly when it involves the future. - Neils Bohr.

And be careful about what you wish for.  Perhaps in Python 4 we can
fix this problem.

Chris Angelico  wrote:
> Thanks to virtual subclassing, we can still do this. The question is, should 
> we?

> Intuition tells me that a frozen dictionary is a form of dictionary
> that adds restrictions, not that a dictionary is a frozen dictionary
> that you left out to thaw.

It's not quite so simple. Sometimes, less is more.
https://www.phrases.org.uk/meanings/226400.html

Suppose every instance of class A has useful property P, and B is a
subclass of A. If the Liskov substitution principle (LSP) holds, then
every instance of B also has useful property P.

Notice that I said USEFUL property P. The negation Q of property P is
also a property. Often, Q is NOT USEFUL. But what if both P and its
negation Q are BOTH USEFUL?

Well, if there should be some strange useful property P, whose
negation is also useful then (drum roll) Liskov substitution says that
neither class is a subclass of the other. (I guess that's one of the
applications of LSP.)

Here's an example of such a property. A tuple of integers is
immutable, and so has a hash and can be used as a dictionary key.
Being immutable is a useful property. A list of integers is mutable,
and so can be used to record changing state. Being mutable is a useful
property.

Aside: Last month I prepared the show part of the show-and-tell for this.

https://github.com/jfine2358/python-show-and-tell/issues/1
How do we explain this to a novice

>>> dct = dict()
>>> point = [0, 1]
>>> dct[point] = 'red'
Traceback (most recent call last):
TypeError: unhashable type: 'list'

Conclusion: If we have LSP, then dict is not a subclass of frozendict,
and frozendict is not a subclass of dict. Neither is a subclass of the
other.

One way to fix this in Python 4 would be to create a common ancestor,
which has only the shared methods of dict and frozendict. Or do
something similar with abstract base classes.

Remark: The issues here might be related to mypy typing, which I've
not used. From what I've read, it seems to rely on LSP.

I've nothing to say at present about the hardest problem here, which
is naming things. We have list and tuple. But dict and what name for
frozen, and what name for common ancestor.
https://martinfowler.com/bliki/TwoHardThings.html

-- 
Jonathan
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Chris Angelico
On Fri, Oct 12, 2018 at 2:41 AM Chris Barker - NOAA Federal via
Python-ideas  wrote:
>
> > This violates the Liskov Substitution Principle.
>
> If we REALLY had a time machine, then dict would subclass frozendict,
> and we’d be all set.

Thanks to virtual subclassing, we can still do this. The question is, should we?

Intuition tells me that a frozen dictionary is a form of dictionary
that adds restrictions, not that a dictionary is a frozen dictionary
that you left out to thaw. But as we see from [frozen]set, it's
probably best to treat them as completely independent classes, both
implementing the basic Mapping interface.

ChrisA
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Chris Barker - NOAA Federal via Python-ideas
> This violates the Liskov Substitution Principle.

If we REALLY had a time machine, then dict would subclass frozendict,
and we’d be all set.

But to what extent do we need to support ALL the ways to check for an
interface?

Personally, I think EAFTP is the most “Pythonic”, but if folks want to
check up front, then isn’t that what ABCs are for? In which case , we
already have Mapping and MutableMapping.

So if you have code that checks for Mapping when you need it mutable,
then that’s arguably a bug.

And if you code checks for dict directly, then it’s arguably unpythonic.

That being said, it probably is best not to break working code.

Would there be unpleasant consequences to making dict a subclass of FrozenDict ?

Or maybe come up with a new name: after all, lists and tuples are
independent, even though you *could* think of a tuple as a FrozenList
...

-CHB
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Jonathan Fine
> https://en.wikipedia.org/wiki/Liskov_substitution_principle
> https://en.wikipedia.org/wiki/Don%27t_repeat_yourself

I did an internet search for: python liskov (over the past year).

The first result was a Ruby page (but principle probably the same)
https://www.netguru.co/codestories/solid-principles-3-lsp

The second result was "Incompatibile signature with supertype"
https://github.com/python/mypy/issues/4250

And the code example was

class FrozenDict(MutableMapping):
 # code

So there's prior Python art for FrozenDict and Liskov inheritance.

-- 
Jonathan
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Jonathan Fine
Steve D'Aprano wrote

> Zaur Shibzukhov wrote
> > class frozendict(dict):
> This violates the Liskov Substitution Principle.
> https://en.wikipedia.org/wiki/Liskov_substitution_principle

and so, Steve said, we should not make frozendict a subclass of dict.

Perhaps Zaur was thinking of Don't Repeat Yourself (DRY)
https://en.wikipedia.org/wiki/Don%27t_repeat_yourself

Certainly, by writing

   class frozendict(dict):
   # methods

Zaur was able to use unchanged superclass methods such as __init__ and
__getitem__, and also to delegate most of __str__ to the superclass.

I see much merit in both

https://en.wikipedia.org/wiki/Liskov_substitution_principle
https://en.wikipedia.org/wiki/Don%27t_repeat_yourself

I wonder whether, in pure Python, we can nicely have them both, when
we implement frozenset. The best I can come up with is (not tested) is

class frozendict:
__slots__ = ('_self',)

def __init__(self, *argv, **kwargs):
self._self = dict(*argv, **kwargs)

def __getitem__(self, key):
return self._self.__getitem__(key)

# And so on.

-- 
Jonathan
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Steven D'Aprano
On Thu, Oct 11, 2018 at 02:18:52AM -0700, Zaur Shibzukhov wrote:
> 
> May be the following simple prototype of frozendict could be useful?
> 
> def frozen_error():
>return RuntimeError("frozendict is not mutable")
> 
> class frozendict(dict):

This violates the Liskov Substitution Principle. 

https://en.wikipedia.org/wiki/Liskov_substitution_principle

Why is that bad? Let's say you have a function that requires a dict, 
and following the principle of "Fail Fast", you check the input up 
front:

def spam(adict):
"""Input:
adict: an instance of dict
"""
if isinstance(adict, dict):
   # lots of code here
   # and deep inside the function, we end up calling:
adict[key] = "something"

I hear people objecting that isinstance checks are "unPythonic". 
Perhaps; however, the basic principle applies regardless of whether we 
are doing LBYL isinstance checks, test for the presence of a __setitem__ 
method, or do no up-front tests at all and rely on duck-typing and EAFP.

Our spam() function now accepts dicts, and rejects non-dicts, and works 
well, until somebody passes a frozendict:

spam(frozendict())

This passes the isinstance test (or the check for __setitem__). It 
passes the documented interface: frozendicts certainly are dicts, since 
they are a subclass of dict. But nevertheless, the call to setitem 
fails, and the function breaks.

We can get a good idea of how this ought to work by looking at set and 
frozenset. frozenset is *not* a subclass of set; it is a distinct class, 
so that frozensets are not sets. Rather than having mutator methods 
which raise an exception, they simply don't provide those methods at 
all:

py> f = frozenset()
py> isinstance(f, set)
False
py> hasattr(f, 'add')
False


That's how we should design frozendict.


-- 
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] Revisiting Immutable Mappings

2018-10-11 Thread Zaur Shibzukhov

May be the following simple prototype of frozendict could be useful?

def frozen_error():
   return RuntimeError("frozendict is not mutable")

class frozendict(dict):
#
def __setitem__(self, key, val):
raise frozen_error()
#
def setdefault(self, key, val=None):
raise frozen_error()
#
def update(self, ob):
raise frozen_error()
#
def pop(self):
raise frozen_error()
#
def popitem(self, ob):
raise frozen_error()
#
def clear(self, ob):
raise frozen_error()
#
def __delitem__(self, key):
raise frozen_error()
#
def __repr__(self):
return "frozendict(" + dict.__repr__(self)[1:-1] + ")"
#
def __str__(self):
return "frozendict(" + dict.__str__(self)[1:-1] + ")"
#
def fromkeys(self, keys, val=None):
return frozendict([(key,val) for key in keys])
#
def copy(self):
return frozendict(self.items())

среда, 10 октября 2018 г., 20:06:03 UTC+3 пользователь Philip Martin 
написал:
>
> Hi, I first want to thank everyone in the community for the contributions 
> over the years. I know the idea of a frozendict has been proposed before 
> and rejected. I have a use case for a frozendict implementation that to my 
> knowledge was not discussed during previous debates. My reasoning for a 
> frozendict class stems from patterns I typically see arise when performing 
> ETL or data integrations and conversions. I generally have used 
> MappingProxyType as a way to set default mapping to a function or to set an 
> empty mapping to a function. I've created a gist with an example use case:
>
> https://gist.github.com/pmart123/493edf84d9aa61691ca7321325ebb6ab
>
> I've included an example of what code typically looks like when using 
> MappingProxyType and what it could look like with a 
> frozendict implementation. I believe this use case may also be 
> under-reported in open source code as it often crops up when integrating 
> third-party data sources, which at times can't be open sourced due to 
> licensing issues. I would love to hear if anyone has used MappingProxyType 
> in a similar manner, or if this use case could help warrant a frozendict in 
> the standard library.
>
___
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] Revisiting Immutable Mappings

2018-10-11 Thread Steven D'Aprano
On Thu, Oct 11, 2018 at 01:27:50PM +1100, Chris Angelico wrote:

[...]

[Cameron Simpson]
> > Well, if it were called frozendict, indeed not. It should act like dict.
> >
> > So:
> >
> >   def frozendict(**kw):
> >   return MappingProxyType(kw)
> >
> > You could make an argument for that (or a slightly heftier version
> > accepting the various things dict accepts).

How would we make the opposite argument? That [frozen]dict *shouldn't* 
accept the same constructions that dict actually does?

Seems to me that since we've proven the utility of the various 
constructor signatures that regular dicts already support, the addition 
of "read-only" doesn't change that.

Now for the limited use-cases that MappingProxyType was originally 
designed for, as a wrapper around an existing dict, it made historical 
sense for it to only support a single dict argument. After all, it is a 
proxy, so there needs to be a dict for it to proxy.

But if we promoted it to a real mapping, not just a proxy, or introduced 
a new read-only mapping, it seems to me that the full dict constructor 
interface ought to be a no-brainer.


> > But not everything needs a special name.
> >
> 
> Point of note: A mapping proxy is NOT immutable; it is merely read-only.
[...]
> A frozendict type, if it's meant to parallel frozenset, ought to be
> hashable (subject to the hashability of its members, of course)

Good point! That's exactly the sort of difference between 
MappingProxyType and a true frozendict that I was looking for.

So there's still a use-case for a true frozendict.


> Interestingly, frozenset isn't a subclass of set. I was going to say
> that a frozendict ought to be a dict, but maybe that isn't so
> important. 

If there were a subclass relationship between frozendict and dict, it 
ought to be equivalent to this:

py> issubclass(collections.MutableMapping, collections.Mapping)
True

but having two independent types works for me too.


> Which might make a simple pure-Python frozendict actually
> pretty easy.

There's historical precedent: sets (and frozensets?) were initially 
introduced as a std library module, and only later elevated to builtins.

I would be +1 for a frozendict module in 3.8, and if it proves 
sufficient useful to elevate to a builtin, that can happen in 3.9 or 
above.



-- 
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] Revisiting Immutable Mappings

2018-10-10 Thread Serhiy Storchaka

11.10.18 07:20, João Santos пише:
One important difference between MappingProxyType and a "proper" 
frozendict, as analog to frozenset, is that MappingProxyType doesn't 
have any method to return mutated versions of itself.


MappingProxyType.copy()?

___
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] Revisiting Immutable Mappings

2018-10-10 Thread Anders Hovmöller
In tri.struct we have a class Frozen 
https://github.com/TriOptima/tri.struct/blob/master/lib/tri/struct/__init__.py 
that can be used to freeze stuff. I think something like this would be even 
better in the standard library, especially now with data classes! If we had 
this frozendict would just be:

class frozendict(dict, Frozen):
pass

/ Anders

> On 10 Oct 2018, at 19:04, Philip Martin  wrote:
> 
> Hi, I first want to thank everyone in the community for the contributions 
> over the years. I know the idea of a frozendict has been proposed before and 
> rejected. I have a use case for a frozendict implementation that to my 
> knowledge was not discussed during previous debates. My reasoning for a 
> frozendict class stems from patterns I typically see arise when performing 
> ETL or data integrations and conversions. I generally have used 
> MappingProxyType as a way to set default mapping to a function or to set an 
> empty mapping to a function. I've created a gist with an example use case:
> 
> https://gist.github.com/pmart123/493edf84d9aa61691ca7321325ebb6ab
> 
> I've included an example of what code typically looks like when using 
> MappingProxyType and what it could look like with a frozendict 
> implementation. I believe this use case may also be under-reported in open 
> source code as it often crops up when integrating third-party data sources, 
> which at times can't be open sourced due to licensing issues. I would love to 
> hear if anyone has used MappingProxyType in a similar manner, or if this use 
> case could help warrant a frozendict in the standard library.
> ___
> 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] Revisiting Immutable Mappings

2018-10-10 Thread João Santos
One important difference between MappingProxyType and a "proper"
frozendict, as analog to frozenset, is that MappingProxyType doesn't have
any method to return mutated versions of itself.

On Thu, 11 Oct 2018 at 01:24, Steven D'Aprano  wrote:

> Hi Philiip, and welcome,
>
> On Wed, Oct 10, 2018 at 12:04:48PM -0500, Philip Martin wrote:
>
> > I generally have used MappingProxyType as a way to set default mapping
> > to a function or to set an empty mapping to a function.
>
> > I've created a gist with an example use case:
> >
> > https://gist.github.com/pmart123/493edf84d9aa61691ca7321325ebb6ab
>
> Please try to keep the discussion in one place (i.e. here), for the
> benefit of the archives and for those who have email access but not
> unrestricted web access.
>
> Can you explain (in English) your use-case, and why MappingProxyType
> isn't suitable? If it *is* suitable, how does your proposal differ?
>
> If the only proposal is to rename types.MappingProxyType to a builtin
> "frozendict", that's one thing; if the proposal is something else, you
> should explain what.
>
>
> > I've included an example of what code typically looks like when using
> > MappingProxyType and what it could look like with a
> > frozendict implementation.
>
> Wouldn't that be just:
>
> from types import MappingProxyType as frozendict
> d = frozendict({'spam': 1, 'eggs': 2})
>
> versus:
>
> d = frozendict({'spam': 1, 'eggs': 2})
>
> Apart from the initial import, how would they be different? You want a
> frozendict; the existing MappingProxyType provides a frozendict (with a
> surprising name, but never mind...). Wouldn't you use them exactly the
> same way? They both (I presume) offer precisely the same read-only
> access to the mapping interface.
>
>
>
> --
> 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 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] Revisiting Immutable Mappings

2018-10-10 Thread Philip Martin
That is interesting. From my recollection, when OrderedDict was
reimplemented in C, there was advice on the thread to not implement it as a
subclass of dict.

https://bugs.python.org/issue16991

I'm far from the right person to comment on the exact reasons, but perhaps
frozenset being decoupled from set gives precedence for a frozendict not
subclassing dict? The methods clear, pop, popitem, update and setdefault
would not be necessary.


On Wed, Oct 10, 2018 at 9:28 PM Chris Angelico  wrote:

> On Thu, Oct 11, 2018 at 1:02 PM Cameron Simpson  wrote:
> >
> > On 10Oct2018 20:25, Philip Martin  wrote:
> > >Steven, that's a great idea, and I would be 100% up for your suggestion
> to
> > >have types.MappingProxyType renamed to frozendict.
> >
> > I'm not for the rename, myself. Though I'd not be against a frozendict
> > factory in builtins, a tiny shim for MappingProxyType.
> >
> > >However, the differences
> > >in the behavior of MappingProxyType's constructor versus dict's would
> make
> > >the API's behavior confusing IMO. For example, MappingProxyType(x=5,
> y=10)
> > >throws a TypeError. I don't think most people would expect this.
> >
> > Well, if it were called frozendict, indeed not. It should act like dict.
> >
> > So:
> >
> >   def frozendict(**kw):
> >   return MappingProxyType(kw)
> >
> > You could make an argument for that (or a slightly heftier version
> > accepting the various things dict accepts). Or... you could just keep
> > such a thing in your personal kit as a trivial way to spell
> > "frozendict". One could argue for the above as a nice example to live in
> > the docs perhaps.
> >
> > But not everything needs a special name.
> >
>
> Point of note: A mapping proxy is NOT immutable; it is merely read-only.
>
> >>> from types import MappingProxyType
> >>> d = {'a':1, 'b':2}
> >>> p = MappingProxyType(d)
> >>> p
> mappingproxy({'a': 1, 'b': 2})
> >>> d['a'] = 3
> >>> p
> mappingproxy({'a': 3, 'b': 2})
>
> A frozendict type, if it's meant to parallel frozenset, ought to be
> hashable (subject to the hashability of its members, of course), but
> you can't just take MPT and toss in a __hash__ method. No idea how
> important that use-case is, but Michael Selik mentioned "want[ing] to
> use a dict as a dict key about once or twice a year", which MPT is not
> able to do.
>
> Interestingly, frozenset isn't a subclass of set. I was going to say
> that a frozendict ought to be a dict, but maybe that isn't so
> important. Which might make a simple pure-Python frozendict actually
> pretty easy.
>
> ChrisA
> ___
> 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] Revisiting Immutable Mappings

2018-10-10 Thread Philip Martin
Cameron,

That's a good suggestion. Ultimately, if there are not enough various use
cases for a frozendict class, I think we could add something like this as
an example recipe similar to the recipe section in itertools. I would be
hesitant to add a quick shim to the standard library as I can't think of
another instance where a developer calls a function expecting a specific
class, and receives a different class. I'm happy to draft up some
documentation if we decide to take this route because there aren't enough
use cases. It would be great though to hear what other use cases developers
have for a frozendict to ultimately decide whether this is the case.

On Wed, Oct 10, 2018 at 9:01 PM Cameron Simpson  wrote:

> On 10Oct2018 20:25, Philip Martin  wrote:
> >Steven, that's a great idea, and I would be 100% up for your suggestion to
> >have types.MappingProxyType renamed to frozendict.
>
> I'm not for the rename, myself. Though I'd not be against a frozendict
> factory in builtins, a tiny shim for MappingProxyType.
>
> >However, the differences
> >in the behavior of MappingProxyType's constructor versus dict's would make
> >the API's behavior confusing IMO. For example, MappingProxyType(x=5, y=10)
> >throws a TypeError. I don't think most people would expect this.
>
> Well, if it were called frozendict, indeed not. It should act like dict.
>
> So:
>
>   def frozendict(**kw):
>   return MappingProxyType(kw)
>
> You could make an argument for that (or a slightly heftier version
> accepting the various things dict accepts). Or... you could just keep
> such a thing in your personal kit as a trivial way to spell
> "frozendict". One could argue for the above as a nice example to live in
> the docs perhaps.
>
> But not everything needs a special name.
>
> Cheers,
> Cameron Simpson 
>
___
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] Revisiting Immutable Mappings

2018-10-10 Thread Chris Angelico
On Thu, Oct 11, 2018 at 1:02 PM Cameron Simpson  wrote:
>
> On 10Oct2018 20:25, Philip Martin  wrote:
> >Steven, that's a great idea, and I would be 100% up for your suggestion to
> >have types.MappingProxyType renamed to frozendict.
>
> I'm not for the rename, myself. Though I'd not be against a frozendict
> factory in builtins, a tiny shim for MappingProxyType.
>
> >However, the differences
> >in the behavior of MappingProxyType's constructor versus dict's would make
> >the API's behavior confusing IMO. For example, MappingProxyType(x=5, y=10)
> >throws a TypeError. I don't think most people would expect this.
>
> Well, if it were called frozendict, indeed not. It should act like dict.
>
> So:
>
>   def frozendict(**kw):
>   return MappingProxyType(kw)
>
> You could make an argument for that (or a slightly heftier version
> accepting the various things dict accepts). Or... you could just keep
> such a thing in your personal kit as a trivial way to spell
> "frozendict". One could argue for the above as a nice example to live in
> the docs perhaps.
>
> But not everything needs a special name.
>

Point of note: A mapping proxy is NOT immutable; it is merely read-only.

>>> from types import MappingProxyType
>>> d = {'a':1, 'b':2}
>>> p = MappingProxyType(d)
>>> p
mappingproxy({'a': 1, 'b': 2})
>>> d['a'] = 3
>>> p
mappingproxy({'a': 3, 'b': 2})

A frozendict type, if it's meant to parallel frozenset, ought to be
hashable (subject to the hashability of its members, of course), but
you can't just take MPT and toss in a __hash__ method. No idea how
important that use-case is, but Michael Selik mentioned "want[ing] to
use a dict as a dict key about once or twice a year", which MPT is not
able to do.

Interestingly, frozenset isn't a subclass of set. I was going to say
that a frozendict ought to be a dict, but maybe that isn't so
important. Which might make a simple pure-Python frozendict actually
pretty easy.

ChrisA
___
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] Revisiting Immutable Mappings

2018-10-10 Thread Cameron Simpson

On 10Oct2018 20:25, Philip Martin  wrote:

Steven, that's a great idea, and I would be 100% up for your suggestion to
have types.MappingProxyType renamed to frozendict.


I'm not for the rename, myself. Though I'd not be against a frozendict 
factory in builtins, a tiny shim for MappingProxyType.



However, the differences
in the behavior of MappingProxyType's constructor versus dict's would make
the API's behavior confusing IMO. For example, MappingProxyType(x=5, y=10)
throws a TypeError. I don't think most people would expect this.


Well, if it were called frozendict, indeed not. It should act like dict.

So:

 def frozendict(**kw):
 return MappingProxyType(kw)

You could make an argument for that (or a slightly heftier version 
accepting the various things dict accepts). Or... you could just keep 
such a thing in your personal kit as a trivial way to spell 
"frozendict". One could argue for the above as a nice example to live in 
the docs perhaps.


But not everything needs a special name.

Cheers,
Cameron Simpson 
___
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] Revisiting Immutable Mappings

2018-10-10 Thread Philip Martin
It would help over using a regular dict as a default argument to a function
by preventing accidental mutation of the default or constant mapping. This
is a quickly contrived example of the convert_price function now having a
side effect by changing the translation_map.

from unicodedata import normalize
prices = [{'croissant': 1}, {'coffee': 3}]
translation_map = {'apple': 'pomme',  'coffee': 'café'}
def normalize_text(s):
return normalize('NFD', s).encode('ascii', 'ignore').decode("utf-8")

def usd_to_eur(v):
return v / 1.2

def passthrough(v):
return v

def convert_price(record, convert_map=translation_map):
# remove accents for price mapping. Oops!
for key, value in convert_map.items():
convert_map[key] = normalize_text(value)

record = {
convert_map[k]: usd_to_eur(v) for k, v in record.items()
}
return record

On Wed, Oct 10, 2018 at 6:24 PM Steven D'Aprano  wrote:

> Hi Philiip, and welcome,
>
> On Wed, Oct 10, 2018 at 12:04:48PM -0500, Philip Martin wrote:
>
> > I generally have used MappingProxyType as a way to set default mapping
> > to a function or to set an empty mapping to a function.
>
> > I've created a gist with an example use case:
> >
> > https://gist.github.com/pmart123/493edf84d9aa61691ca7321325ebb6ab
>
> Please try to keep the discussion in one place (i.e. here), for the
> benefit of the archives and for those who have email access but not
> unrestricted web access.
>
> Can you explain (in English) your use-case, and why MappingProxyType
> isn't suitable? If it *is* suitable, how does your proposal differ?
>
> If the only proposal is to rename types.MappingProxyType to a builtin
> "frozendict", that's one thing; if the proposal is something else, you
> should explain what.
>
>
> > I've included an example of what code typically looks like when using
> > MappingProxyType and what it could look like with a
> > frozendict implementation.
>
> Wouldn't that be just:
>
> from types import MappingProxyType as frozendict
> d = frozendict({'spam': 1, 'eggs': 2})
>
> versus:
>
> d = frozendict({'spam': 1, 'eggs': 2})
>
> Apart from the initial import, how would they be different? You want a
> frozendict; the existing MappingProxyType provides a frozendict (with a
> surprising name, but never mind...). Wouldn't you use them exactly the
> same way? They both (I presume) offer precisely the same read-only
> access to the mapping interface.
>
>
>
> --
> 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 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] Revisiting Immutable Mappings

2018-10-10 Thread Philip Martin
Steven, that's a great idea, and I would be 100% up for your suggestion to
have types.MappingProxyType renamed to frozendict. However, the differences
in the behavior of MappingProxyType's constructor versus dict's would make
the API's behavior confusing IMO. For example, MappingProxyType(x=5, y=10)
throws a TypeError. I don't think most people would expect this.

MappingProxyType to me though does seem to be a non-obvious name compared
to say frozenset as you have mentioned. Plus, it's included in a module
that I would say is very low level alongside functions like prepare_class,
new_class, etc.



On Wed, Oct 10, 2018 at 6:24 PM Steven D'Aprano  wrote:

> Hi Philiip, and welcome,
>
> On Wed, Oct 10, 2018 at 12:04:48PM -0500, Philip Martin wrote:
>
> > I generally have used MappingProxyType as a way to set default mapping
> > to a function or to set an empty mapping to a function.
>
> > I've created a gist with an example use case:
> >
> > https://gist.github.com/pmart123/493edf84d9aa61691ca7321325ebb6ab
>
> Please try to keep the discussion in one place (i.e. here), for the
> benefit of the archives and for those who have email access but not
> unrestricted web access.
>
> Can you explain (in English) your use-case, and why MappingProxyType
> isn't suitable? If it *is* suitable, how does your proposal differ?
>
> If the only proposal is to rename types.MappingProxyType to a builtin
> "frozendict", that's one thing; if the proposal is something else, you
> should explain what.
>
>
> > I've included an example of what code typically looks like when using
> > MappingProxyType and what it could look like with a
> > frozendict implementation.
>
> Wouldn't that be just:
>
> from types import MappingProxyType as frozendict
> d = frozendict({'spam': 1, 'eggs': 2})
>
> versus:
>
> d = frozendict({'spam': 1, 'eggs': 2})
>
> Apart from the initial import, how would they be different? You want a
> frozendict; the existing MappingProxyType provides a frozendict (with a
> surprising name, but never mind...). Wouldn't you use them exactly the
> same way? They both (I presume) offer precisely the same read-only
> access to the mapping interface.
>
>
>
> --
> 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 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] Revisiting Immutable Mappings

2018-10-10 Thread Steven D'Aprano
Hi Philiip, and welcome,

On Wed, Oct 10, 2018 at 12:04:48PM -0500, Philip Martin wrote:

> I generally have used MappingProxyType as a way to set default mapping 
> to a function or to set an empty mapping to a function.

> I've created a gist with an example use case:
> 
> https://gist.github.com/pmart123/493edf84d9aa61691ca7321325ebb6ab

Please try to keep the discussion in one place (i.e. here), for the 
benefit of the archives and for those who have email access but not 
unrestricted web access.

Can you explain (in English) your use-case, and why MappingProxyType 
isn't suitable? If it *is* suitable, how does your proposal differ?

If the only proposal is to rename types.MappingProxyType to a builtin 
"frozendict", that's one thing; if the proposal is something else, you 
should explain what.


> I've included an example of what code typically looks like when using
> MappingProxyType and what it could look like with a
> frozendict implementation.

Wouldn't that be just:

from types import MappingProxyType as frozendict
d = frozendict({'spam': 1, 'eggs': 2})

versus:

d = frozendict({'spam': 1, 'eggs': 2})

Apart from the initial import, how would they be different? You want a 
frozendict; the existing MappingProxyType provides a frozendict (with a 
surprising name, but never mind...). Wouldn't you use them exactly the 
same way? They both (I presume) offer precisely the same read-only 
access to the mapping interface.



-- 
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] Revisiting Immutable Mappings

2018-10-10 Thread Michael Selik
How does a frozendict help in that example? It's not obvious to me.

Despite not understanding that example, I'm +1 for having a frozendict. I
don't think it'll increase cognitive load much, as it'll sit right next to
frozenset when someone reads the builtins in alphabetical order. In my own
experience, I want to use a dict as a dict key about once or twice a year.
It'd be nice to have a quick way to convert to a frozendict.

On Wed, Oct 10, 2018 at 10:05 AM Philip Martin 
wrote:

> Hi, I first want to thank everyone in the community for the contributions
> over the years. I know the idea of a frozendict has been proposed before
> and rejected. I have a use case for a frozendict implementation that to my
> knowledge was not discussed during previous debates. My reasoning for a
> frozendict class stems from patterns I typically see arise when performing
> ETL or data integrations and conversions. I generally have used
> MappingProxyType as a way to set default mapping to a function or to set an
> empty mapping to a function. I've created a gist with an example use case:
>
> https://gist.github.com/pmart123/493edf84d9aa61691ca7321325ebb6ab
>
> I've included an example of what code typically looks like when using
> MappingProxyType and what it could look like with a
> frozendict implementation. I believe this use case may also be
> under-reported in open source code as it often crops up when integrating
> third-party data sources, which at times can't be open sourced due to
> licensing issues. I would love to hear if anyone has used MappingProxyType
> in a similar manner, or if this use case could help warrant a frozendict in
> the standard library.
> ___
> 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/