Redundancy in __init__ in python?

  • Thread starter Isaac0427
  • Start date
  • Tags
    Python
In summary: There may already be a plugin or extension that can handle this for you. In summary, Python has the ability to examine its own code, but it is generally considered too complex and potentially slow to be worth it for something as simple as copying function arguments into class members. However, there are ways to do it, such as using the __dict__.update() method or utilizing data classes. There may also be plugins or extensions for code editors that can automatically generate self.param = param statements.
  • #1
Isaac0427
Insights Author
716
162
TL;DR Summary
I am learning about classes, and something about __init__ seems redundant-- I'm sure there's a reason for it, which is what I am looking for.
Here is an example code in python, describing a class of fruits:
Python:
class Fruits(object):
    def __init__(self, color, taste):
        self.color = color
        self.taste = taste

If, in general, we ALWAYS do this:
Python:
class ExampleClass(object):
    def __init__(self, property1, property2):
        self.property1 = property1
        self.property2 = property2
why don't we just write
Code:
def __init__(self, property1, property2)
instead of adding the self.property1 = property1 etc?

Is there ever a time where we wouldn't follow the "general formula" in this post's second block of code? If not, is there a reason python can't just fill in the rest of the "formula" if given
Code:
def __init__(self, property1, property2)
?

Thank you!
 
Technology news on Phys.org
  • #2
We don't always do that. You could imagine a class that stores a direction vector and can take initialisation in terms of (x,y,z) or (r,theta,phi):
Python:
class UnitDirectionVector:
    def __init__(self, r1, r2, r3, vectorType):
        if vectorType == "cartesian":
            # Interpret r1,r2,r3 as x,y,z and convert to unit vector
            r = math.sqrt(r1*r1+r2*r2+r3*r3)
            self.x = r1 / r
            self.y = r2 / r
            self.z = r3 / r
        elif vectorType == "polar":
            # Interpret r1,r2,r3 as r,theta,phi and store unit vector
            self.x = math.cos(r3) * math.sin(r2)
            self.y = math.sin(r3) * math.sin(r2)
            self.z = math.cos(r2)
        else:
            raise ValueError("Unrecognised vectorType "+str(vectorType))
That said, it is a common pattern to be just copying the __init__ function arguments into members, at least as part of what __init__ does. There are ways of using python's ability to examine its own code to do just that (Google lead me here), but the general feeling seems to be that it's overly complex for something straightforward. Do you really want python to re-examine a function's argument list every time you create an object, just to save you a bit of typing? That would potentially be rather slow, possibly critically so if the object is being created in a loop.

Now, if someone could write a macro for my code editor that parses my __init__() definition and auto-generates the self.param1 = param1 statements for me, that would be great.
 
Last edited:
  • Like
Likes Isaac0427
  • #3
Ibix said:
if someone could write a macro for my code editor that parses my __init__() definition and auto-generates the self.param1 = param1 statements for me, that would be great.

There's a somewhat hackish way to do this:

Python:
class Test:
    def __init__(self, a, b, c):
        self.__dict__.update((k, v) for k, v in locals().items() if k != 'self')

test = Test("a", "b", "c")
print(test.a)  # prints a
print(test.b)  # prints b
print(test.c)  # prints c
print(test.__dict__)  #  {'a': 'a', 'b': 'b', 'c': 'c'}
 
  • #4
PeterDonis said:
There's a somewhat hackish way to do this:

Python:
class Test:
    def __init__(self, a, b, c):
        self.__dict__.update((k, v) for k, v in locals().items() if k != 'self')

test = Test("a", "b", "c")
print(test.a)  # prints a
print(test.b)  # prints b
print(test.c)  # prints c
print(test.__dict__)  #  {'a': 'a', 'b': 'b', 'c': 'c'}
That's related to one of the suggestions in the page I linked, which did self.__dict__.update(kwargs). The comments seemed to be along the lines of "think of the poor guy who has to maintain this". I was thinking more of a code generator in the editor that, given def __init__(self,a,b,c):, would generate
Python:
        self.a=a
        self.b=b
        self.c=c
 
  • #5
