Python abstract attribute and inheritance - python

Say I have the following code:
class Archive(object):
""" Archiv-File wrapper """
READ_MODE = 0
WRITE_MODE = 1
def __init__(self, file_):
self.file_ = file_
self._mode = None
#property
def mode(self):
return self._mode
#mode.setter
def mode(self, value):
self._mode = value
def open(self, mode="r", pwd=None):
raise NotImplemented("Subclasses should implement this method!")
def close(self):
raise NotImplemented("Subclasses should implement this method!")
################################################
class GzipGPGArchive(Archive):
READ_MODE = 'r:gz' # Open for reading with gzip compression.
WRITE_MODE = 'w:gz' # Open for gzip compressed writing.
SUFFIX = "tar.gz.gpg"
def __init__(self, *args, **kwargs):
super(GzipGPGArchive, self).__init__(*args, **kwargs)
#mode.setter # This causes unresolved reference
def mode(self, value):
# do internal changes
self._mode = value
def open(self):
pass
def close(self):
pass
so know what is the best pythonic way to override the setter and getter method of the Abstract class attribute mode.
Overriding #mode.setter in the sub-class GzipGPGArchive causes unresolved reference!

First of all, there is no such thing as abstract attributes in Python. You can achieve abstraction, however, by using abc module. Perhaps it is not really "pythonic", but it works.
This is the minimal example with inheritance and abstraction. Use it as as template:
from abc import ABCMeta, abstractmethod
class Mother(metaclass=ABCMeta):
#abstractmethod
def method_(self):
pass
#property
#abstractmethod
def property_(self):
return -1
#property_.setter
#abstractmethod
def property_(self, value):
pass
class Daughter(Mother):
def __init__(self):
self.value_ = 0
def method_(self):
print(self.value_)
#property
def property_(self):
return = self.value_
#property_.setter
def property_(self, value):
self.value_ = value

Related

How can I get a class parameter from a function of class via decorator class?

The problem:
I want to get an attribute of class via decorator which is a class but I can not.
The question is how can?
class DecoratorClass:
def __call__(self, fn, *args, **kwargs) -> Callable:
try:
# do something with the TestClass value
return fn
finally:
pass
class TestClass:
def __init__(self):
self.value = 1
#DecoratorClass()
def bar(self):
return 1
How can I reach the the TestClass's value attr via DecoratorClass?
I got the solution :)
class Decoratorclass:
def __call__(self, fn, *args, **kwargs) -> Callable:
def decorated(instance):
try:
# do something with the TestClass value
print(instance.value)
return fn(instance)
finally:
pass
return decorated
class TestClass:
def __init__(self):
self.value = 1
#Decoratorclass()
def bar(self):
return 1

Can I add attributes to class methods in Python?

I have a class like this:
class A:
def __init__(self):
self.size=0
def change_size(self,new):
self.size=new
I want to add an attribute to the change_size method to say what it changes - i.e. so that
A(blah)
blah.change_size.modifies
returns
'size'
is this possible? I have tried:
class A:
def __init__(self):
self.size=0
def change_size(self,new):
self.change_size.modifies = 'size'
self.size=new
nope
class A:
def __init__(self):
self.size=0
self.change_size.modifies = 'size'
def change_size(self,new):
self.size=new
nope
class A:
def __init__(self):
self.size=0
def change_size(self,new,modifies='size'):
self.size=new
none of which seem to work.
That's simple enough. It goes basically the same way you'd add attributes to any other function:
class A:
def __init__(self):
self.size=0
def change_size(self,new):
self.size=new
change_size.modifies = 'size'
print(A.change_size.modifies) # prints size
A more universal solution with a help decorator.
from functools import wraps
def attributes(**attrs):
def decorator(f):
#wraps(f)
def wrapper(*args, **kwargs):
return f(*args, **kwargs)
for attr_name, attr_value in attrs.items():
setattr(wrapper, attr_name, attr_value)
return wrapper
return decorator
and rewrite you class as
class A:
def __init__(self):
self.size = 0
#attributes(modifies='size')
def change_size(self, new):
self.size = new

Design Pattern to merge two implementations into one class

