1

this is probably a super nub question, apologies. I'm trying to achieve an effect in Python I am familiar with from PHP, which is building getter and setter functions for private attributes.

In PHP I will commonly do something like this:

<?php
class newClass() {
    private $var = null;

    function newClass($initVal) {
        //init
    }

    public function get($var) {
        if ( isset($this->$var) ) {
            return $this->$var;
        }
    }
}
?>

But, trying the same idea in Python:

class newClass():
    def __init__(self, initVal):
        self.__nameOfVar1 = initVal
        self.__nameOfVar2 = initVal


    def get(self, var):
                #assuming, when called, var = nameOfVar1
        if self.__var:
            return self.__var

Throws an error AttributeError:'newClass' object has no attribute '__var'

And quite rightly so, it doesn't. How do I build getter and setter functions to access private attributes?


UPDATE:

I've left the original question because it seems useful for new comers to Python to learn which conventions from other languages they might accidentally be bringing forward. But in reality, my initial problem was a bit different, in attempting to make the problem more general I obfuscated my actual need. So here's an amendment:

In fact I was not working with private attributes; in fact, I am dealing with trying to pass an attribute downward through a composition circumstance. ie:

Class A, as an attribute, has a Class B object that does not inherit from Class A . It is almost never the case that Class B needs any information from Class A, but in my project there is one circumstance where, if a user chooses not provide information to Class B, there is a statement that makes a last-ditch attempt to infer a reasonable solution, but it requires information from Class A that, normally, it never needs.

I could build Class B to always have had that information, but that means that almost always I'm just wasting that time and memory (trivial though it might be). To make this concrete, imagine this:

toothbrush has bristles, and bristles can, provided the user supplies a preferred brushing experience, create a number of bristles appropriate to either a "soft" or a "firm" brush. But, if the user doesn't provide this, then I'd like bristles to ask brush for it's surface area, allowing it to guess what an average number should be.

I came up with this, though I have the intuitive sense that Python programmers will hate me for it; I'd just like to understand why:

@staticmethod
def request(self, var):
    appIndex = self.__dict__
    if appIndex[var]:
        return appIndex[var]

print Class.request(instance, var)

Works like a charm, but I think this is Python heresy. Why?

