On Sun, May 14, 2017 at 9:14 PM, Steven D'Aprano firstname.lastname@example.org wrote:
There are a couple of solutions to that, though. The easiest to implement would be to change the first line to `self = subclass(ParentClass())` where the subclass function looks at the next item in the call stack (i.e. `MyClass`) and makes it the type of the object.
You say this is the easiest to implement. Do you have an implementation? Does it work for CPython, Jython, IronPython, PyPy, Stackless, Nuitka, and other Python implementations? What of Python implementations that don't support intraspection of the call stack?
(Perhaps we should just make that a required language feature. But that's a separate argument.)
Here's a much easier way to achieve that:
@Class def MyClass(...): ...
As well as declaring that this is, in fact, a class (more reliable than depending on a naming convention), this decorator could take the return value from the original function and then tag it as a subclass of that object, with the subclass's name being lifted from the function's name. Something like:
def Class(func): @wraps(func) def wrapper(*a, **kw): ret = func(*a, **kw) if ret is None: return ret ret.__class__ = func.__name__ # pretend this works return ret return wrapper
This would chain, because "self = ParentClass()" will be going through this decorator too. But honestly, I think I'd rather do something like this:
def Class(func): class Thing: @wraps(func) def __new__(*a, **kw): func() Thing.__name__ = func.__name__ return Thing
In other words, the transformation is to an actual class. The function form becomes syntactic sugar for a particular form of class definition. You could even do subclassing through the decorator:
def Class(*parents): def deco(func): class Thing(*parents): # etc
AFAIK all this is fully legal in current versions of Python 3. If you want to mess around with classes and functions, decorators can do all that and more, and IMO are the best way to prototype the syntax. No changes needed to grammar or anything. It'll still be a class under the hood, so isinstance checks will work, for instance (sorry, couldn't resist). And it can all be done through a single entry point that you can easily publish in a module on PyPI.