Instance attribute attribute_name defined outside __init__ - python

I split up my class constructor by letting it call multiple functions, like this:
class Wizard:
def __init__(self, argv):
self.parse_arguments(argv)
self.wave_wand() # declaration omitted
def parse_arguments(self, argv):
if self.has_correct_argument_count(argv):
self.name = argv[0]
self.magic_ability = argv[1]
else:
raise InvalidArgumentsException() # declaration omitted
# ... irrelevant functions omitted
While my interpreter happily runs my code, Pylint has a complaint:
Instance attribute attribute_name defined outside __init__
A cursory Google search is currently fruitless. Keeping all constructor logic in __init__ seems unorganized, and turning off the Pylint warning also seems hack-ish.
What is a/the Pythonic way to resolve this problem?

The idea behind this message is for the sake of readability. We expect to find all the attributes an instance may have by reading its __init__ method.
You may still want to split initialization into other methods though. In such case, you can simply assign attributes to None (with a bit of documentation) in the __init__ then call the sub-initialization methods.

Just return a tuple from parse_arguments() and unpack into attributes inside __init__ as needed.
Also, I would recommend that you use Exceptions in lieu of using exit(1). You get tracebacks, your code is reusable, etc.
class Wizard:
def __init__(self, argv):
self.name,self.magic_ability = self.parse_arguments(argv)
def parse_arguments(self, argv):
assert len(argv) == 2
return argv[0],argv[1]

The best practice to solve this question is you need to build the parameter in Init part first,
Then adjust it in the Def
class MainApplication(tk.Frame):
def __init__(self, master):
self.master = master
tk.Frame.__init__(self, self.master)
self.settingsFrame = None
self.create_widgets(master)
def create_widgets(self, master):
# frame Container
self.settingsFrame = tk.Frame(self.master, width=500, height=30, bg='white')

Although the definition of instance variables outside init isn't recommended in general, there are rare cases in which it is natural. For example, when you have a parent class that defines several variables that its child classes won't use, and whose definition will make its child waste time or resources, or will be simply unaesthetic.
One possible solution to this is using an init-extention function, that each child class may override, and in this function use function setattr in order to define the class-unique instance variables. May be this is not too aesthetic as well, but it eliminates the here-discussed linting warning.

For each attribute you want to set via function, call the function from the init. For example, the following works for me to set the attribute ascii_txt...
def __init__(self, raw_file=None, fingerprint=None):
self.raw_file = raw_file
self.ascii_txt = self.convert_resume_to_ascii()
def convert_resume_to_ascii(self):
ret_val = self.raw_file.upper()
return ret_val

If you are using Python 3, you can try
class Wizard:
def __init__(self, argv):
self.name: str = str()
self.magic_ability: str = str()
self.parse_arguments(argv)
self.wave_wand() # declaration omitted
def parse_arguments(self, argv):
if self.has_correct_argument_count(argv):
self.name = argv[0]
self.magic_ability = argv[1]
else:
raise InvalidArgumentsException() # declaration omitted
# ... irrelevant functions omitted
Although not as pythonic as the accepted answer, but it should get away the Pylint alert.
And if you don't concern about type and don't want to create a new object with object() use:
class Wizard:
def __init__(self, argv):
self.name = type(None)()
# ...
As None will cause type not match error.

Related

Pylint complains "no value for argument 'cls'"

