0

I am trying to creating a class Customer which creates it's attribute from sqlalchemy query object.

data = {'Name':'John Doe','Age':67} #in the real code , data is a not a dictionary but an object. 

class Customer:
   
    def __init__(self,data) -> None:
        assert type(data) == Customers
        for key in data.keys():
            exec(f"self.__{key[1:] if key.startswith('_') else key} = data['{key}']",{'self':self,'data':data})
    
    @property
    def name(self):
        return self.__Name
data['bank'] = green
person = Customer(data)

I was able to access the Customer attributes as a public attribute :

print(person.__Name) it prints out John Doe

but when i try to access the attribute through the name method, like this : print(person.name) it raises an error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\HP\PyProject\FlaskProject\green\bank\modelx.py", line 66, in name
    return self.__Name
AttributeError: 'Customer' object has no attribute '_Customer__Name'

How can i make the class atributes created in the exec function act as a private attribute of the class and not a public attribute.

Adétóbi
  • 1
  • 1
  • Name mangling doesn't work when setting via `exec`, it's done at compile time and thus the `self.__...` must literally exist in the source code, not cobbled together at runtime. – deceze Nov 22 '22 at 15:27

1 Answers1

0

You don' need exec here. Use setattr.

for key in data:
    setattr(self, key[1:] if key.startswith('_') else key, data[key])

Also, use isinstance, not type comparison.

assert isinstance(data, Customers)

though in your example, data is not an instance of Customers; it's an ordinary dict passed to Customer.__init__.

chepner
  • 497,756
  • 71
  • 530
  • 681