1

Let's consider the example below:

class Student:
    school = "stackoverflow"
    
    def __init__(self, name, course):
        self.name = name
        self.course = course

I understand that __init__ is the constructor. I understand that it is a method (since it's a function within a class). Or, to be more precise, as I've come to understand from the numerous tutorials - an attribute that holds a method. But is __init__ considered a class attribute in this example? Would that be correct to say? Or is it only school that is considered a class attribute?

Edit: I do understand that considering the essence of my question, any method may replace __init __(). But I would like to get an understanding using __init __() as the example at hand.

  • 3
    Have a look at `dir(Student)` - you can see both `__init__` _and_ `school`. – jonrsharpe Apr 09 '23 at 09:46
  • 2
    In the above example, only `school` is a class attribute, `name` and `course` are member attributes, and `__init__` is a method construction that can initiate some values on class creation. Also, a correction, `__init__`, does not create the class instance, it is done by the `__new__` method, and `__init__` is called after it. – Artyom Vancyan Apr 09 '23 at 09:47

2 Answers2

4

What makes the answer here a bit difficult is the conceptual idea and the technical implementation don't necessarily agree.

  • Anything that can be accessed via obj.foo is an attribute of the object.
  • Classes are objects.
  • We reserve different terminology for different kinds of attributes:
    • Function attributes are called methods.
    • The special Python @property decorator creates "properties", which act like attributes but are methods. This is specific to Python, other languages might call that getters/setters or similar.
  • Attributes/methods may exist or work only on instances of classes, while others may exist and/or work on the class. These are appropriately called instance or class attributes/methods.

So far so good, but the technical implementation in Python is a bit muddled, in the sense that instance methods do exist on the class as "unbound"* function. So you can call Student.__init__() on the class, if you pass it the right arguments.

* ("unbound" is Python 2 terminology, but IMO easy to understand)

When accessing such a method on an instance, you get a "bound" method, which automatically gets its self value passed implicitly. That is really the technical difference between class and instance methods in Python's implementation: whether they receive a self or not. To create a class method which receives a cls object, you need to use the @classmethod decorator.

But technically, they're all the same underneath: functions as attributes on objects.

If you want to learn more about how Python binds methods, I recommend @Martijn Pieters' writing on the subject, e.g. https://stackoverflow.com/a/15977850/476.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • Thank you. This is how I understand your explanation: class or instance attributes/methods differ by receiving (or not receiving) the self argument. If it does receive a self as a parameter - it is a bound attribute/method and hence an attribute/method of an instance. Not a class. The same goes with __init__ - even though (as in the example I initially provided) it is located (indentation wise) as a class method and is passed to every instance of the class exactly the same - the fact that __init__ receives a self argument - makes it bound and makes it an instance attribute. Did I get it right? – user21488634 Apr 09 '23 at 12:03
  • 2
    As I said above, there's nothing special about `__init__`. So this is generally about methods which aren't explicitly decorated with `@classmethod` or `@staticmethod`. The method does exist on the class and when called on the class could arguably be seen as a class method. However, if it's designed to take a `self` then it's an instance method (by design) which can technically be called as a class method, though then you need to pass an instance to the `self` argument. So, you need to differentiate between the *design goal* and the way you're technically invoking the method. – deceze Apr 09 '23 at 12:30
0

Yes, init is an instance method of the Student class, not a class attribute. In your example, the class attribute is school, which is a static property that is shared by all instances of the class.

The init method is a special method that is called when an instance of the class is created. It is used to initialize the attributes of the instance with the values passed to it as arguments. Since it is a method that operates on an instance of the class, it is not considered a class attribute.

To clarify, a class attribute is a property of the class itself, not its instances. It is shared by all instances of the class and can be accessed using the class name. For example, Student.school would return the value of the school class attribute.

In summary, init is an instance method used to initialize the attributes of instances of the class, while school is a class attribute that is shared by all instances of the class.

edit

I understand your confusion. Although the init method is called for each instance of the class, it is not considered a class attribute because it belongs to each instance of the class, not to the class itself.

In other words, the init method is defined in the class definition, but it is not a class attribute. Instead, it is a special method that is called on each instance of the class to initialize its attributes. The self parameter in the init method refers to the specific instance of the class that is being initialized.

To summarize, a class attribute is a property or method that belongs to the class itself and is shared by all instances of the class. The init method, on the other hand, is a special method that is called on each instance of the class to initialize its attributes, and therefore it is not a class attribute.

  • OK, just when I thought I had everything in my head arranged in order... So, in other words, it "acts" like a class attribute since it's inevitably called on every instance of the class but... it is not a class attribute because init is just special? How about the dir(Student) - a reccommendation from jonrsharpe - it actually returns both init and school... That just adds to the confusion. – user21488634 Apr 09 '23 at 10:20
  • @user21488634 `__init__` is only special in the sense that is being called behind the scenes when creating a new object. Apart from that, your question could be asked about an arbitrary method. In general any method `foo` can be called as `obj.foo(args)` or `Class.foo(obj, args)` so yes - `foo` is an attribute of the class ***as well***. As jonrsharpe suggested, try both `dir(Student)` and `dir(Student(a, b))` – Tomerikoo Apr 09 '23 at 10:25
  • @Tomerikoo - Thank you. So, __init__ can be considered a class attribute. But "...as well." Could you please explain "as well" as what else? P.s. I've tried dir(Student(a, b)) - but it just returned an error. I guess I did'nt understand what to do... – user21488634 Apr 09 '23 at 10:35
  • 1
    @user21488634 First off, with `Student(a, b)` I just meant `a` and `b` as the two arguments it expects. I should have written `Student('a', 'b')` to avoid the `NameError` you probably got if you took me too literal. Second, by ***as well*** I meant that it is a class attribute *and* an instance attribute which can be observed when inspecting the `dir` results – Tomerikoo Apr 09 '23 at 10:37