5

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?

4
  • 1
    dis.show_code(string) is not the flags of the string object. Its the flags of the code object derived from compiling this string as source code. dis.show_code will "Print detailed code object information for the supplied function, method, source code string or code object (...)". Compare dis.show_code("for for s"). What makes you think dis could disassemble types? Commented Jul 31, 2020 at 11:47
  • 1
    Does this answer your question? Python - code type flags Commented Jul 31, 2020 at 11:51
  • Thanks for explanation @MisterMiyagi you are right, but everything is an object, which means every entity has some metadata called attributes and associated functionality, that made me think i can disassemble types. Commented Jul 31, 2020 at 11:57
  • You cannot disassemble types. As the documentation states, dis.show_code() does "Print detailed code object information for the supplied function, method, source code string or code object". Commented Jul 31, 2020 at 12:43

2 Answers 2

3

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:\Users\sayan\Anaconda3\envs\tensorflow_gpu\lib\asyncio\coroutines.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.

Sign up to request clarification or add additional context in comments.

Comments

2

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

1 Comment

CO_FUTURE_BARRY_AS_BDFL is my favourite. stackoverflow.com/questions/4007289/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.