How to add classmethod to a python class? - python

I'm trying to define a generate_username for my User class. (django's user)
The library code will make use of it..
def generate_username(self, user_class):
""" Generate a new username for a user
"""
m = getattr(user_class, 'generate_username', None)
if m:
return m()
How do I define and add the function generate_username to the User class?
I'm supposed to add a classmethod right?

You add a class method the same way you would monkeypatch an instancemethod but has you have to apply the classmethod decorator to it.
class Test(object):
pass
#classmethod
def classfunc(cls, attr):
print(cls, attr)
Test.cf = classfunc
Usage:
>>> Test.cf(33)
<class '__main__.Test'> 33

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 ?

What is the role of the argument for #classmethod in Python Documentation?

I am trying to understand decorators and currently reading the documentation
import types
class SelfDocumenting( object ):
#classmethod
def getMethods( aClass ):
return [ (n,v.__doc__) for n,v in aClass.__dict__.items()
if type(v) == types.FunctionType ]
def help( self ):
"""Part of the self-documenting framework"""
print self.getMethods()
class SomeClass( SelfDocumenting ):
attr= "Some class Value"
def __init__( self ):
"""Create a new Instance"""
self.instVar= "some instance value"
def __str__( self ):
"""Display an instance"""
return "%s %s" % ( self.attr, self.instVar )
I do not understand why getMethods gets an argument called aClass but when SomeClass is defined and it is called later (see below) it can figure out what to replace with aClass in getMethods method:
>>> ac= SomeClass()
>>> ac.help()
[('__str__', 'Display an instance'), ('__init__', 'Create a new Instance')]
UPDATE:
Thanks to the answer but for future reference my confusion originated from the fact that self is a reserved word and aClass is not. So I wasn't sure how that is being handled. #abarnert's comment I think clarifies that the code in documentation is not really representative.
This isn't really related to the fact that it is a classmethod.
For the same reason we don't need to pass the instance when calling a "normal" instance method, the instance (and in this case, the class) is passed implicitly.
class Foo:
def instance_method(self):
print('No need to pass {} explictly'.format(self))
#classmethod
def class_method(cls):
print('No need to pass {} explictly'.format(cls))
obj = Foo()
obj.instance_method()
# No need to pass <__main__.Foo object at 0x0000000002A38DD8> explictly
obj.class_method()
# No need to pass <class '__main__.Foo'> explictly
Straight from the classmethod documentation:
A class method receives the class as implicit first argument, just like an instance method receives the instance
This is the same for derived classes:
If a class method is called for a derived class, the derived class object is passed as the implied first argument.
According to the description, as in the below mentioned link
https://docs.python.org/2/library/functions.html#classmethod
A class method is a method that is bound to a class rather than its object. It doesn't require creation of a class instance, much like staticmethod.
The difference between a static method and a class method is:
Static method knows nothing about the class and just deals with the
parameters Class method works with the class since its parameter is
always the class itself.
The class method can be called both by the class and its object.
source:
https://www.programiz.com/python-programming/methods/built-in/classmethod
You can see the description of the #ClassMethod here in the __ builtin __.py
class classmethod(object):
"""
classmethod(function) -> method
Convert a function to be a class method.
A class method receives the class as implicit first argument,
just like an instance method receives the instance.
To declare a class method, use this idiom:
class C:
#classmethod
def f(cls, arg1, arg2, ...):
...
It can be called either on the class (e.g. C.f()) or on an instance
(e.g. C().f()). The instance is ignored except for its class.
If a class method is called for a derived class, the derived class
object is passed as the implied first argument.
Class methods are different than C++ or Java static methods.
If you want those, see the staticmethod builtin.
"""
def __getattribute__(self, name): # real signature unknown; restored from __doc__
""" x.__getattribute__('name') <==> x.name """
pass
def __get__(self, obj, type=None): # real signature unknown; restored from __doc__
""" descr.__get__(obj[, type]) -> value """
pass
def __init__(self, function): # real signature unknown; restored from __doc__
pass
#staticmethod # known case of __new__
def __new__(S, *more): # real signature unknown; restored from __doc__
""" T.__new__(S, ...) -> a new object with type S, a subtype of T """
pass
__func__ = property(lambda self: object(), lambda self, v: None, lambda self: None) # default

How to make a Python 2.x AND 3.x abstract base class? [duplicate]

