Re: [Tutor] raising exceptions in constructor code?
On 16Jul2019 23:49, Alan Gauld wrote: On 16/07/2019 22:56, Mats Wichmann wrote: thrown. This gets watered down to the mantra "Don't throw exceptions from within constructors." Does this carry over to Python? If you mean __init__, that's not a constructor, so you should set your mind at rest :) It's more properly an "initializer", the instance has already been constructed when it's called. FWIW The true constructor is __new__() and its quite rarely overridden by application programmers. But if you do, it's not common that you'd do anything that would merit an exception. __new__ pretty much just sets up the structure of the object ready for initialisation by __init__. Incidentally, this two stage construction/initialisation is also found in other OOP languages like Smalltalk and Objective C (and Lisp?). And to return to the OP's question: The __init__ method (and arguably __new__ if you touch it - very rare) is like other Python code: resource allocation should normally get unwound as objects become unreferenced. So raising an exception should be a pretty safe thing to do. That is a simplification. Of course if you implement an object with side effects _outside_ the Python object space (maybe it opened a scratch file to support something), it is your responsibility to ensure release in the object's __del__ method. But an object that just allocates a bunch of lists or dicts or the like? Python will clean that up for you. That said, I try to do cheap initialisation before exspensive initialisation. So allocating locks, opening files, starting worker threads: these come at the bottom of the __init__ method. Also, it is _ROUTINE_ to raise exceptions from __init__: like any other method we _expect_ you to raise ValueError if the initialiser parameters are insane (negatively sized arrays, etc etc). So in Python, raising exceptions in __init__ is normal: it shouldn't happen when you programme is running correctly of course, but it is the _preferred_ action when your initialiser cannot complete correctly. Consider: x = Foo() After this assignment we expect "x" to be a usable instance of Foo. We don't put special checks; what would such checks look like? (There are some answers for that, but they're all poor.) So raising an exception is what happens if __init__ fails. Cheers, Cameron Simpson ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] raising exceptions in constructor code?
On Tue, Jul 16, 2019 at 04:29:15PM -0500, James Hartley wrote: > I ask this having more C++ knowledge than sense. > > There is an adage in the halls of everything Stroustrup that one needs to > think about how resource allocation will be unwound if an exception is > thrown. This gets watered down to the mantra "Don't throw exceptions from > within constructors." Does this carry over to Python? I'm trying to > develop a Pythonistic mindset as opposed to carrying over old baggage... No, it is perfectly safe to raise exceptions from within the Python constructors, whether you are using __new__ (the true constructor) or __init__ (the initialiser). The only tricky part is if you allocate resources external to the object, like this: class Weird(object): openfiles = [] def __new__(cls, fname): f = open(fname) cls.openfiles.append(f) # New instance: instance = super().__new__(cls) if condition: raise ValueError return instance Even if the __new__ constructor fails, I've kept a reference to an open file in the class. (I could have used a global variable instead.) That would be bad. But notice I had to work hard to make this failure mode, and write the code in a weird way. The more natural way to write that^1 would be: class Natural(object): def __init__(self, fname): self.openfile = open(fname) if condition: raise ValueError Now if there is an exception, the garbage collector will collect the instance and close the open file as part of the collection process. That might not be immediately, for example Jython might not close the file until interpreter shutdown. But the earlier example will definitely leak an open file, regardless of which Python interpreter you use, while the second will only leak if the garbage collector fails to close open files. Here's a better example that doesn't depend on the quirks of the garbage collector: class Leaky(object): instances = [] def __init__(self): self.instance.append(self) if random.random() < 0.1: raise ValueError This will hold onto a reference to the instance even if the initialiser (constructor) fails. But you normally wouldn't do that. class NotLeaky(object): def __init__(self): if random.random() < 0.1: raise ValueError try: x = NotLeaky() except ValueError: pass Now either the call to NotLeaky succeeds, and x is bound to the instance, or it fails, and x is *not* bound to the instance. With no references to the newly-created instance, it will be garbage collected. ^1 Actually that's not too natural either. It is not usually a good idea to hold onto an open file when you aren't actively using it, as the number of open files is severely constrained on most systems. -- Steven ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] raising exceptions in constructor code?
On 16/07/2019 22:56, Mats Wichmann wrote: >> thrown. This gets watered down to the mantra "Don't throw exceptions from >> within constructors." Does this carry over to Python? > > If you mean __init__, that's not a constructor, so you should set your > mind at rest :) It's more properly an "initializer", the instance has > already been constructed when it's called. FWIW The true constructor is __new__() and its quite rarely overridden by application programmers. But if you do, it's not common that you'd do anything that would merit an exception. __new__ pretty much just sets up the structure of the object ready for initialisation by __init__. Incidentally, this two stage construction/initialisation is also found in other OOP languages like Smalltalk and Objective C (and Lisp?). -- Alan G Author of the Learn to Program web site http://www.alan-g.me.uk/ http://www.amazon.com/author/alan_gauld Follow my photo-blog on Flickr at: http://www.flickr.com/photos/alangauldphotos ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] raising exceptions in constructor code?
On 7/16/19 3:29 PM, James Hartley wrote: > I ask this having more C++ knowledge than sense. > > There is an adage in the halls of everything Stroustrup that one needs to > think about how resource allocation will be unwound if an exception is > thrown. This gets watered down to the mantra "Don't throw exceptions from > within constructors." Does this carry over to Python? I'm trying to > develop a Pythonistic mindset as opposed to carrying over old baggage... If you mean __init__, that's not a constructor, so you should set your mind at rest :) It's more properly an "initializer", the instance has already been constructed when it's called. ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor
[Tutor] raising exceptions in constructor code?
I ask this having more C++ knowledge than sense. There is an adage in the halls of everything Stroustrup that one needs to think about how resource allocation will be unwound if an exception is thrown. This gets watered down to the mantra "Don't throw exceptions from within constructors." Does this carry over to Python? I'm trying to develop a Pythonistic mindset as opposed to carrying over old baggage... Thanks! Jim ___ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor