def __init__(self, items=None):
if items is None: items = []
self.l = items
In response to @Eastsun's edit, I propose a different structure to __init__
def __init__(self, items=()):
''' Accepts any iterable
The appropriate TypeError will be raised if items is not iterable '''
self.l = list(items)
Note that lowercase l is a bad name, it can be confused with 1
Hello everyone!
While learning about classes in Python, I encountered the following two questions. Consider the following two classes:
class Dog:
def __init__(self, name, age):
self.name = name
self.age = ageand
class Dog:
def dog_constructor(self, name, age):
self.name = name
self.age = age
The main difference is that the first class contains an __init__ method, but the second one does not.
To create an instance in the first class, I used: my_dog = Dog('Willie', 5). However,
for the second one I tried: my_dog = Dog.dog_constructor('Willie', 10) which did not work. Then eventually
I was told that I should use
my_dog = Dog()
my_dog.dog_constructor('Willie', 5).I am so confused about why we should use this approach.
Can anyone explain to me the importance of having an __init__ method in a class and why instances are created differently depending on whether we have __init__ or not?
I have been struggling with this for a while but still cannot grasp it.
I'd be very thankful for the explanation! Thank you!
def __init__(self, items=None):
if items is None: items = []
self.l = items
In response to @Eastsun's edit, I propose a different structure to __init__
def __init__(self, items=()):
''' Accepts any iterable
The appropriate TypeError will be raised if items is not iterable '''
self.l = list(items)
Note that lowercase l is a bad name, it can be confused with 1
def __init__(self, items=None):
self.l = items or []
Or
def __init__(self, items=None):
self.l = items if items else []
Edit in response to Dougal's comment.
(I have been learning Python about two weeks, so here is just my personal opinion. Correct me if I am wrong.)
In a programming language like python, it is hard to prevent someone passing an unwanted type of object to your function or method.
In my idea, the security way to assure the __init__ always work is like this:
def __init__(self, items = None):
if isinstance(items, Iterable):
self.l = list(items)
elif items is None:
self.l = []
else:
raise TypeError('items must be iterable')
Note: the above method always make a shallow copy if items is already a list.
class - Python Classes without using def __init__(self) - Stack Overflow
Python inheritance: TypeError: object.__init__() takes no parameters - Stack Overflow
How do I pass __init__ arguments to a subclass without repeating them?
python - using __init__ method with and without parameters - Stack Overflow
What is __init__ in Python?
Is __init__ a constructor in Python?
Can __init__ return a value in Python?
You can circumvent __init__ by calling __new__ directly. Then you can create a object of the given type and call an alternative method for __init__. This is something that pickle would do.
However, first I'd like to stress very much that it is something that you shouldn't do and whatever you're trying to achieve, there are better ways to do it, some of which have been mentioned in the other answers. In particular, it's a bad idea to skip calling __init__.
When objects are created, more or less this happens:
a = A.__new__(A, *args, **kwargs)
a.__init__(*args, **kwargs)
You could skip the second step.
Here's why you shouldn't do this: The purpose of __init__ is to initialize the object, fill in all the fields and ensure that the __init__ methods of the parent classes are also called. With pickle it is an exception because it tries to store all the data associated with the object (including any fields/instance variables that are set for the object), and so anything that was set by __init__ the previous time would be restored by pickle, there's no need to call it again.
If you skip __init__ and use an alternative initializer, you'd have a sort of a code duplication - there would be two places where the instance variables are filled in, and it's easy to miss one of them in one of the initializers or accidentally make the two fill the fields act differently. This gives the possibility of subtle bugs that aren't that trivial to trace (you'd have to know which initializer was called), and the code will be more difficult to maintain. Not to mention that you'd be in an even bigger mess if you're using inheritance - the problems will go up the inheritance chain, because you'd have to use this alternative initializer everywhere up the chain.
Also by doing so you'd be more or less overriding Python's instance creation and making your own. Python already does that for you pretty well, no need to go reinventing it and it will confuse people using your code.
Here's what to best do instead: Use a single __init__ method that is to be called for all possible instantiations of the class that initializes all instance variables properly. For different modes of initialization use either of the two approaches:
- Support different signatures for
__init__that handle your cases by using optional arguments. - Create several class methods that serve as alternative constructors. Make sure they all create instances of the class in the normal way (i.e. calling
__init__), as shown by Roman Bodnarchuk, while performing additional work or whatever. It's best if they pass all the data to the class (and__init__handles it), but if that's impossible or inconvenient, you can set some instance variables after the instance was created and__init__is done initializing.
If __init__ has an optional step (e.g. like processing that data argument, although you'd have to be more specific), you can either make it an optional argument or make a normal method that does the processing... or both.
Use classmethod decorator for your Load method:
class B(object):
def __init__(self, name, data):
self._Name = name
#store data
@classmethod
def Load(cls, file, newName):
f = open(file, "rb")
s = pickle.load(f)
f.close()
return cls(newName, s)
So you can do:
loaded_obj = B.Load('filename.txt', 'foo')
Edit:
Anyway, if you still want to omit __init__ method, try __new__:
>>> class A(object):
... def __init__(self):
... print '__init__'
...
>>> A()
__init__
<__main__.A object at 0x800f1f710>
>>> a = A.__new__(A)
>>> a
<__main__.A object at 0x800f1fd50>
Your code is perfectly fine. You don't have to have an __init__ method.
You can still use __init__, even with an ABC. All that the ABC meta tests for is if the names have been defined. Setting images in an __init__ does requires that you define a class attribute, but you can set that to None at first:
class Servers(BaseMenu):
menu_name = "Servers"
images = None
foo = None
def __init__(self):
self.images = list_images.get_images()
self.foo = list_list.get_list()
Now you can set constraints on the ABC requiring that a images abstract property be available; the images = None class attribute will satisfy that constraint.
Your code is fine. The example below shows a minimal example.
You can still instantiate a class that doesn't specify the __init__ method. Leaving it out does not make your class abstract.
class A:
def a(self, a):
print(a)
ob = A()
ob.a("Hello World")
You are calling the wrong class name in your super() call:
class SimpleHelloWorld(IRCReplyModule):
def __init__(self):
#super(IRCReplyModule,self).__init__('hello world')
super(SimpleHelloWorld,self).__init__('hello world')
Essentially what you are resolving to is the __init__ of the object base class which takes no params.
Its a bit redundant, I know, to have to specify the class that you are already inside of, which is why in python3 you can just do: super().__init__()
This has bitten me twice recently (I know I should have learned from my mistake the first time) and the accepted answer hasn't helped me either time so while it is fresh in my mind I thought I would submit my own answer just in case anybody else is running into this (or I need this again in future).
In my case the issue was that I was passing a kwarg into the initialisation of the subclass but in the superclass that keyword arg was then being passed though into the super() call.
I always think these types of things are best with an example:
class Foo(object):
def __init__(self, required_param_1, *args, **kwargs):
super(Foo, self).__init__(*args, **kwargs)
self.required_param = required_param_1
self.some_named_optional_param = kwargs.pop('named_optional_param', None)
def some_other_method(self):
raise NotImplementedException
class Bar(Foo):
def some_other_method(self):
print('Do some magic')
Bar(42) # no error
Bar(42, named_optional_param={'xyz': 123}) # raises TypeError: object.__init__() takes no parameters
So to resolve this I just need to alter the order that I do things in the Foo.__init__ method; e.g.:
class Foo(object):
def __init__(self, required_param_1, *args, **kwargs):
self.some_named_optional_param = kwargs.pop('named_optional_param', None)
# call super only AFTER poping the kwargs
super(Foo, self).__init__(*args, **kwargs)
self.required_param = required_param_1
class Modifier:
def __init__(self, value, name):
self.value = value
self.name = name
self.hidden = "yes"
self.generate_add_modifiers = "{produces}"
def generate_script(self):
script = f"""{{
#value = {self.value}
#name = {self.name}
hidden = {self.hidden}
generate_add_modifiers = {self.generate_add_modifiers}
}}"""
return script
class DerivedModifier(Modifier):
def __init__(self, is_positive):
self.is_positive = is_positiveThe above code is part of a game scripting language generator I'm working on. I've not dealt much with classes, but I assumed that arguments from a parents init method would get passed to it's childs init automatically.
However, pycharm is complaining about invalid arguments when I try to do the following:
m = DerivedModifier(name = Test, value = "50", is_positive = "True")
Is this not the case? How can I achieve this without repeating myself?
Simply equate the the parameters that you would want to be defaulted to their default value.
For instance, __init__(a,b,c=0) would give 0 as the default value to c which you can override by passing another value when object is created.
def __init__(a,b,c='your default value')
Every class has an __init__ method. If it doesn't explicitly define one, then it will inherit one from its parent class. In your 2nd example, the class inherits __init__ and a bunch of other methods (and other non-method attributes) from the base object class. We can see that via the dir function:
class Dog:
def init_instance(self,name):
self.name = name
print('My name is',name)
print(dir(Dog))
output
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'init_instance']
__init__ gets called automatically after the instance is constructed (via the __new__ method), so we might as well use it if we need to initialize our instance. But we can call your init_instance explicitly:
bob = Dog()
bob.init_instance('Bob')
print(bob.name)
output
My name is Bob
Bob
If you give you class an initializer that isn't named __init__ then it won't get called automatically. How should Python know that that method is an initializer? Although it's customary to make __init__ the first method in the class definition, that's by no means mandatory, and some people like to put __init__ last.
You said: "I have seen code where the init method has not been used, how come?" Well, some classes simply don't need their instances to be initialized: their instance attributes are set via various other methods, or by direct assignment in code outside the class definition, eg bob.color = 'brown'. Or they inherit a perfectly usable __init__ from a parent class.
init is nothing else then a method to initially prepare the state of your object. In other languages they have similar concepts as Constructors and it's not necessarily needed.