why is defining an object variable outside of __init__ frowned upon?
Python allows you to add and delete attributes at any time. There are two problems with not doing it at __init__
- Your definitions aren't all in one place
- If you use it in a function, you may not have defined it yet
Note that you can fix the above problem of setting an attribute later by defining it in __init__
as:
self.dontknowyet = None # Everyone is happy
Python - instance attribute defined outside __init__()
It's always important to keep in mind that not all Warnings require fixing. Warnings are just Warnings. They are supposed to point out a specific part of the code because it's a "common" source of problems. But sometimes you need/want to do it that way.
I could fix the warning by adding 8 definition lines assigning None to all the variables
That's just "silencing" the Warnings, in my opinion that's just as good as ignoring the Warnings.
So what is the right thing to do?
The right way would be to just use __init__
. I did a quick test and I don't have any problems.
However that's just an example how one could do it. I haven't checked what Frame
wants as arguments for __init__
so it could lead to conflicts:
from tkinter import *
from tkinter import ttk
class Autocomplete(Frame, object):
def __init__(self, *args, **kwargs):
width, height, entries = kwargs.pop('width'), kwargs.pop('height'), kwargs.pop('entries')
super(Autocomplete, self).__init__(*args, **kwargs)
self.list = []
self._entries = entries
self.listbox_height = height
self.entry_width = width
self.text = StringVar()
self.entry = ttk.Entry(self, textvariable=self.text, width=self.entry_width)
self.frame = Frame(self)
self.listbox = Listbox(self.frame, height=self.listbox_height, width=self.entry_width)
self.dropdown = Listbox(self.frame, height=self.listbox_height, width=self.entry_width, background="#cfeff9",
takefocus=0)
self.entry.pack()
self.frame.pack()
self.listbox.grid(column=0, row=0, sticky=N)
self.dropdown.grid(column=0, row=0, sticky=N)
self.dropdown.grid_forget()
root = Frame(Tk())
autocomplete = Autocomplete(root, width=74, height=10, entries=entries)
root.pack()
autocomplete.pack()
mainloop()
This inspection detects instance attribute definition outside __init__ method PyCharm
Yes it's generally considered a good practice to explicitly define/declare all your attributes in the __init__
function, this way you have a quick list of all used (or unused) attributes in the class.
class Firebird:
username= "..."
password= "..."
def __init__(self, archive):
self.archive = archive
self.connection = None
def connect(self):
try:
self.connection = connect(dsn=self.archive, user=self.username, password=self.password)
except Error, e:
print "Failed to connect to database", e
exit(0)
Defining a class property within __init__ as opposed to within another class method -- python
I think it's a best practice to define all of your attributes up front, even if you're going to redefine them later. When I read your code, I want to be able to see your data structures. If there's some attribute hidden in a method that only becomes defined under certain circumstances, it makes it harder to understand the code.
If it is inconvenient or impossible to give an attribute it's final value, I recommend at least initializing it to None
. This signals to the reader that the object includes that attribute, even if it gets redefined later.
class exampleClass:
"""
This is an example class to demonstrate my question to stack exchange
"""
def __init__( self, fileName ):
# Note: this will be modified when a file is loaded
self.name = None
exampleClass.loadData( self, fileName )
Another choice would be for loadData
to return the value rather than setting it, so your init might look like:
def __init__(self, fileName):
self.name = self.loadData(fileName)
I tend to think this second method is better, but either method is fine. The point is, make your classes and objects as easy to understand as possible.
pylint attribute-defined-outside-init; but attributes are in __init__() method
Although correct, this still did not do the trick. I ended up reinstalling pylint and now the error is not showing anymore.
How do I avoid the self.x = x; self.y = y; self.z = z pattern in __init__?
Edit:
If you have python 3.7+ just use dataclasses
A decorator solution that keeps the signature:
import decorator
import inspect
import sys
@decorator.decorator
def simple_init(func, self, *args, **kws):
"""
@simple_init
def __init__(self,a,b,...,z)
dosomething()
behaves like
def __init__(self,a,b,...,z)
self.a = a
self.b = b
...
self.z = z
dosomething()
"""
#init_argumentnames_without_self = ['a','b',...,'z']
if sys.version_info.major == 2:
init_argumentnames_without_self = inspect.getargspec(func).args[1:]
else:
init_argumentnames_without_self = tuple(inspect.signature(func).parameters.keys())[1:]
positional_values = args
keyword_values_in_correct_order = tuple(kws[key] for key in init_argumentnames_without_self if key in kws)
attribute_values = positional_values + keyword_values_in_correct_order
for attribute_name,attribute_value in zip(init_argumentnames_without_self,attribute_values):
setattr(self,attribute_name,attribute_value)
# call the original __init__
func(self, *args, **kws)
class Test():
@simple_init
def __init__(self,a,b,c,d=4):
print(self.a,self.b,self.c,self.d)
#prints 1 3 2 4
t = Test(1,c=2,b=3)
#keeps signature
#prints ['self', 'a', 'b', 'c', 'd']
if sys.version_info.major == 2:
print(inspect.getargspec(Test.__init__).args)
else:
print(inspect.signature(Test.__init__))
Related Topics
Compare Two CSV Files and Search for Similar Items
How to Redirect Print Statements to Tkinter Text Widget
Pandas - Convert Strings to Time Without Date
Importing Flask.Ext Raises Modulenotfounderror
Python SQLite Parameter Substitution with Wildcards in Like
Class Inheritance in Python 3.7 Dataclasses
How to Insert a Jpeg Image into a Python Tkinter Window
Python Regular Expression Re.Match, Why This Code Does Not Work
Is There Any Built-In Way to Get the Length of an Iterable in Python
Add an Image in a Specific Position in the Document (.Docx)
Saving Upload in Flask Only Saves to Project Root
How to Configure Atom to Run Python3 Scripts
Why Is the Value of _Name_ Changing After Assignment to Sys.Modules[_Name_]