class __getitem__ when item is not a sequence ???

Steven D'Aprano steve at REMOVEME.cybersource.com.au
Thu Apr 19 22:38:39 EDT 2007


On Thu, 19 Apr 2007 16:47:55 -0700, cfriedalek wrote:

> Sorry for the vague subject. Not sure what the right terminology is.
> 
> How can I use an instance's data by reference to the instance name,
> not the instance attribute? OK the question is probably really poor
> but hopefully an example will make it clear.
> 
>> x=1
>> type(x)
> <type 'int'>
>> x.__add__(1)
> 2
>> print x
> 1
>> 3*x
> 3
> 
> In this case x is an integer. My understanding is that x in an
> instance of an integer class. Since it refers to only a single value
> things like print x, 3*x etc operate on the instance name which seems
> to refer to the instance data, not the instance itself.

No, names are separate from instances. Instances don't know what
name(s) they have been called. Everything in Python is an object, so you
can think of it like this... 

Here's an int:
<int, 7>

Python knows that instance as the literal 7, so any time you write 7 in
your code, that tells Python to use that specific instance.

When you write "x = 7" that tells Python to bind the _name_ "x" to the
instance 7. But notice that the instance itself doesn't know what
name, or names, it is bound to. In fact, there may be no name at all. 

When you say "x.__add__(1)" Python looks up the name "x", finds that it is
the instance 7, and then calls 7.__add__(1). And yes, you can write that,
although you have to sneak a space between 7 and the dot so it doesn't
look like a float:

>>> 7 .__add__(1)  # the long way of writing 7+1
8

Now, you might be thinking that ints have an attribute like "value", and
that x.__add__(1) does something like this:

def __add__(self, other):
    return self.value + other

That's what you will probably do for custom classes that you create
yourself, but that's not what ints do. They understand how to do addition
"magically". 7.__add__(1) knows the answer is 8 (because under the hood
it does arithmetic on bits) and it returns the instance 8, creating it if
it doesn't already exist.


> I want to do
> the same for my own classes.
> 
> For example:
>> class y:
>      def __init__(self,val):
>          self.val = val
>> y1 = y(10)
>> print y1
> <__main__.y instance at 0x043C7B20>
>> 3*y1
> <type 'exceptions.TypeError'>: unsupported operand type(s) for *:
> 'int' and 'instance
> 
> I have been able to do this by overriding __getitem__ when self.val is
> a sequence. 

How did you do that?


> But I can't find out what to do when self.val is a simple
> type like int, float etc.

In the same way that the + operator is turned into the __add__ method, the
* operator is turned into __mul__.

y1*3 => y1.__mul__(3)
3*y1 => y1.__rmul__(3)

Can you see why you need both a __mul__ and a __rmul__ operator?


Here is a simple way to do what I think you want:

class Y: 
# the convention is the class names start with a capital letter
    def __init__(self,val):
        self.val = val # assume val is an int
    def __mul__(self, other):
        value = self.val*other
        # Now value will be an int; if you are happy with that,
        # just "return value".
        # But I assume you want to return the same type:
        return self.__class__(value)
    __rmul__ = __mul__



-- 
Steven D'Aprano 




More information about the Python-list mailing list