[Python-Dev] Re: PEP 467: Minor bytes and bytearray improvements

2021-11-08 Thread Victor Stinner
The ascii() constructor is not well specified by the PEP. There are
only a few examples. I don't understand how it's supposed by be
implemented. Would you mind to elaborate its specification?

Is it implement "like" ascii(obj).encode("ascii") but with minor
changes? What changes?

Victor
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/LE5WDOPOCEVSLSFYVZQYDGZYUBYPLAN4/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Oh wow, this is really impressive

2021-11-08 Thread Victor Stinner
What's New in Python 3.10 lists other suggestions and enhanced error messages:
https://docs.python.org/dev/whatsnew/3.10.html#better-error-messages

Victor

On Fri, Oct 29, 2021 at 7:22 PM Steven D'Aprano  wrote:
>
> I was using Python 3.10 and got this NameError when I mistyped a name:
>
> NameError: name 'KeyboardInterrupted' is not defined. Did you mean: 
> 'KeyboardInterrupt'?
>
> It even works for attribute errors too.
>
> That's fantastic! This is a really amazing useability improvement, thank
> you everyone who was involved! I literally squeed :-)
>
> I just may spend a few days deliberately mistyping names in the REPL
> just to see this :-)
>
>
> --
> Steve
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at 
> https://mail.python.org/archives/list/python-dev@python.org/message/2CUCVKZ44IYCW5QRV4CMVC7YDYBCJFYG/
> Code of Conduct: http://python.org/psf/codeofconduct/



-- 
Night gathers, and now my watch begins. It shall not end until my death.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/3CCG3BMMGG2RDI4IXIRCO3C6ULCCJHPV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 467: Minor bytes and bytearray improvements

2021-11-08 Thread Ethan Furman

On 11/8/21 4:45 AM, Victor Stinner wrote:

> Is it implement "like" ascii(obj).encode("ascii") but with minor
> changes? What changes?