I'm trying to get a python2 program working in python3, it has the following Meta class definition. Which works just fine on Py2. What's the "best" way to have this be compatible with both py2 and py3?
It's failing in the unit test where it does:
try:
raise Actor.DoesNotExist
except Actor.DoesNotExist:
pass
Failure is:
AttributeError: type object 'Actor' has no attribute 'DoesNotExist'
The base meta class definition is:
class MetaDocument(type):
def __new__(meta,name,bases,dct):
class DoesNotExist(BaseException):
pass
class MultipleDocumentsReturned(BaseException):
pass
dct['DoesNotExist'] = DoesNotExist
dct['MultipleDocumentsReturned'] = MultipleDocumentsReturned
class_type = type.__new__(meta, name, bases, dct)
if not class_type in document_classes:
if name == 'Document' and bases == (object,):
pass
else:
document_classes.append(class_type)
return class_type
class Document(object):
__metaclass__ = MetaDocument
You could use the MetaDocument() metaclass as a factory to produce a class replacing your Document class, re-using the class attributes:
class Document(object):
# various and sundry methods and attributes
body = vars(Document).copy()
body.pop('__dict__', None)
body.pop('__weakref__', None)
Document = MetaDocument(Document.__name__, Document.__bases__, body)
This doesn't require you to build the 3rd argument, the class body, manually.
You can turn this into a class decorator:
def with_metaclass(mcls):
def decorator(cls):
body = vars(cls).copy()
# clean out class body
body.pop('__dict__', None)
body.pop('__weakref__', None)
return mcls(cls.__name__, cls.__bases__, body)
return decorator
then use as:
#with_metaclass(MetaDocument)
class Document(object):
# various and sundry methods and attributes
Alternatively, use the six library for this:
#six.add_metaclass(MetaDocument)
class Document(object):
where the #six.add_metaclass() decorator also takes care of any __slots__ you may have defined; my simpler version above doesn't.
six also has a six.with_metaclass() base-class factory:
class Document(six.with_metaclass(MetaDocument)):
which injects an extra base class into the MRO.
six has a utility for this.
class Document(six.with_metaclass(MetaDocument, object)):
# class definition, without the __metaclass__
The only side effect is that the class hierarchy changes from
>>> Document.__mro__
(<class 'test.Document'>, <type 'object'>)
to
>>> Document.__mro__
(<class 'test.Document'>, <class 'test.NewBase'>, <type 'object'>)
because with_metaclass actually returns a new class with the appropriate metaclass.

Python class with static method and reference to self

I have a class where I want to reference self from within a static method. Is there a way to do this?
class User(object):
email = "username"
password = "********"
#staticmethod
def all():
return {"ex": self.password}
print(User.all())
The way to do this is with a classmethod instead. The way this works is that the first argument is the class itself, which you can access your variables using the dot operator.
For example:
class User(object):
email = "username"
password = "********"
#classmethod
def all(cls):
return {"ex": cls.password}
print(User.all())
https://docs.python.org/2/library/functions.html#classmethod
No, there isn't.
The point of a staticmethod is that it does not need either instance (self) nor class (typically called cls) information to do its job.
If your staticmethod needs self then it isn't a staticmethod and you should just define it normally.

Django: override get_FOO_display()

In general, I'm not familiar with python's way of overriding methods and using super().
question is: can I override get_FOO_display()?
class A(models.Model):
unit = models.IntegerField(choices=something)
def get_unit_display(self, value):
... use super(A, self).get_unit_display()
I want to override get_FOO_display() because I want to pluralize my display.
But super(A, self).get_unit_display() doesn't work.
Normally you would just override a method as you have shown. But the trick here is that the get_FOO_display method is not present on the superclass, so calling the super method will do nothing at all. The method is added dynamically by the field class when it is added to the model by the metaclass - see the source here (EDIT: outdated link as permalink).
One thing you could do is define a custom Field subclass for your unit field, and override contribute_to_class so that it constructs the method you want. It's a bit tricky unfortunately.
(I don't understand your second question. What exactly are you asking?)
Now in Django > 2.2.7:
Restored the ability to override get_FOO_display() (#30931).
You can override:
class FooBar(models.Model):
foo_bar = models.CharField(_("foo"), choices=[(1, 'foo'), (2, 'bar')])
def get_foo_bar_display(self):
return "something"
You could do it this way:
Override the Django IntegerField to make a copy of your get_FOO_display function:
class MyIntegerField(models.IntegerField):
def contribute_to_class(self, cls, name, private_only=False):
super(MyIntegerField, self).contribute_to_class(cls, name, private_only)
if self.choices is not None:
display_override = getattr(cls, 'get_%s_display' % self.name)
setattr(cls, 'get_%s_display_override' % self.name, display_override)
In your class, replace your choice field with MyIntegerField:
class A(models.Model):
unit = MyIntegerField(choices=something)
Finally, use the copy function to return the super value:
def get_unit_display(self, value):
if your condition:
return your value
return self.get_unit_display_override()
You can't directly call super() because the original method doesn't "exist" yet on the parent model.
Instead, call self._get_FIELD_display() with the field object as its input. The field object is accessible through the self._meta.get_field() method.
def get_unit_display(self):
singular = self._get_FIELD_display(self._meta.get_field('unit'))
return singular + 's'
You should be able to override any method on a super class by creating a method with the same name on the subclass. The argument signature is not considered. For example:
class A(object):
def method(self, arg1):
print "Method A", arg1
class B(A):
def method(self):
print "Method B"
A().method(True) # "Method A True"
B().method() # "Method B"
In the case of get_unit_display(), you do not have to call super() at all, if you want to change the display value, but if you want to use super(), ensure that you're calling it with the correct signature, for example:
class A(models.Model):
unit = models.IntegerField(choices=something)
def get_unit_display(self, value):
display = super(A, self).get_unit_display(value)
if value > 1:
display = display + "s"
return display
Note that we are passing value to the super()'s get_unit_display().

Categories