Cara menggunakan python get class attributes

In a recent phone screen, I decided to use a class attribute in my implementation of a certain Python API. My interviewer challenged me, questioning whether my code was syntactically valid, when it was executed, etc. In fact, I wasn’t sure of the answers myself. So I did some digging. Python class attributes: when (or how) to use them. In this guide, I walk you through common pitfalls and conclude with a list of valid use cases that could save you time, energy, and lines of code.

Share

Share

Cara menggunakan python get class attributes

In a recent phone screen, I decided to use a class attribute in my implementation of a certain Python API. My interviewer challenged me, questioning whether my code was syntactically valid, when it was executed, etc. In fact, I wasn’t sure of the answers myself. So I did some digging. Python class attributes: when (or how) to use them. In this guide, I walk you through common pitfalls and conclude with a list of valid use cases that could save you time, energy, and lines of code.

Cara menggunakan python get class attributes

By Charles Marsh

Charles has been an engineering lead at Khan Academy, Cedar, and Spring Discovery.

Editor’s note: This article was updated on 11/29/22 by our editorial team. It has been modified to include recent sources and to align with our current editorial standards.

I recently had a programming interview phone screen in which we used a collaborative text editor and it got me thinking about Python class attributes.

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

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
3 and some
{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
4.

I took a deep breath and started typing. After a few lines, I had something like this:

    class Service(object):
        data = []

        def __init__(self, other_data):
            self.other_data = other_data
        ...

My interviewer stopped me:

  • Interviewer: “That line

    {:lang='python'}
        class MyClass(object):
            class_var = 1
    
            def __init__(self, i_var):
                self.i_var = i_var
    
    5. I don’t think that’s valid Python.”

  • Me: “I’m pretty sure it is. It’s just setting a default value for the instance attribute.”

  • Interviewer: “When does that code get executed?”

  • Me: “I’m not really sure. I’ll just fix it up to avoid confusion.”

For reference, and to give you an idea of what I was going for, here’s how I amended the code:

    class Service(object):

        def __init__(self, other_data):
            self.data = []
            self.other_data = other_data
        ...

As it turns out, we were both wrong. The real answer lay in understanding the distinction between Python class attributes and Python instance attributes.

Cara menggunakan python get class attributes

Note: If you have an expert handle on Python class attributes, you can skip ahead to use cases.

Python Class Attributes

My interviewer was wrong in that the above code is syntactically valid.

I was wrong in that the code isn’t setting a “default value” for the instance attribute. Instead, it’s defining

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
3 as a class attribute with value
{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
7.

In my experience, Python class attributes are a topic that many people know something about, but few understand completely.

Python Class Variables vs. Instance Variables: 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,

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
8 is a class attribute, and
{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
9 is an instance attribute:

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

Note that all instances of the class have access to

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
8, and that it can also be accessed as a property of the class itself:

{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1

For Java or C++ programmers, the class attribute is similar—but not identical—to the static member. We’ll see how they differ later.

Python Class Properties vs. Instance Namespaces

To 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.,

{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
1) or as a local variable (e.g.,
{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
2). As a concrete example:

{:lang='python'}
    class MyClass(object):
        ## No need for dot syntax
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

    ## Need dot syntax as we’ve left scope of class namespace
    MyClass.class_var
    ## 1

Python classes and instances of classes each have their own distinct namespaces represented by the

{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
3 and
{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
4, respectively.

When you try to access Python attributes 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, otherwise throwing an error). For example:

{:lang='python'}
    foo = MyClass(2)

    ## Finds i_var in foo’s instance namespace
    foo.i_var
    ## 2

    ## Doesn’t find class_var in instance namespace…
    ## So looks in class namespace (MyClass.__dict__)
    foo.class_var
    ## 1

The instance namespace takes precedence over the class namespace: If there is a Python attribute with the same name in both, the instance namespace will be checked first and its value returned. Here’s a for attribute lookup:

{:lang='python'}
    def instlookup(inst, name):
        ## simplified algorithm
        if inst.__dict__.has_key(name):
            return inst.__dict__[name]
        else:
            return inst.__class__.__dict__[name]

And, in visual form:

Cara menggunakan python get class attributes

How Python Class Attributes Handle Assignment

With this in mind, we can make sense of how class attributes handle assignment:

  • If a class attribute is set by accessing the class, it will override the value for all instances. For example:

      {:lang='python'}
        foo = MyClass(2)
        foo.class_var
        ## 1
        MyClass.class_var = 2
        foo.class_var
        ## 2
    

At the namespace level we’re setting

{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
5. (Note: This isn’t the exact code which would be
{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
6 as
{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
7 returns a , an immutable wrapper that prevents direct assignment, but it helps for demonstration’s sake). Then, when we access
{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
8,
{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
8 has a new value in the class namespace and thus 2 is returned.

  • If a Python class variable is set by accessing an instance, it will override the value only for that instance. This essentially overrides the class variable and turns it into an instance variable available intuitively only for that instance. For example:

    foo = MyClass(2)
    foo.class_var
    ## 1
    foo.class_var = 2
    foo.class_var
    ## 2
    MyClass.class_var
    ## 1
    

At the namespace level we’re adding the

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
8 attribute to
{:lang='python'}
    class MyClass(object):
        ## No need for dot syntax
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

    ## Need dot syntax as we’ve left scope of class namespace
    MyClass.class_var
    ## 1
1, so when we look up
{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
8, we return 2. Meanwhile, other instances of
{:lang='python'}
    class MyClass(object):
        ## No need for dot syntax
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

    ## Need dot syntax as we’ve left scope of class namespace
    MyClass.class_var
    ## 1
3 will not have
{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
8 in their instance namespaces, so they continue to find
{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
8 in
{:lang='python'}
    foo = MyClass(2)
    bar = MyClass(3)

    foo.class_var, foo.i_var
    ## 1, 2
    bar.class_var, bar.i_var
    ## 1, 3
    MyClass.class_var ## <— This is key
    ## 1
3 and thus return 1.

Mutability

What if your class attribute has a mutable type? You can manipulate 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).

Let’s go back to the

{:lang='python'}
    class MyClass(object):
        ## No need for dot syntax
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

    ## Need dot syntax as we’ve left scope of class namespace
    MyClass.class_var
    ## 1
7 I defined earlier and see how my use of a class variable could have led to problems down the road:

{:lang='python'}
    class Service(object):
        data = []

        def __init__(self, other_data):
            self.other_data = other_data
        ...

My goal was to have the empty list (

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
7) as the default value for
{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
3, and for each instance of
{:lang='python'}
    class MyClass(object):
        ## No need for dot syntax
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

    ## Need dot syntax as we’ve left scope of class namespace
    MyClass.class_var
    ## 1
7 to have its own data that would be altered over time on an instance-by-instance basis. But in this case, we got the following behavior (note that
{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
4 is arbitrary in this example):

    class Service(object):

        def __init__(self, other_data):
            self.data = []
            self.other_data = other_data
        ...
0

This is no good—altering our Python class variable via one instance alters it for all the others!

At the namespace level all instances of

{:lang='python'}
    class MyClass(object):
        ## No need for dot syntax
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

    ## Need dot syntax as we’ve left scope of class namespace
    MyClass.class_var
    ## 1
7 are accessing and modifying the same list in
{:lang='python'}
    foo = MyClass(2)

    ## Finds i_var in foo’s instance namespace
    foo.i_var
    ## 2

    ## Doesn’t find class_var in instance namespace…
    ## So looks in class namespace (MyClass.__dict__)
    foo.class_var
    ## 1
3 without making their own
{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
3 attributes in their instance namespaces.

We could get around this using assignment; that is, instead of exploiting the list’s mutability, we could assign our

{:lang='python'}
    class MyClass(object):
        ## No need for dot syntax
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

    ## Need dot syntax as we’ve left scope of class namespace
    MyClass.class_var
    ## 1
7 objects to have their own lists, as follows:

    class Service(object):

        def __init__(self, other_data):
            self.data = []
            self.other_data = other_data
        ...
1

In this case, we’re adding

{:lang='python'}
    foo = MyClass(2)

    ## Finds i_var in foo’s instance namespace
    foo.i_var
    ## 2

    ## Doesn’t find class_var in instance namespace…
    ## So looks in class namespace (MyClass.__dict__)
    foo.class_var
    ## 1
6, so the original
{:lang='python'}
    foo = MyClass(2)

    ## Finds i_var in foo’s instance namespace
    foo.i_var
    ## 2

    ## Doesn’t find class_var in instance namespace…
    ## So looks in class namespace (MyClass.__dict__)
    foo.class_var
    ## 1
7 remains unchanged.

Unfortunately, this requires that

{:lang='python'}
    class MyClass(object):
        ## No need for dot syntax
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

    ## Need dot syntax as we’ve left scope of class namespace
    MyClass.class_var
    ## 1
7 users have intimate knowledge of its variables, and this workaround is certainly prone to mistakes. In a sense, we’d be addressing the symptoms rather than the cause. It’s preferable to have something that is correct by construction.

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

{:lang='python'}
    class MyClass(object):
        ## No need for dot syntax
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var

    ## Need dot syntax as we’ve left scope of class namespace
    MyClass.class_var
    ## 1
7 was going to override
{:lang='python'}
    def instlookup(inst, name):
        ## simplified algorithm
        if inst.__dict__.has_key(name):
            return inst.__dict__[name]
        else:
            return inst.__class__.__dict__[name]
0 with its own instance attribute eventually, so using an empty list as the default led to a tiny bug that was easily overlooked. Instead of the above, we could have either:

  1. Stuck to instance attributes entirely, as demonstrated in the introduction.

  2. Avoided using the empty list (a mutable value) as our “default.”

For example:

    class Service(object):

        def __init__(self, other_data):
            self.data = []
            self.other_data = other_data
        ...
2

Of course, we’d have to handle the

{:lang='python'}
    def instlookup(inst, name):
        ## simplified algorithm
        if inst.__dict__.has_key(name):
            return inst.__dict__[name]
        else:
            return inst.__class__.__dict__[name]
1 case appropriately, but that’s a small price to pay.

When Should You Use Python Class Attributes?

Class attributes are tricky, but let’s look at a few cases where they would come in handy:

  1. Storing constants. As class attributes can be accessed as attributes of the class itself, it’s often nice to use them for storing class-wide, class-specific constants. For example:

        class Service(object):
    
            def __init__(self, other_data):
                self.data = []
                self.other_data = other_data
            ...
    
    3
  2. Defining default values. As a small example, we might create a bounded list (i.e., a list that can only hold a certain number of elements or fewer) and choose to have a default cap of 10 items:

        class Service(object):
    
            def __init__(self, other_data):
                self.data = []
                self.other_data = other_data
            ...
    
    4

    We could then create instances with their own specific limits too, by assigning them to the instance’s

    {:lang='python'}
        def instlookup(inst, name):
            ## simplified algorithm
            if inst.__dict__.has_key(name):
                return inst.__dict__[name]
            else:
                return inst.__class__.__dict__[name]
    
    2 attribute.

        class Service(object):
    
            def __init__(self, other_data):
                self.data = []
                self.other_data = other_data
            ...
    
    5

    This only makes sense if you will want your typical instance of

    {:lang='python'}
        class MyClass(object):
            ## No need for dot syntax
            class_var = 1
    
            def __init__(self, i_var):
                self.i_var = i_var
    
        ## Need dot syntax as we’ve left scope of class namespace
        MyClass.class_var
        ## 1
    
    3 to hold just 10 elements or fewer—if you’re giving all of your instances different limits, then
    {:lang='python'}
        def instlookup(inst, name):
            ## simplified algorithm
            if inst.__dict__.has_key(name):
                return inst.__dict__[name]
            else:
                return inst.__class__.__dict__[name]
    
    2 should be an instance variable. (Remember to be careful when using mutable values as your defaults.)

  3. Tracking all data across all instances of a given class. This is sort of specific, but I could see a scenario in which you might want to access a piece of data related to every existing instance of a given class.

    To make the scenario more concrete, let’s say we have a

    {:lang='python'}
        def instlookup(inst, name):
            ## simplified algorithm
            if inst.__dict__.has_key(name):
                return inst.__dict__[name]
            else:
                return inst.__class__.__dict__[name]
    
    5 class, and every person has a
    {:lang='python'}
        def instlookup(inst, name):
            ## simplified algorithm
            if inst.__dict__.has_key(name):
                return inst.__dict__[name]
            else:
                return inst.__class__.__dict__[name]
    
    6. We want to keep track of all the names that have been used. One approach might be to iterate over the garbage collector’s list of objects, but it’s simpler to use class variables.

    Note that, in this case,

    {:lang='python'}
        def instlookup(inst, name):
            ## simplified algorithm
            if inst.__dict__.has_key(name):
                return inst.__dict__[name]
            else:
                return inst.__class__.__dict__[name]
    
    7 will only be accessed as a class variable, so the mutable value default is acceptable.

        class Service(object):
    
            def __init__(self, other_data):
                self.data = []
                self.other_data = other_data
            ...
    
    6

    We could even use this design pattern to track all existing instances of a given class, rather than just some associated data.

        class Service(object):
    
            def __init__(self, other_data):
                self.data = []
                self.other_data = other_data
            ...
    
    7
  4. Considering Performance

Related: Python Best Practices and Tips by Toptal Developers

Under the Hood

Note: 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 it 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 for a given class variable, while instance variables must be assigned every time a new instance is created.

Let’s take an example:

    class Service(object):

        def __init__(self, other_data):
            self.data = []
            self.other_data = other_data
        ...
8

We assign to

{:lang='python'}
    def instlookup(inst, name):
        ## simplified algorithm
        if inst.__dict__.has_key(name):
            return inst.__dict__[name]
        else:
            return inst.__class__.__dict__[name]
8 just once, but
{:lang='python'}
    def instlookup(inst, name):
        ## simplified algorithm
        if inst.__dict__.has_key(name):
            return inst.__dict__[name]
        else:
            return inst.__class__.__dict__[name]
9 on every call to
  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
0.

As further evidence, let’s use the Python disassembler:

    class Service(object):

        def __init__(self, other_data):
            self.data = []
            self.other_data = other_data
        ...
9

When we look at the byte code, it’s again obvious that

  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
1 has to do two assignments, while
  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
2 does just one.

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

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
0

The initializations of

  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
3 are faster by over a second, so the difference here does appear to be statistically significant.

So why is this the case? One speculative explanation: We do two assignments in

  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
1, but just one in
  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
2.

Assignment

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
1

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

  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
6 only takes about 60% as long as
  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
3 to handle assignments.

Why is this the case? One speculative explanation: When we assign to

  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
8, we first look in the instance namespace (
  {:lang='python'}
    foo = MyClass(2)
    foo.class_var
    ## 1
    MyClass.class_var = 2
    foo.class_var
    ## 2
9), fail to find
foo = MyClass(2)
foo.class_var
## 1
foo.class_var = 2
foo.class_var
## 2
MyClass.class_var
## 1
0, and then look in the class namespace (
foo = MyClass(2)
foo.class_var
## 1
foo.class_var = 2
foo.class_var
## 2
MyClass.class_var
## 1
1), then make the proper assignment. When we assign to
foo = MyClass(2)
foo.class_var
## 1
foo.class_var = 2
foo.class_var
## 2
MyClass.class_var
## 1
2, we do half as many lookups, as we immediately assign to the instance namespace (
foo = MyClass(2)
foo.class_var
## 1
foo.class_var = 2
foo.class_var
## 2
MyClass.class_var
## 1
3).

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 Conclusion

Class 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 Variables

One additional variable to mention: private instance variables.

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:

{:lang='python'}
    class MyClass(object):
        class_var = 1

        def __init__(self, i_var):
            self.i_var = i_var
2

Look at that: The instance attribute

foo = MyClass(2)
foo.class_var
## 1
foo.class_var = 2
foo.class_var
## 2
MyClass.class_var
## 1
4 is automatically prefixed with the class name to yield
foo = MyClass(2)
foo.class_var
## 1
foo.class_var = 2
foo.class_var
## 2
MyClass.class_var
## 1
5.

While still settable and gettable using

foo = MyClass(2)
foo.class_var
## 1
foo.class_var = 2
foo.class_var
## 2
MyClass.class_var
## 1
6, this name mangling is a means of creating a “private” variable as it prevents you and others from accessing it by accident or through ignorance.

Edit: As Pedro Werneck kindly pointed out, this behavior is largely intended to help out with subclassing. In the , 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.

Further Reading on the Toptal Engineering Blog:

  • Ensuring Clean Code: A Look at Python, Parameterized
  • Python Design Patterns: For Sleek And Fashionable Code
  • Top 10 Mistakes That Django Developers Make
  • An Introduction to Mocking in Python
  • The Six Commandments of Good Code: Write Code That Stands the Test of Time

Understanding the basics

  • What is a Python namespace?

    A Python namespace is a mapping from names to objects, with the property that there is zero relation between names in different namespaces. Namespaces are usually implemented as Python dictionaries, although this is abstracted away.

  • Python class method versus instance method: What’s the difference?

    In Python, a class method is a method that is invoked with the class as the context. This is often called a static method in other programming languages. An instance method, on the other hand, is invoked with an instance as the context.

  • What happens if both instance attribute and class attribute are defined?

    In that case, the instance namespace takes precedence 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.

    Bagaimana cara mendeklarasikan suatu class pada Python?

    Cara mendeklarasikan object dari sebuah class pada python adalah dengan memanggil nama class beserta dengan parameter yang diberikan pada fungsi constructor ( __init__ ).

    Apa itu atribut pada Python?

    Atribut adalah data anggota (variabel kelas dan variabel contoh) dan metode, diakses melalui notasi titik. Sebuah variabel yang dibagi oleh semua contoh kelas. Variabel kelas didefinisikan dalam kelas tapi di luar metode kelas manapun.

    Apa fungsi class di Python?

    Class atau kelas-kelas adalah prototipe untuk wadah menghimpun data dan kebergunaan yang kemudian menghasilkan objek. Setiap class baru akan menghasilkan objek baru yang kemudian bisa dibuat instance dengan memiliki atribut yang ada.

    Apa itu objek dalam Python?

    Objek pada python adalah kumpulan dari variabel-variabel (dinamakan atribut) dan kumpulan dari fungsi-fungsi (dinamakan perilaku). Atas definisi itu, maka semua hal di dalam python adalah sebuah Objek. Objek dan Kelas dalam python bermakna sama.