It works like `str()`, but you get ascii-encoded bytes (or an exception if 
that's not possible).

The difference with the built-in ascii is the absence of extra quotes and the 
`b` indicator when a string is used:

```
>>> u_var = u'abc'
>>> b_var = b'abc'

>>> str(u_var)
'abc'

>>> str(b_var)
"b'abc'"

>>> ascii(b_var)
"b'abc'"

>>> b'%a' % (u_var)  # the docs will be updated to refer to %a as "ascii-repr"
b"'abc'" # as it mirrors %r but only returns ascii-encoded bytes

>>> bytes.ascii(u_var)
b'abc'


--
~Ethan~
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/X3XUYTCEM7IWTID2GING62LCEG3XKM7Q/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] containment and the empty container

2021-11-08 Thread Ethan Furman

When is an empty container contained by a non-empty container?

For example:

{} in {1:'a', 'b':2]   <-- TypeError because of hashability

set() in {1, 2, 'a', 'b'}  <-- ditto

[] in ['a', 'b', 1, 2]  <-- False

'' in 'a1b2'  <-- True

SomeFlag.nothing in SomeFlag.something  <--  ???


Personally, I have never had a use for '' in 'some string' being True, and always have to guard against that scenario. 
Likewise, if an empty collection of flags is contained by a collection of flags, then that will trip me up as well; on 
the other hand, it seems that collections of related flags are often treated as in set theory, where the empty set is a 
member of any non-empty set...


So, does Flag adhere to set theory, or is just happenstance that some operators 
work the same for both groups?

Can we have `SomeFlag.nothing in SomeFlag.something` be `False`, or would that 
be too surprising?

--
~Ethan~
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/DAQV4BQDX6NLPF4PLEZ233FPANNKKIVW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread Cameron Simpson
Note: I know you understand all this, I'm not "explaining" how things 
work below, I'm explaining how/why I think about how these work.

On 08Nov2021 13:43, Ethan Furman  wrote:
>When is an empty container contained by a non-empty container?
[...]
>For example:
>
>{} in {1:'a', 'b':2]   <-- TypeError because of hashability
>set() in {1, 2, 'a', 'b'}  <-- ditto

Right. Also, the members are not dicts or sets, respectively.

>[] in ['a', 'b', 1, 2]  <-- False

The members are not lists.

>'' in 'a1b2'  <-- True

This is because "in" isn't measuring a setlike membership (I mean here, 
"subset"). It is looking for a substring. Compare:

>>> 'abc' in 'abcdef'
True
>>> 'abc' in 'abxcdef'
False

So str is not a set, because of its sequential nature.

>SomeFlag.nothing in SomeFlag.something  <--  ???

I would expect "true", myself.

>Personally, I have never had a use for '' in 'some string' being True, 
[...]
>So, does Flag adhere to set theory, or is just happenstance that some 
>operators work the same for both groups?

I would expect flags to be like sets. I've always thought of them that 
way - independent presence/absence of things. They're not sequenced. (If 
they're packed into ints there's some sequencing in the storage behind 
the scenes, but that isn't part of my model the rest of the time.)

>Can we have `SomeFlag.nothing in SomeFlag.something` be `False`, or 
>would that be too surprising?

I'd be surprised by this. I would rather a clean "subset" notion here.

I was going to digress about "<" vs "in". For sets, "<" means subset and 
"in" means "element in set". That isn't exactly parallel to flags. What 
if "SomeFlag.nothing < SomeFlag.something" meant a subset test? Would we 
need "in" at all? Or is "<" out of the picture because FLags, or at 
least IntFlags, might do numeric-like stuff with "<"?

Cheers,
Cameron Simpson 
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/Y2D2CUBO3C76DFTQTFV2V4IN7WPS72HD/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread Tim Peters
[Ethan Furman ]
> When is an empty container contained by a non-empty container?

That depends on how the non-empty container's type defines
__contains__. The "stringish" types (str, byte, bytearray) work _very_
differently from others (list, set, tuple) in this respect.

   t in x

for the latter answers whether t is contained in x, but in the former
case answers whether t is a _sub_sequence (contiguous) of x.

So, e.g.,

>>> "ab" in "cab"
True
>>> b"ab" in b"cab"
True
>>> bytearray(b"ab") in bytearray(b"cab")
True

while

>>> ['a', 'b'] in ['c', 'a', 'b']
False
>>> ('a', 'b') in ('c', 'a', 'b')
False

For every stringish type S, S() (the empty value of that type) is a
subsequence of every value of type S, and `in` reflects that truth.

> Personally, I have never had a use for '' in 'some string' being True, and
> always have to guard against that scenario.

Don't know whether or not any of my code relies on it, but am pretty
sure any relevant code would have already special-cased an empty
string out any code path that would have tried to apply 'in` to it.
Not particularly because it would be surprised by True, but because
there's nothing useful it could _do_ with an empty string regardless
(e.g., every slice of it would be equal to the original - an empty
string is an end case for any string algorithm).

> .. on the other hand, it seems that collections of related flags are often 
> treated
> as in set theory, where the empty set is a member of any non-empty set.

Not how any set theory I've ever seen works: a set S contains the
empty set if and only if some member of S _is_ the empty set.  Which
is also how Python's frozenset.__contains__ works (a plain Python set
can never contain the empty set, because only a frozenset can contain
a set (empty or not)).
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/SSIRKW7TR5RUTOXLFWVGI7NAIZOHQKGH/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread Steven D'Aprano
On Mon, Nov 08, 2021 at 01:43:03PM -0800, Ethan Furman wrote:

> When is an empty container contained by a non-empty container?
[...]
> SomeFlag.nothing in SomeFlag.something  <--  ???

I don't think that consistency with other containers is particularly 
relevant here. More useful is consistency with other flag objects.

What's SomeFlag? I presume it is some sort of Enum, or bitset.

Presumably SomeFlag.nothing is equivalent to a bitset of all zeroes. 
(If it means something else, then I have no clue what to suggest.) You 
might have:

something = 0b11010

0 in something # ???
1 in something # False
2 in something # True
4 in something # False
8 in something # True
16 in something # True
32 in something # False

So much is obvious. But what about `3 in something`?

If that is interpreted as an *all* operation, you get:

3 in something --> all(i in something for i in (1, 2)) # False

