Here I'm subclassing a wxPython class and defining a class method called singleton.
class AddressCellAttr(wx.grid.GridCellAttr):
_instance = None
def __init__(self):
wx.grid.GridCellAttr.__init__(self)
self.SetTextColour('#0000FF')
#classmethod
def singleton(cls):
if cls._instance == None:
cls._instance = cls()
return cls._instance
class ValidAddressCellAttr(AddressCellAttr):
def __init__(self):
AddressCellAttr.__init__(self)
self.SetTextColour('#00FF00')
class CorrectedAddressCellAttr(AddressCellAttr):
def __init__(self):
AddressCellAttr.__init__(self)
self.SetTextColour('#FFFF00')
class InvalidAddressCellAttr(AddressCellAttr):
def __init__(self):
AddressCellAttr.__init__(self)
self.SetTextColour('#FF0000')
class UnparsableAddressCellAttr(AddressCellAttr):
def __init__(self):
AddressCellAttr.__init__(self)
self.SetTextColour('#555555')
The rest of the classes are subclasses of the first subclass. I figured that the singleton class method would work for all the subclasses as well since it operates on the class, and the subclass is indeed a separate class.
What happens is that after I call singleton once on AddressCellAttr, the singleton method returns that same object on all the subclasses too. Why does this happen?
Not sure why you think you need a singleton pattern here, but in any case, you should really be doing this in __new__.
class Singleton(object):
def __new__(cls):
try:
return cls._instance
except AttributeError:
cls._instance = object.__new__(cls)
return cls._instance
Just make sure all subclasses call parent __new__(), and remember that the signature for __new__() and __init__() must match.
OK, I kind of figured this one out myself while writing the question. It turns out that when the singleton method is called it does indeed receive the correct subclass as the parameter, but since the subclasses don't specifically define _instance anywhere, cls._instance will look up the class chain back to AddressCellAttr and to the original _instance.
The solution is to specifically define _instance for each subclass, like so:
class ValidAddressCellAttr(AddressCellAttr):
_instance = None
def __init__(self):
AddressCellAttr.__init__(self)
self.SetTextColour('#00FF00')
And so on.
Related
I read that it is considered bad practice to create a variable in the class namespace and then change its value in the class constructor.
(One of my sources: SoftwareEngineering SE: Is it a good practice to declare instance variables as None in a class in Python.)
Consider the following code:
# lib.py
class mixin:
def __init_subclass__(cls, **kwargs):
cls.check_mixin_subclass_validity(cls)
super().__init_subclass__(**kwargs)
def check_mixin_subclass_validity(subclass):
assert hasattr(subclass, 'necessary_var'), \
'Missing necessary_var'
def method_used_by_subclass(self):
return self.necessary_var * 3.14
# app.py
class my_subclass(mixin):
necessary_var = None
def __init__(self, some_value):
self.necessary_var = some_value
def run(self):
# DO SOME STUFF
self.necessary_var = self.method_used_by_subclass()
# DO OTHER STUFF
To force its subclass to declare the variable necessary_var, the class mixin uses the metaclass subclass_validator.
And the only way I know to makes it work on app.py side, is to initialized necessary_var as a class variable.
I am missing something or is it the only way to do so?
Short answer
You should check that attributes and methods exist at instantiation of a class, not before. This is what the abc module does and it has good reasons to work like this.
Long answer
First, I would like to point out that it seems what you want to check is that an instance attribute exists.
Due to Python dynamic nature, it is not possible to do so before an instance is created, that is after the call to __init__. We could define Mixin.__init__, but we would then have to rely on the users of your API to have perfect hygiene and to always call super().__init__.
One option is thus to create a metaclass and add a check in its __call__ method.
class MetaMixin(type):
def __call__(self, *args, **kwargs):
instance = super().__call__(*args, **kwargs)
assert hasattr(instance, 'necessary_var')
class Mixin(metaclass=MetaMixin):
pass
class Foo(Mixin):
def __init__(self):
self.necessary_var = ...
Foo() # Works fine
class Bar(Mixin):
pass
Bar() # AssertionError
To convince yourself that it is good practice to do this at instantiation, we can look toward the abc module which uses this behaviour.
from abc import abstractmethod, ABC
class AbstractMixin(ABC):
#abstractmethod
def foo(self):
...
class Foo(AbstractMixin):
pass
# Right now, everything is still all good
Foo() # TypeError: Can't instantiate abstract class Foo with abstract methods foo
As you can see the TypeError was raise at instantiation of Foo() and not at class creation.
But why does it behave like this?
The reason for that is that not every class will be instantiated, consider the example where we want to inherit from Mixin to create a new mixin which checks for some more attributes.
class Mixin:
def __init_subclass__(cls, **kwargs):
assert hasattr(cls, 'necessary_var')
super().__init_subclass__(**kwargs)
class MoreMixin(Mixin):
def __init_subclass__(cls, **kwargs):
assert hasattr(cls, 'other_necessary_var')
super().__init_subclass__(**kwargs)
# AssertionError was raised at that point
class Foo(MoreMixin):
necessary_var = ...
other_necessary_var = ...
As you see, the AssertionError was raised at the creation of the MoreMixin class. This is clearly not the desired behaviour since the Foo class is actually correctly built and that is what our mixin was supposed to check.
In conclusion, the existence of some attribute or method should be done at instantiation, Otherwise, you are preventing a whole lot of helpful inheritance techniques. This is why the abc module does it like that and this is why we should.
I am trying to understand the relation in between python metaclass and class. I was trying to create singleton class and found this code
class SingleTon(type):
def __call__(self, *args, **kwargs):
if self._instances is None:
self._instances = super(SingleTon, self).__call__(*args, **kwargs)
return self._instances
class Counter:
__metaclass__ = SingleTon
_instances = None
def __init__(self):
self.count = 1
c = Counter()
my question here is how counter class object is getting created using metaclass. I know metaclass call method gets called whenever we create an object but the confusion is here what this code super(SingleTon, self).__call__(*args, **kwargs) does here. Please explain. It would be very appreciable.
super will just forward the arguments to type.__call__ which is responsible for the class creation.
It's like calling super in a 'normal' class hierarchy only now, you're calling it in a metaclass. Since SingleTon is a subclass of type, that'll get called. In a class scenario, you'd (normally) forward calls to the base class object.
I've read a bunch of useful information on SO as well as the article at http://www.phyast.pitt.edu/~micheles/python/metatype.html
However, I think I still did not find the answer. Hence a new question.
I'm creating a library of functions/classes for in-house use. As part of that I would like to create a Singleton class. Any other class should be able to inherit it and become Singleton. These classes should be sub-classable.
Per SO post at Creating a singleton in Python, I implemented:
class _Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(
_Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Singleton(_Singleton('SingletonMeta', (object,), {})):
pass
It works. It helps create a singleton class that can be sub-classed.
There would be some classes in my library that would implement an abstract class using abc. Such class or a class implementing this abstract class can likely be Singleton.
So,
import abc
class Foo(metaclass=abc.ABCMeta):
#abc.abstractmethod
def bar(self): pass
class Bar(Singleton, Foo): # This generates the meta-class conflict
def bar(self):
return 'implemented'
def bat(self):
return 'something else'
I am looking for inputs/help to help implement such a scenario.
**
Summary Requirements:
**
A mechanism to create a Singleton class.
A class implemented as
Singleton (via the above mechanism) should be sub-classable. The sub-
class my have additional/new methods than the base class.
A mechanism to create an abstract class (abc helps with this).
An implementation of this abstract class that acts as a Singleton. It
may have additional methods than the abstract class itself.
Any inputs/help/pointers will be appreciated.
Regards
Sharad
Instead of resorting to a metaclass to register your singletons, you can do that on the Base class for your hierarchy - just put the singleton logic on the __new__ method instead. That way, you don't have to change the metaclass just due to this aditional behaviors, and abc.metaclasses will just work.
import abc
class Foo(metaclass=abc.ABCMeta):
_singleton_registry = {}
def __new__(cls, *args, **kw):
if cls in in __class__._singleton_registry:
return __class__._singleton_registry[cls]
singleton = super().__new__(*args, **kw)
__class__._singleton_registry[cls] = singleton
return singleton
#abc.abstractmethod
def bar(self): pass
I need to deliver something like this in my program
class the_class_name(Parent):
the_attribute = self.parent_class_method()
#the parent class method will return a value
#but I cannot use self here since there's no self
How can I carry this out? Is there any other alternative that can do the job for me?
I have tried using __init__ like this:
def __init__(self):
Parent.__init__(self)
self.attribute = self.the_method()
But then I have problem creating the object, it won't receive any parameters that the Parent class normally receives anymore
Sounds like you are looking for __init__:
class TheClassName(Parent):
def __init__(self):
# Set attribute to the result of the parent method
self.attribute = super(TheClassName, self).the_method()
EDIT
If your parent class has parameters in it's own __init__ function, include them in the child class:
class Parent(object):
def __init__(self, foo, bar):
...
#classmethod
def the_method(cls):
...
class TheClassName(Parent):
def __init__(self, foo, bar):
super(TheClassName, self).__init__(foo, bar)
self.attribute = super(TheClassName, self).the_method()
I don't quite understand why you don't just call the parent method on your child object when you need the value though.
There is no self at that point of the creation of the subclass, nor is there an instance of the Parent class. That means the only Parent class methods you could call would have to be either static or class methods.
To demonstrate:
class Parent(object):
#staticmethod
def static_method():
return 42
#classmethod
def class_method(cls):
return 43
class TheClassName(Parent):
the_attribute = Parent.static_method()
another_attribute = Parent.class_method()
print(TheClassName.the_attribute) # -> 42
print(TheClassName.another_attribute) # -> 43
You must use class methods, declared with the #classmethod decorator, or a #staticmethod. The #classmethod decorator is preferable so that inheritance is handled correctly, i.e. the method is invoked on the derived class (a bit of a technicality, if you are still learning this).
class Alpha(object):
#classmethod
def method1(cls):
return 'method1 has been called on {}'.format(cls)
class Beta(Alpha):
def __init__(self):
self.myattr = Beta.method1()
print(Beta().myattr)
method1 has been called on class <'__main__.Beta'>
Use
super(ClassName, self).methodname(arg)
inside a method
def child_method(self, arg):
super(ClassName, self).methodname(arg)
You cannot use self outside a method.
i had a class called CacheObject,and many class extend from it.
now i need to add something common on all classes from this class so i write this
class CacheObject(object):
def __init__(self):
self.updatedict = dict()
but the child class didn't obtain the updatedict attribute.i know calling super init function was optional in python,but is there an easy way to force all of them to add the init rather than walk all the classes and modify them one by one?
I was in a situation where I wanted classes to always call their base classes' constructor in order before they call their own. The following is Python3 code that should do what you want:
class meta(type):
def __init__(cls,name,bases,dct):
def auto__call__init__(self, *a, **kw):
for base in cls.__bases__:
base.__init__(self, *a, **kw)
cls.__init__child_(self, *a, **kw)
cls.__init__child_ = cls.__init__
cls.__init__ = auto__call__init__
class A(metaclass=meta):
def __init__(self):
print("Parent")
class B(A):
def __init__(self):
print("Child")
To illustrate, it will behave as follows:
>>> B()
Parent
Child
<__main__.B object at 0x000001F8EF251F28>
>>> A()
Parent
<__main__.A object at 0x000001F8EF2BB2B0>
I suggest a non-code fix:
Document that super().__init__() should be called by your subclasses before they use any other methods defined in it.
This is not an uncommon restriction. See, for instance, the documentation for threading.Thread in the standard library, which says:
If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.
There are probably many other examples, I just happened to have that doc page open.
You can override __new__. As long as your base classes doesn't override __new__ without calling super().__new__, then you'll be fine.
class CacheObject(object):
def __new__(cls, *args, **kwargs):
instance = super().__new__(cls, *args, **kwargs)
instance.updatedict = {}
return instance
class Foo(CacheObject):
def __init__(self):
pass
However, as some commenters said, the motivation for this seems a little shady. You should perhaps just add the super calls instead.
This isn't what you asked for, but how about making updatedict a property, so that it doesn't need to be set in __init__:
class CacheObject(object):
#property
def updatedict(self):
try:
return self._updatedict
except AttributeError:
self._updatedict = dict()
return self._updatedict
Hopefully this achieves the real goal, that you don't want to have to touch every subclass (other than to make sure none uses an attribute called updatedict for something else, of course).
There are some odd gotchas, though, because it is different from setting updatedict in __init__ as in your question. For example, the content of CacheObject().__dict__ is different. It has no key updatedict because I've put that key in the class, not in each instance.
Regardless of motivation, another option is to use __init_subclass__() (Python 3.6+) to get this kind of behavior. (For example, I'm using it because I want users not familiar with the intricacies of Python to be able to inherit from a class to create specific engineering models, and I'm trying to keep the structure of the class they have to define very basic.)
In the case of your example,
class CacheObject:
def __init__(self) -> None:
self.updatedict = dict()
def __init_subclass__(cls) -> None:
orig_init = cls.__init__
#wraps(orig_init)
def __init__(self, *args, **kwargs):
orig_init(self, *args, **kwargs)
super(self.__class__, self).__init__()
cls.__init__ = __init__
What this does is any class that subclasses CacheObject will now, when created, have its __init__ function wrapped by the parent class—we're replacing it with a new function that calls the original, and then calls super() (the parent's) __init__ function. So now, even if the child class overrides the parent __init__, at the instance's creation time, its __init__ is then wrapped by a function that calls it and then calls its parent.
You can add a decorator to your classes :
def my_decorator(cls):
old_init = cls.__init__
def new_init(self):
self.updatedict = dict()
old_init(self)
cls.__init__ = new_init
return cls
#my_decorator
class SubClass(CacheObject):
pass
if you want to add the decorators to all the subclasses automatically, use a metaclass:
class myMeta(type):
def __new__(cls, name, parents, dct):
return my_decorator(super().__new__(cls, name, parents, dct))
class CacheObject(object, metaclass=myMeta):
pass