3

After using Django for a while, I got use to using classes without def __init__(self): ... when declaring variables. I used to declare my variables in the __init__ function, I now realize that there are cases where don't need to, I'm just unclear on when to use it or not. It seems there is a problem when trying to pass a class to a variable, should I use init in these cases?

I know I could just use __init__ for all cases, but it just makes my short classes like cleaner without it, so I would like to know when I can and cannot use it.

example:

class BaseScraper(object):
    # whithout __init__, passing Site() to site wont work.
    # site = Site()
    # parser = None

    def __init__(self):
        self.site = Site()
        self.parser = None 


class Site(object):
    # no trouble declaring url as a str
    url = ""

    def set(self, url):
        self.url = url

    def get(self):
        return self.url



if __name__ == "__main__":
    scraper = BaseScraper()

    scraper.site.set('http://www.google.com')   
    print scraper.site.get()
Brandon Nadeau
  • 3,568
  • 13
  • 42
  • 65
  • 1
    Django doesn't really represent Python. Django model fields are class-level attributes, they are in fact actual objects that aren't at all "holders" for your data, and they serve as medatada that the base `Model`'s `__init__()` method (or some other part of that wad of code) uses to automagically create instance-level attributes and do a bunch of other stuff. Python doesn't normally work that way. – millimoose May 14 '13 at 22:44
  • 1
    When initialising instance data, you should do so in `__init__` unless you know what you're doing. (That class-level attributes kinda sorta act like they're default values for instance attributes is a bit of a hack with a bunch of caveats.) – millimoose May 14 '13 at 22:46
  • that's pretty interesting, thanks for explaing – Brandon Nadeau May 14 '13 at 22:48

2 Answers2

6

Attributes declared in the class are owned by the class rather than by individual instances of the class. In your site example, url is no more a property of individual Site objects than set or get are. For this kind of example, you want instance data - which you can initialize in __init__.

Python: Difference between class and instance attributes has a good discussion of the differences.

Community
  • 1
  • 1
Peter DeGlopper
  • 36,326
  • 7
  • 90
  • 83
1

This fails because Site class is not defined yet. And (as @Peter DeGlopper) said, there is a big difference between class variables and instance variables.

class BaseScraper(object):
    # This fails!
    site = Site()
    parser = None


class Site(object):
    # no trouble declaring url as a str
    url = ""

    def set(self, url):
        self.url = url

    def get(self):
        return self.url

When the virtual machine compile a python module, read and compile everything in class declaration, but on method declaration (like def __init__(...):) only read this line, ignoring the method body.

Example:

class Foo(object):
    bar1 = "bar"
    foo1 = "foo"

    def __init__(self):
        self.bar2 = "BAZ"

foo = Foo #Put a class in a veriable? yes, you can.
foo.bar1 # returns "bar"
foo.foo1 # returns "foo"
foo.bar2 # fails!!!! This will be a instance variable, but doesn't exist yet

foo2 = Foo() # Here the __init__ is called
foo2.bar2 # returns "BAZ"
foo2.bar1 #Returns "bar" because all class variables are availables from instances

Hope this helps =)

Leandro
  • 2,217
  • 15
  • 18