but if it is an *any* operation:

3 in something --> any(i in something for i in (1, 2)) # True

I don't mean to imply that you must actually use all/any in your 
implementation. I mean only that it is conceptually equivalent to ANDing 
each of the flags (all) versus ORing the flags (any).

*If* that is how you interpret your containment tests, that implies a 
natural interpretation for `nothing in something`. The vacuous truth of 
all is True, and of any is False:

0 in something --> all(i in something for i in ()) # True
0 in something --> any(i in something for i in ()) # False

Vacuous truth is not the only possible interpretation. If you have some 
other obvious and natural interpretation of `0 in something` then you 
probably wouldn't be asking here, but if you did, you could follow that 
interpretation. With a good reason to violate the vacuous truth rules, 
it would only be a *little* surprising.


-- 
Steve
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/ZRSZG4UM67GGZLHMUG5GQ4BINLMFC2O4/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread MRAB

On 2021-11-08 22:10, Cameron Simpson wrote:

Note: I know you understand all this, I'm not "explaining" how things
work below, I'm explaining how/why I think about how these work.

On 08Nov2021 13:43, Ethan Furman  wrote:

When is an empty container contained by a non-empty container?

[...]

For example:

{} in {1:'a', 'b':2]   <-- TypeError because of hashability
set() in {1, 2, 'a', 'b'}  <-- ditto


Right. Also, the members are not dicts or sets, respectively.


More precisely, none of the keys are an empty set.


[] in ['a', 'b', 1, 2]  <-- False


The members are not lists.


'' in 'a1b2'  <-- True


This is because "in" isn't measuring a setlike membership (I mean here,
"subset"). It is looking for a substring. Compare:

 >>> 'abc' in 'abcdef'
 True
 >>> 'abc' in 'abxcdef'
 False

So str is not a set, because of its sequential nature.


SomeFlag.nothing in SomeFlag.something  <--  ???


I would expect "true", myself.


I'm not so sure.

A flag could be a member, but could a set of flags?

Personally, I have never had a use for '' in 'some string' being True, 

[...]
So, does Flag adhere to set theory, or is just happenstance that some 
operators work the same for both groups?


I would expect flags to be like sets. I've always thought of them that
way - independent presence/absence of things. They're not sequenced. (If
they're packed into ints there's some sequencing in the storage behind
the scenes, but that isn't part of my model the rest of the time.)

Can we have `SomeFlag.nothing in SomeFlag.something` be `False`, or 
would that be too surprising?


I'd be surprised by this. I would rather a clean "subset" notion here.

I was going to digress about "<" vs "in". For sets, "<" means subset and
"in" means "element in set". That isn't exactly parallel to flags. What
if "SomeFlag.nothing < SomeFlag.something" meant a subset test? Would we
need "in" at all? Or is "<" out of the picture because FLags, or at
least IntFlags, might do numeric-like stuff with "<"?

Actually, '<' means _proper_ subset (not ==), '<=' means subset 
(possibly ==).

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/ML34IPBMSSNATGU3343HJVDOPNSF7FGO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread Cameron Simpson
On 08Nov2021 23:32, MRAB  wrote:
>On 2021-11-08 22:10, Cameron Simpson wrote:
>>>{} in {1:'a', 'b':2]   <-- TypeError because of hashability
>>>set() in {1, 2, 'a', 'b'}  <-- ditto
>>>[] in ['a', 'b', 1, 2]  <-- False
>>
>>Right. Also, the members are not dicts or sets, respectively.
>>
>More precisely, none of the keys are an empty set.

Aye, for the examples. But I was highlighting that the set/lists members 
are a different type from the left-hand thing (empty set/list). A 
category error, to my mind.

>>>SomeFlag.nothing in SomeFlag.something  <--  ???
>>
>>I would expect "true", myself.
>>
>I'm not so sure.
>
>A flag could be a member, but could a set of flags?

Probably one flavour should raise a TypeError then with this comparison.  
I wouldn't want "member flag present in SomeFlag.something" and 
"set-of-members present in SomeFlag.something" to both be valid, there 
is so much scope for ambiguity/accidents there. I would rather punt the 
"set-of-members present" off to "<"/"<=" if we want to say either (which 
of course we should be able to say).

