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.
Related
I have a method run() in subclasses, which has an API POST request in each subclass, gets data from the POST request, and assigns an ID from this data to self._id. Now I would like to get a description too. However, description is returned only in the API request self._api_obj.trigger(...) in SubClassB.run, not in the API request self._api_obj.trigger_run(...) in SubClassA.run. For SubclassA I need a separate API request to get the description.
I tried the following, but I don't think it's a good idea to assign 2 attributes in SubClassB.run, but only 1 attribute in SubClassA.run. Right? Since from my understanding, the same method in subclasses should have the same behavior (Just different implementation).
class SuperClass:
def __init__(self):
self._id = None # Assigned in run()
self._description = None
#property
def description(self):
raise NotImplementedError
def run(self, *args):
raise NotImplementedError
#property
def id(self):
return self._id
class SubClassA(SuperClass):
def __init__(self):
super().__init__()
self._api_obj = ApiObj1()
#property
def description(self):
if not self._description:
_result = self._api_obj.get_data()
self._description = _result["description"]
return self._description
def run(self, *args):
_result = self._api_obj.trigger_run(foo="foo")
self._id = _result["RunId"]
class SubClassB(SuperClass):
def __init__(self):
super().__init__()
self._api_obj = ApiObj2()
#property
def description(self):
return self._description
def run(self, *args):
_result = self._api_obj.trigger(foo="foo", bar="bar", arg1="arg1", arg2="arg2")
self._id = _result["data"]["id"]
self._description = _result["data"]["description"]
Is there a better way to add assignment to self._description? Or some other solution to include description?
Here is a solution I thought of: Creating a private method _run(), that will set and return the complete result of the run. The method SubClassB.get_description() will be able to get any required info from it. However, SubClassA.get_description() will get the description from the API.
class SuperClass:
def __init__(self):
self._id = None # Assigned in run()
self._run_result_info = None # Assigned in _run()
def _run(self, *args):
raise NotImplementedError
def run(self):
raise NotImplementedError
def get_description(self):
raise NotImplementedError
#property
def id(self):
return self._id
class SubClassA(SuperClass):
def __init__(self):
super().__init__()
self._api_obj = ApiObj1()
def _run(self):
self._run_result_info = self._api_obj.trigger_run(foo="foo")
return self._run_result_info
def run(self):
_result = self._run()
self._id = _result["RunId"]
def get_description(self):
_result = self._api_obj.get_data()
_description = _result["description"]
return _description
class SubClassB(SuperClass):
def __init__(self):
super().__init__()
self._api_obj = ApiObj2()
def _run(self):
self._run_result_info = self._api_obj.trigger(foo="foo", bar="bar", arg1="arg1", arg2="arg2")
return self._run_result_info
def run(self):
_result = self._run()
self._id = _result["data"]["id"]
def get_description(self):
return self._run_result_info["data"]["description"]
Another option: Not keeping the result of the run, since it's not always needed. Just have a property description that will get the description through an API request only in cases it's needed. It means that we will need an API request in SubClassB to get the description too, instead of having the data available after SubClassB.run, but at least we're not keeping unneeded data, if it's not requested. We keep it only if it's requested.
class SuperClass:
def __init__(self):
self._id = None # Assigned in run()
self._description = None
#property
def description(self):
raise NotImplementedError
def run(self):
raise NotImplementedError
#property
def id(self):
return self._id
class SubClassA(SuperClass):
def __init__(self):
super().__init__()
self._api_obj = ApiObj1()
#property
def description(self):
if not self._description:
_result = self._api_obj.get_data()
self._description = _result["description"]
return self._description
def run(self, *args):
_result = self._api_obj.trigger_run(foo="foo")
self._id = _result["RunId"]
class SubClassB(SuperClass):
def __init__(self):
super().__init__()
self._api_obj = ApiObj2()
#property
def description(self):
if not self._description:
_result = self._api_obj.get_info()
self._description = _result["description"]
return self._description
def run(self, *args):
_result = self._api_obj.trigger(foo="foo", bar="bar", arg1="arg1", arg2="arg2")
self._id = _result["data"]["id"]
I need a Multi-level #property decorator.
I have a base class Base
I have a wrapper class Wrapper
Wrapper wraps Base and when Base is changed, it needs to be reflected to View
I want to ensure that the change is reflected
Example of what I need
class Base:
def __init__(self):
self.attribute = 0
#property
def attribute(self):
return self._attribute
#attribute.setter
def attribute(self, value):
self._attribute = value
class Wrapper:
def __init__(self, view: View, base: Base):
self.base = base
self.view = view
#property
def base.attribute(self):
return self.base.attribute
#base.attribute.setter
def base.attribute(self, value):
self.base.attribute = value
self.view.update(value)
I know I can simply do the following.
def base_attribute(self, value = None):
if value:
self.base.attribute = value
self.view.update(value)
return self.base.attribute
But since I used #property in Base, I wanted to keep that style.
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
How to override an inherited class method, that needs to query for specific properties on the child class?
I'm not sure how to go about this. This is what I've got:
class base_class:
#classmethod
def a_method(cls, something):
return ndb.Query(kind=cls.__name__).fetch(keys_only=True)
#classmethod
def calls_a_method(cls, size=1, soemthing):
entity_keys = cls.a_method(something)
class child_class(base_class):
a_property = ndb.BooleanProperty()
def another_method():
stuff = child_class.calls_a_method() #?
How do I override a_method from the base_class, such that it will also filter out keys where a_property = False for the child_class?
I think that if you break up the query across the methods, you can construct a custom query in the child class:
class base_class:
#classmethod
def a_method(cls, something):
return ndb.Query(kind=cls.__name__)
#classmethod
def calls_a_method(cls, size=1, something):
entity_keys = cls.a_method(something).fetch(keys_only=True)
class child_class(base_class):
a_property = ndb.BooleanProperty()
#classmethod
def another_method(cls):
q = cls.a_method(something).filter(cls.a_property == False)
entity_keys = q.fetch(keys_only=True)
How about something like this?
class base_class(ndb.Model):
#classmethod
def a_method(cls, something):
return cls.Query().fetch(keys_only=True)
#classmethod
def calls_a_method(cls, something):
entity_keys = cls.a_method(something)
class child_class(base_class):
a_property = ndb.BooleanProperty()
#classmethod
def another_method(cls, value):
return cls.calls_a_method(value)
#classmethod
def a_method(cls, something):
return cls.query(cls.a_property==something).fetch(keys_only=True)
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