Create Code with Exec

PythonPythonBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

Objectives:

  • Learn to create code with exec()

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("`Python`")) -.-> python/BasicConceptsGroup(["`Basic Concepts`"]) python(("`Python`")) -.-> python/ControlFlowGroup(["`Control Flow`"]) python(("`Python`")) -.-> python/DataStructuresGroup(["`Data Structures`"]) python(("`Python`")) -.-> python/FunctionsGroup(["`Functions`"]) python(("`Python`")) -.-> python/ModulesandPackagesGroup(["`Modules and Packages`"]) python(("`Python`")) -.-> python/ObjectOrientedProgrammingGroup(["`Object-Oriented Programming`"]) python(("`Python`")) -.-> python/ErrorandExceptionHandlingGroup(["`Error and Exception Handling`"]) python/BasicConceptsGroup -.-> python/comments("`Comments`") python/ControlFlowGroup -.-> python/conditional_statements("`Conditional Statements`") python/ControlFlowGroup -.-> python/for_loops("`For Loops`") python/DataStructuresGroup -.-> python/lists("`Lists`") python/DataStructuresGroup -.-> python/tuples("`Tuples`") python/DataStructuresGroup -.-> python/sets("`Sets`") python/FunctionsGroup -.-> python/function_definition("`Function Definition`") python/ModulesandPackagesGroup -.-> python/importing_modules("`Importing Modules`") python/ModulesandPackagesGroup -.-> python/using_packages("`Using Packages`") python/ModulesandPackagesGroup -.-> python/standard_libraries("`Common Standard Libraries`") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("`Classes and Objects`") python/ObjectOrientedProgrammingGroup -.-> python/constructor("`Constructor`") python/ObjectOrientedProgrammingGroup -.-> python/polymorphism("`Polymorphism`") python/ObjectOrientedProgrammingGroup -.-> python/encapsulation("`Encapsulation`") python/ErrorandExceptionHandlingGroup -.-> python/catching_exceptions("`Catching Exceptions`") python/ErrorandExceptionHandlingGroup -.-> python/raising_exceptions("`Raising Exceptions`") python/BasicConceptsGroup -.-> python/python_shell("`Python Shell`") python/FunctionsGroup -.-> python/build_in_functions("`Build-in Functions`") subgraph Lab Skills python/comments -.-> lab-132512{{"`Create Code with Exec`"}} python/conditional_statements -.-> lab-132512{{"`Create Code with Exec`"}} python/for_loops -.-> lab-132512{{"`Create Code with Exec`"}} python/lists -.-> lab-132512{{"`Create Code with Exec`"}} python/tuples -.-> lab-132512{{"`Create Code with Exec`"}} python/sets -.-> lab-132512{{"`Create Code with Exec`"}} python/function_definition -.-> lab-132512{{"`Create Code with Exec`"}} python/importing_modules -.-> lab-132512{{"`Create Code with Exec`"}} python/using_packages -.-> lab-132512{{"`Create Code with Exec`"}} python/standard_libraries -.-> lab-132512{{"`Create Code with Exec`"}} python/classes_objects -.-> lab-132512{{"`Create Code with Exec`"}} python/constructor -.-> lab-132512{{"`Create Code with Exec`"}} python/polymorphism -.-> lab-132512{{"`Create Code with Exec`"}} python/encapsulation -.-> lab-132512{{"`Create Code with Exec`"}} python/catching_exceptions -.-> lab-132512{{"`Create Code with Exec`"}} python/raising_exceptions -.-> lab-132512{{"`Create Code with Exec`"}} python/python_shell -.-> lab-132512{{"`Create Code with Exec`"}} python/build_in_functions -.-> lab-132512{{"`Create Code with Exec`"}} end

Experiment with exec()

Define a fragment of Python code in a string and try running it:

>>> code = '''
for i in range(n):
    print(i, end=' ')
'''
>>> n = 10
>>> exec(code)
0 1 2 3 4 5 6 7 8 9
>>>

That's interesting, but executing random code fragments is not especially useful. A more interesting use of exec() is in making code such as functions, methods, or classes. Try this example in which we make an __init__() function for a class.

>>> class Stock:
        _fields = ('name', 'shares', 'price')

>>> argstr = ','.join(Stock._fields)
>>> code = f'def __init__(self, {argstr}):\n'
>>> for name in Stock._fields:
        code += f'    self.{name} = {name}\n'
>>> print(code)
def __init__(self, name,shares,price):
    self.name = name
    self.shares = shares
    self.price = price

>>> locs = { }
>>> exec(code, locs)
>>> Stock.__init__ = locs['__init__']

>>> ## Now try the class
>>> s = Stock('GOOG', 100, 490.1)
>>> s.name
'GOOG'
>>> s.shares
100
>>> s.price
490.1
>>>

In this example, an __init__() function is made directly from the _fields variable.
There are no weird hacks involving a special _init() method or stack frames.

Creating an __init__() function

In Exercise 6.3, you wrote code that inspected the signature of the __init__() method to set the attribute names in a _fields class variable. For example:

class Stock(Structure):
    def __init__(self, name, shares, price):
        self._init()

Stock.set_fields()

Instead of inspecting the __init__() method, write a class method create_init(cls) that creates an __init__() method from the value of _fields. Use the exec() function to do this as shown above. Here's how a user will use it:

class Stock(Structure):
    _fields = ('name', 'shares', 'price')

Stock.create_init()

The resulting class should work exactly the name way as before:

>>> s = Stock(name='GOOG', shares=100, price=490.1)
>>> s
Stock('GOOG',100,490.1)
>>> s.shares = 50
>>> s.share = 50
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "structure.py", line 12, in __setattr__
    raise AttributeError('No attribute %s' % name)
AttributeError: No attribute share
>>>

Modify the Stock class in progress to use the create_init() function as shown.
Verify with your unit tests as before.

While you're at it, get rid of the _init() and set_fields() methods on the Structure class--that approach was kind of weird.

Named Tuples

In Exercise 2.1, you experimented with namedtuple objects in the collections module. Just to refresh your memory, here is how they worked:

>>> from collections import namedtuple
>>> Stock = namedtuple('Stock', ['name', 'shares', 'price'])
>>> s = Stock('GOOG', 100, 490.1)
>>> s.name
'GOOG'
>>> s.shares
100
>>> s[1]
100
>>>

Under the covers, the namedtuple() function is creating code as a string and executing it using exec(). Look at the code and marvel:

>>> import inspect
>>> print(inspect.getsource(namedtuple))
... look at the output ...
>>>

Summary

Congratulations! You have completed the Create Code With Exec lab. You can practice more labs in LabEx to improve your skills.

Other Python Tutorials you may like