Annotate subclass's method? - python

Suppose I have a Mixin class Mixin, and a method a in this class uses another method
b which will be in another Base class. I want to annotate b in class Mixin so that I can take the advantages of inspection.
The real usage is multiple inherition. I create a mixin for tornado.web.RequestHandler, and the subclass could inherit both RequestHandler and Mixin to get some useful functions.
As far as I know, I can annotate b as Callable, but I cannot annotate its signature.
class Base
def b():
# do something
class Mixin:
b: Callable # not enough, losing signature.
#b: RequestHandler.b # not work, still losing signature.
def a():
# call b here.
class subclass(Base, Mixin):
pass
BTW, I'm using Pycharm.

Related

Can a parent's class method call an abstract method which will be implemented in a child class?

If I have a parent class with two methods:
class Parent():
#abstractmethod
#staticmethod
def functionA():
pass
def functionB():
return __class__.functionA() + 1
And I implement a child class:
class Child(Parent):
def functionA(): # this function is different for each kind of child
return 3
In the end, the purpose of the child classes would be to call functionB() only.
Does it work? Of course, I could place functionB() into the child class and make it work, but because functionB() is the same for every kind of child class, I wouldn't want to write repeated code for each class?
Also, is my use of __class__ appropriate here?
First, functionB itself should be a class method.
#classmethod
def functionB(cls):
return cls.functionA() + 1
Second, you still have to decorate functionA as a static method in each child class; otherwise, you are replacing the inherited static method with an instance method.
class Child(Parent):
#staticmethod
def functionA():
return 3
Here is a working version:
from abc import ABC, abstractmethod
class Parent(ABC):
#staticmethod # not needed, but is documentation
#abstractmethod
def a(): pass
#classmethod
def b(cls): return cls.a() + 1
class Child(Parent):
#staticmethod
def a(): return 3
We can test it:
>>> c = Child()
>>> c.b()
4
Noteworthy things:
We need to use the ABC base class (or the ABCMeta metaclass) in order to have access to the abstractmethod decorator, as explained in the abc module documentation.
__class__ is not a keyword; it is an attribute of objects. We cannot just do things like __class__.a() because there is nothing to get the __class__ from. We could address this using the self parameter of an ordinary method, but what we are really trying to do here is to get behaviour that doesn't require an instance, yet depends on which derived class we are using. And that is what classmethod is for, and why there are separate classmethod and staticmethod decorators.
When you use classmethod, the class will be passed as a parameter, like how the instance is passed when you use a normal method. By convention, we name it cls. For more information about classmethod, please see this excellent talk by Raymond Hettinger (on the Python dev team).
Our implementations of the abstract method must also be decorated in the child classes, because they are still not ordinary methods - so Python needs to know not to pass an instance.
The staticmethod decoration on the abstract method needs to be listed first, before the abstractmethod decoration, for technical reasons. It effectively does nothing here; the abstractmethod would already behave like a staticmethod when we call e.g. Parent.a() (no instance; we can't create one anyway, since it's an abstract class).
We could also use classmethod instead of staticmethod for the a methods. This would allow children of Child to inherit the Child behaviour without explicitly writing their own a implementations. In this case, we would want an explicit classmethod decoration on the base abstract method, rather than staticmethod; and of course we would need to add cls parameters to each a implementation.

How to create abstract classes using abc without using an abstract method?

Using abc, I can create abstract classes using the following:
from abc import ABC, abstractmethod
class A(ABC):
#abstractmethod
def foo(self):
print('foo')
class B(A):
pass
obj = B()
This will fail because B has not defined the method foo.
This mimics the abstract method functionality in Java.
I wanted to know if the abstract class functionality is also present in Python, where instantiation of a class is prevented without having any abstract methods.
The conventional way to create an abstract class in Python is to raise the built-in exception NotImplementedError.
class A(object):
def __init__(self):
raise NotImplementedError('abstract base class')
class B(A):
def __init__(self):
# don't call A.__init__ here.
pass
b = B()
# a = A() # This will fail.
Yes. You can.
If you want to not enforce method implementation:
Simply inherit from ABC but don't delcare a method abstract, so it needn't be implemented in its subclasses.
If you want the abstract class to enforce the implementation of all methods:
Decorate all methods.
If you want to enforce the implementation of a method that does not belong to an ABC:
Raise NotImplementedErrorin the method. This won't prevent instantiation, but usage. However, if you want to prevent it in the instantiation, you should rather use ABC's.
You can also delcare __init__ an abstractmethod, but generally this does not look very useful to me.

Python mixin with dynamic method names

Supposing I have the following classes:
class SomeMixin:
def apply(self):
pass
class Foo(SomeMixin):
pass
class Bar(SomeMixin):
pass
How do I implement SomeMixin so that the attached method apply becomes apply_foo in Foo and apply_bar in Bar? The methods in the mixin follows a generic algorithm, but the generated names matter to the framework I'm using.
You wouldn't do that in the mixin, but in the concrete classes themselves. Just define the methods so that they call apply directly.
class Foo(SomeMixin):
def apply_foo(self):
return self.apply()
class Bar(SomeMixin):
def apply_bar(self):
return self.apply()

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.

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.

Categories

Resources