[Tutor] Importing from classes or functions
Danny Yoo
dyoo at hkn.eecs.berkeley.edu
Thu Oct 30 18:09:42 EST 2003
On Thu, 30 Oct 2003, Daniel Ehrenberg wrote:
> I'm trying to write a module to make it so that you can use Ruby-style
> methods on various types in Python (similar to the methods on strings,
> but in Ruby, *every* method that would be builtin or in the standard
> library is callable from that variable). I'm starting with an integer
> where, if you call the sin() function, it returns the sine of the
> number. I called this class (for right now) sinnum. So sinnum(5).sin()
> should return -0.95892427466313845.
Hi Daniel,
Yes, it's possible to do something like this, if we do some attribute
lookup trickery:
###
>>> class sinnum(int):
... def __getattr__(self, attr):
... def f(*args):
... return apply(getattr(__builtins__, attr),
... (self,) + args)
... return f
...
>>> x = sinnum(5)
>>> x.abs()
5
>>> x = sinnum(-5)
>>> x.abs()
5
###
So it's sorta working. But this isn't quite right, though:
###
>>> x.abs().abs()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'int' object has no attribute 'abs'
###
The error here shows that the definition above isn't providing "closure",
in the sense that the value of 'x.abs()' isn't a Ruby-style "sinnum", so
we can't compose two operations, like:
x.abs.abs()
(Tangent note: Terminology is a funny thing, and the term "closure" is
also used to describe something totally different in computer science: in
computer science terms, that embedded 'f' function that's being returned
by the __getattr__() is an example of a "closure" function. So the bug
here is that the closure function isn't providing mathematical closure.
*grin*)
Anyway, once we see this, we can fix this problem:
###
>>> class sinnum(int):
... def __getattr__(self, attr):
... def f(*args):
... return sinnum(apply(getattr(__builtins__, attr),
... (self,) + args))
... return f
...
>>> x = sinnum(42)
>>> x.pow(2).pow(2)
3111696
###
> I wanted to import it within the class, since when I'm finished, the
> module should contain more than one datatype (an extended int, an
> extended float, an extended string, etc). But when I try to impliment
> importing within the class, the import doesn't work.
Think of 'import math' as a statement that creates a local variable called
'math'. Then the error message should be less mysterious:
> >>> class sinnum(int):
> ... def __init__(s, number):
> ... import math
> ... s.num = number
> ... def sin(s):
> ... return math.sin(s)
> ...
> >>> x = sinnum(5)
> >>> x.sin()
> Traceback (most recent call last):
> File "<input>", line 1, in ?
> File "<input>", line 6, in sin
> NameError: global name 'math' is not defined
'math' here is a local variable within __init__, so it won't be visible
from the 'sin()' function. So the error is actually not too serious: it's
a scope issue.
> If Ruby-style methods for Python is a bad idea or would be extremely
> inefficient, please tell me.
To tell the truth, I think it might be a bad idea in Python. *grin*
It's probably not outrageously inefficient --- all Python method access is
done through attribute lookup anyway --- but it's just something that most
Python programmers won't recognize at first.
Good luck to you!
More information about the Tutor
mailing list