I created a message class, which stores an arbitrary message like so:
class MessageBase:
"""Wrapper class for messages from different resources"""
def __init__(
self,
subject,
body,
sender,
recipient,
received,
to
):
self.subject = subject
self.body = body
self.sender = sender
self.recipient = recipient
self.received = received
self.to = to
Messages can come from different sources, and I want my class to be flexible with these resources. I want to create such a syntax:
message1 = Message.from_source(source='outlook', raw_outlook_message)
message2 = Message.from_source(source='sendinblue_email', raw_sendinblue_message)
message1.perform_action()
message2.perform_action()
od way to code a class, or whether this goes against some practices.
To achieve this, I created several class methods, and want to map them as such:
self.sources = {
'outlook': self.from_outlook,
'sendinblue_email': self.from_sendinblue_email,
}
@classmethod
def from_source(cls, source_name, *args):
return cls.sources[source_name.lower()](*args)
@classmethod
def from_outlook(cls, raw_message: dict):
return cls(<parse_outlook_message>)
@classmethod
def from_sendinblue_email(cls, raw_message: dict):
return cls(<parse_outlook_message>)
I have one issue with this setup and one concern. The issue is that I cannot access the sources dictionary of self.sources
, and I do not know how to achieve this functionality. The concern is whether this is a go
You want a class attribute that maps strings to class methods.
Since the objects are instances of classmethod
, you can't call them directly in from_source
; you'll have to extract the underlying function
and call it with an explicit class argument.
class MessageBase:
@classmethod
def from_outlook(cls, ...):
...
@classmethod
def from_sendinblue_email(cls, ...):
...
# When this dict is defined, the above are still just names
# in the current namespace, not class attributes.
sources = {
'outlook': from_outlook,
'sendinblue_email': from_sendinblue_email,
}
@classmethod
def from_source(cls, source, ...):
f = cls.sources[source.lower()].__func__
return f(cls, ...)
An alternative is to add the name of the class method to the mapping, and letting from_source
perform attribute look up on the class.
class MessageBase:
@classmethod
def from_outlook(cls, ...):
...
@classmethod
def from_sendinblue_email(cls, ...):
...
# When this dict is defined, the above are still just names
# in the current namespace, not class attributes.
sources = {
'outlook': 'from_outlook',
'sendinblue_email': 'from_sendinblue_email'
}
@classmethod
def from_source(cls, source, ...):
method_name = cls.sources[source.lower()].__func__
return getattr(cls, method_name)(...)