Mario Figueiredo wrote: > Hello everyone, > > [Python 3.X] > > I have the following factory model for the initialization of a class > tree (code abbreviated for simplicity). > > # item.py > class BadItemType(Exception): > pass
If this is a type error, why aren't you using TypeError? Or at least inheriting from TypeError? class BadItemType(TypeError): pass > class Item: > def __init__(self, _data): > > class Container(Item): > def __init__(self, _data): > Item.__init__(self, _data) > # ... > > class Tool(Item): > def __init__(self, _data): > Item.__init__(self, _data) > # ... Unless you have good reason not to, you should use super rather than directly call the superclass. https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ > def spawn(type_, id_): > if type_ not in Item.__subclasses__(): > raise BadItemType() > # ... > return type_(data) > > I'd like to know your opinions on an acceptable way to flag the Item > class and its derived classes so users of this module know they should > avoid instantiating them directly. > > Other than the obvious notes on the classes docstrings, is it good > enough I mark the constructor argument as an implementation variable as > I did? Oh, so you did. No, that's not good enough. I never even noticed that, and if I had noticed it, I would have guessed that you had some bizarre naming scheme and didn't understand the Python underscore conventions. I never would have guessed that you meant "don't instantiate this class". Are users supposed to subclass Item themselves? If so, you should make Item an ABC (Abstract Base Class): class ItemABC: def __init__(self, data): if type(self) is ItemABC: raise TypeError("You must subclass ItemABC") But if users aren't supposed to use the classes *at all*, but only use the spawn factory function, you don't have a lot of good choices in pure Python code. Python isn't designed to be that restrictive. The *simplest thing which will work* is simply not worry about it. You should consider the factory function to be merely for convenience. It might be *really* convenient, but if the user wants to ignore the factory and reinvent the wheel, why should you care? Just document the fact that people are expected to use the factory, but don't expressly prohibit the use of the classes directly. Otherwise, you can flag the classes with single underscores to mark them as private implementation details: class _Item: ... then declare "consenting adults". If your users decide to instantiate the classes directly, you can't really stop them, so if they blow their foot off they have nobody to blame but themselves. If you want to be a little more strict, you can use a little obfuscation to discourage direct use. Note that in this case you *must* inherit from object in Python 2. In Python 3 it doesn't matter. # Untested class Item(object): def __init__(self): raise TypeError('do not instantiate') @classmethod def _my_secret_constructor(cls, data): obj = super(Item, cls).__new__(cls) obj.data = data return obj def spawn(type_, id_): # error checking as before return type_._my_secret_constructor(data) but of course even here if your users *really* want to instantiate the class, they can do so. -- Steven -- https://mail.python.org/mailman/listinfo/python-list