3.7 KiB
[ Index | Exercise 6.3 | Exercise 6.5 ]
Exercise 6.4
Objectives:
- Learn to create code with
exec()
(a) 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:
= ('name', 'shares', 'price')
_fields
>>> argstr = ','.join(Stock._fields)
>>> code = f'def __init__(self, {argstr}):\n'
>>> for name in Stock._fields:
+= f' self.{name} = {name}\n'
code >>> 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.
(b) Creating an
__init__()
function
In link:ex6_3.txt[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):
= ('name', 'shares', 'price')
_fields
Stock.create_init()
The resulting class should work exactly the name way as before:
>>> s = Stock(name='GOOG', shares=100, price=490.1)
>>> s
'GOOG',100,490.1)
Stock(>>> s.shares = 50
>>> s.share = 50
Traceback (most recent call last):"<stdin>", line 1, in <module>
File "structure.py", line 12, in __setattr__
File 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.
(c) Named Tuples
In link:ex2_1.html[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 ...>>>
[ Solution | Index | Exercise 6.3 | Exercise 6.5 ]
>>>
Advanced Python Mastery
...
A course by dabeaz
...
Copyright 2007-2023
.
This work is licensed under a Creative Commons
Attribution-ShareAlike 4.0 International License