1

I'm new to Python and I'm facing some issues when it comes to private functions. I want to call two of them inside a public method, just for the sake of making the code look clear, but I cannot understand at all what the run-time error shows. Here is the problematic part of the complete code:

def __loadVec(self,vec,res):
    for i in range(0,res.getRows()):
        for j in range(0,res.getColumns()):
            vec.append(self.matrix[i][j])
    return

def __savetoMatrix(self,vec,res):
    index = 0
    for i in range(0,res.getRows()):
        for j in range(0,res.getColumns()):
            self.matrix[i][j] = vec[index]
            index += 1
    return

def fmatrixSort(self,res):
    try:
        print "Sorting matrix information..."
        vec = []
        self._matrix.__loadVec(vec,res)
        vec.sort()
        self_matrix.__savetoMatrix(vec,res)
    except TypeError:
        print "TypeError in fmatrixSort"            
    return

What I'm trying to do is to completely organize a matrix so as it starts with the lowest value and ends with the highest.

This is the error the program shows:

Traceback (most recent call last):
  File "MatrixClass.py", line 211, in <module>
    main()
  File "MatrixClass.py", line 203, in main
    mat.fmatrixSort(res)
  File "MatrixClass.py", line 154, in fmatrixSort
    self._matrix.__loadVec(vec,res)
AttributeError: matrix instance has no attribute '_matrix'

How should I fix this?

msw
  • 42,753
  • 9
  • 87
  • 112
Julian Ailan
  • 15
  • 1
  • 4

2 Answers2

4

Python doesn't quite have the concept of private functions. It does, however, treat class attributes whose names start with at least two underbars and end with at most one underbar a little specially - it mangles the names to make them slightly harder to access. In this example, you can see that the function __func2 has had its name mangled. It's still possible to access and call the function - but you have to make a special effort to do it, simply calling o.func2() fails:

james@bodacious:tmp$cat test.py

class myclass:

    def func1(self):
        print "one"

    def __func2(self):
        print "two"

o = myclass()

print dir(o)

o._myclass__func2()
o.func2()
james@bodacious:tmp$python test.py
['__doc__', '__module__', '_myclass__func2', 'func1']
two
Traceback (most recent call last):
  File "test.py", line 15, in <module>
    o.func2()
AttributeError: myclass instance has no attribute 'func2'
james@bodacious:tmp$

So to answer the question you asked:

How do you correctly use private functions in Python?

The answer is: just like any other function, but you have to be aware of the mangled name.

Moving on to the question you wanted to ask:

AttributeError: matrix instance has no attribute '_matrix'

This is coming from line 154:

self._matrix.__loadVec(vec,res)

The error message is telling you that the object called self is an instance of class matrix; but it has no attribute called _matrix. Referring to the __savetoMatrix function above, it looks like the attribute is simply called matrix- so you need to refer to it as self.matrix ("the attribute called matrix of the object called self).

This The __savetoMatrix function references self.matrix rather than self._matrix.

However, there's a deeper problem here. Reading between the lines, it looks as though this code comes from a class called matrix; and instances of the class have an attribute called matrix. When you call self.matrix.__loadVec(), you're calling the function called __loadvec() which is bound to the attribute matrix bound to the object called self.

Even if this is what you wanted to do, this won't work because of name mangling as outlined above - assuming that the attribute called matrix has class inner_matrix, you'd have to call the function as self._matrix._inner_matrix__loadVec()

I think that what you're actually trying to do is call the method called __loadVec() defined in class matrix though. To do this, you just need to call self.__loadVec(). Because it's a call to a function within the same class, you don't even need to worry about the name mangling - these functions are intended to be used inside the class, and the interpreter will handle the mangling for you.

james@bodacious:tmp$cat test.py

class myclass:

    def func1(self):
        print "one"

    def __func2(self):
        print "two"

    def func3(self):
        self.__func2()
        print "three"

o = myclass()
print dir(o)
o.func3()
james@bodacious:tmp$python test.py
['__doc__', '__module__', '_myclass__func2', 'func1', 'func3']
two
three
James Polley
  • 7,977
  • 2
  • 29
  • 33
  • You said "Python doesn't quite have the concept of private functions." and this would be a much better answer if you'd stopped there. – msw Aug 04 '13 at 03:19
  • Disagree; Julian's underlying question had nothing to do with private functions, that was just a distraction that had to be handled so we could get to the real issues. – James Polley Aug 05 '13 at 05:13
3

You've mixed up self.matrix, self._matrix, and self_matrix in several parts of your code. Most likely, you meant self.matrix or self._matrix, and the others are typos. Also, fmatrixSort should probably be calling __loadVec and __savetoMatrix on self instead of what it's currently doing.

Additional notes:

You don't need to return at the end of a function if you don't have a value to return. When execution hits the end of a function, the function returns automatically.

range can be called in 3 ways:

range(stop)
range(start, stop)
range(start, stop, step)

If you're going to start the range at 0, just leave out the start parameter and call range with 1 argument.

user2357112
  • 260,549
  • 28
  • 431
  • 505