Voyager
Voyager

Reputation: 759

In python3, what's the difference between defining a class method inside or outside __init__ function?

Example

class Foo:
    def __init__(self, val):
        self.val = val
    def f(self,arg=None):
        if arg: print(arg)
        else: print(self.val)
    @classmethod
    def otherclassmethods(cls):pass

class Foo2:
    def __init__(self, val):
        # self.val = val, no need that
        def f(arg=val):
            print(arg)
        self.f = f
    @classmethod
    def otherclassmethods(cls):pass

I found it's perfect to define a class method inside __init__ function:

  1. in the normal class method I don't need self argument anymore.
  2. I don't need setattr to Foo2, and it's encapsulated automatically.
  3. Function looks more similar to c++.

If I define all class members inside __init__ function, and I am more concerned with their real practical effect. Maybe in concept, a closure inside __init__ is not a class method, but I think it work well as a classmethod. Based on it my question is: what's the difference between defining a class method inside or outside __init__ function?

Please help me.

Upvotes: 0

Views: 110

Answers (2)

MisterMiyagi
MisterMiyagi

Reputation: 50096

Method objects are shared between all instances of the class and its subclasses. An "__init__ method" object is recreated for each instance.

Methods use the same mechanism as classmethods, staticmethods, propertys or any other descriptor. An "__init__ method" uses its own unique, non-standard protocol.

Methods may defer to baseclass implementations, and use the default Method-Resolution-Order. An "__init__ method" needs its own means to access its base implementations.

Methods are bound to their instance only as needed. An "__init__ method" always exists in a bound state.

Methods have an accessible, qualified name; this makes them pickleable and other things. An "__init__ method" has no accessible, qualified name, since it is technically local to a function execution.

Methods define the interface of a class and all its instances. An "__init__ method" only defines the interface of its instances, since it is not visible on the class.

Methods use one set of attributes, namely instance attributes. An "__init__ method" uses two sets, namely instance attributes and __init__ closures.

Methods are accessible to the metaclass facilities, e.g. for abstract subclass implementations. An "__init__ method" is not accessible to the metaclass.

Methods can be distinguished from callable attributes. An "__init__ method" cannot be distinguished from callable attributes.

Methods use the same mechanism for special methods and regular methods. An "__init__ method" cannot implement a special method.

Upvotes: 2

chepner
chepner

Reputation: 531165

A method is a class attribute. By defining f inside __init__ and assigning it to an instance attribute, you hadn't defined an instance method, just a callable instance attribute.

class Foo2:
    def __init__(self, val):
        # self.val = val, no need that
        def f(arg=val):
            print(arg)
        self.f = f


class Bar(Foo2):
    def f(self, arg):
        print("Not called")

b = Bar(3)
b.f()  # outputs 3, not "Not called"

Upvotes: 2

Related Questions