OK now I'm confused, let me explain how I see things at the moment and
you can correct me...
A class is like a template which combines a complex data type (made from
a combination of other data types) and the methods that operate on that
data type.
You generally don't work with classes directly but you make instances of
them, each instance has it's own internal state and methods, initially
these are the same as the templates but can be changed or overridden
without affecting the state of any other instances you might have.
While the perceived wisdom is that you should encapsulate all the
methods you need to modify your classes' state within the class itself
Python does (for better or worse) permit you to reach inside a class and
futz with it's state directly from outside.
The bits of an instance's state one might futz with (from within or
without) i.e. the primitives that make up the complex object the class
is a representation of, I think of as it's variables.
It would seem from this setattr function that the proper term for these
is 'attributes'. That for many years I have considered pretty much any
named thing that may vary a 'variable' might be at the root of the
problem here as it's a very un-specific term...
So I gather you are saying that the fragments of state within a class Within an instance
are so distinct from ordinary common or garden variables that it is
incorrect to think of them, or describe them, as variables, much like
quarks should not really be regarded as distinct particles, and they
should only be thought of and described as 'attributes' to avoid confusion?
Is this correct enough for me to avoid the aforementioned bug pile?
Yes, I think so.
Also then, what _is_ an "instance variable" ?
Metasyntatic variables:
C - some class
x - some instance
y - the "word" after the dot in the expression: x.y
My working definitions based on my knowledge of Python:
Attribute - y is an attribute of x. Includes instance variables,
properties, and dynamically generated attributes. Since x.y really
ends up doing x.__getattribute__("y") behind the scenes, overriding
__getattribute__ lets you make attribute lookup more dynamic and have
it do interesting things. For example, you could write a class
overriding __getattribute__ so that x.y (for any valid Python name y)
opened a file with the name y and returned a file object for this file
(i.e. x.z returns file("z","w"), x.q returns file("q","w"), etc
without enumerating "q", "z", etc anywhere in the class).
Instance variable - In `x.y`, y is an instance variable of x if it's
stored in x.__dict__ or x.__slots__, it's not a method of x (though it
can be a function), and it's not a property.
Property - y is a property if x.y causes a method call and returns the
result of said method call. Basically, x.y becomes equivalent to x.z()
if y is a property. Properties can also allow `x.y = a` to be
equivalent to `x.z(a)` and `del x.y` to be equivalent to `x.z()`.
Properties are created using the built-in function property()
Class variable - Unless you're using metaclasses, in C.y, y is always
a class variable of C. Thus, methods are technically also class
variables. Using metaclasses, C is both a class itself and an instance
of another class D, in which case the definition of "instance
variable" (interpreted with regards to C being an instance of D)
applies to whether y is a class variable of C or not.
Class method - Created using the built-in function classmethod()
Essentially, attribute lookup is very dynamic in Python, which
complicates things a good bit, so the only thing we know for sure
about x.y is that y is an attribute of x.
Cheers,
Chris