I can't figure out the correct way to model this problem.
Here I give you a minimalistic version of my code:
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
class AreaCalculator():
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getArea(self):
pass
def compute(self):
self.getArea()
class PerimeterCalculator():
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getPerimeter(self):
pass
def compute(self):
self.getPerimeter()
class TriangleAreaCalculator(AreaCalculator):
def __init__(self):
AreaCalculator.__init__(self)
def getArea(self):
return area
class TrianglePerimeterCalculator(PerimeterCalculator):
def __init__(self):
PerimeterCalculator.__init__(self)
def getPerimeter(self):
return perimeter
a = TriangleAreaCalculator()
b = TrianglePerimeterCalculator()
Is there an elegant way to merge "TrianglePerimeterCalculator" and "TriangleAreaCalculator" classes into one, but keeping "PerimeterCalculator" and "AreaCalculator" separated?
[edit] As Kyle suggested in the comments, I can create a new class (let's call it "Triangle") that inherits from "PerimeterCalculator" and "AreaCalculator" at the same time, but what I want is to be able to tell a new instance of "Triangle" to behave as "PerimeterCalculator" or "AreaCalculator", but not both at the same time.
I think the "design pattern" you should use is multiple inheritance. Below is a modified version of your code demonstrating how do it (plus a few other changes to make it actually runnable and all classes new-style).
from abc import ABCMeta, abstractmethod
class AreaCalculator(object):
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getArea(self):
pass
def compute(self):
self.getArea()
class PerimeterCalculator(object):
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getPerimeter(self):
pass
def compute(self):
self.getPerimeter()
class TriangleAreaCalculator(AreaCalculator):
def __init__(self):
super(TriangleAreaCalculator, self).__init__()
def getArea(self):
print('TriangleAreaCalculator.getArea() called on instance of {}'.format(
self.__class__.__name__))
# return area
return 13
class TrianglePerimeterCalculator(PerimeterCalculator):
def __init__(self):
super(TrianglePerimeterCalculator, self).__init__()
def getPerimeter(self):
print('TrianglePerimeterCalculator.getPerimeter() called on instance of {}'.format(
self.__class__.__name__))
# return perimeter
return 42
class MergedCalculator(TriangleAreaCalculator, TrianglePerimeterCalculator):
def __init__(self):
super(MergedCalculator, self).__init__()
merged = MergedCalculator()
print('merged.getArea() -> {}'.format(merged.getArea()))
print('merged.getPerimeter() -> {}'.format(merged.getPerimeter()))
Output:
TriangleAreaCalculator.getArea() called on instance of MergedCalculator
merged.getArea() -> 13
TrianglePerimeterCalculator.getPerimeter() called on instance of MergedCalculator
merged.getPerimeter() -> 42
Here's another answer, following the editing and clarification of your question. It allows creation of a single Triangle instance that can behave like either an AreaCalculator or PerimeterCalculator, as needed.
This programming pattern is called "delegation" and is used where the responsibility for implementing a particular operation is handed off to a different object—in this case an internally held instance of some other class. A common way to do this in Python is by overriding the class's default __getattr__() method.
Since you've never responded to the comment under my other answer about exactly what it is that controls which behavior is used, I added a set_behavior() method to allow it to be specified explicitly.
from abc import ABCMeta, abstractmethod
class AreaCalculator:
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getArea(self):
pass
def compute(self):
return self.getArea()
class PerimeterCalculator:
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getPerimeter(self):
pass
def compute(self):
return self.getPerimeter()
class TriangleAreaCalculator(AreaCalculator):
def __init__(self):
super(TriangleAreaCalculator, self).__init__()
def getArea(self):
print('TriangleAreaCalculator.getArea() called')
area = 13
return area
class TrianglePerimeterCalculator(PerimeterCalculator):
def __init__(self):
super(TrianglePerimeterCalculator, self).__init__()
def getPerimeter(self):
print('TrianglePerimeterCalculator.getPerimeter() called')
perimeter = 42
return perimeter
class Triangle:
def __init__(self):
delegate_classes = TriangleAreaCalculator, TrianglePerimeterCalculator
# Map delegate classes to instances of themselves.
self._delegates = {delegate_class: delegate_class()
for delegate_class in delegate_classes}
self.set_behavior(TriangleAreaCalculator) # Set default delegate.
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._behavior, attrname)
def set_behavior(self, delegate_class):
try:
self._behavior = self._delegates[delegate_class]
except KeyError:
raise TypeError("{} isn't a valid {} behavior delegate class"
.format(delegate_class, self.__class__.__name__))
if __name__ == '__main__':
triangle = Triangle()
# Uses instance's default behavior.
print('triangle.compute() -> {}'.format(triangle.compute()))
triangle.set_behavior(TrianglePerimeterCalculator) # Change behavior.
print('triangle.compute() -> {}'.format(triangle.compute()))
Output:
TriangleAreaCalculator.getArea() called
triangle.compute() -> 13
TrianglePerimeterCalculator.getPerimeter() called
triangle.compute() -> 42
I figured it out myself, with inspiration on the commentas/answers of Kyle and martineau.
I can create a merged class "Triangle" as follows:
class Triangle():
def __init__(self):
pass
def getTriangleArea(self):
print 'Triangle area'
def getTrianglePerimeter(self):
print 'Triangle perimeter'
And then modify TriangleAreaCalculator and TrianglePerimeterCalculator as follows:
class TriangleAreaCalculator(AreaCalculator, Triangle):
def __init__(self):
TriangleCalculator.__init__(self)
AreaCalculator.__init__(self)
def getArea(self):
super(TriangleAreaCalculator, self).getTriangleArea()
class TrianglePerimeterCalculator(PerimeterCalculator, Triangle):
def __init__(self):
TriangleCalculator.__init__(self)
PerimeterCalculator.__init__(self)
def getPerimeter(self):
super(TrianglePerimeterCalculator, self).getTrianglePerimeter()
This way, I can create a new Triangle-like instance that behaves as "PerimeterCalculator" or "AreaCalculator" (but not both at the same time):
a = TriangleAreaCalculator()
b = TrianglePerimeterCalculator()
a.compute() # correctly prints "Triangle area"
b.compute() # correctly prints "Triangle perimeter"