Ibix said:
The comments seemed to be along the lines of "think of the poor guy who has to maintain this".

I agree that just having def __init__(self, **kwargs) is not good. That's why I explicitly specified the arguments to __init__ and did the dictionary update excluding self.

Ibix said:
I was thinking more of a code generator in the editor

My general attitude towards code generators is that I would rather write a library function or use some other general feature of the language so that I don't have to write boilerplate code at all. I am probably an outlier in this respect. :wink:
 
  • #6
PeterDonis said:
My general attitude towards code generators is that I would rather write a library function or use some other general feature of the language so that I don't have to write boilerplate code at all. I am probably an outlier in this respect. :wink:
I've done both. For something like copying a half dozen parameters into members I'd prefer the boilerplate just to save the cognitive load involved in parsing your update() call. On the other hand I've seen code that calculated the mean values of each one of eighty columns in a dataset by summing each one, counting it, and dividing the two, with eighty cut-and-paste copies. I ended up writing a new program to analyse the original program in order to convince myself that every variable had gone through the same process. That got replaced with smarter code.
 
  • #7
Ibix said:
For something like copying a half dozen parameters into members I'd prefer the boilerplate just to save the cognitive load involved in parsing your update() call.

Python now (as of 3.7) has data classes, which are a less hacky way of doing what I did and can also help to reduce the cognitive load involved:

https://www.python.org/dev/peps/pep-0557/
 
  • #8
Ibix said:
Now, if someone could write a macro for my code editor that parses my __init__() definition and auto-generates the self.param1 = param1 statements for me, that would be great.
Which editor are you using?
 

Related to Redundancy in __init__ in python?

1. What is redundancy in __init__ in Python?

Redundancy in __init__ in Python refers to the practice of having multiple lines of code that perform the same or similar tasks within the __init__ method of a class. This can lead to code that is difficult to understand and maintain.

2. Why is redundancy in __init__ a problem?

Redundancy in __init__ can be problematic because it can make code more complex and difficult to debug. It can also lead to errors and inconsistencies in the codebase. In addition, it can make it harder for other developers to understand and modify the code.

3. How can redundancy in __init__ be avoided?

To avoid redundancy in __init__ in Python, it is important to carefully plan and organize the code. This means identifying common tasks and creating separate methods or functions to handle them, rather than repeating code in the __init__ method. Additionally, using inheritance and polymorphism can help reduce redundancy in __init__.

4. What are the benefits of reducing redundancy in __init__?

Reducing redundancy in __init__ can lead to more efficient and maintainable code. It can also make it easier for other developers to understand and modify the code. Additionally, it can help improve overall code quality and reduce the likelihood of errors and bugs.

5. Are there any specific tools or techniques for identifying and eliminating redundancy in __init__?

There are several tools and techniques that can be used to identify and eliminate redundancy in __init__. One approach is to use a code analysis tool, such as Pylint, which can flag instances of code duplication. Another technique is to have a code review process in place where developers can identify and suggest ways to reduce redundancy. Additionally, following coding best practices, such as DRY (Don't Repeat Yourself), can help prevent redundancy in __init__.

Similar threads

  • Programming and Computer Science
Replies
13
Views
1K
  • Programming and Computer Science
Replies
3
Views
1K
  • Programming and Computer Science
Replies
9
Views
971
  • Programming and Computer Science
Replies
23
Views
2K
  • Programming and Computer Science
2
Replies
43
Views
2K
  • Programming and Computer Science
Replies
2
Views
816
  • Programming and Computer Science
Replies
9
Views
2K
  • Programming and Computer Science
Replies
5
Views
3K
  • Programming and Computer Science
Replies
5
Views
10K
  • Programming and Computer Science
Replies
3
Views
863
Back
Top