How to inherit Base class with singleton in python - python

I have base class which is singleton, i need to inherit that in my another class but i get error message as
TypeError: Error when calling the metaclass bases
function() argument 1 must be code, not str
Can someone help with this.
Below is sample code.
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
#singleton
class ClassOne(object):
def methodOne(self):
print "Method One"
def methodTwo(self):
print "Method Two"
class ClassTwo(ClassOne):
pass

You must make the singleton a class instead of a function for derivation to work. Here is an example that has been tested on both Python 2.7 and 3.5:
class singleton(object):
instances = {}
def __new__(cls, clz = None):
if clz is None:
# print ("Creating object for", cls)
if not cls.__name__ in singleton.instances:
singleton.instances[cls.__name__] = \
object.__new__(cls)
return singleton.instances[cls.__name__]
# print (cls.__name__, "creating", clz.__name__)
singleton.instances[clz.__name__] = clz()
singleton.first = clz
return type(clz.__name__, (singleton,), dict(clz.__dict__))
If you use this with your example classes:
#singleton
class ClassOne(object):
def methodOne(self):
print "Method One"
def methodTwo(self):
print "Method Two"
class ClassTwo(ClassOne):
pass
classes A and B will both be singletons
Beware, it is uncommon to inherit from a singleton class.

Related

Delegation design pattern with abstract methods in python

