[Python-ideas] IntFlags

Andrew Barnert abarnert at yahoo.com
Sat Mar 7 14:53:09 CET 2015


On Mar 7, 2015, at 12:07 AM, Ethan Furman <ethan at stoneleaf.us> wrote:
> 
>> On 03/03/2015 07:52 AM, Serhiy Storchaka wrote:
>> 
>> We need new type IntFlags. It is like IntEnum, but has differences:
>> 
>> 1. The value of an instance should be not limited to the set of predefined constants. It can be a combination of
>> predefined constants or even arbitrary integer.
>> 
>> 2. The result of "|", "&" and "~" operators for IntFlags arguments should be an instance of the same IntFlags subclass.
>> 
>> 3. It should have nice str() and repr().
> 
> As long as we are dreaming  :)
> 
> class Stat(IntFlag):
>    RDONLY = 1
>    NOSUID = 2
>    NODEV = 4
>    NOEXEC = 8
>    SYNCHRONOUS = 16
>    MANDLOCK = 64
>    WRITE = 128
>    APPEND = 256
>    NOATIME = 1024
>    NODIRATIME = 2048
>    RELATIME = 4096
> 
> a = Stat.RDONLY  # creates a new instance of Stat, not a singleton

Why? Assuming the values are immutable (like int), the only difference is your is test, and I have no idea why your code would care about that. (If you're worried about the "a |=" below changing b--or, worse, changing the constant--there's no reason to worry. Just as "a = 1; a |= 2" doesn't affect any other variable holding the int 1, the same would be true here.)

> b = Stat.RDONLY
> a is b  # False
> a == b  # True
> 
> c = a
> a |= Stat.MANDLOCK
> c.MANDLOCK  # 64
> b.MANDLOCK  # 0
> c is a  # True
> 
> repr(a)  # <Stat.MANDLOCK|RDONLY: 65>
> repr(b)  # <Stat.RDONLY: 1>
> 
> d = b | 32  # undefined value
> repr(d)  # <Stat.32|RDONLY: 33>
> d.MANDLOCK = True
> repr(d)  # <Stat.MANDLOCK|32|RDONLY: 97>
> 
> repr(~d)  # <Stat.RELATIME|NODIRATIME|NOATIME|512|APPEND|WRITE|SYNCHONOUS|NOEXEC|NODEV|NOSUID: 8094>
> 
> I'm not at all sure I have that last one correct.

That last one is the big question. In C, ~d is going to have the 8192, 16384, ... 2b bits set, not just the bits you defined and the gaps in between. Are you sure you want a different result in Python? (Especially if you're on a platform that does something with those extra bits, so you can get values back that actually have them set. Although I don't think that's an issue with stat, it is with lots of other flags from POSIX-land.)

Look at all of the alternatives that have been suggested (round up to power of 256, guess what C would do on your platform with the most likely equivalent definitions, use signed instead of unsigned so the issue moves somewhere else, handle complementing with a special bool, maybe others); why is this one better? Why is it OK to set the undefined 512 bit but not the equally-undefined 8192 bit when someone does ~ on a value of 32?


More information about the Python-ideas mailing list