4

This may be a stupid / trivial question, but I'm confused in this matter.

What is the encouraged (pythonic) way of declaring instance fields - in the constructor, or in the class body itself?

class Foo:
    """ Foo class """

    # While we are at it, how to properly document the fields?
    bar = None

    def __init__(self, baz):
        """ Make a Foo """

        self.bar = baz

OR:

class Foo:
    """ Foo class """

    def __init__(self, baz):
        """ Make a Foo """

        self.bar = baz
MightyPork
  • 18,270
  • 10
  • 79
  • 133
  • 3
    i think second is better – Vahid Kharazi Aug 07 '14 at 06:53
  • Documentation: I simply write `"""bar initial value"""` below the field. – Maroun Aug 07 '14 at 06:54
  • 1
    To me, the first reads like a class attribute rather than an instance attribute (http://stackoverflow.com/questions/207000/python-difference-between-class-and-instance-attributes). One day you'll forget to assign to `bar` in `__init__()` and inadvertently end up with a class attribute (and a hard-to-find bug). For these reasons, I'd use #2 every day of the week. – NPE Aug 07 '14 at 07:02
  • @NPE If a method sets it as `self.foo = 123`, does that override the "class attribute" effect and make it an instance attribute? Because if so, then I'm fine with this - the class attribute will just hold a never-changed default value. – MightyPork Aug 07 '14 at 07:04

2 Answers2

7

It's a matter of expectations. People reading your code will expect that the attributes defined at the top level of the class will be class attributes. The fact that you then always replace them in __init__ will only create confusion.

For that reason you should go with option 2, defining instance attributes inside __init__.

In terms of documenting the attributes, pick a docstring style and stick to it; I like Google's, other options include numpy's.

class Foo:
    """A class for foo-ing bazs. 

    Args:
      baz: the baz to foo

    Attributes:
      bar: we keep the baz around 

    """

    def __init__(self, baz):
        self.bar = baz
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
3

To keep it simple, let us define class Foo with a class variable bar:

In [34]: class Foo: bar = 1

Now, observe:

In [35]: a = Foo()

In [36]: a.bar
Out[36]: 1

In [37]: Foo.bar = 2

In [38]: a.bar
Out[38]: 2

A change to Foo.bar affects existing instances of the class.

For this reason, one generally avoids class variables, as opposed to instance variables unless one wants these side-effects.

John1024
  • 109,961
  • 14
  • 137
  • 171
  • I see where you are coming from. However, in the first example, *exactly as it's written*, `bar` is not shared by instances of `Foo`. – NPE Aug 07 '14 at 07:00
  • So is this claim true or false? I totally do not want anything to be shared. – MightyPork Aug 07 '14 at 07:01
  • @MightyPork I have added an example to demonstrate. NPE is right that my example is not exactly your code. However, I do think it goes to the more general question that you were asking. – John1024 Aug 07 '14 at 07:17