I have the following classes implementing a "Delegation Design Pattern" with an additional DelegatorParent class:
class DelegatorParent():
def __init__(self):
self.a = 'whatever'
class ConcreteDelegatee():
def myMethod(self):
return 'myMethod'
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee = ConcreteDelegatee()
DelegatorParent.__init__(self)
def __getattr__(self, attrname):
return getattr(self.delegatee, attrname)
a = Delegator()
result = a.myMethod()
Everything looks fine.
Now I would like to put an abstract method in DelegatorParent, to ensure that "myMethod" is always defined.
from abc import ABCMeta, abstractmethod
class DelegatorParent():
__metaclass__ = ABCMeta
#abstractmethod
def myMethod(self):
pass
def __init__(self):
self.a = 'whatever'
class ConcreteDelegatee():
def myMethod(self):
return 'myMethod'
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee = ConcreteDelegatee()
DelegatorParent.__init__(self)
def __getattr__(self, attrname):
return getattr(self.delegatee, attrname)
# This method seems unnecessary, but if I erase it an exception is
# raised because the abstract method's restriction is violated
def myMethod(self):
return self.delegatee.myMethod()
a = Delegator()
result = a.myMethod()
Can you help me find an "elegant" way to remove "myMethod" from "Delegator"... Intuition tells me that it is somehow redundant (considering that a custom getattr method is defined).
And more importantly, notice that with this implementation, if I forget to define myMethod in ConcreteDelegatee the program compiles, but it may crash in runtime if I call Delegator.myMethod(), which is exactly what I wanted to avoid by using abstract methods in DelegatorParent.
Obviously a simple solution would be to move #abstractmethod to the Delegator class, but I want to avoid doing that because in my program DelegatorParent is a very important class (and Delegator is just an auxiliary class).
You can decide to automatically implement abstract methods delegared to ConcreteDelegatee.
For each abstract method, check if it's name exist in the ConcreteDelegatee class and implement this method as a delegate to this class method.
from abc import ABCMeta, abstractmethod
class DelegatorParent(object):
__metaclass__ = ABCMeta
def __init__(self):
self.a = 'whatever'
#abstractmethod
def myMethod(self):
pass
class Delegatee(object):
pass
class ConcreteDelegatee(Delegatee):
def myMethod(self):
return 'myMethod'
def myMethod2(self):
return 'myMethod2'
class Delegator(DelegatorParent):
def __new__(cls, *args, **kwargs):
implemented = set()
for name in cls.__abstractmethods__:
if hasattr(ConcreteDelegatee, name):
def delegated(this, *a, **kw):
meth = getattr(this.delegatee, name)
return meth(*a, **kw)
setattr(cls, name, delegated)
implemented.add(name)
cls.__abstractmethods__ = frozenset(cls.__abstractmethods__ - implemented)
obj = super(Delegator, cls).__new__(cls, *args, **kwargs)
obj.delegatee = ConcreteDelegatee()
return obj
def __getattr__(self, attrname):
# Called only for attributes not defined by this class (or its bases).
# Retrieve attribute from current behavior delegate class instance.
return getattr(self.delegatee, attrname)
# All abstract methods are delegared to ConcreteDelegatee
a = Delegator()
print(a.myMethod()) # correctly prints 'myMethod'
print(a.myMethod2()) #correctly prints 'myMethod2'
This solves the main problem (prevent ConcreteDelegatee from forgetting to define myMethod). Other abstract methods are still checked if you forgot to implement them.
The __new__ method is in charge of the delegation, that frees your __init__ to do it.
Since you use ABCMeta, you must defined the abstract methods. One could remove your method from the __abstractmethods__ set, but it is a frozenset. Anyway, it involves listing all abstract methods.
So, instead of playing with __getattr__, you can use a simple descriptor.
For instance:
class Delegated(object):
def __init__(self, attrname=None):
self.attrname = attrname
def __get__(self, instance, owner):
if instance is None:
return self
delegatee = instance.delegatee
return getattr(delegatee, self.attrname)
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee = ConcreteDelegatee()
DelegatorParent.__init__(self)
myMethod = Delegated('myMethod')
An advantage here: the developer has the explicit information that "myMethod" is delegated.
If you try:
a = Delegator()
result = a.myMethod()
It works! But if you forget to implement myMethod in Delegator class, you have the classic error:
Traceback (most recent call last):
File "script.py", line 40, in <module>
a = Delegator()
TypeError: Can't instantiate abstract class Delegator with abstract methods myMethod
Edit
This implementation can be generalized as follow:
class DelegatorParent():
__metaclass__ = ABCMeta
#abstractmethod
def myMethod1(self):
pass
#abstractmethod
def myMethod2(self):
pass
def __init__(self):
self.a = 'whatever'
class ConcreteDelegatee1():
def myMethod1(self):
return 'myMethod1'
class ConcreteDelegatee2():
def myMethod2(self):
return 'myMethod2'
class DelegatedTo(object):
def __init__(self, attrname):
self.delegatee_name, self.attrname = attrname.split('.')
def __get__(self, instance, owner):
if instance is None:
return self
delegatee = getattr(instance, self.delegatee_name)
return getattr(delegatee, self.attrname)
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee1 = ConcreteDelegatee1()
self.delegatee2 = ConcreteDelegatee2()
DelegatorParent.__init__(self)
myMethod1 = DelegatedTo('delegatee1.myMethod1')
myMethod2 = DelegatedTo('delegatee2.myMethod2')
a = Delegator()
result = a.myMethod2()
Here, we can specify the delegatee name and delegatee method.
Here is my current solution. It solves the main problem (prevent ConcreteDelegatee from forgetting to define myMethod), but I'm still not convinced because I still need to define myMethod inside Delegator, which seems redundant
from abc import ABCMeta, abstractmethod
class DelegatorParent(object):
__metaclass__ = ABCMeta
def __init__(self):
self.a = 'whatever'
#abstractmethod
def myMethod(self):
pass
class Delegatee(object):
def checkExistence(self, attrname):
if not callable(getattr(self, attrname, None)):
error_msg = "Can't instantiate " + str(self.__class__.__name__) + " without abstract method " + attrname
raise NotImplementedError(error_msg)
class ConcreteDelegatee(Delegatee):
def myMethod(self):
return 'myMethod'
def myMethod2(self):
return 'myMethod2'
class Delegator(DelegatorParent):
def __init__(self):
self.delegatee = ConcreteDelegatee()
DelegatorParent.__init__(self)
for method in DelegatorParent.__abstractmethods__:
self.delegatee.checkExistence(method)
def myMethod(self, *args, **kw):
return self.delegatee.myMethod(*args, **kw)
def __getattr__(self, attrname):
# Called only for attributes not defined by this class (or its bases).
# Retrieve attribute from current behavior delegate class instance.
return getattr(self.delegatee, attrname)
# if I forget to implement myMethod inside ConcreteDelegatee,
# the following line will correctly raise an exception saying
# that 'myMethod' is missing inside 'ConcreteDelegatee'.
a = Delegator()
print a.myMethod() # correctly prints 'myMethod'
print a.myMethod2() #correctly prints 'myMethod2'

