Using '__mul__' within a class

G

Gerard Flanagan

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'

------------------------------
 
J

jepler

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-----
 
T

Terry Reedy

Gerard Flanagan said:
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
 
J

James Stroud

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

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/
 
J

James Stroud

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


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/
 
M

Martin Miller

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
====
 
J

James Stroud

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/
 
J

James Stroud

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/
 
J

jepler

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-----
 
P

Piet van Oostrum

James Stroud said:
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)
 
G

Gerard Flanagan

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
got your point.

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
 
J

John J. Lee

Gerard Flanagan said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,526
Members
44,997
Latest member
mileyka

Latest Threads

Top