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.
Related
I'm working on a project using abstract classes in Python (specifically, the abc module).
I have a few implementations of this abstract class, which have their own constructors and need to use self.
This is what my code looks like, but simplified:
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
self.sublinks = [] # not meant to be passed in, that's why it isn't an argument in __init__
#classmethod
def display(cls):
print(cls.get_contents())
#abstractmethod
def get_contents():
pass
class ImplementationOne(Base):
def __init__(self, url):
self.url = url
def get_contents(self):
return "The url was: " + url
class ImplementationTwo(Base):
def get_contents():
return "This does not need a url"
test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()
test_one.display()
When I run this, however, I get the error TypeError: get_contents() missing 1 required positional argument: 'self'.
I figured that this is because get_contents() in ImplementationOne takes self, but it's not specified in the abstract method.
So, if I changed:
#abstractmethod
def get_contents():
pass
to
#abstractmethod
def get_contents(self):
pass
But I get the same error.
I've tried many combinations, including putting self as an argument to every occurrence or get_contents, and passing in cls to get_contents in the abstract class - but no luck.
So, pretty much, how can I use the self keyword (aka access attributes) in only some implementations of an abstract method, that's called within a class method in the abstract class itself.
Also, on a side note, how can I access self.sublinks from within all implementations of BaseClass, while having its values different in each instance of an implementation?
There are a few things wrong here. One is that the #classmethod decorator should only be used when you need it to be called on a class.
Example:
class ImplementationOne:
#classmethod
def display(cls):
print(f'The class name is {cls.__name__}.')
ImplementationOne.display()
There is nothing special about the name self. It's just what is used by everyone to refer to the instance. In python the instance is implicitly handed to the first argument of the class unless you have a #classmethod decorator. In that case the class is handed as the first argument.
That is why you are getting the TypeError. Since you are calling the method on the instance test_one.display() you are essentially calling it as an instance method. Since you need to access the instance method get_contents from within it that is what you want. As a classmethod you wouldn't have access to get_contents.
That means you need both the ABC and ImplementationOne to have those methods implemented as instance methods.
Since it is now an instance method on the ABC it also should be an instance method in ImplementationTwo.
Your other question was how to get self.sublinks as an attribute in both subclasses.
Since your are overriding __init__ in ImplementationOne you need to call the parent class's __init__ as well. You can do this by using super() to call the Super or Base class's methods.
class ImplementationOne(BaseClass):
def __init__(self, url):
self.url = url
super().__init__()
Full working code:
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
self.sublinks = []
def display(self):
print(self.get_contents())
#abstractmethod
def get_contents(self):
pass
class ImplementationOne(BaseClass):
def __init__(self, url):
self.url = url
super().__init__()
def get_contents(self):
return "The url was: " + self.url
class ImplementationTwo(BaseClass):
def get_contents(self):
return "This does not need a url"
test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()
test_one.display()
test_two.display()
print(test_one.sublinks)
I have an instance of a Python class that is creating another, and I'm wondering if the "created" class can access members of the "creator" without passing them in explicitly, or doing something like this:
class Creator(object):
def __init__(self, parameter):
self.parameter = parameter
self.created = Created(self)
class Created(object):
def __init__(self, creator):
self.creator = creator
self.parameter = self.creator.parameter
I guess what I'm trying to do is allow parameter to be accessed by both, except in practice there will be multiple parameters, so passing them all will result in a long list of arguments. My solution right now is to use a Creator as an argument to a Created. Is there a less awkward or smarter way to do this? Maybe put all the parameters in a dictionary?
You can do this, and you've almost done it, with one minor problem:
class Created():
def __init__(self, creator):
self.parameter = self.creator.parameter
There is no self.creator. If you never need to access it again after this __init__ call, just use the creator parameter directly:
class Created():
def __init__(self, creator):
self.parameter = creator.parameter
If you need it later, store it as self.creator, and then of course you can access it there:
class Created():
def __init__(self, creator):
self.creator = creator
self.parameter = self.creator.parameter
… although you probably don't even need to copy over parameter in that case, because you can always get to it as self.creator.parameter.
This is a very common pattern.
The only real downside to this is that if you keep the back-reference around (self.creator = creator), you can't have any __del__ methods. (Or you need to make it a weakref, or an indirect reference, like a key that can be used to look up the creator as needed.)
Another option
class Creator():
def __init__(self, parameter):
self.parameter = parameter
self.created = Created()
self.created.creator = self
IMHO it looks fine. If parameter is a class attribute instead of instance, you can use inheritance, but I don't think it is such an improvement.
def creator_factory(param):
class Creator(object):
parameter = param
return Creator
Creator = creator_factory(something)
class Created(Creator):
pass
>>> Created().parameter
'something'
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
I am newbie in Python.I know this question is useless.But I am frustrated with my issue.I have 2 methods defined in my base class Animals.When I try to call the base methods in my inherited classes it shows these error:
NameError: name 'display_name' is not defined
class Animals():
def display_name(self):
print ('Name is Mr.X')
def display_age(self):
print('Age is 25')
class Name(Animals):
display_name(self)
class Age(Animals):
display_age(self)
n=Name()
a=Age()
n.display_name()
a.display_age()
You need to refer to the display_name function with a self prefix instead of passing self as an argument.
Also, as noted by Antimony, you need to call the display_name from within a function that is associated with an instance of the class (inside a function that accepts the self argument).
Code that appears outside a method function but inside a class is associated with the whole class, not with any particular instance of that class - using the self variable in this context has no meaning - if you create multiple objects from the class which one does it refer to?
class Animals():
def display_name(self):
print ('Name is Mr.X')
def display_age(self):
print('Age is 25')
class Name(Animals):
def call_display_name(self):
self.display_name()
class Age(Animals):
def call_display_name(self):
self.display_age()
Name().call_display_name()
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().