Using #classmethod with #property [duplicate]

This question already has answers here:
Using property() on classmethods
(19 answers)
Closed 3 years ago.
In python I can add a method to a class with the #classmethod decorator. Is there a similar decorator to add a property to a class? I can better show what I'm talking about.
class Example(object):
the_I = 10
def __init__( self ):
self.an_i = 20
#property
def i( self ):
return self.an_i
def inc_i( self ):
self.an_i += 1
# is this even possible?
#classproperty
def I( cls ):
return cls.the_I
#classmethod
def inc_I( cls ):
cls.the_I += 1
e = Example()
assert e.i == 20
e.inc_i()
assert e.i == 21
assert Example.I == 10
Example.inc_I()
assert Example.I == 11
Is the syntax I've used above possible or would it require something more?
The reason I want class properties is so I can lazy load class attributes, which seems reasonable enough.
Here's how I would do this:
class ClassPropertyDescriptor(object):
def __init__(self, fget, fset=None):
self.fget = fget
self.fset = fset
def __get__(self, obj, klass=None):
if klass is None:
klass = type(obj)
return self.fget.__get__(obj, klass)()
def __set__(self, obj, value):
if not self.fset:
raise AttributeError("can't set attribute")
type_ = type(obj)
return self.fset.__get__(obj, type_)(value)
def setter(self, func):
if not isinstance(func, (classmethod, staticmethod)):
func = classmethod(func)
self.fset = func
return self
def classproperty(func):
if not isinstance(func, (classmethod, staticmethod)):
func = classmethod(func)
return ClassPropertyDescriptor(func)
class Bar(object):
_bar = 1
#classproperty
def bar(cls):
return cls._bar
#bar.setter
def bar(cls, value):
cls._bar = value
# test instance instantiation
foo = Bar()
assert foo.bar == 1
baz = Bar()
assert baz.bar == 1
# test static variable
baz.bar = 5
assert foo.bar == 5
# test setting variable on the class
Bar.bar = 50
assert baz.bar == 50
assert foo.bar == 50
The setter didn't work at the time we call Bar.bar, because we are calling
TypeOfBar.bar.__set__, which is not Bar.bar.__set__.
Adding a metaclass definition solves this:
class ClassPropertyMetaClass(type):
def __setattr__(self, key, value):
if key in self.__dict__:
obj = self.__dict__.get(key)
if obj and type(obj) is ClassPropertyDescriptor:
return obj.__set__(self, value)
return super(ClassPropertyMetaClass, self).__setattr__(key, value)
# and update class define:
# class Bar(object):
# __metaclass__ = ClassPropertyMetaClass
# _bar = 1
# and update ClassPropertyDescriptor.__set__
# def __set__(self, obj, value):
# if not self.fset:
# raise AttributeError("can't set attribute")
# if inspect.isclass(obj):
# type_ = obj
# obj = None
# else:
# type_ = type(obj)
# return self.fset.__get__(obj, type_)(value)
Now all will be fine.
If you define classproperty as follows, then your example works exactly as you requested.
class classproperty(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, owner):
return self.f(owner)
The caveat is that you can't use this for writable properties. While e.I = 20 will raise an AttributeError, Example.I = 20 will overwrite the property object itself.
[answer written based on python 3.4; the metaclass syntax differs in 2 but I think the technique will still work]
You can do this with a metaclass...mostly. Dappawit's almost works, but I think it has a flaw:
class MetaFoo(type):
#property
def thingy(cls):
return cls._thingy
class Foo(object, metaclass=MetaFoo):
_thingy = 23
This gets you a classproperty on Foo, but there's a problem...
print("Foo.thingy is {}".format(Foo.thingy))
# Foo.thingy is 23
# Yay, the classmethod-property is working as intended!
foo = Foo()
if hasattr(foo, "thingy"):
print("Foo().thingy is {}".format(foo.thingy))
else:
print("Foo instance has no attribute 'thingy'")
# Foo instance has no attribute 'thingy'
# Wha....?
What the hell is going on here? Why can't I reach the class property from an instance?
I was beating my head on this for quite a while before finding what I believe is the answer. Python #properties are a subset of descriptors, and, from the descriptor documentation (emphasis mine):
The default behavior for attribute access is to get, set, or delete the
attribute from an object’s dictionary. For instance, a.x has a lookup chain
starting with a.__dict__['x'], then type(a).__dict__['x'], and continuing
through the base classes of type(a) excluding metaclasses.
So the method resolution order doesn't include our class properties (or anything else defined in the metaclass). It is possible to make a subclass of the built-in property decorator that behaves differently, but (citation needed) I've gotten the impression googling that the developers had a good reason (which I do not understand) for doing it that way.
That doesn't mean we're out of luck; we can access the properties on the class itself just fine...and we can get the class from type(self) within the instance, which we can use to make #property dispatchers:
class Foo(object, metaclass=MetaFoo):
_thingy = 23
#property
def thingy(self):
return type(self).thingy
Now Foo().thingy works as intended for both the class and the instances! It will also continue to do the right thing if a derived class replaces its underlying _thingy (which is the use case that got me on this hunt originally).
This isn't 100% satisfying to me -- having to do setup in both the metaclass and object class feels like it violates the DRY principle. But the latter is just a one-line dispatcher; I'm mostly okay with it existing, and you could probably compact it down to a lambda or something if you really wanted.
If you use Django, it has a built in #classproperty decorator.
from django.utils.decorators import classproperty
For Django 4, use:
from django.utils.functional import classproperty
I think you may be able to do this with the metaclass. Since the metaclass can be like a class for the class (if that makes sense). I know you can assign a __call__() method to the metaclass to override calling the class, MyClass(). I wonder if using the property decorator on the metaclass operates similarly.
Wow, it works:
class MetaClass(type):
def getfoo(self):
return self._foo
foo = property(getfoo)
#property
def bar(self):
return self._bar
class MyClass(object):
__metaclass__ = MetaClass
_foo = 'abc'
_bar = 'def'
print MyClass.foo
print MyClass.bar
Note: This is in Python 2.7. Python 3+ uses a different technique to declare a metaclass. Use: class MyClass(metaclass=MetaClass):, remove __metaclass__, and the rest is the same.
As far as I can tell, there is no way to write a setter for a class property without creating a new metaclass.
I have found that the following method works. Define a metaclass with all of the class properties and setters you want. IE, I wanted a class with a title property with a setter. Here's what I wrote:
class TitleMeta(type):
#property
def title(self):
return getattr(self, '_title', 'Default Title')
#title.setter
def title(self, title):
self._title = title
# Do whatever else you want when the title is set...
Now make the actual class you want as normal, except have it use the metaclass you created above.
# Python 2 style:
class ClassWithTitle(object):
__metaclass__ = TitleMeta
# The rest of your class definition...
# Python 3 style:
class ClassWithTitle(object, metaclass = TitleMeta):
# Your class definition...
It's a bit weird to define this metaclass as we did above if we'll only ever use it on the single class. In that case, if you're using the Python 2 style, you can actually define the metaclass inside the class body. That way it's not defined in the module scope.
def _create_type(meta, name, attrs):
type_name = f'{name}Type'
type_attrs = {}
for k, v in attrs.items():
if type(v) is _ClassPropertyDescriptor:
type_attrs[k] = v
return type(type_name, (meta,), type_attrs)
class ClassPropertyType(type):
def __new__(meta, name, bases, attrs):
Type = _create_type(meta, name, attrs)
cls = super().__new__(meta, name, bases, attrs)
cls.__class__ = Type
return cls
class _ClassPropertyDescriptor(object):
def __init__(self, fget, fset=None):
self.fget = fget
self.fset = fset
def __get__(self, obj, owner):
if self in obj.__dict__.values():
return self.fget(obj)
return self.fget(owner)
def __set__(self, obj, value):
if not self.fset:
raise AttributeError("can't set attribute")
return self.fset(obj, value)
def setter(self, func):
self.fset = func
return self
def classproperty(func):
return _ClassPropertyDescriptor(func)
class Bar(metaclass=ClassPropertyType):
__bar = 1
#classproperty
def bar(cls):
return cls.__bar
#bar.setter
def bar(cls, value):
cls.__bar = value
bar = Bar()
assert Bar.bar==1
Bar.bar=2
assert bar.bar==2
nbar = Bar()
assert nbar.bar==2
I happened to come up with a solution very similar to #Andrew, only DRY
class MetaFoo(type):
def __new__(mc1, name, bases, nmspc):
nmspc.update({'thingy': MetaFoo.thingy})
return super(MetaFoo, mc1).__new__(mc1, name, bases, nmspc)
#property
def thingy(cls):
if not inspect.isclass(cls):
cls = type(cls)
return cls._thingy
#thingy.setter
def thingy(cls, value):
if not inspect.isclass(cls):
cls = type(cls)
cls._thingy = value
class Foo(metaclass=MetaFoo):
_thingy = 23
class Bar(Foo)
_thingy = 12
This has the best of all answers:
The "metaproperty" is added to the class, so that it will still be a property of the instance
Don't need to redefine thingy in any of the classes
The property works as a "class property" in for both instance and class
You have the flexibility to customize how _thingy is inherited
In my case, I actually customized _thingy to be different for every child, without defining it in each class (and without a default value) by:
def __new__(mc1, name, bases, nmspc):
nmspc.update({'thingy': MetaFoo.services, '_thingy': None})
return super(MetaFoo, mc1).__new__(mc1, name, bases, nmspc)
If you only need lazy loading, then you could just have a class initialisation method.
EXAMPLE_SET = False
class Example(object):
#classmethod
def initclass(cls):
global EXAMPLE_SET
if EXAMPLE_SET: return
cls.the_I = 'ok'
EXAMPLE_SET = True
def __init__( self ):
Example.initclass()
self.an_i = 20
try:
print Example.the_I
except AttributeError:
print 'ok class not "loaded"'
foo = Example()
print foo.the_I
print Example.the_I
But the metaclass approach seems cleaner, and with more predictable behavior.
Perhaps what you're looking for is the Singleton design pattern. There's a nice SO QA about implementing shared state in Python.

