# Using '__mul__' within a class

Discussion in 'Python' started by Gerard Flanagan, Sep 24, 2005.

1. ### Gerard FlanaganGuest

Hello

I'm pretty new to Python and was wondering why the 'Square' method in
the following code doesn't work. It doesn't fail, just doesn't do
anything ( at least, not what I'd like! ). Why doesn't 'A.a' equal 2
after squaring?
TIA.

class FibonacciMatrix:
def __init__( self ):
self.a = 1
self.b = 1
self.c = 0

def __mul__( self, other ):
result = FibonacciMatrix()
result.a = self.a * other.a + self.b * other.b
result.b = self.a * other.b + self.b * other.c
result.c = self.b * other.b + self.c * other.c
return result

def Square( self ):
self *= self

A = FibonacciMatrix()
A.Square()

print A.a #prints '1'

A = FibonacciMatrix()
B = A * A

print B.a #prints '2'

------------------------------

Gerard Flanagan, Sep 24, 2005

2. ### Guest

For the same reason that
def f(z):
z *= z
c = 1
f(c)
print c
prints 1.

Jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFDNXm7Jd01MZaTXX0RAguqAJ9u9Txaz8AOJaBn4t3v1e+ExsQ0DACgiv2l
urtGBbqtiSXWM4SKoBcP77E=
=mTpx
-----END PGP SIGNATURE-----

, Sep 24, 2005

3. ### Ivan VorasGuest

Gerard Flanagan wrote:

> def Square( self ):
> self *= self

You probably mean
return self * self

> A = FibonacciMatrix()
> A.Square()

Make this
A = A.Square()

Ivan Voras, Sep 24, 2005
4. ### Terry ReedyGuest

"Gerard Flanagan" <> wrote in message
news:...
> def __mul__( self, other ):
> def Square( self ):
> self *= self

Among the other reasons cited, I believe that 'op=' maps to a different
special method than 'op'. __imul__? or something? do check.

tjr

Terry Reedy, Sep 24, 2005
5. ### James StroudGuest

I think the gist of your problem is that you are re-binding self in the
method. Here is a simpler example of your problem:

py> def doit(c):
.... c = 5
.... print "c in the method is", c
....
py> c = 42
py> print "c before calling the method is", c
c before calling the method is 42
py> doit(c)
c in the method is 5
py> print "c after calling the method is", c
c after calling the method is 42

James

On Saturday 24 September 2005 08:36, Gerard Flanagan wrote:
> Hello
>
> I'm pretty new to Python and was wondering why the 'Square' method in
> the following code doesn't work. It doesn't fail, just doesn't do
> anything ( at least, not what I'd like! ). Why doesn't 'A.a' equal 2
> after squaring?
> TIA.
>
>
> class FibonacciMatrix:
> def __init__( self ):
> self.a = 1
> self.b = 1
> self.c = 0
>
> def __mul__( self, other ):
> result = FibonacciMatrix()
> result.a = self.a * other.a + self.b * other.b
> result.b = self.a * other.b + self.b * other.c
> result.c = self.b * other.b + self.c * other.c
> return result
>
> def Square( self ):
> self *= self
>
>
> A = FibonacciMatrix()
> A.Square()
>
> print A.a #prints '1'
>
> A = FibonacciMatrix()
> B = A * A
>
> print B.a #prints '2'
>
> ------------------------------

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/

James Stroud, Sep 24, 2005
6. ### James StroudGuest

Additionally, your __mul__() returns a new FibonnacciMatrix. You do not want a
new FibbonacciMatrix, you want to operate on an existing matrix (otherwise,
you would want to go with Ivan Voras's solution, where you re-assign outside
of the class). If you don't want the overhead of creating a instance of your
class, you may want to be more explicit in Square(), eg:

def Multiply(self, other):
self.a = self.a * other.a + self.b * other.b
self.b = self.a * other.b + self.b * other.c
self.c = self.b * other.b + self.c * other.c

def Square(self, other):
self.Multiply(other)

With __imul__(), as Terry Reedy suggested, you can also save the overhead of
creating a new instance, but it works a little differently than Square()
above, because you need to return self (assuming Square() is as above):

def __imul__(self, other):
self.Multiply(other)
return self

With these methods, __mul__() can be factored:

def __mul__(self, other):
result = FibonacciMatrix()
result.Multiply(other)
return result

Leaving all of the messiest stuff in the Multiply method.

James

On Saturday 24 September 2005 08:36, Gerard Flanagan wrote:
> Hello
>
> I'm pretty new to Python and was wondering why the 'Square' method in
> the following code doesn't work. It doesn't fail, just doesn't do
> anything ( at least, not what I'd like! ). Why doesn't 'A.a' equal 2
> after squaring?
> TIA.
>
>
> class FibonacciMatrix:
> def __init__( self ):
> self.a = 1
> self.b = 1
> self.c = 0
>
> def __mul__( self, other ):
> result = FibonacciMatrix()
> result.a = self.a * other.a + self.b * other.b
> result.b = self.a * other.b + self.b * other.c
> result.c = self.b * other.b + self.c * other.c
> return result
>
> def Square( self ):
> self *= self
>
>
> A = FibonacciMatrix()
> A.Square()
>
> print A.a #prints '1'
>
> A = FibonacciMatrix()
> B = A * A
>
> print B.a #prints '2'
>
> ------------------------------

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/

James Stroud, Sep 24, 2005
7. ### Martin MillerGuest

As others have pointed out, you are just reassigning a new value to the
self argument in the Square() method shown. Instead, what you need to
do is change the object that 'self' refers to within the method. To do
this, change it to:

def Square( self ):
result = self * self
self.a = result.a
self.b = result.b
self.c = result.c

You would also have to do something similar in an __imul__() method if
you decided to implement one.

Hope this helps,
-Martin
====

Gerard Flanagan wrote:
> Hello
>
> I'm pretty new to Python and was wondering why the 'Square' method in
> the following code doesn't work. It doesn't fail, just doesn't do
> anything ( at least, not what I'd like! ). Why doesn't 'A.a' equal 2
> after squaring?
> TIA.
>
>
> class FibonacciMatrix:
> def __init__( self ):
> self.a = 1
> self.b = 1
> self.c = 0
>
> def __mul__( self, other ):
> result = FibonacciMatrix()
> result.a = self.a * other.a + self.b * other.b
> result.b = self.a * other.b + self.b * other.c
> result.c = self.b * other.b + self.c * other.c
> return result
>
> def Square( self ):
> self *= self
>
>
> A = FibonacciMatrix()
> A.Square()
>
> print A.a #prints '1'
>
> A = FibonacciMatrix()
> B = A * A
>
> print B.a #prints '2'
>
> ------------------------------

Martin Miller, Sep 24, 2005
8. ### James StroudGuest

Shoot, Square() should be:

def Square(self):
self.Multiply(self)

Forgot to proofread before hitting send.

James

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/

James Stroud, Sep 24, 2005
9. ### James StroudGuest

On Saturday 24 September 2005 09:07, wrote:
> For the same reason that
> def f(z):
> z *= z
> c = 1
> f(c)
> print c
> prints 1.
>
> Jeff

I don't mean to be rude, but this is a horrible example if your are intending
to help a neophyte:

py> 1*1
1

See what I mean?

James

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/

James Stroud, Sep 24, 2005
10. ### Guest

Oops!

I should have used '2' in the example, or some other number.

I was trying to make a point about what
x *= ...
means when it is in the context of a function (or method) body.
I think this is key to understanding what Python did in the case the user posted.

Being rude wasn't my intent at all.

Jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFDNbrxJd01MZaTXX0RAmD0AJ9/kqPDQPv9TsnIYjGWJ6+huc7kkACgit9R
Ux0e1O+8FeSx6oeEgBhyDiM=
=qFsK
-----END PGP SIGNATURE-----

, Sep 24, 2005
11. ### Piet van OostrumGuest

>>>>> James Stroud <> (JS) wrote:

>JS> def Multiply(self, other):
>JS> self.a = self.a * other.a + self.b * other.b
>JS> self.b = self.a * other.b + self.b * other.c
>JS> self.c = self.b * other.b + self.c * other.c

I gues this will give the wrong result because the calculation of self.b is
supposed to use the original value of self.a, not the newly calculated one.
Similar for self.c. The following should do that:

self.a, self.b, self.c = (self.a * other.a + self.b * other.b,
self.a * other.b + self.b * other.c,
self.b * other.b + self.c * other.c)
--
Piet van Oostrum <>
URL: http://www.cs.uu.nl/~piet [PGP 8DAE142BE17999C4]
Private email:

Piet van Oostrum, Sep 24, 2005
12. ### Gerard FlanaganGuest

Thanks for all the replies - you are very nice people!

Don't worry Jeff, I assumed you weren't telling me what 1*1 equals! I

James Stroud impressively got to the heart of what I was trying to do -
which was just to wrap up the code here:

en.wikipedia.org/wiki/Fibonacci_number_program#Matrix_equation

in object-oriented fashion but without too much overhead - I appreciate
you taking the time James! Thanks.

I managed to do what i wanted with the code below, though there's
definitely a lack of understanding on my part with respect to how
Python works - binding/re-binding? - that I'll have to study.

Cheers 'n' all

class FibonacciMatrix:
def __init__( self ):
self.a = 1
self.b = 1
self.c = 0

def Copy( self ):
copy = FibonacciMatrix()
copy.a = self.a
copy.b = self.b
copy.c = self.c
return copy

def __mul__( self, other ):
result = FibonacciMatrix()
result.a = self.a * other.a + self.b * other.b
result.b = self.a * other.b + self.b * other.c
result.c = self.b * other.b + self.c * other.c
return result

def __pow__( self, N ):
if N == 1:
return self
if N & 1 == 0:
return pow( self * self, N/2 )
else:
return self * pow( self * self, (N-1)/2 )

A = FibonacciMatrix() ** 8

print '------------------------------'
print A.a

Gerard Flanagan, Sep 24, 2005
13. ### John J. LeeGuest

"Gerard Flanagan" <> writes:
[...]
> class FibonacciMatrix:

[...]
> def Copy( self ):

[...]

__copy__ would be a more standard name. Then:

import copy
fm = FibonacciMatrix()
fm2 = copy.copy(fm)

I suppose you could also add:

__deepcopy__ = __copy__

in the body of the class definition.

John

John J. Lee, Sep 25, 2005