Jonline
  • 1,677
  • 2
  • 22
  • 53
  • 1
    Before doing this you should ask yourself two questions: 1) Why are you using private attributes? 2) Why are you using getter/setter functions? Both of these are not very Pythonic and there are usually better ways to accomplish your task in Python. A third issue is that, instead of checking if a variable is set, you should just always set it initially, to some default value, and then check for that instead of checking whether it "is set". – BrenBarn Apr 24 '13 at 19:39
  • 3
    No it won't; this code will throw a `SyntaxError` instead because there is no `def` for `__init__`. Even if that was there, the `__var` would not throw an attribute error because it is [mangled](http://docs.python.org/2/reference/expressions.html#atom-identifiers) in place like the reference in `__init__`. – Martijn Pieters Apr 24 '13 at 19:39
  • keep in mind in python there is no such thing as truly private variables ... – Joran Beasley Apr 24 '13 at 19:44
  • @MartijnPieters Yes, you're right, but that really wasn't the problem, I'm really obviously using a general form of the problem to follow stackoverflow conventions about being useful to everyone. So, thanks for pointing out the really, really, really obvious and trivial problem that couldn't possibly throw the error I actually mention in the question, but, though I am new to python, I *do* know how to define a function. But, hey, you definitely got me, nice job code police. – Jonline Apr 24 '13 at 19:46
  • 1
    @Jonline: It is much more your claim that the code would throw `AttributeError` that I have issues with, because it doesn't. I tried to run your code to verify that I wasn't reading it wrong. You are asking questions about a specific piece of code, so perhaps you should test the code stating what that code does? – Martijn Pieters Apr 24 '13 at 19:50
  • If it didn't, that was for trivial reasons, but I've changed it to be more clear. Personally, I still think the question I was asking was general, and obvious, and the other responses on this page confirm it. If you had to run this code to even understand the question then this probably wasn't a question you should be answering. Not that I'm not grateful you wanted to help, I am, but no one else had any trouble grasping my point. I could have copied-and-pasted my own code, but chose to write it in a general way for everyone else. Sorry it wasn't flawless, but it did communicate the point. – Jonline Apr 25 '13 at 15:12
  • Possible duplicate of [What's the pythonic way to use getters and setters?](http://stackoverflow.com/questions/2627002/whats-the-pythonic-way-to-use-getters-and-setters) – tripleee Jun 23 '16 at 12:11

2 Answers2

10

What you're searching for is properties:

class Foo():
    def __init__(self):
        self._spam = 0

    @property
    def spam(self):
        print("in the getter: ")
        return self._spam

    @spam.setter
    def spam(self, move):
        print("in the setter: ")
        self._spam = move + self._spam

f = Foo()
f.spam = 2
print(f.spam)

Output:

in the setter: 
in the getter: 
2
aldeb
  • 6,588
  • 5
  • 25
  • 48
  • Ah. I see. Thank you for not just saying what I'm now realizing you should have said, which is "go read how object oriented programming is done in python". Thanks very much, ah ha. – Jonline Apr 24 '13 at 19:40
  • @Jonline: "How object oriented programming is done in Python" is that data attributes are part of an object's interface. Do not use getters and setters unless absolutely necessary. When it _is_ necessary, hide the getters and setters from the interface by using `@property`. If the lesson you take from this is "I should build getters and setters for every attribute by using `@property`", you're doing things as wrong as possible. – abarnert Apr 24 '13 at 20:12
  • @abarnert Thanks, this is the sort of advice I really appreciate. I made an example based around private attributes because that seemed (at the time!) more likely to be generally useful. In fact my real problem was building a function to allow sibling classes with no shared inheritance (besides being an object) to request (on _rare_ occasion) attributes from each other. Can you point to a resource you recommend for learning Py's OOP conventions? – Jonline Apr 25 '13 at 14:49
  • 1
    @Jonline: For your first question, what you want already is, and should be, allowed. This is the key to duck typing. For the purposes of 99% of your code, the "type" or "interface" of an object isn't its class, but the set of members/methods/operators it supports. So, one class doesn't have to have any inheritance relationship to the other, or even know about the other's existence; it just has to use an implicit contract that the other implicitly specifies. You don't care whether something is related to `list`, just that it can be subscripted, right? Well, that's how _everything_ should work. – abarnert Apr 25 '13 at 19:30
  • 1
    @Jonline: For your second question, sadly, I don't know of any good resources to learning Python's conventions for OOP, or for almost any area besides the basics (what's in PEP 8 and `import this`) and the recent/cool stuff (e.g., David Beazley's presentations on generator pipelines, Greg Ewing's yield from tutorial, …). And I can't even think of where you can usefully ask that question (on SO, it'll almost certainly be closed, and maybe downvoted, as not appropriate to the Q&A format). Sorry about that. – abarnert Apr 25 '13 at 19:33
  • @abarnert Thanks a million for the pointers, this is the kind of thing amateurs like me benefit from because now I have a much better sense of which things—explicitly—I need to go study up on; I always find the hardest part is not the learning but the finding out what to learn. I really appreciate your taking the time to "teach a man[sic] to fish" as the saying goes. – Jonline Apr 29 '13 at 15:34
  • Not sure why this is marked as accepted answer when question is about python 2 and answer is for python 3. – Matt Mar 05 '21 at 03:30
-1

Well, first, Python doesn't have private variables. What you are referring to is name–mangling. The purpose is to prevent name collisions when importing modules. Whenever you write a variablein a class with two ununderscores in front of it, the name of the class gets added to the front of it. So it would be more advisable to name the variable "__var__" which is the custom for python "private" things.

On the other hand however, in python if you want some on to become able to set and get a variable, it generally makes most sense to just allow direct access (unlike in Java or other languages).

W. B. Reed
  • 1,614
  • 1
  • 10
  • 9
  • 1
    "`__magic__`" names are reserved for implementation (Python implementation that is). The pythonic naming convention for "private" (as in "none of your concerns, warranty void if unsealed") attributes is '_single_leading_underscore' – bruno desthuilliers Apr 24 '13 at 20:04
  • Okay. I suppose I didn't draw the distinction there, but it's a good one to make. – W. B. Reed Apr 24 '13 at 23:54