How to make this code work in python 2

class Event(metaclass=ABCMeta):
def __init__(self):
self.type = self.get_full_type()
#classmethod
def get_full_type(cls):
return None
def as_dict(self):
return self.__dict__
class BaseEvent(Event, metaclass=ABCMeta):
SUB_TYPE = ''
#classmethod
def get_base_type(cls):
return super().get_full_type()
#classmethod
def get_full_type(cls):
base_type = cls.get_base_type()
if base_type:
return '.'.join([base_type, cls.SUB_TYPE])
else:
return cls.SUB_TYPE
Here you can see my attempt to make class that represents some abstract event. What is crucial here is the ability to distinguish event types. So every event has it's type and it's base type. Full type is base type + subtype.
This gives the ability to define new event type like this
class MockEvent(BaseEvent):
SUB_TYPE = 'mock'
def __init__(self, some_object):
super(self.__class__, self).__init__()
self.some_object = some_object
So the full type is mirroring the class hierarchy ClassA.ClassB.ClassC etc. I think you get the point.
Unfortunately this is not working with python 2
class Event(object):
__metaclass__ = ABCMeta
SUB_TYPE = None
def __init__(self):
self.type = self.get_full_type()
#classmethod
def get_base_type(cls):
return None
#classmethod
def get_full_type(cls):
base_type = cls.get_base_type()
if base_type:
return '.'.join([base_type, cls.SUB_TYPE])
else:
return cls.SUB_TYPE
def as_dict(self):
return self.__dict__
class BaseEvent(Event):
__metaclass__ = ABCMeta
SUB_TYPE = ''
#classmethod
def get_base_type(cls):
return super(cls.__class__, cls).get_full_type()
File "/opt/leos/code/event_service/events/EventBus.py", line 38, in
get_base_type
return super(cls.class, cls).get_full_type()
AttributeError: 'super' object has no attribute 'get_full_type'
How can I make this work?
class Event(object):
__metaclass__ = ABCMeta
def __init__(self):
self.type = self.get_full_type()
#classmethod
def get_full_type(cls):
return None
def as_dict(self):
return self.__dict__
class BaseEvent(Event):
__metaclass__ = ABCMeta
SUB_TYPE = None
#classmethod
def get_full_type(cls):
super_type = cls.get_super_type()
base_type = super_type.get_full_type()
if base_type:
return '.'.join([base_type, cls.SUB_TYPE])
else:
return cls.SUB_TYPE
#classmethod
def get_super_type(cls):
return cls.__base__
I needed to get the base type automatically. Without mentioning current class in super(currectClass, self) So I used cls.base and it's working ok.

Decorate a class in Python by defining the decorator as a class

What is a simple example of decorating a class by defining the decorator as a class?
I'm trying to achieve what has been implemented in Python 2.6 using PEP 3129 except using classes not functions as Bruce Eckel explains here.
The following works:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
def wrappedClass(*args):
return cls(*args)
return type("TestClass", (cls,), dict(newMethod=self.newMethod, classattr=self.arg))
def newMethod(self, value):
return value * 2
#Decorator("decorated class")
class TestClass(object):
def __init__(self):
self.name = "TestClass"
print "init %s"%self.name
def TestMethodInTestClass(self):
print "test method in test class"
def newMethod(self, value):
return value * 3
Except, in the above, wrappedClass is not a class, but a function manipulated to return a class type. I would like to write the same callable as follows:
def __call__(self, cls):
class wrappedClass(cls):
def __init__(self):
... some code here ...
return wrappedClass
How would this be done?
I'm not entirely sure what goes into """... some code here ..."""
If you want to overwrite new_method(), just do it:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
class Wrapped(cls):
classattr = self.arg
def new_method(self, value):
return value * 2
return Wrapped
#Decorator("decorated class")
class TestClass(object):
def new_method(self, value):
return value * 3
If you don't want to alter __init__(), you don't need to overwrite it.
After this, the class NormalClass becomes a ClassWrapper instance:
def decorator(decor_arg):
class ClassWrapper:
def __init__(self, cls):
self.other_class = cls
def __call__(self,*cls_ars):
other = self.other_class(*cls_ars)
other.field += decor_arg
return other
return ClassWrapper
#decorator(" is now decorated.")
class NormalClass:
def __init__(self, name):
self.field = name
def __repr__(self):
return str(self.field)
Test:
if __name__ == "__main__":
A = NormalClass('A');
B = NormalClass('B');
print A
print B
print NormalClass.__class__
Output:
A is now decorated. <br>
B is now decorated. <br>
\__main__.classWrapper

Categories