Using Private Attributes and Private Methods


By default, all of an object's attributes and methods are public, meaning that they can be directly accessed or invoked by a client. To encourage encapsulation, you can define an attribute or method as private, meaning that only other methods of the object itself can easily access or invoke them.

Introducing the Private Critter Program

The Private Critter program instantiates an object with both private and public attributes and methods. Figure 8.8 shows a sample run.

click to expand
Figure 8.8: The object's private attribute and private method are indirectly accessed.

Creating Private Attributes

To limit the direct access of object attributes by clients, you can use private attributes. In the constructor method, I create two attributes, one public and one private:

 # Private Critter # Demonstrates private variables and methods # Michael Dawson - 3/25/03 class Critter(object):     """A virtual pet"""     def __init__(self, name, mood):         print "A new critter has been born!"         self.name = name             # public attribute         self.__mood = mood           # private attribute 

The two underscore characters that begin the second attribute name tell Python that this is a private attribute. To create a private attribute of your own, just begin the attribute name with two underscores.

Accessing Private Attributes

It's perfectly fine to access an object's private attribute inside the class definition of the object. (Remember, private attributes are meant to discourage client code from directly accessing the attribute.) I access a private attribute in the talk() method:

     def talk(self):         print "\nI'm", self.name         print "Right now I feel", self.__mood, "\n" 

This method prints the value of the object's private attribute, which represents a critter's mood.

If I tried to access this attribute outside of the Critter class definition, I'd have trouble. Here's an interactive session to show you what I mean:

 >>> crit = Critter(name = "Poochie", mood = "happy") A new critter has been born! >>> print crit.mood Traceback (most recent call last):   File "<pyshell#2>", line 1, in ?     print crit.mood AttributeError: 'Critter' object has no attribute 'mood' 

By raising an AttributeError exception, Python is saying that crit has no attribute mood. If you think you can outsmart Python by adding the two leading underscores, you'd be wrong. That's just what I tried in the next part of my interactive session:

 >>> print crit.__mood Traceback (most recent call last):   File "<pyshell#3>", line 1, in ?     print crit.__mood AttributeError: 'Critter' object has no attribute '__mood' 

This also raises an AttributeError exception. Python is again saying that the attribute doesn't exist. So does this mean that the value of a private attribute is completely inaccessible outside of its class definition? Well, no. Python hides the attribute through a special naming convention, though it's still technically possible to access the attribute. That's what I did in the next part of my interactive session:

 >>> print crit._Critter__mood happy 

This line prints the value of the elusive private attribute, which in this case is the string "happy".

Since it's possible to access private attributes, you may be thinking: What good are they? Well, defining an attribute or method as private is not about completely preventing access. Rather, it's about preventing inadvertent access. It says that a particular attribute or method is meant only for an object's internal use. So, you should never try to directly access the private attributes or methods of an object from outside of its class definition.

Creating Private Methods

You can create a private method in the same, simple way you create a private attribute: by adding two leading underscores to its name. That's just what I do in the next method definition in the class:

     def __private_method(self):         print "This is a private method." 

This is a private method but can easily be accessed by any other method in the class. Like private attributes, private methods are meant only to be accessed by an object's own methods.

Accessing Private Methods

Just as with private attributes, accessing an object's private methods within its class definition is simple. In the public_method() method, I access the class' private method:

     def public_method(self):         print "This is a public method."         self.__private_method() 

This method prints the string "This is a public method." and then invokes the object's private method.

Like private attributes, private methods aren't meant to be directly accessed by clients. Back in my interactive session, I try to access crit's private method:

 >>> crit.private_method() Traceback (most recent call last):   File "<pyshell#6>", line 1, in ?     crit.private_method() AttributeError: 'Critter' object has no attribute 'private_method' 

This attempt raises the familiar AttributeError exception. Python is saying that crit has no method with this name. Python hides the method through the same, special naming convention. If I try again by adding the two leading underscores to the method name, I run into the same error message:

 >>> crit.__private_method() Traceback (most recent call last):   File "<pyshell#7>", line 1, in ?     crit.__private_method() AttributeError: 'Critter' object has no attribute '__private_method' 

However, just as with private attributes, it is technically possible to access private methods from anywhere in a program. Here's the final part of my interactive session as proof:

 >>> crit._Critter__private_method() This is a private method. 

But, as you probably know by now, a client should never attempt to directly access an object's private methods.

Respecting an Object's Privacy

In the main part of the program, I behave myself and don't go prodding into an object's private attributes or methods. Instead, I create an object and invoke its two public methods:

 # main crit = Critter(name = "Poochie", mood = "happy") crit.talk() crit.public_method() raw_input("\n\nPress the enter key to exit.") 

crit's talk() method announces to the world how the critter is feeling. crit's public_method() method prints the string "This is a public method." and then invokes crit's private method, which prints the string "This is a private method." Finally, the program ends.

Understanding When to Implement Privacy

So now that you know how to use privacy, should you make every attribute in every class private to protect them from the evil, outside world? Well, no. Privacy is like a fine spice: used sparingly, it can greatly improve what you're making. Make private any method you don't want a client to invoke. If it's critical that an attribute never be directly accessed by a client, you can make it private. But keep this to a minimum, as creating private attributes is rare in Python. The philosophy among programmers is to trust that clients will use an object's methods and not directly alter its attributes.

HINT

When you write a class:

  • Create methods so that clients won't need to directly access an object's attributes.

  • Use privacy sparingly and only for those few attributes and methods that are completely internal to the operation of objects.

When you use an object:

  • Minimize the direct reading of an object's attributes.

  • Avoid directly altering an object's attributes.

  • Never directly access an object's private attributes or methods.




Python Programming for the Absolute Beginner
Python Programming for the Absolute Beginner, 3rd Edition
ISBN: 1435455002
EAN: 2147483647
Year: 2003
Pages: 194

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net