I have defined the following class-method to define my object from a pandas.DataFrame instead of from a list like so:
class Container(object):
#classmethod
def from_df(cls, df):
rows = [i for _, i in df.iterrows()]
return cls(rows)
and pylint complains at the return line with the E1120 'code-smell':
No value for argument 'cls' in constructor call
I can't see anything wrong with it, and it seems to work. Does anybody else maybe have an idea what could be wrong with it?
Update: Ugh, user rogalski got it (I think): I confused myself by using the same variable name for a class that comes in as argument:
def __init__(self, iterable, cls):
self.content = [cls(item) for item in iterable]
I do this because I have different kind of objects coming in and this Container class is the abstract version of this daughter:
class FanContainer(Container):
def __init__(self, iterable):
super().__init__(iterable, Fan)
with Fan being one of several classes that need to be 'contained'.
Rogalski, want to write up an answer along the lines of saying that the error might reference a name of the __init__ constructor? Cheers! (Now I have to dig why my code isn't stumbling over this...)
Update2
Only realizing know how feeble I have coded this: I am using this basically like so:
fancontainer = FanContainer.from_df(df)
and because I am overwriting the __init__ in the FanContainer class, I guess that's why my code still worked? So, the abstract __init__ is never being called directly, because I never call Container.from_df(df) but only the daughter classes' classmethods. Guess that can be done prettier a different way.
Typically this error is related to non-complaint function signatures.
Given your code:
class Container(object):
def __init__(self, iterable, cls):
self.content = [cls(item) for item in iterable]
#classmethod
def from_df(cls, df):
rows = [i for _, i in df.iterrows()]
return cls(rows)
Pylint resolves cls in from_df scope object to be Container. Class objects are callables (like functions) and they return new instance of given class. Pylint investigates constructor interface and checks if passed arguments are correct.
In your case passed arguments are incorrect - second required argument (which happens to have same name - cls - but it exists in different score) is missing. That's why Pylint yields error.
Follow up your edits:
Pylint does not run your code. It statically analyzes it. Since it's possible to call it like Container.from_df PyLint will warn about possible misuse.
If constructor is never intended to use both arguments outside of your subclasses you may pass default argument and explicitly raise an exception:
class Container(object):
def __init__(self, iterable, cls=None):
if cls is None:
raise NotImplementedError()
self.content = [cls(item) for item in iterable]
#classmethod
def from_df(cls, df):
rows = [i for _, i in df.iterrows()]
return cls(rows)

Why do classes with no constructor arguments need parenthesis

I started off learning programming/OOP in PHP. To the best of my knowledge of best practices in PHP, you can instantiate a class without parenthesis if it does not take any arguments.
Such as
$class = new Class;
As opposed to:
$class = new Class();
I am starting to expand my skills into python and wasted about 5 hours yesterday trying to figure out why a function wouldn't pass an argument even though it was ridiculously simple. My Code:
class MainViewWidgets(MainViewContainer):
def __init__(self):
# instantiating like this prevents MainViewController.getHeaderItems from returning the arg passed to it, however the code still "works" in some sense
self.controller = MainViewController
#this works
self.controller = MainViewController()
def createHeaderOptionCheckbox(self, pane):
self.header_string = StringVar()
header_checkbox = ttk.Checkbutton(pane, text='Data Contains Headers', variable=self.header_string, onvalue='headers', offvalue='keys')
self.header_string.trace('w', self.headerOptionCheckboxChanged)
return header_checkbox
def headerOptionCheckboxChanged(self, *args):
print(self.header_string.get())
#will print "headers" or "keys" on checkbox toggle
print(self.controller.getHeaderItems(self.header_string.get()))
#prints "default"
class MainViewController:
def __init__(self):
self.CheckFile = CheckFile()
get_config = GetConfiguration('config.ini')
self.config_file = get_config.getProperty('directory', 'input_file')
self.csv = CSVReader(self.config_file)
self.chosen_index = None
def getHeaderItems(self, header='default'):
return header
Can someone please help me understand why in Python you need to instantiate a class with parenthesis even if there are no constructor arguments other than self. Also, why did the MainViewController still kind of work, but it did not behave as I wanted it to? As in it was loaded, and the functions "did things", but it would not seem to accept arguments. Is there any advantages of instantiating a class without its parenthesis?
Please note, I do not need help getting this code to work, I just want to understand why this happens.
Can someone please help me understand why in Python you need to instantiate a class with parenthesis even if there are no constructor arguments other than self.
The reason is simple: when you instantiate an object, you are actually calling its class (which is itself an object), and you call objects using ().
In python, everything is a first-class object, even classes (and functions!) themselves. In order for a class to be a first class object, it follows that the class needs its own class (metaclass) to define its behavior. We call the class of a class "metaclass" so as to avoid confusion when talking about classes and classes of classes.
To answer the second part of your question: "things" were happening when you used MainViewController instead of MainViewController() because MainViewController is a full-fledged object, just like any other object.
So you might ask: what is the class - actually the metaclass - of the MainViewController object?
As you know, you can create a class like this:
class MyClass:
pass
When you do this, you are in actuality creating a new instance of the metaclass known as type.
Note that you can create the same class this way; there is literally no difference between the below and the above:
MyClass = type('MyClass', (object,), {})
The type metaclass is the base metaclass of all classes. All python "new style classes" (not so "new" anymore since they were implemented in python 2.1, I believe) are of the class type:
print(type(MyClass)) # type
print(type(list)) # type
print(type(int)) # type
# Note that above, type is being used as a "function" (it's really just a callable)
Interestingly enough, type is even its own metaclass:
print(type(type)) # type
So to reiterate: the class MyClass is actually an instantiation of type. It follows, then, that calling the class results in running the __call__ method of its metaclass.
When you do:
obj = MyClass()
...you are calling MyClass, which results (in the background) in running the method type.__call__().
This is the case with all user defined classes, btw; if you include the __call__ method in your class, your class is callable, and the __call__ method is executed when you call class instances:
class MyCallable():
def __call__(self):
print("You rang?")
my_instance = MyCallable()
my_instance() # You rang?
You can see this in action. If you create your own metaclass by subclassing type, you can cause things to happen when an instance of the class based on your custom metaclass is created. For example:
class MyMeta(type):
def __call__(self, *args, **kwargs):
print "call: {} {} {}".format(self, args, kwargs)
return super().__call__(*args, **kwargs)
# Python 3:
class MyClass(metaclass = MyMeta):
pass
# Python 2:
class MyClass():
__metaclass__ = MyMeta
pass
Now when you do MyClass(), you can see that the __call__ method of MyMeta happens before anything else (including before __new__ AND before __init__).
Because function calls require (). When you do MyClass(), you are calling MyClass. The expression MyClass evaluates to the class itself, which is an object.

Python calling super constructor - am I doing it right?

I have a base class like so:
class Token:
def __init__(self, value):
self.value = value.strip()
self.tokens = None
def get_value(self):
return self.value
def tokenize(self):
pass # abstract stub
def __str__(self):
return type(self).__name__ + ': '+ re.sub(r'\s+', ' ', self.value)
And a ton of it's child classes:
class T_DefineDirective(Token):
def __init__(self, value):
super().__init__(value)
class T_IncludeDirective(Token):
def __init__(self, value):
super().__init__(value)
class T_IfdefDirective(Token):
def __init__(self, value):
super().__init__(value)
class T_Identifier(Token):
def __init__(self, value):
super().__init__(value)
class T_Rvalue(Token):
def __init__(self, value):
super().__init__(value)
def tokenize(self):
pass # stuff here
Now I'm a DRY programmer. I hate repetition. If you look at the code, the __init__ piece is copy-pasted in all the child classes.
My question, is there some way to avoid the repetition, or is this really the right way?
(note that the example is a bit shortened, so it may not make too much sense. But you can see the issue I mean).
If you do not have any additional setup work to do in the Token subclasses, then it is safe not to override __init__.
If you do have to perform some subclass-specific initialisation, then the patten that you're using is fine and 'pythonic'.
To clarify:
if __init__ is not defined on a class, then Python will use the __init__ method defined on (one of) its parent class(es), if possible
this is because there aren't any special rules for overriding 'magic' methods like __init__
even if the initialiser on a parent class is used, an instance of the subclass will be created
this is because the actual creation happens in __new__; the newly created object is then passed to __init__ for initialisation
If you really want to eliminate as much boilerplate as possible:
First, you don't need __init__ if all it does is call super(); special methods are inherited just like any other methods, as sapi's answer explains.
Second, you can dynamically create a bunch of classes:
token_classes = {
'T_{}'.format(name): type('T_{}'.format(name), (Token,), {})
for name in 'DefineDirective IncludeDirective IfdefDirective Identifier'.split()
}
And you can use them straight out of that dict, but if you really want to make them into globals you can:
globals().update(token_classes)
However, the whole goal of avoiding repetition is to make your code more readable and maintainable, and in this case, I think we're achieving the opposite. :)

Possible to return instantiator in Python?

class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
# get Parent instance
self.parent = self.Instantiator()
I know this isn't proper encapsulation but for interest's sake...
Given a "Parent" class that instantiates a "Child" object, is it possible from within Child to return the Parent object that instantiated it? And if no, I'm curious, do any languages support this?
To answer the question, no, there's no way1 the child instance knows about any classes which contain references to it. The common2 way to handle this is:
class Parent(object):
def __init__(self):
self.child = Child()
self.child._parent = self
1 Of course, this isn't strictly true. As another commentor noted, you can extract the stack frame from the executing code within the __init__ method, and examine the f_locals dictionary for the self variable for the frame before the currently executing one. But this is complicated, and prone to error. Highly unrecommended.
2 A slightly better way to handle this (depending on the specific needs of the program) might be to require the parent to pass itself to the child, like so:
class Parent(object):
def __init__(self):
self.child = Child(self)
class Child(object):
def __init__(self, parent):
self._parent = parent
Here's a reasonably-simple metaclass solution to the problem:
import functools
class MetaTrackinits(type):
being_inited = []
def __new__(cls, n, b, d):
clob = type.__new__(cls, n, b, d)
theinit = getattr(clob, '__init__')
#functools.wraps(theinit)
def __init__(self, *a, **k):
MetaTrackinits.being_inited.append(self)
try: theinit(self, *a, **k)
finally: MetaTrackinits.being_inited.pop()
setattr(clob, '__init__', __init__)
def Instantiator(self, where=-2):
return MetaTrackinits.being_inited[where]
setattr(clob, 'Instantiator', Instantiator)
return clob
__metaclass__ = MetaTrackinits
class Parent():
def __init__(self):
self.child = Child()
class Child():
def __init__(self):
self.parent = self.Instantiator()
p = Parent()
print p
print p.child.parent
a typical output, depending on the platform, will be something like
<__main__.Parent object at 0xd0750>
<__main__.Parent object at 0xd0750>
You could obtain a similar effect (in 2.6 and later) with a class decorator, but then all classes needing the functionality (both parent and children ones) would have to be explicitly decorated -- here, they just need to have the same metaclass, which may be less intrusive thanks to the "module-global __metaclass__ setting" idiom (and the fact that metaclasses, differently from class-decorations, also get inherited).
In fact, this is simple enough that I would consider allowing it in production code, if the need for that magical "instantiator" method had a proven business basis (I would never allow, in production code, a hack based on walking the stack frames!-). (BTW, the "allowing" part comes from the best-practice of mandatory code reviews: code changes don't get into the trunk of the codebase without consensus from reviewers -- this how typical open source projects work, and also how we always operate at my employer).
Here's an example based off of some of Chris B.'s suggestions to show how absolutely terrible it would be to inspect the stack:
import sys
class Child(object):
def __init__(self):
# To get the parent:
# 1. Get our current stack frame
# 2. Go back one level to our caller (the Parent() constructor).
# 3. Grab it's locals dictionary
# 4. Fetch the self instance.
# 5. Assign it to our parent property.
self.parent = sys._getframe().f_back.f_locals['self']
class Parent(object):
def __init__(self):
self.child = Child()
if __name__ == '__main__':
p = Parent()
assert(id(p) == id(p.child.parent))
Sure that'll work, but just never try to refactor it into a seperate method, or create a base class from it.
you could* try to use the traceback module, just to prove a point.
**Don't try this at home, kids*
This can be done in python with metaclasses.

Python: How To copy function parameters into object's fields effortlessly?

Many times I have member functions that copy parameters into object's fields. For Example:
class NouveauRiches(object):
def __init__(self, car, mansion, jet, bling):
self.car = car
self.mansion = mansion
self.jet = jet
self.bling = bling
Is there a python language construct that would make the above code less tedious?
One could use *args:
def __init__(self, *args):
self.car, self.mansion, self.jet, self.bling = args
+: less tedious
-: function signature not revealing enough. need to dive into function code to know how to use function
-: does not raise a TypeError on call with wrong # of parameters (but does raise a ValueError)
Any other ideas? (Whatever your suggestion, make sure the code calling the function does stays simple)
You could do this with a helper method, something like this:
import inspect
def setargs(func):
f = inspect.currentframe(1)
argspec = inspect.getargspec(func)
for arg in argspec.args:
setattr(f.f_locals["self"], arg, f.f_locals[arg])
Usage:
class Foo(object):
def __init__(self, bar, baz=4711):
setargs(self.__init__)
print self.bar # Now defined
print self.baz # Now defined
This is not pretty, and it should probably only be used when prototyping. Please use explicit assignment if you plan to have others read it.
It could probably be improved not to need to take the function as an argument, but that would require even more ugly hacks and trickery :)
I would go for this, also you could override already defined properties.
class D:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
But i personally would just go the long way.
Think of those:
- Explicit is better than implicit.
- Flat is better than nested.
(The Zen of Python)
Try something like
d = dict(locals())
del d['self']
self.__dict__.update(d)
Of course, it returns all local variables, not just function arguments.
I am not sure this is such a good idea, but it can be done:
import inspect
class NouveauRiches(object):
def __init__(self, car, mansion, jet, bling):
arguments = inspect.getargvalues(frame)[0]
values = inspect.getargvalues(frame)[3];
for name in arguments:
self.__dict__[name] = values[name]
It does not read great either, though I suppose you could put this in a utility method that is reused.
You could try something like this:
class C(object):
def __init__(self, **kwargs):
for k in kwargs:
d = {k: kwargs[k]}
self.__dict__.update(d)
Or using setattr you can do:
class D(object):
def __init__(self, **kwargs):
for k in kwargs:
setattr(self, k, kwargs[k])
Both can then be called like:
myclass = C(test=1, test2=2)
So you have to use **kwargs, rather than *args.
I sometimes do this for classes that act "bunch-like", that is, they have a bunch of customizable attributes:
class SuperClass(object):
def __init__(self, **kw):
for name, value in kw.iteritems():
if not hasattr(self, name):
raise TypeError('Unexpected argument: %s' % name)
setattr(self, name, value)
class SubClass(SuperClass):
instance_var = None # default value
class SubClass2(SubClass):
other_instance_var = True
#property
def something_dynamic(self):
return self._internal_var
#something_dynamic.setter # new Python 2.6 feature of properties
def something_dynamic(self, value):
assert value is None or isinstance(value, str)
self._internal_var = value
Then you can call SubClass2(instance_var=[], other_instance_var=False) and it'll work without defining __init__ in either of them. You can use any property as well. Though this allows you to overwrite methods, which you probably wouldn't intend (as they return True for hasattr() just like an instance variable).
If you add any property or other other descriptor it will work fine. You can use that to do type checking; unlike type checking in __init__ it'll be applied any time that value is updated. Note you can't use any positional arguments for these unless you override __init__, so sometimes what would be a natural positional argument won't work. formencode.declarative covers this and other issues, probably with a thoroughness I would not suggest you attempt (in retrospect I don't think it's worth it).
Note that any recipe that uses self.__dict__ won't respect properties and descriptors, and if you use those together you'll just get weird and unexpected results. I only recommend using setattr() to set attributes, never self.__dict__.
Also this recipe doesn't give a very helpful signature, while some of the ones that do frame and function introspection do. With some work it is possible to dynamically generate a __doc__ that clarifies the arguments... but again I'm not sure the payoff is worth the addition of more moving parts.
I am a fan of the following
import inspect
def args_to_attrs(otherself):
frame = inspect.currentframe(1)
argvalues = inspect.getargvalues(frame)
for arg in argvalues.args:
if arg == 'self':
continue
value = argvalues.locals[arg]
setattr(otherself, arg, value)
class MyClass:
def __init__(self, arga="baf", argb="lek", argc=None):
args_to_attrs(self)
Arguments to __init__ are explicitly named, so it is clear what attributes are being set. Additionally, it is a little bit streamlined over the currently accepted answer.

Categories