2

I was Googling some Python-related questions earlier, and stumbled upon this page. The author does something like the following:

class TestClass(object):
    first = str()
    def __init__(self):
        self.first = "Hello"

What's the point of "declaring" the variable first like that? I've never seen this done before, and I can't for the life of me think of a situation where it is beneficial to create a variable before assigning it some value.

The above example could just as well have looked like this:

class TestClass(object):
    def __init__(self, first="Hello"):
        self.first = first

...or am I missing something?

4
  • The example could have, but the results are not exactly the same. Commented May 29, 2013 at 10:35
  • The "first = str()" creates a variable associated to the class while the "self.first = ..." creates a new one for the instance (this doesn't mean that it makes sense). Commented May 29, 2013 at 10:43
  • 1
    Just remember: There's probably more horribly bad code out there than good one. Commented May 29, 2013 at 10:44
  • 2
    Don't believe everything you read, especially if it's on the Internet. Commented May 29, 2013 at 10:46

4 Answers 4

6

The fact that the author uses

first = str()

as opposed to

first = ''

shows, alongside setting self.first in __init__ anyway, that there that is no purpose in doing this.

Maybe the author is confused and thinks python variable need to be declared first -_- (evident when viewing the link)

Sign up to request clarification or add additional context in comments.

Comments

3

That's not a declaration, that's an assignment ... to a variable inside the class, as opposed to a variable inside an instance.

Consider the following output:

>>> class K1(object):
...     def __init__(self):
...         self.attr = 'value'
... 
>>> x = K1()
>>> x.__dict__
{'attr': 'value'}
>>> class K2(object):
...     attr = 'value'
...     def __init__(self):
...         self.another = 'value2'
... 
>>> y = K2()
>>> y.__dict__
{'another': 'value2'}

Here x is an instance of class K1 and has an attribute named attr, and y is an instance of class K2 and has a different attribute named another. But:

>>> y.attr
'value'

Where did that come from? It came from the class:

>>> y.__class__.__dict__
dict_proxy({'__module__': '__main__', 'attr': 'value',
'__dict__': <attribute '__dict__' of 'K2' objects>,
'__weakref__': <attribute '__weakref__' of 'K2' objects>,
'__doc__': None, '__init__': <function __init__ at 0x80185b9b0>})

That's kind of messy but you can see the attr sitting in there. If you look at x.__class__.__dict__ there's no attr:

>>> x.__class__.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'K1' objects>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'K1' objects>,
'__doc__': None, '__init__': <function __init__ at 0x80185b938>})

When you get an attribute on an instance, like x.attr or y.attr, Python first looks for something attached to the instance itself. If nothing is found, though, it "looks upward" to see if something else defines that attribute. For classes with inheritance, that involves going through the "member resolution order" list. In this case there is no inheritance to worry about, but the next step is to look at the class itself. Here, in K2, there's an attribute in the class named attr, so that's what y.attr produces.

You can change the class attribute to change what shows up in y.attr:

>>> K2.attr = 'newvalue'
>>> y.attr
'newvalue'

And in fact, if you make another instance of K2(), it too will pick up the new value:

>>> z = K2()
>>> z.attr
'newvalue'

Note that changing x's attr does not affect new instances of K1():

>>> w = K1()
>>> w.attr = 'private to w'
>>> w.attr
'private to w'
>>> x.attr
'value'

That's because w.attr is really w.__dict__['attr'], and x.attr is really x.__dict__['attr']. On the other hand, y.attr and z.attr are both really y.__class__.__dict__['attr'] and z.__class__.__dict__['attr'], and since y.__class__ and z.__class__ are both K2, changing K2.attr changes both.

(I'm not sure the guy who wrote the page referenced in the original question realizes all this, though. Creating a class-level attribute and then creating an instance-level one with the same name is kind of pointless.)

1 Comment

Very thorough answer, and I am accepting it. It seems consensus is the author of that post didn't really know what he was doing...
3

str() is equal to ""

>>> str()
''

I think the author wants to show that instance attributes override class attributes having same name. So on executing

test = testclass()  
print test.__dict__  

you'll get:

{'second': 'weird', 'third': 'test', 'first': 'Some'}

not

{'second': '', 'third': '', 'first': ''}

but

print testclass.__dict__

will print the class attributes:

{'__module__': '__main__', 'third': '', 'second': '', '__doc__': None, '__init__': <function __init__ at 0xb5fed6bc>, 'first': ''}

2 Comments

simple confusion still sounds more likely :)
I seriously doubt that was the author's intention.
1

There is indeed a little difference between the two examples:

class TestClass(object):
    first = 'foo'
    def __init__(self):
        self.first = "Hello"

print(TestClass.first)

Output:

foo

However with:

class TestClass(object):
    def __init__(self, first="Hello"):
        self.first = "Hello"

print(TestClass.first)

Output:

Traceback (most recent call last):
  File "C:\Users\...\Desktop\test.py", line 5, in <module>
    print(TestClass.first)
AttributeError: type object 'TestClass' has no attribute 'first'

Note: But that doesn't mean that the author's code make sense. Just wanted to point out the difference.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.