Python access property of class
I had a programming interview recently, a phone-screen in which we used a collaborative text editor. Show
I was asked to implement a certain API, and chose to do so in
Python. Abstracting away the problem statement, let’s say I needed a class whose instances stored some I took a deep breath and started typing. After a few lines, I had something like this:
My interviewer stopped me:
For reference, and to give you an idea of what I was going for, here’s how I amended the code:
As it turns out, we were both wrong. The real answer lay in understanding the distinction between Python class attributes and Python instance attributes. Note: if you have an expert handle on class attributes, you can skip ahead to use cases. Python Class AttributesMy interviewer was wrong in that the above code is syntactically valid. I too was wrong in that it isn’t setting a “default value” for the instance attribute. Instead, it’s defining In my experience, Python class attributes are a topic that many people know something about, but few understand completely. Python Class Variable vs. Instance Variable: What’s the Difference?A Python class attribute is an attribute of the class (circular, I know), rather than an attribute of an instance of a class. Let’s use a Python class example to illustrate the difference. Here,
Note that all instances of the class have access to
For Java or C++ programmers, the class attribute is similar—but not identical—to the static member. We’ll see how they differ later. Class vs. Instance NamespacesTo understand what’s happening here, let’s talk briefly about Python namespaces. A namespace is a mapping from names to objects, with the property that there is zero relation between names in different namespaces. They’re usually implemented as Python dictionaries, although this is abstracted away. Depending on the context, you may need to access a namespace using dot syntax (e.g.,
Python classes and instances of classes each have their own distinct namespaces represented by pre-defined attributes When you try to access an attribute from an instance of a class, it first looks at its instance namespace. If it finds the attribute, it returns the associated value. If not, it then looks in the class namespace and returns the attribute (if it’s present, throwing an error otherwise). For example:
The instance namespace takes supremacy over the class namespace: if there is an attribute with the same name in both, the instance namespace will be checked first and its value returned. Here’s a simplified version of the code (source) for attribute lookup:
And, in visual form: How Class Attributes Handle AssignmentWith this in mind, we can make sense of how Python class attributes handle assignment:
MutabilityQuiz question: What if your class attribute has a mutable type? You can manipulate (mutilate?) the class attribute by accessing it through a particular instance and, in turn, end up manipulating the referenced object that all instances are accessing (as pointed out by Timothy Wiseman). This is best demonstrated by example. Let’s go back to
the
My goal was to have the empty list (
This is no good—altering the class variable via one instance alters it for all the others! At the namespace level… all instances of We could get around this using assignment; that is, instead of exploiting the list’s mutability, we could assign our
In this case, we’re adding Unfortunately, this requires that My personal solution: if you’re just using a class variable to assign a default value to a would-be Python instance variable, don’t use mutable values. In this case,
every instance of
So When Should you Use Python Class Attributes?Class attributes are tricky, but let’s look at a few cases when they would come in handy:
Under-the-hoodNote: If you’re worrying about performance at this level, you might not want to be use Python in the first place, as the differences will be on the order of tenths of a millisecond—but it’s still fun to poke around a bit, and helps for illustration’s sake. Recall that a class’s namespace is created and filled in at the time of the class’s definition. That means that we do just one assignment—ever—for a given class variable, while instance variables must be assigned every time a new instance is created. Let’s take an example.
We assign to As further evidence, let’s use the Python disassembler:
When we look at the byte code, it’s again obvious that In practice, what does this gain really look like? I’ll be the first to admit that timing tests are highly dependent on often uncontrollable factors and the differences between them are often hard to explain accurately. However, I think these small snippets (run with the Python timeit module) help to illustrate the differences between class and instance variables, so I’ve included them anyway. Note: I’m on a MacBook Pro with OS X 10.8.5 and Python 2.7.2. Initialization
The initializations of So why is this the case? One speculative explanation: we do two assignments in Assignment
Note: There’s no way to re-run your setup code on each trial with timeit, so we have to reinitialize our variable on our trial. The second line of times represents the above times with the previously calculated initialization times deducted. From the above, it looks like Why is this the case? One speculative explanation: when we assign to In summary, though these performance gains won’t matter in reality, these tests are interesting at the conceptual level. If anything, I hope these differences help illustrate the mechanical distinctions between class and instance variables. In ConclusionClass attributes seem to be underused in Python; a lot of programmers have different impressions of how they work and why they might be helpful. My take: Python class variables have their place within the school of good code. When used with care, they can simplify things and improve readability. But when carelessly thrown into a given class, they’re sure to trip you up. Appendix: Private Instance VariablesOne thing I wanted to include but didn’t have a natural entrance point… Python doesn’t have private variables so-to-speak, but another interesting relationship between class and instance naming comes with name mangling. In the Python style guide, it’s said that pseudo-private variables should be prefixed with a double underscore: ‘__’. This is not only a sign to others that your variable is meant to be treated privately, but also a way to prevent access to it, of sorts. Here’s what I mean:
Look at that: the instance attribute While still settable and gettable using Edit: as Pedro Werneck kindly pointed out, this behavior is largely intended to help out with subclassing. In the PEP 8 style guide, they see it as serving two purposes: (1) preventing subclasses from accessing certain attributes, and (2) preventing namespace clashes in these subclasses. While useful, variable mangling shouldn’t be seen as an invitation to write code with an assumed public-private distinction, such as is present in Java. How do I see properties of an object in Python?Use Python's dir to Print an Object's Attributes
One of the easiest ways to access a Python object's attributes is the dir() function. This function is built-in directly into Python, so there's no need to import any libraries.
How do you access the data members of a class in Python?In Python, we use a dot (.) operator to access the members of a class.
Do Python classes have properties?Class Properties
In Python, a property in the class can be defined using the property() function. The property() method in Python provides an interface to instance attributes. It encapsulates instance attributes and provides a property, same as Java and C#.
|