title: Restrict creation/setting of an attribute
body: <p>How to restrict the creation of an attribute, outside its class/sub-class?</p>
  
  <pre><code>__all__ = ["Employee","Salary","Wage"]
  ##################################################################################################
  class Person(object):
      def __init__(self,fname,lname,gender):
          self.__setfname(fname) # "We are all adults." vs. "Name mangling."
          self.__setlname(lname)
          self.__setgender(gender)
      def __setfname(self,fname): self.__fname = fname
      def __setlname(self,lname): self.__lname = lname
      def __setgender(self,gender): self.__gender = gender
      def getname(self): return "{} {}".format(self.__fname,self.__lname)
      def getformattedname(self):
          if(self.__gender.lower() == "m"):
              return "Mr. {}".format(self.getname())
          if(self.__gender.lower() == "f"):
              return "Ms. {}".format(self.getname())
          if(self.__gender.lower() == ""):
              return "{}".format(self.getname())
  class Payment(object):
      def __init__(self,amount,currency="INR"): # currency="USD"
          self.__setamount(amount)
          self.__setcurrency(currency)
      def __setamount(self,amount): self.__amount = amount
      def __setcurrency(self,currency): self.__currency = currency
      def getamount(self): return "{}".format(self.__amount)
      def getformattedamount(self): return "{} {}".format(self.getamount(),self.__currency)
  ##################################################################################################
  ##################################################################################################
  class Employee(Person):
      def __init__(self,fname,lname,gender): super(Employee,self).__init__(fname,lname,gender)
      def __str__(self): return self.getformattedname()
  class Salary(Payment):
      def __init__(self,amount,currency="INR"): super(Salary,self).__init__(amount,currency)
      def __str__(self): return self.getformattedamount()
  class Wage(Payment):
      def __init__(self,amount,currency="INR"): super(Wage,self).__init__(amount,currency)
      def __str__(self): return self.getformattedamount()
  ##################################################################################################
  </code></pre>
  
  <hr>
  
  <p>I'm OK with this:</p>
  
  <pre><code>e1._Person__fname = "Spam"
  s1._Payment__amount = "1000000000000000"
  </code></pre>
  
  <p>but the following code creates new attributes:</p>
  
  <pre><code>e1.fname = "New"
  s1.amount = -10
  </code></pre>
  
  <hr>
  
  <pre><code>import re
  from com.example.model import Employee,Salary,Wage
  
  def printzip(l1,l2): print(list(zip([str(e) for e in l1],[str(e) for e in l2])))
  
  (e1,e2) = (Employee("Sandeep","Mehta","m"),Employee("Varsha","Mehta","f"))
  (s1,s2) = (Salary(3000,"USD"),Salary(3000,"USD"))
  
  printzip([e1,e2],[s1,s2])
  e1.fname = "New"
  s1.amount = -3000
  e1._Person__fname = "Spam"
  s1._Payment__amount = "3000000000000000"
  
  for e in enumerate([e for e in dir(e1) if not (re.search(r"^__.*__$",e))]): print(e)
  for e in enumerate([e for e in dir(s1) if not (re.search(r"^__.*__$",e))]): print(e)
  printzip([e1],[s1])
  </code></pre>
  
  <p><img src="https://i.stack.imgur.com/6496W.jpg" alt="Python IDLE"></p>