Re: [Python-Dev] The type of the result of the copy() method

2017-10-31 Thread Serhiy Storchaka

29.10.17 19:04, Guido van Rossum пише:
It's somewhat problematic. If I subclass dict with a different 
constructor, but I don't overload copy(), how can the dict.copy() method 
construct a correct instance of the subclass? Even if the constructor 
signatures match, how can dict.copy() make sure it copies all attributes 
properly? Without an answer to these questions I think it's better to 
admit defeat and return a dict instance -- classes that want to do 
better should overload copy().


I notice that Counter.copy() has all the problems I indicate here -- it 
works as long as you don't add attributes or change the constructor 
signature. I bet this isn't documented anywhere.


I am familiar with these reasons, and agree with them. But I'm curious 
why some collections chose the way of creating an instance of the same 
class. For creating an instance of the same class we have the __copy__() 
method.


An attempt to preserve a class in the returned value can cause problems. 
For example, the __add__() and __mul__() methods of deque first make a 
copy of the same type, and this can cause a crash [1]. Of course this is 
not occurred in real code, it is just yet one way of crashing the 
interpreter from Python code. list and tuple are free from this problem 
since their corresponding methods (as well as copy()) create an instance 
of the corresponding base type.


I think there were reasons for copying the type in results. It would be 
nice to formalize the criteria, in what cases copy() and other methods 
should return an instance of the base class, and in what cases they 
should create an instance of the same type as the original object. This 
would help for new types. And maybe we need to change some existing type 
(the inconsistency between WeakKeyDictionary and WeakSet looks weird).


[1] https://bugs.python.org/issue31608

___
Python-Dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] The syntax of replacement fields in format strings

2017-10-31 Thread Serhiy Storchaka
According to the specification of format string syntax [1] (I meant 
str.format(), not f-strings), both argument name and attribute name must 
be Python identifiers.


But the current implementation is more lenient and allow arbitrary 
sequences of characters while they don't contain '.', '[', ']', '{', 
'}', ':', '!'.


>>> '{#}'.format_map({'#': 42})
'42'
>>> import types
>>> '{0.#}'.format(types.SimpleNamespace(**{'#': 42}))
'42'

This can be confusing due to similarity with the format string syntaxes 
in str.format() and f-strings.


>> name = 'abc'
>>> f'{name.upper()}'
'ABC'
>>> '{name.upper()}'.format(name='abc')
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'str' object has no attribute 'upper()'

If accept only identifiers, we could produce more specific error message.

Is there a bug in the documentation or in the implementation?

[1] https://docs.python.org/3/library/string.html#format-string-syntax

___
Python-Dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] The syntax of replacement fields in format strings

2017-10-31 Thread Eric V. Smith
If I had it to do over again, I’d implement it more strictly and only allow 
chars that are valid in identifiers. 

But see https://bugs.python.org/issue31907 for a case that is currently valid 
and would break if we changed how it worked. 

I’m not sure it’s worth the churn of deprecating this and eventually making it 
illegal. 

--
Eric.

> On Oct 31, 2017, at 6:37 AM, Serhiy Storchaka  wrote:
> 
> According to the specification of format string syntax [1] (I meant 
> str.format(), not f-strings), both argument name and attribute name must be 
> Python identifiers.
> 
> But the current implementation is more lenient and allow arbitrary sequences 
> of characters while they don't contain '.', '[', ']', '{', '}', ':', '!'.
> 
> >>> '{#}'.format_map({'#': 42})
> '42'
> >>> import types
> >>> '{0.#}'.format(types.SimpleNamespace(**{'#': 42}))
> '42'
> 
> This can be confusing due to similarity with the format string syntaxes in 
> str.format() and f-strings.
> 
> >> name = 'abc'
> >>> f'{name.upper()}'
> 'ABC'
> >>> '{name.upper()}'.format(name='abc')
> Traceback (most recent call last):
>  File "", line 1, in 
> AttributeError: 'str' object has no attribute 'upper()'
> 
> If accept only identifiers, we could produce more specific error message.
> 
> Is there a bug in the documentation or in the implementation?
> 
> [1] https://docs.python.org/3/library/string.html#format-string-syntax
> 
> ___
> Python-Dev mailing list
> [email protected]
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: 
> https://mail.python.org/mailman/options/python-dev/eric%2Ba-python-dev%40trueblade.com
___
Python-Dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] The type of the result of the copy() method

2017-10-31 Thread Guido van Rossum
On Tue, Oct 31, 2017 at 3:12 AM, Serhiy Storchaka 
wrote:

> 29.10.17 19:04, Guido van Rossum пише:
>
>> It's somewhat problematic. If I subclass dict with a different
>> constructor, but I don't overload copy(), how can the dict.copy() method
>> construct a correct instance of the subclass? Even if the constructor
>> signatures match, how can dict.copy() make sure it copies all attributes
>> properly? Without an answer to these questions I think it's better to admit
>> defeat and return a dict instance -- classes that want to do better should
>> overload copy().
>>
>> I notice that Counter.copy() has all the problems I indicate here -- it
>> works as long as you don't add attributes or change the constructor
>> signature. I bet this isn't documented anywhere.
>>
>
> I am familiar with these reasons, and agree with them. But I'm curious why
> some collections chose the way of creating an instance of the same class.
> For creating an instance of the same class we have the __copy__() method.
>
> An attempt to preserve a class in the returned value can cause problems.
> For example, the __add__() and __mul__() methods of deque first make a copy
> of the same type, and this can cause a crash [1]. Of course this is not
> occurred in real code, it is just yet one way of crashing the interpreter
> from Python code. list and tuple are free from this problem since their
> corresponding methods (as well as copy()) create an instance of the
> corresponding base type.
>
> I think there were reasons for copying the type in results. It would be
> nice to formalize the criteria, in what cases copy() and other methods
> should return an instance of the base class, and in what cases they should
> create an instance of the same type as the original object. This would help
> for new types. And maybe we need to change some existing type (the
> inconsistency between WeakKeyDictionary and WeakSet looks weird).
>
> [1] https://bugs.python.org/issue31608
>

I think it all depends on the use case. (Though in some cases I suspect the
class' author didn't think too hard about it.)

The more strict rule should be that a base class cannot know how to create
a subclass instance and hence it should not bother. (Or perhaps it should
use the __copy__ protocol.) But there are some cases where a useful pattern
of subclassing a stdlib class just to add some convenience methods to it,
without changing its essence. In those cases, it might be convenient that
by default you get something that preserves its type (and full contents)
when copying without having to explicitly implement copy() or __copy__().

Another useful rule is that if a class *does* have a copy() method, a
subclass *ought* to override it (or __copy__()) to make it work right.

IOW from the class author's POV, copy() should not attempt to copy the type
of a subclass. But from the user's POV copy() is more useful if it copies
the type. This places the burden on the subclass author to override copy()
or __copy__().

Traditionally we've done a terrible job at documenting what you should to
do subclass a class, and what you can expect from the base class (e.g.
which parts of the base class are part of the API for subclasses, and which
parts are truly private -- underscores aren't used consistently in many
class implementations).

For those classes that currently preserve the type in copy(), perhaps we
could document that if one overrides __init__() or __new__() one should
also override copy() or __copy__().

And for future classes we should recommend whether it's preferred to
preserve the type in copy() or not -- I'm not actually sure what to
recommend here. I guess it depends on what other methods of the class
return new instances. If there are a lot (like for int or str) then copy()
should follow those methods' lead.

Sorry about the rambling, this is hard to get consistent.

-- 
--Guido van Rossum (python.org/~guido)
___
Python-Dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] The syntax of replacement fields in format strings

2017-10-31 Thread Guido van Rossum
I'd say let sleeping dogs lie.

On Tue, Oct 31, 2017 at 3:52 AM, Eric V. Smith  wrote:

> If I had it to do over again, I’d implement it more strictly and only
> allow chars that are valid in identifiers.
>
> But see https://bugs.python.org/issue31907 for a case that is currently
> valid and would break if we changed how it worked.
>
> I’m not sure it’s worth the churn of deprecating this and eventually
> making it illegal.
>
> --
> Eric.
>
> On Oct 31, 2017, at 6:37 AM, Serhiy Storchaka  wrote:
>
> According to the specification of format string syntax [1] (I meant
> str.format(), not f-strings), both argument name and attribute name must be
> Python identifiers.
>
> But the current implementation is more lenient and allow arbitrary
> sequences of characters while they don't contain '.', '[', ']', '{', '}',
> ':', '!'.
>
> >>> '{#}'.format_map({'#': 42})
> '42'
> >>> import types
> >>> '{0.#}'.format(types.SimpleNamespace(**{'#': 42}))
> '42'
>
> This can be confusing due to similarity with the format string syntaxes in
> str.format() and f-strings.
>
> >> name = 'abc'
> >>> f'{name.upper()}'
> 'ABC'
> >>> '{name.upper()}'.format(name='abc')
> Traceback (most recent call last):
>  File "", line 1, in 
> AttributeError: 'str' object has no attribute 'upper()'
>
> If accept only identifiers, we could produce more specific error message.
>
> Is there a bug in the documentation or in the implementation?
>
> [1] https://docs.python.org/3/library/string.html#format-string-syntax
>
> ___
> Python-Dev mailing list
> [email protected]
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/
> eric%2Ba-python-dev%40trueblade.com
>
>
> ___
> Python-Dev mailing list
> [email protected]
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/
> guido%40python.org
>
>


-- 
--Guido van Rossum (python.org/~guido)
___
Python-Dev mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com