So: To me "SomeFlag.nothing" is a set of flags, empty. _Not_ an 
individual flag (a member).

Which means that _if_ we had a subset/strict-subset test, I'd want 
"SomeFlag.nothing in" to raise a TypeError, since we should use the 
subset/strict-subset operator for that flavour.

Which means I'm backtracking to TypeError, not 'true". _Provided" this 
is a "member in set" comparison.

Of course, I think resently we don't distinguish a flag combination name 
(".nothing", ".red_and_blue"==0b11) from single flags overtly. If there 
are trite, _fast_, way to test count_of_flags(flag_value)==1 ? i.e. can 
"members" be automatically distinguished from flag combinations 
(obviously such a definition would exclude a 
combination-of-just-1-flag).

>>I was going to digress about "<" vs "in". For sets, "<" means subset 
>>and
>>"in" means "element in set". That isn't exactly parallel to flags. What
>>if "SomeFlag.nothing < SomeFlag.something" meant a subset test? Would we
>>need "in" at all? Or is "<" out of the picture because FLags, or at
>>least IntFlags, might do numeric-like stuff with "<"?
>>
>Actually, '<' means _proper_ subset (not ==), '<=' means subset 
>(possibly ==).

Point taken. I'll try to be more precise. Warning: I'll become more 
wordy.

Cheers,
Cameron Simpson 
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/5SQCDE7HMKQUTAQPZKAK2SWZZ22SN36D/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread MRAB

On 2021-11-09 00:27, Cameron Simpson wrote:

On 08Nov2021 23:32, MRAB  wrote:
>On 2021-11-08 22:10, Cameron Simpson wrote:
>>>{} in {1:'a', 'b':2]   <-- TypeError because of hashability
>>>set() in {1, 2, 'a', 'b'}  <-- ditto
>>>[] in ['a', 'b', 1, 2]  <-- False
>>
>>Right. Also, the members are not dicts or sets, respectively.
>>
>More precisely, none of the keys are an empty set.

Aye, for the examples. But I was highlighting that the set/lists members
are a different type from the left-hand thing (empty set/list). A
category error, to my mind.

>>>SomeFlag.nothing in SomeFlag.something  <--  ???
>>
>>I would expect "true", myself.
>>
>I'm not so sure.
>
>A flag could be a member, but could a set of flags?

Probably one flavour should raise a TypeError then with this comparison.
I wouldn't want "member flag present in SomeFlag.something" and
"set-of-members present in SomeFlag.something" to both be valid, there
is so much scope for ambiguity/accidents there. I would rather punt the
"set-of-members present" off to "<"/"<=" if we want to say either (which
of course we should be able to say).

So: To me "SomeFlag.nothing" is a set of flags, empty. _Not_ an
individual flag (a member).

Which means that _if_ we had a subset/strict-subset test, I'd want
"SomeFlag.nothing in" to raise a TypeError, since we should use the
subset/strict-subset operator for that flavour.

Which means I'm backtracking to TypeError, not 'true". _Provided" this
is a "member in set" comparison.

Of course, I think resently we don't distinguish a flag combination name
(".nothing", ".red_and_blue"==0b11) from single flags overtly. If there
are trite, _fast_, way to test count_of_flags(flag_value)==1 ? i.e. can
"members" be automatically distinguished from flag combinations
(obviously such a definition would exclude a
combination-of-just-1-flag).


Are you asking whether there's a quick way to check if only 1 bit is set?

If yes, then the answer is yes:

    bitflags != 0 and (bitflags & (bitflags - 1)) == 0

>>I was going to digress about "<" vs "in". For sets, "<" means subset 
>>and

>>"in" means "element in set". That isn't exactly parallel to flags. What
>>if "SomeFlag.nothing < SomeFlag.something" meant a subset test? Would we
>>need "in" at all? Or is "<" out of the picture because FLags, or at
>>least IntFlags, might do numeric-like stuff with "<"?
>>
>Actually, '<' means _proper_ subset (not ==), '<=' means subset 
>(possibly ==).


