How do I combine wxPython, abc, and a metaclass mixin? - python

I have a base class from which other classes should inherit:
class AppToolbar(wx.ToolBar):
''' Base class for the Canary toolbars '''
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ... a few common implementation details that work as expected...
self._PopulateToolbar()
self.Realize()
The base class does not (and cannot) implement _PopulateToolbar(); it should be an abstract method. As such, I figured using abc was a good plan, so I tried this:
class AppToolbar(wx.ToolBar, metaclass=abc.ABCMeta):
# ... as above, but with the following added
#abc.abstractmethod
def _PopulateToolbar():
pass
Perhaps unsurprisingly, attempting to run this led to TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases. I thought, "Oh, right, I'll just use a mixin":
class PopulateToolbarMixin(metaclass=ABCMeta):
#abstractmethod
def _PopulateToolbar(self):
pass
PopulateToolbarMixin.register(wx.ToolBar)
PopulateToolbarMixin.register(AppToolbar)
No change: still the same TypeError message. I suspect I'm missing something obvious with the use of ABCMeta here; this doesn't look like an error specific to wxPython. What am I doing wrong? Is there a better way to approach the same issue?
Edit: it has been pointed out to me in a conversation with a colleague that one cannot mix metaclasses. Since wx.ToolBar apparently derives from sip.wrappertype, it looks like there is no way to do this. What is another, still Pythonic way to handle the "abstract method" approach here?

In your first example, where you inherit from wx.ToolBar and abc.ABCMeta, you don't want AppToolbar to be a subclass of abc.ABCMeta, you want AppToolbar to be an instance of it. Try this:
class AppToolbar(wx.ToolBar, metaclass=abc.ABCMeta):
# ... as above, but with the following added
#abc.abstractmethod
def _PopulateToolbar():
pass
Though looking at this a bit closer, it seems that you can't define a subclass of wx.Toolbar with abc.ABCMeta as its metaclass, as wx.Toolbar is an instance of a metaclass other than bultins.type. You can, however, get abstract-like behavior out of AppToolbar._PopulateToolbar:
class AppToolbar(wx.ToolBar):
def _PopulateToolbar():
''' This is an abstract method; subclasses must override it. '''
raise NotImplementedError('Abstract method "_PopulateToolbar" must be overridden before it can be called.')

Related

Dynamically add class variables to classes inheriting mixin class

I've got a mixin class, that adds some functionality to inheriting classes, but the mixin requires some class attributes to be present, for simplicity let's say only one property handlers. So this would be the usage of the mixin:
class Mixin:
pass
class Something(Mixin):
handlers = {}
The mixin can't function without this being defined, but I really don't want to specify the handlers in every class that I want to use the mixin with. So I solved this by writing a metaclass:
class MixinMeta:
def __new__(mcs, *args, **kwargs):
cls = super().__new__(mcs, *args, **kwargs)
cls.handlers = {}
return cls
class Mixin(metaclass=MixinMeta):
pass
And this works exactly how I want it to. But I'm thinking this can become a huge problem, since metaclasses don't work well together (I read various metaclass conflicts can only be solved by creating a new metaclass that resolves those conflicts).
Also, I don't want to make the handlers property a property of the Mixin class itself, since that would mean having to store handlers by their class names inside the Mixin class, complicating the code a bit. I like having each class having their handlers on their own class - it makes working with them simpler, but clearly this has drawbacks.
My question is, what would be a better way to implement this? I'm fairly new to metaclasses, but they seem to solve this problem well. But metaclass conflicts are clearly a huge issue when dealing with complex hierarchies without having to define various metaclasses just to resolve those conflicts.
Your problem is very real, and Python folks have thought of this for Python 3.6 (still unrealsed) on. For now (up to Python 3.5), if your attributes can wait to exist until your classes are first instantiated, you could put cod to create a (class) attribute on the __new__ method of your mixin class itself - thus avoiding the (extra) metaclass:
class Mixin:
def __new__(cls):
if not hasattr(cls, handlers):
cls.handlers = {}
return super().__new__(cls)
For Python 3.6 on, PEP 487 defines a __init_subclass__ special method to go on the mixin class body. This special method is not called for the mixin class itself, but will be called at the end of type.__new__ method (the "root" metaclass) for each class that inherits from your mixin.
class Mixin:
def __init_subclass__(cls, **kwargs):
cls.handlers = {}
return super().__init_subclass__(**kwargs)
As per the PEP's background text, the main motivation for this is exactly what led you to ask your question: avoid the need for meta-classes when simple customization of class creation is needed, in order to reduce the chances of needing different metaclasses in a project, and thus triggering a situation of metaclass conflict.

Inheritance in Python, requiring certain methods to be defined in subclasses

