
# #################################################
# Short hand to managing Managed attributes
# 
#    How to make "shares" into a MANAGED attribute


# NOTE: The new setter method is also called when there is 
# an assignment within the class, including inside the __init__() method.

class Stock:
    def __init__(self, name, shares, price):
        self.name = name
        self.shares = shares    # CALLS the @shares.setter method !!!
        self.price = price

    @property			# Define "shares" are a "property" function !
    def shares(self):           # Meaning: obj.share <=> obj.share()
        return(self._shares)

    # Function that layers the "set" operation 
    @shares.setter
    def shares(self, value):
        if not isinstance(value, int):
            raise TypeError("Value is not an integer")
        self._shares = value

s = Stock('IBM', 50, 91.1)	## Access __init__( )

# Trouble:
#
# We can update shares with an INTEGER:
#
s.shares = 100			# Correct
print(s.__dict__)

# We MUST use  set_shares( ) to update  _shares:
#
s.shares = [1, 0, 0]			# Raises exception !!!
print(s.__dict__)

# Attribute access now triggers the getter and setter methods 
# under @property and @shares.setter.





