6 Best Practices for Defining the Initialization Method In Python

The essential cornerstone of Python as an object-oriented programming language is the definition of related classes to manage and process the data in your programs. When we create our classes, the first method that we define is the initialization method:?__init__. Applying the best practices to this method will ensure that it’s easy for readers to understand the class’s instance objects. In this article, I’d like to review these best practices for defining the?__init__?method.

1. Place It at The Top

It sounds obvious to most of us, but I have seen people “hide” it deep in the body of the class, together with other attributes. It’s important to place it at the top of the class, before any other methods. This is where readers should look for the?__init__?method.

If you have class attributes, you should place the?__init__?method after these class attributes. You must do it consistently across all the classes that you define for your project so that readers won’t be confused.

2. Name the First Parameter As Self

First of all, you should understand what the first parameter means. The first parameter refers to the instance object that invokes the?__init__?method. You may have heard the term instantiation, but the?__init__?method itself isn’t equivalent to instantiation. As the name indicates,?__init__?means initialization, which refers to the process of setting the initial state of the newly created instance object.

As a convention, it’s important for you to name the first parameter as self, although it’s not required to do so. As a side note,?self?isn’t a keyword in Python, unlike many other languages which may use?this,?self, or?it?which serve as reserved keywords to refer to the current calling instance object.

3. Set All Instance Attributes

Python doesn’t restrict where you define instance attributes within your class. However, it doesn’t mean that you can spread the instance attributes everywhere in your class. Consider the following example:

class Student:
    def __init__(self, name):
        self.name = name

    def verify_registration(self):
        self.registered = True

    def get_guardian_name(self):
        self.guardian = "Someone"
                

Defining Instance Attributes

As shown above, we can create a?Student?instance by initializing their name. Later, we can call?verify_registration?to get the registration status and?get_guardian_name?to get the student’s guardian information. However, this implementation pattern isn’t desired, because when you spread instance attributes everywhere, the readers of your code won’t be certain about what attributes an instance has. Instead, the best practice is to place all the instance attributes in?__init__?such that readers can know what attributes instances have with certainty. The following implementation adopts the desired pattern:

class Student:
    def __init__(self, name):
        self.name = name
        self.registered = False
        self.guardian = None
                

A Single Place for Instance Attributes

4. Avoid Using **kwargs

In Python,?**kwargs?is used to indicate a varied number of keyword parameters in function definitions. Thus, it’s syntactically correct to include?**kwargs?in the?__init__?method. Although there must be certain circumstances where using?**kwargs?in?__init__?is valid, in most cases, you don’t want to use it because it masks the needed parameters for the initialization of the instances.

I guess that one major justification for using?**kwargs?by some people is to make the?__init__?method look “clean.” However, I do believe that explicit is always better than implicit. Although listing all the parameters in the?__init__?method head may look cumbersome, we’re explicit about what parameters the users need to specify when they create instance objects.

5. Set Proper Default Values

If you know what initial values should be set to certain attributes, you can specify them in the?__init__?head, such that the users don’t need to set these parameters when they create instances. Alternatively, if certain values are applicable to most instantiation scenarios, you can set these parameters too. A possible example is shown below:


class Student:
    def __init__(self, name, bus_rider=True):
        self.name = name
        self.bus_rider = bus_rider        

However, it should be noted that when the parameter is a mutable data structure, you’ll do something different. The following is wrong:

class Student:
    def __init__(self, name, subjects=["maths", "physics"]):
        self.name = name
        self.subjects = subjects        

The problem is that when you set?[“maths”, “physics”]?as the default value,?this list object is created at the function definition?and will be?shared?by all instances. The following code shows you the problem:

>>> student0 = Student("John")
>>> student0.subjects.append("music")
>>> student0.subjects
['maths', 'physics', 'music']
>>> student1 = Student("Ashley")
>>> student1.subjects
['maths', 'physics', 'music']        

6. Docstrings

Just like other public methods, you should have proper docstrings for the?__init__?method. Although some people like to document the construction information at the class level (i.e., put initialization-related information below the class head), it’s typically recommended that you place the docstrings right below the?__init__?method.

For each parameter, you want to specify the type of the parameter — whether it’s a?str?or an?int. Following this information, you provide a brief description of what this parameter is or what it does. If there is a default value, please also specify it with any applicable justification/explanations.

Conclusion

This is the list of best practices that I’m following to define the?__init__?method for the classes in Python. I personally find them useful to maintain the readability of my code.

Abdulrahman Sheikho

Civil Engineer, Freelance Programmer & Team leader

1 年

Nice article, I found it very helpful.

回复

要查看或添加评论,请登录

Mili .的更多文章

社区洞察

其他会员也浏览了