__slots__ conflicts with class variable

I am a newbie to python and just started this week, and for the life of me I do not know where is the conflict: ValueError: ‘toEmailAddress’ in slots conflicts with class variable

Any help is great appreciated !

    import sendgrid
    import os
    from sendgrid.helpers.mail import Mail, Email, To, Content
    
    class SendNotification:
        __slots__ = ("toEmailAddress", "fromEmailAddress")
        
        def __init__(self, toEmailAddress, fromEmailAddress):
            self.toEmailAddress = toEmailAddress
            self.fromEmailAddress = fromEmailAddress
          
        @property
        def toEmailAddress(self):
            return self._toEmailAddress
        
        @toEmailAddress.setter
        def toEmailAddress(self, toEmailAddress):
            self._toEmailAddress = toEmailAddress
    
        @property
        def fromEmailAddress(self):
            return self.fromEmailAddress
    
        @fromEmailAddress.setter
        def fromEmailAddress(self, fromEmailAddress):
            self._fromEmailAddress = fromEmailAddress
    
        def SendEmail(self):
            apiKey = 'abc123'
            sg = sendgrid.SendGridAPIClient(apiKey)
            from_email = Email("myName@myCompany.com")  # Change to your verified sender
            to_email = To("yourName@yourCompany.com")  # Change to your recipient
            subject = "Sending with SendGrid is Fun"
            content = Content("text/plain", "this is from allan")
            mail = Mail(from_email, to_email, subject, content)
    
            # Get a JSON-ready representation of the Mail object
            mail_json = mail.get()
    
            try:
            # Send an HTTP POST request to /mail/send
             response = sg.client.mail.send.post(request_body=mail_json)
             print(response.status_code)
             print(response.headers)
    
            except Exception as e:
             print(e)
             
    #_____________
    
    sendAlert = SendNotification("myName@myCompany.com", "yourName@yourCompany.com")
    
    sendAlert.SendEmail()
    ```

The fix is to specify the slot variables as the private variables you want to use, instead of the properties you want to expose:

    class SendNotification:
        __slots__ = ("_toEmailAddress", "_fromEmailAddress")
        
        def __init__(self, toEmailAddress, fromEmailAddress):
            self._toEmailAddress = toEmailAddress
            self._fromEmailAddress = fromEmailAddress

That said, if your getters and setters are just read/writing underscored variables with no validation or transformation, you might as well just get rid of them and use standard attributes:

    class SendNotification:
        __slots__ = ("toEmailAddress", "fromEmailAddress")
        
        def __init__(self, toEmailAddress, fromEmailAddress):
            self.toEmailAddress = toEmailAddress
            self.fromEmailAddress = fromEmailAddress

        def SendEmail(self):
            apiKey = 'abc123'
            ...
1 Like

Thanks for the quick reply @effigies

That fixed the issue, and I was able to confirmed.

    sendAlert = SendNotification("myName@myCompany.com", "yourName@yourCompany.com")
    print(sendAlert._toEmailAddress)
    sendAlert._toEmailAddress = "2"
    print(sendAlert._toEmailAddress)
    ````

I assumed the setter was needed to update the class attribute.

Question: Since Python does not have class accessors (public, private, protected, internal), I think I saw this somewhere – the way to denote that an attribute is ‘private’ is like this: _attributeName

Or, the way to make an attribute private is with the property getter and setter and raised an ValueError?

Yes, you can make a variable “private” by convention by prefixing with an underscore. But that is just a way of you indicating that a downstream user can’t expect that variable to always exist or behave the way they expect. They can still set sendAlert._toEmailAddress = "whatever". Using properties allows you to let them set sendAlert.toEmailAddress = "whatever" and you can check that "whatever" is a valid email address before storing it. Or you could choose not to set a setter, which would be a way of adding friction to modifying an object in-place instead of through a standard method. If your getter/setter are just pass-through, they’re needless indirection.

If you’re used to private/public/protected, those concepts just don’t exist in Python, and they don’t really need to. I would suggest starting “radically open” and let your attributes be set by callers. As you find a need to validate/modify inputs, then you can start shifting things into properties, but I think you’ll find you don’t need it as much as you might think, if you’re coming from a language where private variables are standard.

1 Like