mcepl
mcepl

Reputation: 2786

Difference between two types of class properties definition?

Is there a difference between

class Foo(object):
    bar = 1
    def __init__(self):
        ... etc.

and

class Foo(object):
    def __init__(self):
       ... etc.

Foo.bar = 1

In both cases bar is a property of the class and it is same for all instances of the class, right?

Upvotes: 4

Views: 277

Answers (3)

Marcin
Marcin

Reputation: 49886

Both versions are the same (see transcript of tests at end of this answer), but note that (a) in neither case is bar the same for all instances of Foo.

At the moment an instance is created, reading bar on the instance will read the value in Foo, and assignments to Foo.bar will be reflected in the instance until instance.bar is assigned to. At that moment of assignment, the instance gets its own __dict__ entry, which is entirely independant of the class.

In [62]: class Foo: pass

In [63]: Foo.bar = 1

In [64]: Foo.bar
Out[64]: 1

In [65]: f = Foo()

In [66]: f.bar
Out[66]: 1

In [67]: f.bar +=1

In [68]: f.bar
Out[68]: 2

In [69]: Foo.bar
Out[69]: 1

In [70]: Foo.bar +=3

In [71]: Foo.bar
Out[71]: 4

In [72]: g = Foo()

In [73]: g.bar
Out[73]: 4

In [74]: class Qux: bar = 1

In [75]: Qux.bar
Out[75]: 1

In [76]: q = Qux()

In [77]: q.bar
Out[77]: 1

In [78]: q.bar+=1

In [79]: q.bar
Out[79]: 2

In [80]: Qux.bar
Out[80]: 1

In [81]: Qux.bar +=1

In [82]: r = Qux()

In [83]: r.bar
Out[83]: 2

In [84]: q.bar
Out[84]: 2

In [85]: s = Qux()

In [87]: s.__dict__
Out[87]: {}

In [88]: q.__dict__
Out[88]: {'bar': 2}

In [89]: Qux.bar = 'foo'

In [90]: Qux.bar
Out[90]: 'foo'

In [91]: s.bar
Out[91]: 'foo'

Upvotes: -1

Rik Poggi
Rik Poggi

Reputation: 29312

If you're writing your own code, go with:

class Foo(object):
    bar = 1

Becase this version:

class Foo(object):
    pass

Foo.bar = 1

Even though it's legit

  1. Looks more like a hack.
  2. Is less readable in most cases.
  3. You might have problems if you try to access the bar attribute before its been created:

    >>> class Foo:
    ...     pass
    ... 
    >>> f = Foo()
    >>> f.bar
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Foo' object has no attribute 'bar'
    >>> Foo.bar = 1
    >>> f.bar   # but hey, now you're ok!
    1
    

Other than that I don't see many differences.

Upvotes: 4

jcollado
jcollado

Reputation: 40424

I'd say that the only difference is that in the second case, Foo.bar doesn't exist until the Foo.bar = 1 statement is executed while in the first case is already available when the class object is created.

That's probably a small difference without any effect in your code (unless there is some code that requires Foo.bar before it's available in the second case). However, I'd say that the first option is better in terms of readability since you don't have to scroll down to know the attributes for your class, they're already there.

Upvotes: 4

Related Questions