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.
Related
In Python, I can create a class method using the #classmethod decorator:
>>> class C:
... #classmethod
... def f(cls):
... print(f'f called with cls={cls}')
...
>>> C.f()
f called with cls=<class '__main__.C'>
Alternatively, I can use a normal (instance) method on a metaclass:
>>> class M(type):
... def f(cls):
... print(f'f called with cls={cls}')
...
>>> class C(metaclass=M):
... pass
...
>>> C.f()
f called with cls=<class '__main__.C'>
As shown by the output of C.f(), these two approaches provide similar functionality.
What are the differences between using #classmethod and using a normal method on a metaclass?
As classes are instances of a metaclass, it is not unexpected that an "instance method" on the metaclass will behave like a classmethod.
However, yes, there are differences - and some of them are more than semantic:
The most important difference is that a method in the metaclass is not "visible" from a class instance. That happens because the attribute lookup in Python (in a simplified way - descriptors may take precedence) search for an attribute in the instance - if it is not present in the instance, Python then looks in that instance's class, and then the search continues on the superclasses of the class, but not on the classes of the class. The Python stdlib make use of this feature in the abc.ABCMeta.register method.
That feature can be used for good, as methods related with the class themselves are free to be re-used as instance attributes without any conflict (but a method would still conflict).
Another difference, though obvious, is that a method declared in the metaclass can be available in several classes, not otherwise related - if you have different class hierarchies, not related at all in what they deal with, but want some common functionality for all classes, you'd have to come up with a mixin class, that would have to be included as base in both hierarchies (say for including all classes in an application registry). (NB. the mixin may sometimes be a better call than a metaclass)
A classmethod is a specialized "classmethod" object, while a method in the metaclass is an ordinary function.
So, it happens that the mechanism that classmethods use is the "descriptor protocol". While normal functions feature a __get__ method that will insert the self argument when they are retrieved from an instance, and leave that argument empty when retrieved from a class, a classmethod object have a different __get__, that will insert the class itself (the "owner") as the first parameter in both situations.
This makes no practical differences most of the time, but if you want access to the method as a function, for purposes of adding dynamically adding decorator to it, or any other, for a method in the metaclass meta.method retrieves the function, ready to be used, while you have to use cls.my_classmethod.__func__ to retrieve it from a classmethod (and then you have to create another classmethod object and assign it back, if you do some wrapping).
Basically, these are the 2 examples:
class M1(type):
def clsmethod1(cls):
pass
class CLS1(metaclass=M1):
pass
def runtime_wrap(cls, method_name, wrapper):
mcls = type(cls)
setattr(mcls, method_name, wrapper(getatttr(mcls, method_name)))
def wrapper(classmethod):
def new_method(cls):
print("wrapper called")
return classmethod(cls)
return new_method
runtime_wrap(cls1, "clsmethod1", wrapper)
class CLS2:
#classmethod
def classmethod2(cls):
pass
def runtime_wrap2(cls, method_name, wrapper):
setattr(cls, method_name, classmethod(
wrapper(getatttr(cls, method_name).__func__)
)
)
runtime_wrap2(cls1, "clsmethod1", wrapper)
In other words: apart from the important difference that a method defined in the metaclass is visible from the instance and a classmethod object do not, the other differences, at runtime will seem obscure and meaningless - but that happens because the language does not need to go out of its way with special rules for classmethods: Both ways of declaring a classmethod are possible, as a consequence from the language design - one, for the fact that a class is itself an object, and another, as a possibility among many, of the use of the descriptor protocol which allows one to specialize attribute access in an instance and in a class:
The classmethod builtin is defined in native code, but it could just be coded in pure python and would work in the exact same way. The 5 line class bellow can be used as a classmethod decorator with no runtime differences to the built-in #classmethod" at all (though distinguishable through introspection such as calls toisinstance, and evenrepr` of course):
class myclassmethod:
def __init__(self, func):
self.__func__ = func
def __get__(self, instance, owner):
return lambda *args, **kw: self.__func__(owner, *args, **kw)
And, beyond methods, it is interesting to keep in mind that specialized attributes such as a #property on the metaclass will work as specialized class attributes, just the same, with no surprising behavior at all.
When you phrase it like you did in the question, the #classmethod and metaclasses may look similar but they have rather different purposes. The class that is injected in the #classmethod's argument is usually used for constructing an instance (i.e. an alternative constructor). On the other hand, the metaclasses are usually used to modify the class itself (e.g. like what Django does with its models DSL).
That is not to say that you can't modify the class inside a classmethod. But then the question becomes why didn't you define the class in the way you want to modify it in the first place? If not, it might suggest a refactor to use multiple classes.
Let's expand the first example a bit.
class C:
#classmethod
def f(cls):
print(f'f called with cls={cls}')
Borrowing from the Python docs, the above will expand to something like the following:
class ClassMethod(object):
"Emulate PyClassMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, klass=None):
if klass is None:
klass = type(obj)
def newfunc(*args):
return self.f(klass, *args)
return newfunc
class C:
def f(cls):
print(f'f called with cls={cls}')
f = ClassMethod(f)
Note how __get__ can take either an instance or the class (or both), and thus you can do both C.f and C().f. This is unlike the metaclass example you give which will throw an AttributeError for C().f.
Moreover, in the metaclass example, f does not exist in C.__dict__. When looking up the attribute f with C.f, the interpreter looks at C.__dict__ and then after failing to find, looks at type(C).__dict__ (which is M.__dict__). This may matter if you want the flexibility to override f in C, although I doubt this will ever be of practical use.
In your example, the difference would be in some other classes that will have M set as their metaclass.
class M(type):
def f(cls):
pass
class C(metaclass=M):
pass
class C2(metaclass=M):
pass
C.f()
C2.f()
class M(type):
pass
class C(metaclass=M):
#classmethod
def f(cls):
pass
class C2(metaclass=M):
pass
C.f()
# C2 does not have 'f'
Here is more on metaclasses
What are some (concrete) use-cases for metaclasses?
Both #classmethod and Metaclass are different.
Everything in python is an object. Every thing means every thing.
What is Metaclass ?
As said every thing is an object. Classes are also objects in fact classes are instances of other mysterious objects formally called as meta-classes. Default metaclass in python is "type" if not specified
By default all classes defined are instances of type.
Classes are instances of Meta-Classes
Few important points are to understand metioned behaviour
As classes are instances of meta classes.
Like every instantiated object, like objects(instances) get their attributes from class. Class will get it's attributes from Meta-Class
Consider Following Code
class Meta(type):
def foo(self):
print(f'foo is called self={self}')
print('{} is instance of {}: {}'.format(self, Meta, isinstance(self, Meta)))
class C(metaclass=Meta):
pass
C.foo()
Where,
class C is instance of class Meta
"class C" is class object which is instance of "class Meta"
Like any other object(instance) "class C" has access it's attributes/methods defined in it's class "class Meta"
So, decoding "C.foo()" . "C" is instance of "Meta" and "foo" is method calling through instance of "Meta" which is "C".
First argument of method "foo" is reference to instance not class unlike "classmethod"
We can verify as if "class C" is instance of "Class Meta
isinstance(C, Meta)
What is classmethod?
Python methods are said to be bound. As python imposes the restriction that method has to be invoked with instance only.
Sometimes we might want to invoke methods directly through class without any instance (much like static members in java) with out having to create any instance.By default instance is required to call method. As a workaround python provides built-in function classmethod to bind given method to class instead of instance.
As class methods are bound to class. It takes at least one argument which is reference to class itself instead of instance (self)
if built-in function/decorator classmethod is used. First argument
will be reference to class instead of instance
class ClassMethodDemo:
#classmethod
def foo(cls):
print(f'cls is ClassMethodDemo: {cls is ClassMethodDemo}')
As we have used "classmethod" we call method "foo" without creating any instance as follows
ClassMethodDemo.foo()
Above method call will return True. Since first argument cls is indeed reference to "ClassMethodDemo"
Summary:
Classmethod's receive first argument which is "a reference to class(traditionally referred as cls) itself"
Methods of meta-classes are not classmethods. Methods of Meta-classes receive first argument which is "a reference to instance(traditionally referred as self) not class"
Say I have the following abstract class Foo:
import abc
class Foo(abc.ABC):
#abc.abstractmethod
def bar(self):
raise NotImplementedError
What should I put in the body of the bar method?
I see a lot of code that has raise NotImplementedError, as shown above. However, this seems redundant, since any subclass that does not implement bar will raise the TypeError: Can't instantiate abstract class Foo with abstract methods bar when it is instantiated.
Is it Pythonic to leave bar empty, as follows:
import abc
class Foo(abc.ABC):
#abc.abstractmethod
def bar(self):
...
This is what is done in the Python docs for Abstract Base Classes, but I'm not sure if that's just a placeholder or an actual example of how to write code.
If it's ok to leave bar with only three dots (...), when should I use NotImplementedError?
The documentation does aim to give you an example. You don't have to follow it.
You could provide a default; subclasses are still free to use super() to call your implementation. This is what most of the collections.abc classes do; see the source code.
Size for example, returns 0 for __len__:
class Sized(metaclass=ABCMeta):
# ...
#abstractmethod
def __len__(self):
return 0
As Martijn Pieters has said, provide a default in places where a default makes sense.
If you want to communicate to your user that they absolutely should override it, use raise NotImplementedError like so:
class FooBar(abc.ABC):
#abstractmethod
def foo(bar):
"""This method foos some bars"""
raise NotImplementedError
Quote:
exception NotImplementedError
This exception is derived from RuntimeError. In user defined base classes, abstract methods should raise this exception when they require derived classes to override the method, or while the class is being developed to indicate that the real implementation still needs to be added.
For completeness sake, here are some other things I have seen out in the wild (contradicting the official recommendation about raise NotImplementedError):
Instead of raising, just use Ellipses (...). this has some official support, since it is how the official python documentation for Abstract Base Classes uses it.
Just using pass is also quite common.
Actually, just using a docstring is sufficient. Imho any method should have a docstring anyways, so this would be more elegant than either ... or pass.
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.')
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.
Suppose that I have the following python base class:
class BaseClass(object):
def a():
"""This method uses method b(), defined in the inheriting class"""
And also a class that inherites BaseClass:
class UsedByUser(BaseClass):
def b():
"""b() is defined here, yet is used by the base class"""
My user would only create instances of class UsedByUser. Typical use would be:
if __name__ == '__main__':
# initialize the class used by the user
usedByUser = UsedByUser()
# invoke method a()
usedByUser.a()
My questions is, is the above use problematic? is this a valid approach, or must I also define method b() in BaseClass and then override it in UsedByUser?
I would define the b method in the BaseClass too:
class BaseClass(object):
def b(self):
raise NotImplementedError('b must be implemented by a subclass')
Remember: explicit is better than implicit and given that the method a needs the method b anyways, better raise a meaningful exception rather than a general AttributeError.
It is worth to point out that this is absolutely NOT needed from a syntactic point of view, but it adds clarity to the code and enforces the subclass to provide an implementation.
The use is correct. Classes can define methods that can be overriden
from subclasses, but those can also define new methods. Defining
every method needed for subclasses in the superclass seems a bit
senseless. (Since object then would also need to have every
function defined ?)
A subclass often has a different bahviour to another subclass.
class Vehicle(object):
def Refuel(self):
# ...
class Plane(Vehicle):
def Fly(self):
# ...
class Car(Vehicle):
def Drive(self):
# ...
Edit: I misread the code.
If only you create a subclass of it and make sure subclasses have B(), then it's theoratically ok, but bad style. It makes more sense and is safer to give the superclass attributes and methods that are used by the superclass. -> Define B()
Sounds like you want A to call a protected member function of UsedByUser that can't go in the abstract BaseClass). Try prefixing the protected function with an underscore (although note this is just a convention used by Python and not strictly checked, as mentioned here).
class BaseClass(object):
def A(self):
print "Grettings from A"
self._B()
def _B(self):
raise NotImplementedError('b must be implemented by a subclass')
class UsedByUser(BaseClass):
def _B(self):
""" prefix with underscore is a python convention for a protected member function """
print "B rocks!"
if ( __name__=='__main__' ):
usedByUser = UsedByUser()
usedByUser.A()
Find more on this convention in the PEP guidelines.
Edit:
As GaretJax suggested, I added a BaseClass _B method for clarity. Nice tip!
BaseClass can't assume that a UsedByUser object exists, so it can't use a B() method from it. You probably want to define a B() in BaseClass, that either does nothing (if it's sensible to attempt B() with something that doesn't support it) or raises an exception (if it's not sensible to attempt B()).
If you tell us what A and B are in your use case, we may be able to advise you better.