Graham wrote: > Many thanks your explaination cleared up many of the questions I had. > I know think i can understand the purpose, regardless of my opinion, i > do however think that one should be able to assign the value in the > same way it is accessed.
You mean, like this? # access the value of an instance attribute: x = instance.name # assign the value of an instance attribute: x = instance.name No, of course that's not what you *meant* -- but it is what you said. So what do you actually mean? I'll assume you mean something like "the scoping rules for access and assignment should be the same". The problem is, they are. When you access an attribute, Python looks in the instance scope, and if that lookup fails, it looks in the class scope. When you assign an attribute, at least ignoring the complication of slots, Python uses the same scoping rules: assign to the instance scope, WHICH ALWAYS SUCCEEDS, and if it fails, assign to the class scope. In fact, Python may not even bother to include code to push the assignment to the class, since the assignment at the instance level is guaranteed to either succeed, or fail in such a way that you have no choice but to raise an exception. But conceptually, assignment and access are using the same scoping rules. (Again, I stress that new-style classes with slots may do things differently.) Now that I've demonstrated that what you want is not either "assignment and access should be the same", nor "the scoping rules should be the same", can you describe precisely what you do want? See below for further details. > Given your previous example: > >>class Counter(object): >> "A mutable counter." >> # implementation elided > > >>class A(object): >> instance_count = Counter() >> def __init__(self): >> self.instance_count.increment() > > > > if you changed > >>class A(object): >> instance_count = Counter() >> def __init__(self): >> self.instance_count.increment() > > > to > > >>class A(object): >> instance_count = 0 >> def __init__(self): >> self.instance_count = self.instance_count + 1 > > > It would not work as planned. Why not? For starters, what is the plan? Do you want all instances of class A to share state? Are all instances of Counter supposed to share state? Depending on whether you want the answers of those to be Yes or No, you would pick one technique or the other. Sometimes you want to increment mutables in place, and sometimes you don't. But I would suggest very strongly that in general, you usually don't want instances to share state. > I understand all the reasons why this > occurs, but i dont understand why its implemented this way. Because it > acts in a different way than you expect. It seems to me that > self.instance_count should not create a new entry in the __dict__ if a > class variable of that name is already present anywhere in that objects > hierarchy. But that would stop inheritance from working the expected way. In standard OO programming, you expect instances to inherit behaviour from their class (and superclasses) unless over-ridden. This lets you do something like this: class Paper: size = A4 Now all instances of Paper are created with a default size of A4 -- they inherit that size from the class. If you are localising your application for the US market, you simply change the class attribute: Paper.size = USLetter and all the instances that inherit from the class will now reflect the new default. Now suppose you have a specific instance that needs a different paper size: instance = Paper() instance.size = Foolscap What do you expect should happen? Should all Paper instances suddenly be foolscap size, or just the one? If you say "just the one", then you want the current behaviour. If you say "all of them", then you want shared state -- but do you really want all class instances, all the time, to have shared state? You can get ride of that behaviour by getting rid of inheritance, or at least inheritance of non-method attributes. Then you have to write code like this: class PrintableThing: """Prints a Thing object with prefix and suffix. Customize the prefix and suffix by setting the appropriate instance attributes. """ prefix = "START " suffix = " STOP" def __str__(self): try: # access the instance attributes, # if they exist prefix = self.prefix suffix = self.suffix except AttributeError: # fall back to class attributes prefix = self.__class__.prefix suffix = self.__class__.suffix # have you spotted the subtle bug in this code? return prefix + self.thing + suffix instead of: class PrintableThing: def __str__(self): return self.prefix + self.thing + self.suffix Even worse would be the suggestion that Python allowed accessing instance.attribute to refer to either a class or instance attribute, decided at runtime as it does now, but *remembered* which it was so that assignment went back to the same object. That would mean that class attributes would mask instance attributes -- or vice versa, depending on which was created first. I assume that in general, class attributes would be created before instances. If you had a class with a default attribute, like Paper.size above, you couldn't over-write it at the instance level because instance.size would always be masked by class.size. You would need to write code like this: class Paper: default_size = A4 def __init__(self, size=None): self.size = size def print(self): if self.size is None: papersize = self.__class__.default_size else: papersize = self.size do_something(papersize) The standard inheritance model used by Python and all OO languages I know of is, in my opinion, the optimal model. It gives you the most convenient behaviour for the majority of cases, and in those few cases where you want non-standard behaviour (e.g. shared state) it is easy to do with some variant of self.__class__.attribute. -- Steven. -- http://mail.python.org/mailman/listinfo/python-list