Python Inheritance, Move method to a common class - python

I am forgetting OOP terminology which was related to inheritance and which used classes dynamically. Here is what I am looking for.
#classmethod
def _match_slug(cls, slug):
""" Method that checks if we still have a match in the db for current 'slug' """
return cls.objects.filter(slug=slug).count()
I have 10 models in my application and each has this _match_slug method. I want to take this method to the parent class, so when I call self._match_slug(slug_to_check) it calls the method with its appropriate class cls.
Thoughts?

Move the method to your parent class:
class Parent(object):
#classmethod
def _match_slug(cls, slug):
""" Method that checks if we still have a match in the db for current 'slug' """
return cls.objects.filter(slug=slug).count()
class Child(Parent):
...
c = Child()
# Equivalent to Parent._match_slug(c.__class__, x)
c._match_slug(x)

Related

Can a decorator modify a class before __init_subclass__ is called?

I'm using __init_subclass__ in order to register subclass in a specific registry. The registry itself is another class that contain a dictionary to store those subclass. I wanted to create a decorator to link those two classes but I'm not sure it is possible as __init_subclass__ is called before the decorator itself.
Here is a simple example that describe what I would like but that is not working for obvious reason:
class Registry:
#classmethod
def link(cls, other_class):
other_class._regsitry = cls()
return other_class
class Foo:
_registry = None
def __init_subclass__(cls):
if cls._registry = None:
raise ...
# Add the class to the registry
....
#Registry.link
class Bar(Foo):
pass
The thing here is that Bar will raise the exception as it does not have _registry. I understand why but I don't know if there is any possibility to do that with decorator ?

Change docstring when inheriting but leave method the same

I'm building an HTTP API and I factored out a lot of code into a superclass that handles requests to a collection of objects. In my subclass, I specify what database models the operation should work on and the superclass takes care of the rest.
This means that I don't need to re-implement the get, post, etc. methods from the superclass, however, I want to change their docstrings in the subclass so that I can have some documentation more specific to the actual model the endpoint is operating on.
What is the cleanest way to inherit the parent class's functionality but change the docstrings?
Example:
class CollectionApi(Resource):
"""Operate on a collection of something.
"""
class Meta(object):
model = None
schema = None
def get(self):
"""Return a list of collections.
"""
# snip
def post(self):
"""Create a new item in this collection.
"""
# snip
class ActivityListApi(CollectionApi):
"""Operations on the collection of Activities.
"""
class Meta(object):
model = models.Activity
schema = schemas.ActivitySchema
Specifically, I need ActivityListApi to have get and post run like in CollectionApi, but I want different docstrings (for automatic documentation's sake).
I can do this:
def get(self):
"""More detailed docs
"""
return super(ActivityListApi, self).get()
But this seems messy.
class CollectionApi(Resource):
"""Operate on a collection of something.
"""
def _get(self):
"""actual work... lotsa techy doc here!
the get methods only serve to have something to hang
their user docstrings onto
"""
pass
def get(self):
"""user-intended doc for CollectionApi"""
return self._get()
class ActivityListApi(CollectionApi):
def get(self):
"""user-intended doc for ActivityListApi"""
return self._get()

Subclass Python class with same decorators

I'm using Flask-Classy to write a Flask app using class based views.
My base class is called SlugView. It catches URLs like example.com/124/catchy-article-name:
class SlugView(FlaskView):
#route('/<id>')
#route('/<id>/<slug>')
def get(self, id, slug=None)
raise NotImplementedError
My second class is called ArticleView:
class ArticleView(SlugView):
def get(self, id, slug=None):
return render_template('article.html', article=get_article_by_id(id))
What decorator magic can I use to have the subclassed function inherit the same decorators as the parent class?
Magic? Yes. Decorator magic? No. Do you object to metaclass magic?
class InheritableRoutesMeta(type):
def __new__(cls, cls_name, bases, attributes):
for name, value in attributes.items():
if not callable(value):
continue
for base in bases:
super_method = getattr(base, name)
if super_method and hasattr(super_method, "_rule_cache"):
value._rule_cache = super_method._rule_cache
break
return super(InheritableRoutesMeta, cls).__new__(cls, cls_name,
bases, attributes)
Then you should be able to do something like this:
class ArticleView(SlugView, metaclass=InheritableRoutesMeta):
# Use the keyword argument metaclass for Python 3
# For Python 2, remove the argument and uncomment the below
# __metaclass__ = InheritableRoutesMeta
def get(self, id, slug=None):
return render_template('article.html', article=get_article_by_id(id))
Warning: This is based on an internal property. If Flask-Classy chooses to change how it stores these decorators the above code will break (assuming that it works in the first place). If you really need this, it is worth filing an issue with the creator(s) to either make this property part of the public API or to provide another way of doing what you are doing. They may choose not to do either, but at least then they are aware of the use case.

rationale behind python class/subclass inheritance

When I create a parent class and child class as shown below, why don't the arguments from the parent class automatically get pulled in by the child class?
I understand that explicit is better, but I'm wondering in what circumstance this code...
class testParent(object):
def __init__(self,testParentParam1,testParentParam2):
pass
class testChild(testParent):
def __init__(self,testParentParam1,testParentParam2,testChildParam1,testChildParam2):
pass
Is better than this code...
class testParent(object):
def __init__(self,testParentParam1,testParentParam2):
pass
class testChild(testParent):
def __init__(self,testChildParam1,testChildParam2):
pass
Derived classes extend base classes. That means they might need more/less/different information at construction time to do their extending. Consider:
class BaseTextDocument(object):
def __init__(self, content):
self.content = content
class WordDocument(object):
def __init__(self, path, word_version="guess_from_file"):
content = parse_word_document(path, word_version)
super(WordDocument, self).__init__(content)

Calling a class method upon creation of Python classes

I'd like to automatically run some code upon class creation that can call other class methods. I have not found a way of doing so from within the class declaration itself and end up creating a #classmethod called __clsinit__ and call it from the defining scope immediately after the class declaration. Is there a method I can define such that it will get automatically called after the class object is created?
You can do this with a metaclass or a class decorator.
A class decorator (since 2.6) is probably easier to understand:
def call_clsinit(cls):
cls._clsinit()
return cls
#call_clsinit
class MyClass:
#classmethod
def _clsinit(cls):
print "MyClass._clsinit()"
Metaclasses are more powerful; they can call code and modify the ingredients of the class before it is created as well as afterwards (also, they can be inherited):
def call_clsinit(*args, **kwargs):
cls = type(*args, **kwargs)
cls._clsinit()
return cls;
class MyClass(object):
__metaclass__ = call_clsinit
#classmethod
def _clsinit(cls):
print "MyClass._clsinit()"

Categories