How to make a "switch" between functions, depending on attribute access type (using class or instance)?

Disclaimer:
This article is more a recipe than a question, but I found the subject quite interesting, with almost no references in the Web.
If there is any better place on StackOverflow to publish this kind of articles, please let me know.
Subject:
How can I force Python to invoke different function depending on the type of attribute access (using class or instance) - e.g. force Python to invoke different method for MyClass.my_method() and MyClass().my_method()?
Usecase:
Let's say, we have custom Enum implementation (based on Python36 Enum, but with some customization). As a user of this Enum, we want to create a CustomEnum, inherit not just from Enum, but also from str: class MyEnum(str, Enum).We also want to add encoding and decoding feature. Our idea is to use MyEnum.encode to encode any object, that includes our enum members, but leave the original str.encode in power for instances of our enum class.
In short: MyEnum.encode invoke our custom encoding function, and have perfectly sens, from this point of view. MyEnum() is a string, so MyEnum().encode should invoke encode function inherited from str class.
Solution:
Write a descriptor, which will work as a switch.
Full answer in my first post.
Solution:
As far as I know, descriptors are the only objects, that can distinguish, if they are invoke for class or instance, because of the __get__ function signature: __get__(self, instance, instance_type). This property allows us to build a switch on top of it.
class boundmethod(object):
def __init__(self, cls_method=None, instance_method=None, doc=None):
self._cls_method = cls_method
self._instance_method = instance_method
if cls_method:
self._method_name = cls_method.__name__
elif instance_method:
self._method_name = instance_method.__name__
if doc is None and cls_method is not None:
doc = cls_method.__doc__
self.__doc__ = doc
self._method = None
self._object = None
def _find_method(self, instance, instance_type, method_name):
for base in instance_type.mro()[1:]:
method = getattr(base, method_name, None)
if _is_descriptor(method):
method = method.__get__(instance, base)
if method and method is not self:
try:
return method.__func__
except AttributeError:
return method
def __get__(self, instance, instance_type):
if instance is None:
self._method = self._cls_method or self._find_method(instance, instance_type, self._method_name)
self._object = instance_type
else:
self._method = self._instance_method or self._find_method(instance, instance_type, self._method_name)
self._object = instance
return self
#staticmethod
def cls_method(obj=None):
def constructor(cls_method):
if obj is None:
return boundmethod(cls_method, None, cls_method.__doc__)
else:
return type(obj)(cls_method, obj._instance_method, obj.__doc__)
if isinstance(obj, FunctionType):
return boundmethod(obj, None, obj.__doc__)
else:
return constructor
#staticmethod
def instance_method(obj=None):
def constructor(instance_method):
if obj is None:
return boundmethod(None, instance_method, instance_method.__doc__)
else:
return type(obj)(obj._cls_method, instance_method, obj.__doc__)
if isinstance(obj, FunctionType):
return boundmethod(None, obj, obj.__doc__)
else:
return constructor
def __call__(self, *args, **kwargs):
if self._method:
try:
return self._method(self._object, *args, **kwargs)
except TypeError:
return self._method(*args, **kwargs)
return None
Example:
>>> class Walkmen(object):
... #boundmethod.cls_method
... def start(self):
... return 'Walkmen start class bound method'
... #boundmethod.instance_method(start)
... def start(self):
... return 'Walkmen start instance bound method'
>>> print Walkmen.start()
Walkmen start class bound method
>>> print Walkmen().start()
Walkmen start instance bound method
I hope it will help some o you guys.
Best.
I actually just asked this question (Python descriptors and inheritance I hadn't seen this question). My solution uses descriptors and a metaclass for inheritance.
from my answer:
class dynamicmethod:
'''
Descriptor to allow dynamic dispatch on calls to class.Method vs obj.Method
fragile when used with inheritence, to inherit and then overwrite or extend
a dynamicmethod class must have dynamicmethod_meta as its metaclass
'''
def __init__(self, f=None, m=None):
self.f = f
self.m = m
def __get__(self, obj, objtype=None):
if obj is not None and self.f is not None:
return types.MethodType(self.f, obj)
elif objtype is not None and self.m is not None:
return types.MethodType(self.m, objtype)
else:
raise AttributeError('No associated method')
def method(self, f):
return type(self)(f, self.m)
def classmethod(self, m):
return type(self)(self.f, m)
def make_dynamicmethod_meta(meta):
class _dynamicmethod_meta(meta):
def __prepare__(name, bases, **kwargs):
d = meta.__prepare__(name, bases, **kwargs)
for base in bases:
for k,v in base.__dict__.items():
if isinstance(v, dynamicmethod):
if k in d:
raise ValueError('Multiple base classes define the same dynamicmethod')
d[k] = v
return d
return _dynamicmethod_meta
dynamicmethod_meta=make_dynamicmethod_meta(type)
class A(metaclass=dynamicmethod_meta):
#dynamicmethod
def a(self):
print('Called from obj {} defined in A'.format(self))
#a.classmethod
def a(cls)
print('Called from class {} defined in A'.format(cls))
class B(A):
#a.method
def a(self):
print('Called from obj {} defined in B'.format(self))
A.a()
A().a()
B.a()
B().a()
results in:
Called from class <class 'A'> defined in A
Called from obj <A object at ...> defined in A
Called from class <class 'B'> defined in A
Called from obj <B object at ...> defined in B

Force implementation of a method in all inheriting classes

I have a situation in which I want to enforce each and every class inheriting from a certain (abstract) class to implement a method. This is something I would normally achieve using #abstractmethod. However, considering this situation of multiple inheritance:
from abc import ABCMeta, abstractmethod
class A(object):
__metaclass__ = ABCMeta
#abstractmethod
def very_specific_method(self):
pass
class B(A):
def very_specific_method(self):
print 'doing something in B'
class C(B):
pass
I want to enforce C to implement the method as well. I want each and every class that inherits A either directly or indirectly to be forced to implement the method. Is this possible?
Clarification: I want this to apply for a specific method, not to all abstract methods. abstract methods should continue to work the same, but perhaps a new decorator signaling a different kind of methods should be created.
Side note: I used abc in the question because this seems like the most related to the issue. I understand how abstract methods usually work and use them regularly. This is a different situation, and I don't mind if it's not done via abc.
A modified version of ABCMeta should do the trick.
Here instead of checking for methods with __isabstractmethod__ set to True only in base classes we can check for this is in class's MRO, and if it is found in any of the class in MRO and it is not present in current class then we can add this to the set abstracts.
from abc import ABCMeta, abstractmethod
from _weakrefset import WeakSet
class EditedABCMeta(ABCMeta):
def __new__(mcls, name, bases, namespace):
cls = type.__new__(mcls, name, bases, namespace)
# Compute set of abstract method names
abstracts = set(name
for name, value in namespace.items()
if getattr(value, "__isabstractmethod__", False))
for base in cls.__mro__:
for name, value in base.__dict__.items():
if getattr(value, "__isabstractmethod__", False) and name not in cls.__dict__:
abstracts.add(name)
cls.__abstractmethods__ = frozenset(abstracts)
# Set up inheritance registry
cls._abc_registry = WeakSet()
cls._abc_cache = WeakSet()
cls._abc_negative_cache = WeakSet()
cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
return cls
class A(object):
__metaclass__ = EditedABCMeta
#abstractmethod
def veryspecificmethod(self):
pass
class B(A):
def veryspecificmethod(self):
print 'doing something in B'
#abstractmethod
def foo(self):
print 'foo from B'
class C(B):
def foo(self):
pass
class D(C, B):
pass
if __name__ == '__main__':
for cls in (C, D):
try:
cls().veryspecificmethod
except TypeError as e:
print e.message
print '-'*20
for cls in (C, D):
try:
cls().foo
except TypeError as e:
print e.message
Output:
Can't instantiate abstract class C with abstract methods veryspecificmethod
Can't instantiate abstract class D with abstract methods foo, veryspecificmethod
--------------------
Can't instantiate abstract class C with abstract methods veryspecificmethod
Can't instantiate abstract class D with abstract methods foo, veryspecificmethod
EDIT:
Adding a special decorator #enforcedmethod that can meet your requirements without affecting #abstractmethod:
from abc import ABCMeta, abstractmethod
def enforcedmethod(func):
func.__enforcedmethod__ = True
return func
class EditedABCMeta(ABCMeta):
def __call__(cls, *args, **kwargs):
enforcedmethods = set()
for base in cls.__mro__:
for name, value in base.__dict__.items():
if getattr(value, "__enforcedmethod__", False) and name not in cls.__dict__:
enforcedmethods.add(name)
if enforcedmethods:
raise TypeError("Can't instantiate abstract class {} "
"with enforced methods {}".format(
cls.__name__, ', '.join(enforcedmethods)))
else:
return super(EditedABCMeta, cls).__call__(*args, **kwargs)
class A(object):
__metaclass__ = EditedABCMeta
#enforcedmethod
def veryspecificmethod(self):
pass
#abstractmethod
def simplemethod(self):
pass
class B(A):
def veryspecificmethod(self):
print 'doing something in B'
def simplemethod(self):
pass
class C(B):
pass
class D(C):
def veryspecificmethod(self):
print 'doing something in D'
Output:
>>> D().veryspecificmethod()
doing something in D
>>> C().veryspecificmethod()
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
C().veryspecificmethod()
File "C:\Python27\so.py", line 19, in __call__
cls.__name__, ', '.join(enforcedmethods)))
TypeError: Can't instantiate abstract class C with enforced methods veryspecificmethod
I'm pretty sure that this isn't a great idea, but I think that you can do this. Checking out the ABCMeta implementation for inspiration:
from abc import ABCMeta
def always_override(func):
func._always_override = True
return func
class always_override_property(property):
_always_override = True
class CrazyABCMeta(ABCMeta):
def __new__(mcls, name, bases, namespace):
cls = super(ABCMeta, mcls).__new__(mcls, name, bases, namespace)
abstracts = set()
# first, get all abstracts from the base classes
for base in bases:
abstracts.update(getattr(base, "_all_always_override", set()))
all_abstracts = abstracts.copy()
# Now add abstracts from this class and remove abstracts that this class defines
for name, value in namespace.items():
always_override = getattr(value, '_always_override', False)
if always_override:
abstracts.add(name)
all_abstracts.add(name)
elif name in abstracts:
abstracts.remove(name)
cls._all_always_override = frozenset(all_abstracts)
cls._always_override = frozenset(abstracts)
return cls
def __call__(cls, *args, **kwargs):
if cls._always_override:
raise TypeError(
'The following methods/properties must '
'be overridden {}'.format(cls._all_always_override))
return super(CrazyABCMeta, cls).__call__(*args, **kwargs)
# # # # # # # # # # #
# TESTS!
# # # # # # # # # # #
class A(object):
__metaclass__ = CrazyABCMeta
#always_override
def foo(self):
pass
#always_override_property
def bar(self):
pass
class B(A):
def foo(self):
pass
bar = 1
class C(B):
pass
class D(C):
pass
class E(D):
def foo(self):
pass
#property
def bar(self):
return 6
for cls in (B, E):
cls()
print ("Pass {}".format(cls.__name__))
for cls in (C, D):
try:
print cls()
except TypeError:
print ("Pass {}".format(cls.__name__))

