2023-07-17 03:21:00 +02:00
\[ [Index ](index.md ) | [Exercise 6.2 ](ex6_2.md ) | [Exercise 6.4 ](ex6_4.md ) \]
# Exercise 6.3
*Objectives:*
- Learn how to inspect the internals of functions
*Files Modified:* `structure.py`
## (a) Inspecting functions
Define a simple function:
```python
>>> def add(x,y):
'Adds two things'
return x+y
>>>
```
Do a `dir()` on the function to look at its attributes.
```python
>>> dir(add)
... look at the result ...
>>>
```
Get some basic information such as the function name, defining module name, and documentation string.
```python
>>> add.__name__
'add'
>>> add.__module__
'__main__'
>>> add.__doc__
'Adds two things'
>>>
```
The `__code__` attribute of a function has low-level information about
the function implementation. See if you can look at this and
determine the number of required arguments and names of local
variables.
## (b) Using the inspect module
Use the inspect module to get calling information about the function:
```python
>>> import inspect
>>> sig = inspect.signature(add)
>>> sig
< Signature ( x , y ) >
>>> sig.parameters
mappingproxy(OrderedDict([('x', < Parameter " x " > ), ('y', < Parameter " y " > )]))
>>> tuple(sig.parameters)
('x', 'y')
>>>
```
## (c) Putting it Together
2023-07-17 17:41:16 +02:00
In [Exercise 6.1 ](ex6_1.md ), you created a class `Structure`
2023-07-17 03:21:00 +02:00
that defined a generalized `__init__()` , `__setattr__()` , and `__repr__()`
method. That class required a user to define a `_fields` class
variable like this:
```python
class Stock(Structure):
_fields = ('name','shares','price')
```
The problem with this class is that the `__init__()` function didn't
have a useful argument signature for the purposes of help and
2023-07-17 17:41:16 +02:00
keyword argument passing. In [Exercise 6.2 ](ex6_2.md ), you
2023-07-17 03:21:00 +02:00
did a sneaky trick involving a special `self._init()` function. For example:
```python
class Stock(Structure):
_fields = ('name', 'shares', 'price')
def __init__ (self, name, shares, price):
self._init()
...
```
This gave a useful signature, but now the class is just weird because
the user has to provide both the `_fields` variable and the `__init__()` method.
Your task is to eliminate the `_fields` variable using some function
inspection techniques. First, notice that you can get the argument
signature from `Stock` as follows:
```python
>>> import inspect
>>> sig = inspect.signature(Stock)
>>> tuple(sig.parameters)
('name', 'shares', 'price')
>>>
```
Perhaps you could set the `_fields` variable from the argument signature
of `__init__()` . Add a class method `set_fields(cls)` to `Structure` that
inspects the `__init__()` function, and sets the `_fields`
variable appropriately. You should use your new function like this:
```python
class Stock(Structure):
def __init__ (self, name, shares, price):
self._init()
...
Stock.set_fields()
```
The resulting class should work the same way as before:
```python
>>> 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
>>>
```
Verify the slightly modified `Stock` class with your unit tests again. There will still
be failures, but nothing should change from the previous exercise.
At this point, it's all still a bit "hacky", but you're making
progress. You have a Stock structure class with a useful `__init__()`
function, there is a useful representation string, and the
`__setattr__()` method restricts the set of attribute names. The
extra step of having to invoke `set_fields()` is a bit odd, but we'll
get back to that.
\[ [Solution ](soln6_3.md ) | [Index ](index.md ) | [Exercise 6.2 ](ex6_2.md ) | [Exercise 6.4 ](ex6_4.md ) \]
----
`>>>` Advanced Python Mastery
`...` A course by [dabeaz ](https://www.dabeaz.com )
`...` Copyright 2007-2023
. This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License ](http://creativecommons.org/licenses/by-sa/4.0/ )