Point taken. I'll try to be more precise. Warning: I'll become more
wordy.

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/VK4RPPJBAZJQ7Z7V3UVU6LE4DS4FJFUC/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread Guido van Rossum
On Mon, Nov 8, 2021 at 1:43 PM Ethan Furman  wrote:

> When is an empty container contained by a non-empty container?
>
> For example:
>
> {} in {1:'a', 'b':2}   <-- TypeError because of hashability
>

(You accidentally wrote a square close bracket, but I know you meant a
curly close brace. :-}


> set() in {1, 2, 'a', 'b'}  <-- ditto
>
> [] in ['a', 'b', 1, 2]  <-- False
>

These examples make me think that you're somehow confused between "is an
element of" (which for Python sets is spelled using 'in', and has a similar
spelling and meaning for dicts and sequences), and "is a subset of" (which
we spell as '<=' for sets, and don't support for other types).


> '' in 'a1b2'  <-- True
>

As Steven explained this is a different case again (subsequence, not subset
or element).

SomeFlag.nothing in SomeFlag.something  <--  ???
>

This case definitely sounds to me like there is that confusion. Assuming
'nothing' is zero, it is not an *element*, so it should not be tested with
'in'. The 'in' operator should only be used if the left operator represents
exactly one flag set.

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/2VTVWAWS3A5KTNOLIAOXWEZEHRGUHOLV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread John Melendowski
I think he's confusing the fact that empty is a subset of every set
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/WQWA3QEODKURIWRPROMQB7BET5K26QSI/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread Ethan Furman

Let's use a concrete example:  `re.RegexFlag`

```
Help on function match in module re:

match(pattern, string, flags=0)
Try to apply the pattern at the start of the string, returning
a Match object, or None if no match was found.
```

In use we have:

result = re.match('present', 'who has a presence here?', 
re.IGNORECASE|re.DOTALL)

Inside `re.match` we have `flags`, but we don't know if `flags` is nothing (0), a single flag (re.ASCII, maybe) or a 
group of flags (such as in the example).  For me, the obvious way to check is with:


if re.IGNORECASE in flags:  # could be re.I in 0, re.I in 2, re.I in 5, etc.
   ...

Now, suppose for the sake of argument that there was a combination of flags 
that had its own code path, say

weird_case = re.ASCII | re.LOCALE | re.MULTILINE

I can see that going two ways:

weird_case in flags   # if other flags allowed

or

weird_case is flags   # if no other flags allowed


The idiom that I'm shooting for is using `in` to check for flags:

- flag1 in flag1 True
- flag1 in (flag1 | flag2)   True
- flag3 in (flag1 | flag2)   True
- flag3 in flag1 False
- flag3 in flag4 False

and

- flag0 in any flag  False
- any flag in flag0  False

And, of course, if we want to know if the thing we have is exactly flag1:

flag is flag1

will tell us.

Does this make sense?

--
~Ethan~
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/7P552C66N6S3OBLH4UPWINU7TVPFT2Y3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread Guido van Rossum
On Mon, Nov 8, 2021 at 7:26 PM Ethan Furman  wrote:

> Let's use a concrete example:  `re.RegexFlag`
>
> ```
> Help on function match in module re:
>
> match(pattern, string, flags=0)
>  Try to apply the pattern at the start of the string, returning
>  a Match object, or None if no match was found.
> ```
>
> In use we have:
>
>  result = re.match('present', 'who has a presence here?',
> re.IGNORECASE|re.DOTALL)
>
> Inside `re.match` we have `flags`, but we don't know if `flags` is nothing
> (0), a single flag (re.ASCII, maybe) or a
> group of flags (such as in the example).  For me, the obvious way to check
> is with:
>
>  if re.IGNORECASE in flags:  # could be re.I in 0, re.I in 2, re.I in
> 5, etc.
> ...
>

Yes.

Now, suppose for the sake of argument that there was a combination of flags
> that had its own code path, say
>
>  weird_case = re.ASCII | re.LOCALE | re.MULTILINE
>
> I can see that going two ways:
>
>  weird_case in flags   # if other flags allowed
>

I would spell this as

if flags & weird_case == weird_case:

(which BTW works too if `flags` and `weird_case` are sets!)

or
>
>  weird_case is flags   # if no other flags allowed
>

this should be spelled using `==`, not using `is` (which is reserved for
identity, but here we're comparing values). And again this works for sets
too. (Just don't confuse set elements with subsets!)


> The idiom that I'm shooting for is using `in` to check for flags:
>
> - flag1 in flag1 True
> - flag1 in (flag1 | flag2)   True
> - flag3 in (flag1 | flag2)   True
>

Did you mean False for this last one?

- flag3 in flag1 False
> - flag3 in flag4 False
>

When `flag` is a single flag bit and `flags` is an unknown combination of
flag bits, you can conceivably make it so you can write this as `flag in
flags`. But `in` doesn't work when sets are represented as bits in an
integer (which is the analogy you're going for?)


> and
>
> - flag0 in any flag  False
>
- any flag in flag0  False
>

What is `any flag` here?


> And, of course, if we want to know if the thing we have is exactly flag1:
>
>  flag is flag1
>
> will tell us.
>

Please use `==` here.


> Does this make sense?
>

WHen thinking about sets of flag bits, do you actually visualize them as
bits in an integer? That's how I always think of them. Suppose we have
three flags, F1, F2 and F3. Let's write them in binary:

F1 = 0b001
F2 = 0b010
F3 = 0b100

Let's have a flags variable composed of F1 and F3:

flags = 0b101

F1 & flags is a bitwise AND of 0b001 and 0b101, which of course is 0b001
(and so on):

F1 & flags == 0b001 & 0b101 == 0b001
F2 & flags == 0b010 & 0b101 == 0b000
F3 & flags == 0b100 & 0b101 == 0b100

IF weird_case is F2 combined with F3, we get

weird_case == F2|F3 == 0b010|0b100 == 0b110

Etc., etc.

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/5CKFGWS2KOVEQCJM745RF6PS7FWY2MGR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: containment and the empty container

2021-11-08 Thread Ethan Furman

Something to keep in mind as these discussions continue:  Enums are already 
unusual in several ways:

- the class itself is iterable
- the class itself supports containment checks of its enum members
- the enum members are created, and guaranteed singletons, during class creation
- the enum members are instannces of the class
- calling the class with a value, which in other classes/types would return a 
new instance, instead
  returns one of the existing enum members, or raises if such a member does not 
exist
- and probably other things I'm forgetting at the moment

Flag is a subclass of Enum.  Some of its peculiarities:

- bitwise operations are supported, and return a "new" instance of the combined 
value
- the "new" instance is also a singleton (so `(F1 | F2) is (F1 | F2) is True`
- the "new" instance is an instance of the Flag class
- flags are iterable -- `list(F1) == [F1]; list(F1 | F2) == [F1, F2]`
- iterating over a Flag only returns the "pure" (aka single-bit) flags, even if 
multi-flag instances
  have been created (at least, they will in 3.11)


On 11/8/21 8:32 PM, Guido van Rossum wrote:
> On Mon, Nov 8, 2021 at 7:26 PM Ethan Furman wrote:
>>
>> Let's use a concrete example:  `re.RegexFlag`
>>
>> ```
>> Help on function match in module re:
>>
>> match(pattern, string, flags=0)
>>   Try to apply the pattern at the start of the string, returning
>>   a Match object, or None if no match was found.
>> ```
>>
>> In use we have:
>>
>>   result = re.match('present', 'who has a presence here?', 
re.IGNORECASE|re.DOTALL)
>>
>> Inside `re.match` we have `flags`, but we don't know if `flags` is nothing 
(0), a single flag (re.ASCII, maybe) or a
>> group of flags (such as in the example).  For me, the obvious way to check 
is with:
>>
>>   if re.IGNORECASE in flags:  # could be re.I in 0, re.I in 2, re.I in 
5, etc.
>>  ...
>
> Yes.

Note that the 0, 2, and 5 above are representative of the flag value passed in.

>> Now, suppose for the sake of argument that there was a combination of flags 
that had its own code path, say
>>
>>   weird_case = re.ASCII | re.LOCALE | re.MULTILINE
>>
>> I can see that going two ways:
>>
>>   weird_case in flags   # if other flags allowed
>>
>
> I would spell this as
>
>  if flags & weird_case == weird_case:
> (which BTW works too if `flags` and `weird_case` are sets!)

That is a legitimate way to spell that operation, although sets wouldn't actually work since re.match expects an integer 
or a RegexFlag.


>> or
>>
>>   weird_case is flags   # if no other flags allowed
>>
>
> this should be spelled using `==`, not using `is` (which is reserved for 
identity, but here we're comparing values).

Instances of combined flags are also guaranteed singletons, so `is` is fine 
(unless we're talking style choices).


>> The idiom that I'm shooting for is using `in` to check for flags:
>>
>> - flag1 in flag1 True
>> - flag1 in (flag1 | flag2)   True
>> - flag3 in (flag1 | flag2)   True
>
> Did you mean False for this last one?

Nope.  flag3 is flag1 | flag2, so the same as (flag1 | flag2) in (flag1 | 
flag2).  I should probably have made that clearer.

>> - flag3 in flag1 False
>> - flag3 in flag4 False
>
> When `flag` is a single flag bit and `flags` is an unknown combination of 
flag bits, you can conceivably
> make it so you can write this as `flag in flags`. But `in` doesn't work when 
sets are represented as bits
> in an integer (which is the analogy you're going for?)

Technically, they work just fine.  The bits and integers are an implementation detail, but one I suspect many, if not 
most, of us are used to.


>> and
>>
>> - flag0 in any flag  False
>>
>> - any flag in flag0  False
>
> What is `any flag` here?

Any combinaation of flags, including no flags at all.

>> And, of course, if we want to know if the thing we have is exactly flag1:
>>
>>   flag is flag1
>>
>> will tell us.
>
>
> Please use `==` here.

Flags are guaranteed singletons, just like Enums.

>> Does this make sense?
>
> When thinking about sets of flag bits, do you actually visualize them as bits 
in an integer?

Yes, but that's an implementation detail (albeit an efficient one).

> That's how I always think of them. Suppose we have three flags, F1, F2 and 
F3. Let's write them in binary:
>
> F1 = 0b001

Agreed with all of that.  My "weird case" above was in relation to the code used to handle that particular combination 
of flags, not that the flags variable had more than one flag specified.


I've had a couple people tell me that they think of flags as sets, and use set theory / set behavior to understand how 
flags and groups of flags should interact.  My main concern is whether that is the only correct way to look at flags, 
and whether the behavior that seems logical to me with regards to, for example, RegexFlag(0), is wrong, unusual, or 
perfectly natural.


The way I see it, the following should hold

   

[Python-Dev] Re: containment and the empty container

2021-11-08 Thread Rob Cliffe via Python-Dev

On 08/11/2021 21:43, Ethan Furman wrote:

When is an empty container contained by a non-empty container?

For example:
These examples are not at all analogous.  `a in b` has different 
meanings for different classes of b.


{} in {1:'a', 'b':2]   <-- TypeError because of hashability

`x in aDict` means `x in aDict.keys()`
1 in {1:'a', 'b':2} == True
'a' in {1:'a', 'b':2} == False

set() in {1, 2, 'a', 'b'}  <-- ditto
[] in ['a', 'b', 1, 2]  <-- False
`x in aSet' / `x in a List` means x is one of the members of 
aSet/aList.  E.g. {1, 2, 'a', 'b'} has 4 members: 1, 2, 'a', 'b'. None 
of these equals set().


'' in 'a1b2'  <-- True
`x in aStr` means x is a substring of aStr (quite different).  The empty 
string is (vacuously but correctly) a substring of any string.  This may 
be inconvenient sometimes (as you say) but it is the logically correct 
behaviour.  Just as the modulus operator for ints returns the 
mathematically correct result (unlike in some languages such as C / C++) 
even though this may not always be what you want.


Best wishes
Rob Cliffe
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/OECCYUHZIX5JFG7MIAUURPIMXJTJ5R3T/
Code of Conduct: http://python.org/psf/codeofconduct/