Object Creation using __new__ method

I'm trying to create a sample object to test the __new__ and __init__ method.
Here is my sample code. When I run this - I see "Its been created" msg and dont see the "Initialized" & "Deleted" msg.
class Test( object ):
def __new__(self):
print 'Its been Created'
def __init__(self):
print 'Its been Initialzed'
def __del__(self):
print 'Its been Deleted'
T = Test()
__new__ needs to return an instance of the class (see docs). What you're effectively doing here is returning the instance on NoneType (since functions with no explicit return value return None (and 'the' in this case because None is a special-case singleton in Python)), then having __init__ of that object called. The simplest way to fix this would be something like:
class Test(object):
def __new__(cls):
print 'Creating'
return super(Test, cls).__new__(cls)
def __init__(self):
print 'Intializing'
def __del__(self):
print 'Deleting'
This will cause Test.__new__() to return the result of Test's superclass' (object in this case) __new__ method as the newly created instance.
It may help you to understand what's going on if you try the following:
class A(object):
def __new__(cls):
print 'A.__new__'
return super(A, cls).__new__(cls)
def __init__(self):
print 'A.__init__'
def __del__(self):
print 'A.__del__'
class FakeA(object):
def __new__(cls):
print 'FakeA.__new__'
return A.__new__()
def __init__(self):
print 'FakeA.__init__'
def __del__(self):
print 'FakeA.__del__'
a = A()
fa = FakeA()
del a
del fa
However, it is important to note that __del__ is not guaranteed to be called on every instance every time.

Categories

Resources