get a self data in a method call

Bengt Richter bokr at oz.net
Mon Dec 23 02:23:15 EST 2002


On Mon, 23 Dec 2002 00:13:28 +0100, polux <polux2001 at wanadoo.fr> wrote:

>I've a class
>
>class MyClass:
>	
>	def __init__(self):
>		self.data = 123
>
>
>now, I want to define a method, which would be like that if it were 
>possible :
>
>	def func(self, data = self.data )
>
>but it doesn't work because python does't know yet what "self" is
>
>
>
>please help
>
Maybe this?
 >>> class MyClass:
 ...     def __init__(self):
 ...         self.data = 123
 ...     def func(self, *data):
 ...         if not data: data = self.data
 ...         else: data = data[0]
 ...         return data
 ...
 >>> mc=MyClass()
 >>> mc.data
 123
 >>> mc.func()
 123
 >>> mc.func(456)
 456
 >>> mc.data
 123
 >>> mc.func()
 123
 >>> mc.func('does that do it?')
 'does that do it?'

Using *data as an arg spec, data becomes () (an empty tuple) if no
args are passed. It's one way to detect no args without checking an arg value,
since values themselves would be data[0], data[1], etc. Another way is to
check if a default arg value is something the caller couldn't normally
specify. A unique value detected for some purpose may be termed a "sentinel."

None is often used as a 'no args' indicator, but unless you know for sure
that that can't be a valid value, it's not a good indicator. The 'is' operator
checks whether its arguments are the same object (not just equivalent ones), so
that is a good way to check whether you got the sentinel. See later example below.

Not answering directly, but you may want to consider
using class data as default also, e.g.:

 >>> class MyClass:
 ...     data = 'class default for "data"'
 ...     def func(self, *data):
 ...         if data: self.data = data[0]
 ...         else: self.data = MyClass.data
 ...
 >>> mc = MyClass()
 >>> mc.data
 'class default for "data"'
 >>> vars(mc)
 {}
I.e., the instance doesn't have a .data attribute yet,
so the search finds the class variable MyClass.data

 >>> mc.func()
This bound self.data, using the default value, since none
was supplied.

 >>> mc.data
 'class default for "data"'
Which data attribute are we looking at, instance or class?

If it's the instance, it will show up with vars(instance), which it does:
 >>> vars(mc)
 {'data': 'class default for "data"'}

 >>> mc.func('a new value for the instance')

Here we see the new instance value:
 >>> vars(mc)
 {'data': 'a new value for the instance'}
 >>> mc.data
 'a new value for the instance'

What happens if we delete the instance attribute?
 >>> del mc.data
 >>> vars(mc)
 {}
That shows it's gone, but now look:

 >>> mc.data
 'class default for "data"'
 
We are finding MyClass.data again ;-)

<you can skip this>
Well, I don't really like referring to SomeClass.anything
from a method within SomeClass. It's an ugly dependency
on a global binding IMO. With new classes there is probably
a way around it. Ok, here's a go at getting around a global binding,
in this case of a sentinel:

 >>> class MyClass(object):
 ...     _sentinel = None
 ...     default = 'A class variable available via any instance'
 ...     class __metaclass__(type):
 ...         def __init__(cls, name, bases, dct):
 ...             def func(self, data=cls._sentinel):
 ...                 if data is cls._sentinel: data = getattr(self,'data','<no data>')
 ...                 return (data, self.default) # or otherwise use them
 ...             setattr(cls, 'func', func)
 ...             def __init__(self, data=cls._sentinel):
 ...                 if data is cls._sentinel: return # don't set it if not specified
 ...                 self.data = data + ' ['+ self.default[0] +']' # silly mod using class data
 ...             setattr(cls, '__init__', __init__)
 ...     def ordinary(self): return 'ordinary, returning self.data if avail: ' + self.data
 ...
 >>> mc=MyClass()
 >>> mc.func()
 ('<no data>', 'A class variable available via any instance')
 >>> vars(mc)
 {}
 >>> mc.func('func arg')
 ('func arg', 'A class variable available via any instance')
 >>> mc.ordinary()
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "<stdin>", line 14, in ordinary
 AttributeError: 'MyClass' object has no attribute 'data'
 ^^^^^^^^^^^^^^---(as expected here, but recall that func returned '<no data>')

 >>> mc.data
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 AttributeError: 'MyClass' object has no attribute 'data'
 >>> mc=MyClass('specified')
 >>> mc.func()
 ('specified [A]', 'A class variable available via any instance')
 >>> vars(mc)
 {'data': 'specified [A]'}
 >>> mc.func('func arg')
 ('func arg', 'A class variable available via any instance')
 >>> mc.data
 'specified [A]'
 >>> mc.ordinary()
 'ordinary, returning self.data if avail: specified [A]' 
 </you can skip this>

Seems to work. I put in def ordinary(): just to show that the
metaclass thing doesn't mean everything has to go under that.

Regards,
Bengt Richter



More information about the Python-list mailing list