Paul Rubin wrote: > > Let's see, say I'm a bank manager, and I want to close my cash vault > at 5pm today and set its time lock so it can't be opened until 9am > tomorrow, including by me. Is that "handcuffs"? It's normal > procedure at any bank, for good reason. It's not necessarily some > distrustful policy that the bank CEO set to keep me from robbing the > bank. I might have set the policy myself. Java lets me do something > similar with instance variables. Why is it somehow an advantage for > Python to withhold such a capability?
If so, you would probably be the type of person that also likes static typing, type safety and variable declaration, right? You like your language with extra baggages to improve some safety concerns, which most Python programmers don't seem to need. > def countdown(): > n = 3 > while n > 0: > yield n > g = countdown() > print g.next() # 3 > print g.next() # 2 > > where's the Python feature that lets me modify g's internal value of n > at this point? You missed the point. I have, for fun, built a GUI application in Python, while the program is running. I just kept on adding more and more code to it. This, while the Python program is running. I was able to change the GUI's look-and-feel, add more buttons, menus, all while the programming is running. I was able to change the class definition, preserve the previous object state variables. For that, you already have event-based program and can use module reload and some metaclass tricks to automatically relink your objects to new classes. Sure, Python is not as friendly as Lisp/Scheme for interactive programming, but you can still do a lot. > [Other stuff incomprehensible and snipped]. Sigh, I gave you the keywords: containment and aggregation. There are two ways of enhancing functionality from an existing object/class. One way is by inheritance, that's aggregation. Another way is by containment, that means that instead of inheriting, you add the additional features as an object contained in the new object. Vault encapsulation is one way to do OOP. But by no means it is the only way. The whole access level thing (the "private" keyword) is not an essential part of OOP. The concept of a "private" namespace is not necessary for OOP. Just because you learned OOP from one particular school of thought, does not mean that that's the only way. Let us call your OOP "school A". Another way of OOP is to accept by default that everything in the class hierarchy is inheritable. And Python is by no means the only language that does that. Now, obviously in this type of OOP you can run into name collision. But if you actually follow this other school of thought, you would organize your variables differently. Let us call this type of OOP "school B". Let me be more clear: when you have variables that are so, so, so private that no one else should touch, from school B's point of view, those variables do not belong to the object. They belong to another object. Let us say there is a financial instrument that pays some fixed coupon interest: class Bond: volatility = None interest = None def __init__(self): self.volatility = 0.3 # volatility from credit risk self.interest = 0.4 Now, you have another instrument that pays variable interest: class VariableInterestBond(Bond): volatility = None # this one collides with the base class def __init__(self): Bond.__init__(self) self.volatility = 0.2 # volatility for variable interest def calculate(self): interest = self.get_variable_interest() ... def get_variable_interest(self): return self.interest * (1 + random.random()*self.volatility) ... In this example, the subclass's "volatility" meant something else but collides with the base class's "volatility". It should have been a private variable, but now it accidentally overwrote an existing variable. We are trying to combine two "features" in the hierarchy tree: Bond | | +----- Variable Interest | | Variable-Interest Bond There are two ways to add the "variable interest" feature to the "bond" object. One way is by aggregation (inheritance), which is shown above. Another way is by containment. If the subsclass's "volatility" should be private and encapsulated from the main class hierarchy (i.e. Bond-like objects), then from school B's point of view, it does not belong to the bond object. It would be better to encapsulate it into another object. class VariableInterest: volatility = None def __init__(self, interest): self.interest = interest self.volatility = 0.2 def get_variable_interest(self): return self.interest * (1 + random.random()*self.volatility) class VariableInterestBond(Bond): variable_interest_calculator = None def __init__(self): Bond.__init__(self) self.variable_interest_calculator = VariableInterest(self.interest) def calculate(self): interest = self.variable_interest_calculator.get_variable_interest() ... That's one way of implementing it. Notice the name collision is gone. It is gone because you have properly organized your concepts and your objects. If you start to follow more along school B's way of thinking, you actually can eliminate the subclass, too. class Bond: ... def set_variable_rate(self): self.variable_interest_calculator = VariableInterest(self.interest) ... That is, by moving the features from aggregation into containment, often the depth of class inheritance tree can be shortened, too. -------------------------------- So, if you really think along the lines of school B, the chance of name collision reduces greatly. Because in your mind the state variables of the objects are more important/meaningful than in the case of school A. In school A you would often clutter the object's namespace with auxiliary variables. In school B you move the clutter to somewhere else. As for Python's double leading underscores, it's just a short-term "hardware" solution to name collision. In my opinion, a "software" code refactoring is the long-term solution. -- http://mail.python.org/mailman/listinfo/python-list