[Tutor] Descriptors api doubt

alan.gauld@bt.com alan.gauld@bt.com
Tue, 15 Jan 2002 11:14:01 -0000


> For example, when you write obj.x, the steps that Python 
> actually performs are:
> 
> descriptor = obj.__class__.x
> descriptor.__get__(obj)

And so it does heres an example, with my comments:

>>> class C:
...    name = ''  ## defie a class member
...    def __init__(self,n): self.name = n  
## assign to it making an instance specific version

...
>>> class D:
...    def __init__(self,n): self.name = n

## D only has an instance version no class member
...
>>> c = C('foo')
>>> d = D('bar')
>>> c.__class__.name
''
## The class version is unchanged

>>> c.name
'foo'
## there's the instance version

>>> d.__class__.name
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: class D has no attribute 'name'

## like it says D has no class member

>>> d.name
'bar'

## but it does have an instance one.

> This is what i did:
> 
> class test(object):
> 	def __init__(self):
> 		self.name = "python"

So the nself.name doesn't come into effect till after 
you create an instance. The class object has no name 
attribute.

> >>> t = test()
> >>> desc = t.__class__.name
> Traceback (most recent call last):
>   File "<pyshell#15>", line 1, in ?
>     ob = t.__class__.name
> AttributeError: type object 'test' has no attribute 'name'

Just like I said...

> if python does that internally, then why am in not able 
> to access the descriptor corresponding to "name". 

You can as I shoiwed but thats how Python accesses *class* 
variables not *instance* variables - they are not the same.

When you define a class any attributes outside the methods 
are class members and shared by all instances.

When an instance assigns to a class member name python 
creates a new instance specific member which is accessible 
to that instance only.
class X:
   foo = 0
   def setFoo(self,x): self.foo = x

a = X()
b = X()  # two instances

print a.foo, b.foo     	### => 0 0
X.foo = 7   		# change shared value
print a.foo, b.foo     	### => 7 7
a.setFoo(5)  		# create new copy in 'a' only
print a.foo, b.foo  	### => 5 7   ie b still using shared one
X.foo = 42   		# change shared one
print a.foo, b.foo  	### => 5 42   change only seen by b

HTH,

Alan G.