In Java, for example, you can make a class MyClass with certain methods that are specified but not implemented in MyClass, but must be implemented in any class MySubClass that inherits from MyClass. So basically there is some common functionality among all subclasses you want, so you put it in MyClass, and there is some functionality unique (but required) for each subclass, so you want it in each subclass. How can this behavior be achieved in Python?
(I know there are concise terms to describe what I'm asking, so feel free to let me know what these are and how I can better describe my question.)
A very basic example but the abc docs provide a few more
import abc
class Foo():
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
def bar(self):
raise NotImplemented
class FooBar(Foo):
pass
f = FooBar()
TypeError: Can't instantiate abstract class FooBar with abstract methods bar
You can't require the implementation of a method in a subclass in a way that will break at compile-time, but the convention on writing a method on the base class that must be implemented in the subclasses is to raise NotImplementedError.
Something like this:
class MyBase(object):
def my_method(self, *args, **kwargs):
raise NotImplementedError("You should implement this method on a subclass of MyBase")
Then your subclasses can implement my_method, but this will break only when the method is called. If you have comprehensive unit tests, as you should, this won't be a problem.

Abstract method and mixin in python

I'd like to submit a code pattern I often see in my python code, here at work, and I'm not satisfy with it and I'd like a better solution.
Here is what we have today:
class AbstractClass(object):
....
def method1(self,...)
raise NotImplementedError
...
class FirstImplementationMixin(object)
def method1(self,....)
...
class SecondImplementationMixin(object)
def method1(self...)
....
class InstanciatedClass1(FirstImplementationMixin, AbstractClass)
....
class InstanciatedClass2(SecondImplementationMixin, AbstractClass)
....
Do you see the trick? I have to add the mixin at first position in the list
of the inheritance, and I don't like this solution. If we add it at the second position, the interpreter will use AbstractClass.method1 and so raise the exception.
In this trivial situation, replacing the mixin by intermediate class is possible, but in case of complex inheritance with already a base class, the solution might not be obvious.
What is for you the best design pattern?
Well, as I noted in my comment this is just how Python works, and I don't think that changing it is a good idea.
Nevertheless, metaclasses to the rescue!
You can create your own metaclass and make it as complex as you need. Here I'll show you a very basic example.
def mixed(name, bases, dct):
return type(name, bases[1:] + (bases[0],), dct)
It simply moves the first baseclasses to the end, so now you put your actual base-class first, followed by all the mixins. That means that you are limited to a single base class. You can lift this limitation by some convention, for example, you'll list base classes first, then None, then mixins; and your metaclass will look for this None and reorder the tuple accordingly.
class MixinA:
pass
class MixinB:
pass
class Base(object):
pass
class Test(Base, MixinA, MixinB):
__metaclass__ = mixed
>>> Test.__mro__
>
(<class '__main__.Test'>,
<class __main__.MixinA at 0x6f8850db48>,
<class __main__.MixinB at 0x6f8850dae0>,
<class '__main__.Base'>,
<type 'object'>)
Of course you won't be specifying __metaclass__ each time, because of the rules that are used to chose a metaclass. You'll probably set __metaclass__ on the module level or, maybe, in your mixins. That's your choice, whatever fits your code structure better.

Subclasses in Python 2.7

I'm trying to do something I consider pretty ordinary in Object Oriented programming
but can't find any documentation on it for Python 2.7
I want to create a subclass of a superclass where, when I'm done
superclass
is bound to the superclass
superclass.subclass is bound to the subclass and
subclass is bound to nothing.
Here's the best solution I can come up with:
class superclass:
pass
class subclass(superclass):
pass
superclass.subclass = subclass
del subclass
Sometimes I want subclass to be in its own file, other times not.
Is there a more elgant solution where I don't have to manually perform the
last two lines?
Although
class superclass:
class subclass:
pass
almost does the right thing, subclass doesn't actually inherit from superclass.
And if I try to do:
class superclass:
class subclass(superclass):
pass
I get an error message that superclass is unbound.
I agree with everyone else that this is a silly thing to do and I don't think you should do it, but in the interest of knowledge:
class Superclass(object):
pass
Superclass.Subclass = type('Subclass', (Superclass,), {
'foo': lambda self: self,
})
where the dictionary argument contains any methods. I don't think there's a nice way to do this with the class syntax, but that's really just syntactic sugar for calling type anyway.
You don't have to define the methods as lambdas; they can be normal functions with def as long as they have the self argument. You'll probably want to hide their definitions if you do that, though....
Here's a simple class decorator to do the referencing:
def refer(cls):
cls.__bases__[0].subclass = cls
return cls
Here's how you use it:
>>> class Superclass:
pass
>>> #refer
class Subclass(SuperClass):
pass
You will still need to delete Subclass if you don't want the name in the module namespace.

A django model that subclasses an abc, gives a metaclass conflict

I have a following model and abstract base class
import abc
from django.db import models
class AbstractBase():
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
def my_method(self):
return
class MyModel(models.Model, AbstractBase):
#abc.abstractmethod
def my_method(self):
return 1
But I am getting the following error.
metaclass conflict: the metaclass of a derived class must be a
(non-strict) subclass of the metaclasses of all its bases
I think the problem here is (As it is described here http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/) that two base class has two different metaclasses so python cannot decide which metaclass to use for child object.
In order to solve this I removed multiple inheritence and use following register method to register child class
abc.register(Child)
But I did not really like this approach since it looks like monkey patching.
Is there another way to solve this problem?
I try to assign Model metaclass to Child explicitly but it did not work.
I am not looking for a way to solve it by writing code. I think this must be solved by changing my class structure.
Apart from creating a new metaclass that inherits from both ABCMeta and ModelBase, or making ABCMeta inherit from ModelBase, there isn't much you can do.
However, possibly a different registration pattern might be appropriate? Maybe something like contrib.admin.autodiscover? Or a class decorator? Or a loop at the bottom of the .py file which calls register on the appropriate classes (ex, for var in globals().values(): if isinstance(var, type) and issubclass(var, AbastractBase): register(var))?
Edit: D'oh. I'd assumed that ABCMeta was an example, not ABCMeta. That's what I get for browsing StackOverflow on too little sleep.

Categories

Resources