extending method descriptors

M

Michael Sliczniak

Suppose I have this:

Python 2.5.1 (r251:54863, Feb 6 2009, 19:02:12)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information..... __slots__ = ('x', 'y')
....
So I am using descriptors (and I want to). I also would like to have
methods A.x.foo(), A.x.bar(), A.y.foo(), and A.y.bar() and my idea was
to extend member_descriptor, but it seems that I cannot:
.... def foo():
.... return 1
....
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
type 'member_descriptor' is not an acceptable base type

Is there some way, outside of using C, to be able to do what I want.
Yes I want a.x and b.x to be different, but type(a).x.foo(), type
(b).x.foo(), and A.x.foo() should all be the same. I have tried other
approaches and get exceptions of one flavor or another with everything
I have tried.

Thanks,
mzs
 
P

Peter Otten

Michael said:
Suppose I have this:

Python 2.5.1 (r251:54863, Feb 6 2009, 19:02:12)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.... __slots__ = ('x', 'y')
...
So I am using descriptors (and I want to). I also would like to have
methods A.x.foo(), A.x.bar(), A.y.foo(), and A.y.bar() and my idea was
to extend member_descriptor, but it seems that I cannot:
... def foo():
... return 1
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
type 'member_descriptor' is not an acceptable base type

Is there some way, outside of using C, to be able to do what I want.
Yes I want a.x and b.x to be different, but type(a).x.foo(), type
(b).x.foo(), and A.x.foo() should all be the same. I have tried other
approaches and get exceptions of one flavor or another with everything
I have tried.

If you define an attribute with the same name in both the class and its
instances the instance attribute just hides the class attribute:
.... def foo(self): return "yadda"
........ def __init__(self, x):
.... self.x = x
.... x = X()
....('foo', 'bar', 'yadda', 'yadda')

This is probably not what you expected. So what are you really trying to
achieve?

Peter
 
C

Carl Banks

Suppose I have this:

Python 2.5.1 (r251:54863, Feb  6 2009, 19:02:12)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.>>> class A(object):

...     __slots__ = ('x', 'y')
...

So I am using descriptors (and I want to). I also would like to have
methods A.x.foo(), A.x.bar(), A.y.foo(), and A.y.bar() and my idea was
to extend member_descriptor, but it seems that I cannot:

<type 'member_descriptor'>>>> class my_descriptor(type(A.x)):

...     def foo():
...             return 1
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    type 'member_descriptor' is not an acceptable base type


The question isn't too clear, but I can explain this error message.

A Python type defined in C must have Py_TP_BASETYPE set in its
tp_flags field, otherwise subclassing it isn't happening.

If you want such functionality, I believe it would be easiest have to
implement a MemberDescriptorWrapper class in Python that delegates to
the actual member_descriptor. You would use it something like this:

class A(object):
__slots__ = ['_x_internal','_y_internal']
x = MemberDescriptorWrapper('_x_internal')
y = MemberDescriptorWrapper('_y_internal')

MemberDescriptorWrapper class would have to implement __get__,
__set__, and __del__ methods and have them call the corresponding
methods on the slot; details are left as an exercise.


Carl Banks
 
M

Michael Sliczniak

Thank you for the very good reply. In fact delegating is the approach
that works. The main thing to notice is that for an uninstantiated
class the first arg to __get__ is None:

class desc(object):
__slots__ = ('x')

def __init__(self, desc):
self.x = desc

def __get__(self, a, b):
#print 'desc get', `self`, `a`, `b`

if a == None:
return self

return self.x.__get__(a)

def __set__(self, a, b):
#print 'desc set', `self`, `a`, `b`

self.x.__set__(a, b)

def foo(self):
return 'foo'

def bar(self):
return 'bar'

class A(object):
__slots__ = ('x', 'y')
def __init__(self, *args):
for i in xrange(len(args)):
setattr(self, A.__slots__, args)

a = A(0, 1)
b = A(2, 3)

print a.x, a.y, b.x, b.y

x = A.x
dx = desc(x)
A.x = dx

y = A.y
dy = desc(y)
A.y = dy

print type(a).x.foo()
print type(a).x.bar()
print type(a).y.foo()
print type(a).y.bar()
print type(b).x.foo()
print type(b).x.bar()
print type(b).y.foo()
print type(b).y.bar()

print a.x, a.y, b.x, b.y

a.x = -1
a.y = -2
b.x = -3
b.y = -4

print a.x, a.y, b.x, b.y

A.x = x

print a.x, a.y, b.x, b.y

This produces this output:

0 1 2 3
foo
bar
foo
bar
foo
bar
foo
bar
0 1 2 3
-1 -2 -3 -4
-1 -2 -3 -4

The manner in which __get__ has to delegate is not pleasant compared
to if you could simply derive a new class from method_descriptor with
the foo and bar methods though, oh well.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,738
Latest member
JinaMacvit

Latest Threads

Top