0

I am trying to create a class with various data which are read in from several files. The usual way is probably to define a constructor (__init__) and read data inside this routine, e.g.,

from SomeOtherMod import reader   # some data reader

class Myclass:

    def __init__( self ):
        self.N = reader.readN()
        self.data = reader.readdata()
        self.foo = self.data.foo()
        self.bar = self.data.bar()
        ...    # more data to read and associated properties follow

    def othefunc( self ):
        ...    # use self.N, self.data, ...

But it also seems that I can write the same thing in a header part of the class without using __init__, e.g.,

class Myclass:

    N = reader.readN()
    data = reader.readdata()
    foo = data.foo()
    bar = data.bar()
    ...

    def otherfunc( self ):
        ...

which looks more terse than the first code. So I am wondering whether this second code is a valid way for defining various fields of a Python class? Is it considered bad practice to do so, or is there any difference between the first and second approaches? I would appreciate any suggestions because I'm still new to Python. Thanks much!

  • 1
    The first method defines instance attributes which can vary between instances of the class. The second method defines class attributes which would be shared by all instances of the class. [9. Classes](https://docs.python.org/3/tutorial/classes.html). ... https://docs.python.org/3/reference/datamodel.html – wwii Apr 14 '17 at 02:52
  • You can think of class attributes like "static attributes" in languages like Java or C++ – juanpa.arrivillaga Apr 14 '17 at 02:56
  • Hmm, really... Acutually, while I read some introductory book on Python, I still cannot understand how instance and class fields are distinguished (syntactically) in Python, except for the usage {Classname}.{fieldname}. I will check this more... –  Apr 14 '17 at 02:58
  • As an aside, ```__init__()``` is not a constructor - it initializes instance attributes. [```__init__``` as a constructor?](http://stackoverflow.com/questions/6578487/init-as-a-constructor) – wwii Apr 14 '17 at 02:59
  • OK, thank you very much! I will check the difference of class and instance fields more closely. I hope I could upvote the answers but cannot still ... Anyway, thanks much! –  Apr 14 '17 at 03:16
  • @spectrum a [real world example...](http://stackoverflow.com/questions/43404247/python-objects-have-the-same-value) – juanpa.arrivillaga Apr 14 '17 at 03:33

3 Answers3

1

In the first approach, N, data, foo and bar are easy members of the instances of Myclass. Each Myclass object has its own and changing one will have no effect on the other instances:

class X():
  def __init__(self):
    self.x = []

a = X()
b = X()
a.x.append(1)
a.x != b.x

In the second approach, they are members of the class. You can still access them through the instances, but they will be shared by all the instances.

class X():
  x = []

a = X()
b = X()
a.x.append(1)
a.x == b.x == [1]

Both are valid code, but they serve different purposes

3Doubloons
  • 2,088
  • 14
  • 26
1

Yes - they are very different - when you assign to self.attribute inside a method you are making it an instance attribute- while when you assign to attribute in the class body, you are creating a class attribute. Class attributes are shared among all instances.

In some circumstances, but not always, you may want exactly that. WHht you have to keep in mind is that if yu change a class attribute, it will be changed for all instances of that class at once.

Of course, there is a natural decurrence of the way Python deal with attribute retrieval and assignment that makes assignments in the class body quite handy. If there is a value that should be the default for all instances of a class - say, employee Payout - but that should be customized at some point in the life cycle of the object, that happens naturally:

class Employee:
    payout = 100

e1 = Employee()
e2 = Employee()

print(e1.payout, e2.payout) 
# Payout is read from the class as it does not exist in any instance
# Python prints 100, 100

e1.payout = 120
# Now, an "payout" attribute is created in the "e1" instance
print(e1.payout, e2.payout)
# shows 120, 100

# And the outpt of the following lines will make
# really clear what is going on:
print(e1.__class__.__dict__, e2.__class__.__dict__)
# shows "{'payout': 100, ...}, {'payout': 100, ...} 
print(e1.__dict__, e2.__dict__)
# shows "{'payout': 120}, {} 
jsbueno
  • 99,910
  • 10
  • 151
  • 209
1

There are important differences between the two approaches. In some use cases you can do it either way, but they are definitely not equivalent.

With the first method, the statements inside the __init__ method are not executed until you instantiate an instance of the class; i.e., until your code executes a statement of the form a = MyClass().

With the second method, the statements inside the class definition block are executed the first time the interpreter reaches the code. That's probably at (or near) the beginning of your program, and will occur when you import a module containing the class definition. That may, or may not, be OK for your application.

Also, read the link provided in a comment by juanpa.arrivilaga, or this one: Why do attribute references act like this with Python inheritance?

Community
  • 1
  • 1
Paul Cornelius
  • 9,245
  • 1
  • 15
  • 24