2

Well I'm just learning Python and I'm experiencing some strange behavior. I guess that garbage collector is responsible for that but I'm not sure.

SORRY LADS I MESSED UP THE QUESTION

I wanted reproduce some weirdness I was getting while using some library without that library but I failed miserably.

So second try:

I'm using python API of Autodesk Maya. It is just python wrap around existing C++ API.

So this code:

import maya.OpenMaya as om

Q = om.MQuaternion(1,2,3,4).conjugateIt()
P = om.MQuaternion(6,6,6,6)
print(Q[0],Q[1],Q[2],Q[3])
print(type(Q))
print(type(P))

produces this output:

(6.0, 6.0, 6.0, 6.0)
<class 'maya.OpenMaya.MQuaternion'>
<class 'maya.OpenMaya.MQuaternion'>

So both P,Q are of type MQuaternion but Q does not hold the data it should hold. Here you can find documentation for MQuaternion class. conjugateIt is conjugation in place and returns by reference.

So what went wrong now ?


Here goes the old question which is just wrong :D

In C++ I'm used to do thing like this.

complex<float> c = complex<float>(1,2).conjInPlace()

conjInPlace() is conjugation in place

But if I do something similar in python I get into trouble

class testClass:
        def __init__(self,_a,_b):
            self.a = _a
            self.b = _b
        def alterMe(self):
            self.b = 123

A = testClass(1,2)
A.alterMe()
print(A.a,A.b)
B = testClass(0,0)
B = testClass(3,4).alterMe()
print(B)

gives me output:

1 123
None

I guess that because object returned by testClass(3,4) is not immediately referenced by something so it gets deleted.

So why is this happening? How to watch out for this kind of things?

tom
  • 1,520
  • 1
  • 12
  • 26
  • 3
    because you are not returning anything from your `alertme` function – abhishekgarg Jun 10 '13 at 19:28
  • 1
    You should be able to add `return self` at the bottom of your `alterMe()` function if you want your example code to work. – Aya Jun 10 '13 at 19:29
  • The answers you have gotten are correct. You can of course `return self` at the end of `alterMe`, and I've done code like that, but it seems generally to be considered "not Pythonic" to modify and return yourself. – torek Jun 10 '13 at 19:30
  • 2
    Good lord, if the garbage collector were that aggressive python would be a much worse language to code in. – Slater Victoroff Jun 10 '13 at 19:32
  • HAHAHAHA :D I cocked up everything :D Sorry lads for such a stupid question :D – tom Jun 10 '13 at 19:37

6 Answers6

6

A is indeed altered by the alterMe method. But B is set to the return value of that method, which is None, not another testClass object.

chepner
  • 497,756
  • 71
  • 530
  • 681
2

alterMe doesn't return anything - that's why you see None.

Maksim Skurydzin
  • 10,301
  • 8
  • 40
  • 53
2

You need to make alertMe method to return the object it is invoked from:

def alterMe(self):
        self.b = 123
        return self

That is, testClass(3, 4) returns an object, but that object when invoked alertMe return None. With the above fix it will return the object again.

Israel Unterman
  • 13,158
  • 4
  • 28
  • 35
2

ConjugateIt returns a reference in C++, so it's not going to return the python object correctly. Try this:

Q = om.MQuaternion(1.0,2.0,3.0,4.0)
print Q.x, Q.y, Q.z, Q.w
Q.conjugateIt()
print Q.x, Q.y, Q.z, Q.w
print "----"
P = om.MQuaternion(6,6,6,6)
print P.x, P.y, P.z, P.w

# 1.0 2.0 3.0 4.0
# -1.0 -2.0 -3.0 4.0
# ----
# 6.0 6.0 6.0 6.0

UPDATED first line to reflect tom's observation

theodox
  • 12,028
  • 3
  • 23
  • 36
  • 1
    FWIW I have no idea why the swig wrapper gives a bum pointer as a return from the ConjugateIt method. *sigh* – theodox Jun 11 '13 at 00:26
  • how come that `ConjugateIt` is `void` it documentation says it is `MQuaternion &` ? – tom Jun 11 '13 at 10:39
  • My bad - it actually returns a reference... although in python you don't need it. ConjugateIt modifies Q in place and you already have Q, so you can work around it as above. The OpenMaya python docs http://download.autodesk.com/us/maya/2010help/index.html?url=Maya_Python_API_Using_the_Maya_Python_API.htm,topicNumber=d0e654062 imply that references are all treated as pointers in Python - and it looks like the function is returning a nonsense "pointer" (if you don't call the P line, you'll see the values in Q are garbage) – theodox Jun 11 '13 at 17:53
  • FWIW, you could just use .conjugate instead of .conjugateIt to get a _new_ quaternion. – theodox Jun 11 '13 at 17:57
  • ok but I still don't get why it returns nonsence pointer?! if I do simply `Q = om.MQuaternion(1,2,3,4).conjugateIt()` `print(Q[0],Q[1],Q[2],Q[3])` I get almost right answer `(0.0, -2.0, -3.0, 4.0)` so it is pointing to the right part of memory. But the memory is not reserved for `Q` and by declaring `P` it gets overwriten. And yes I ended up using `.conjugate` but I thought it is waste I can do better with `conjugateIt` – tom Jun 11 '13 at 22:30
  • You might want to take a look at the discussion here: http://stackoverflow.com/questions/534375/passing-values-in-python -- it's why its hard to translate the C++ idiom into Python. On my system, the result of conjugateIt is garbage (Q retains the right values but the result value is nonsense). I think the behavior here is the same one they mention in the docs under the heading "Modify Parameter Values Instead of Using an Assignment" – theodox Jun 11 '13 at 22:35
  • Uff this is sooo wrong for me as C++ programmer. I'm reading the Blair Conrad [answer](http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference) ansr the example with list is just so confusing. In C++ you can set eference only during initialization but as it seams to me not in Python. – tom Jun 11 '13 at 23:20
1

In your C++ example, conjInPlace must still be returning the complex value, yes? In your Python example, alterMe does not produces None, and so B is assigned the value None, just as if your conjInPlace had returned some value X, then c would be assigned X.

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
1

Add this at the end of alterMe:

return self

The problem here is that alterMe is not explicitly returning a value. If no return value is specified at the end of a function, Python returns None by default. This has nothing to do with garbage collection.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • @Daenyth I was wondering ... what's OP expecting? `self` or `self.b`? – Óscar López Jun 10 '13 at 19:31
  • @ÓscarLópez Given a return type of `complex` from an object of `complex`, then I'd guess it does a `return *this;` which would be `return self` in Python. – Aya Jun 10 '13 at 19:34