What is flags in Python?

Question:

I was playing with interactive shell, testing new stuff etc. I found a function has three flags.

def bar(x,y):
    pass

>>> dis.show_code(bar)
Name:              bar
Filename:          test.py
Argument count:    2
Positional-only arguments: 0
Kw-only arguments: 0
Number of locals:  2
Stack size:        1
Flags:             OPTIMIZED, NEWLOCALS, NOFREE
Constants:
   0: None
Variable names:
   0: x
   1: y

Also a string has 1 flag

string = "s"

>>> dis.show_code(string)
Filename:          <disassembly>
Flags:             NOFREE

The question is why we have them or why do we need them?

Asked By: Yagiz Degirmenci

||

Answers:

The documentation says:

The following flag bits are defined for co_flags: bit 0x04 is set if
the function uses the *arguments syntax to accept an arbitrary number
of positional arguments; bit 0x08 is set if the function uses the
**keywords syntax to accept arbitrary keyword arguments; bit 0x20 is set if the function is a generator.

Future feature declarations (from __future__ import division) also use
bits in co_flags to indicate whether a code object was compiled with a
particular feature enabled: bit 0x2000 is set if the function was
compiled with future division enabled; bits 0x10 and 0x1000 were used
in earlier versions of Python.

Other bits in co_flags are reserved for internal use.

In the Python source code, you can find this more extensive list of flags in code.h:

#define CO_OPTIMIZED    0x0001
#define CO_NEWLOCALS    0x0002
#define CO_VARARGS      0x0004
#define CO_VARKEYWORDS  0x0008
#define CO_NESTED       0x0010
#define CO_GENERATOR    0x0020
#define CO_NOFREE       0x0040
#define CO_COROUTINE            0x0080
#define CO_ITERABLE_COROUTINE   0x0100
#define CO_ASYNC_GENERATOR      0x0200
#define CO_FUTURE_DIVISION      0x20000
#define CO_FUTURE_ABSOLUTE_IMPORT 0x40000
#define CO_FUTURE_WITH_STATEMENT  0x80000
#define CO_FUTURE_PRINT_FUNCTION  0x100000
#define CO_FUTURE_UNICODE_LITERALS 0x200000
#define CO_FUTURE_BARRY_AS_BDFL  0x400000
#define CO_FUTURE_GENERATOR_STOP  0x800000
#define CO_FUTURE_ANNOTATIONS    0x1000000
Answered By: zvone

These FLAGS signify different components of a code object. While the other answer points you towards the right answer, I am just adding a little fun to the mix.

You can try importing a subset of FLAGS from dis.

>>> from dis import COMPILER_FLAG_NAMES
>>> COMPILER_FLAG_NAMES
{1: 'OPTIMIZED',
 2: 'NEWLOCALS',
 4: 'VARARGS',
 8: 'VARKEYWORDS',
 16: 'NESTED',
 32: 'GENERATOR',
 64: 'NOFREE',
 128: 'COROUTINE',
 256: 'ITERABLE_COROUTINE',
 512: 'ASYNC_GENERATOR'}

And then you can write a simple function and see what FLAGS show up:

>>> def foo():
        return

>>> dis.show_code(foo)
Name:              foo
Filename:          <ipython-input-138-32384d979b8a>
Argument count:    0
Kw-only arguments: 0
Number of locals:  0
Stack size:        1
Flags:             OPTIMIZED, NEWLOCALS, NOFREE
Constants:
   0: None

Now, you can start increasing the complexity and see how that changes:

>>> def foo(a, *args, **kwargs):
        yield a
>>> dis.show_code(foo)
Name:              foo
Filename:          <ipython-input-141-56a68ddd064c>
Argument count:    1
Kw-only arguments: 0
Number of locals:  3
Stack size:        1
Flags:             OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR, NOFREE
Constants:
   0: None
Variable names:
   0: a
   1: args
   2: kwargs

Here adding *args, **kwargs and yield added VARARGS, VARKEYWORDS, GENERATOR flags respectively.
Now for something a little more:

>>> from asyncio import coroutine
>>> @coroutine
    async def foo(a, *args, **kwargs):
        yield b
        def bar():
            return foo(b)
        yield bar
>>> dis.show_code(foo)
Name:              coro
Filename:          C:UserssayanAnaconda3envstensorflow_gpulibasynciocoroutines.py
Argument count:    0
Kw-only arguments: 0
Number of locals:  4
Stack size:        8
Flags:             OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, NESTED, GENERATOR, ITERABLE_COROUTINE
Constants:
   0: None
Names:
   0: base_futures
   1: isfuture
   2: inspect
   3: isgenerator
   4: isinstance
   5: CoroWrapper
   6: __await__
   7: AttributeError
   8: collections
   9: abc
  10: Awaitable
Variable names:
   0: args
   1: kw
   2: res
   3: await_meth
Free variables:
   0: func

And there you go, adding @coroutine decorator gives NESTED, async_def + yield gives ITERABLE_COROUTINE and the presence of a freevar, that is the function bar here, removes the NOFREE flag.

Answered By: Sayandip Dutta
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.