pondering about the essence of types in python

G

gangesmaster

let's start with a question:

==========.... def __init__(self):
.... self.blah=5
........ def __init__(self):
.... z.__init__(self)
....Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in __init__
TypeError: unbound method __init__() must be called with z instance as
first argument (got x instance instead)
==========

and the question is -- WHY?

what is a type? generally speaking, if everything were an object, the
type only defines the MRO (method resolution order) for that object.
x.y first looks at the instance, then the class, then the parent
classes, etc. (this was changed a little in python2.3 to something more
complicated, but it's basically the same).

you can see the mro like this:
==========[<class '__main__.z'>, <class '__main__.y'>, <class '__main__.x'>,
<type 'object'>]
==========

after all, if we stay out of builtin types, all python objects are
dicts, which support chian-lookup according to the mro. and a method is
just a function that takes the instance as a first argument. so why is
all this type hassle necessary?

if we've taken it that far already, then let's really go over the edge.
I WANT TO DERIVE FROM INSTANCES. not only types.

why? i'm the developer of rpyc (http://rpyc.sf.net), and i got a
request from someone to add support for deriving from remote types. the
concrete example he gave was quite silly, but after i thought about it
a little, i said why not try?

a little intro about rpyc: it gives you proxies (instances) to remote
objects, which can be instances, functions, or classes. and that user
wanted to do something like this:

class my_frame(conn.modules.wx.Frame):
...

so the client was actually creates the graphics on the server. not very
usable, but why not? all it means is, when he does "my_frame.xyz",
python should add the remote type to the mro chain. not too bizar.

but __mro__ is a readonly attribute, and deriving from instances is
impossible (conn.modules.wx.Frame is a PROXY to the class)...

and again -- WHY? these all look like INTENTIONAL limitations. someone
went around and added type checks (which are NOT pythonic) into the
cPython implementation. argh. why do that?

so i thought -- let's be nasty. i created a function that creates a
class that wraps an instance. very ugly. small children and peope with
heart problems should close their eyes.

============
def derive_from(obj):
class cls(object):
def __getattr(self, name):
return getattr(obj, name)
return cls

class my_frame(derive_from(conn.modules.wx.Frame)):
....
============

the actual implementation is quite more complex, but that shows the
concept.
so now i'm experimenting with that little shit. but then i came to the
problem that methods check the type of the first argument... ARGH. dont
check types. DONT. the whole point of duck-typing is you DONT CHECK THE
TYPES. you just work with objects, and instead of TypeError you'd get
AttribiuteError, which is much better. AAARRRRRRGGGHH.

python is EVIL at the low level. the high-level is just fine, but when
you try to go under the hood... you better go with an exorcist.



-tomer
 
S

Steve Holden

gangesmaster said:
let's start with a question:

==========

... def __init__(self):
... self.blah=5
...

... def __init__(self):
... z.__init__(self)
...

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 3, in __init__
TypeError: unbound method __init__() must be called with z instance as
first argument (got x instance instead)
==========

and the question is -- WHY?

what is a type? generally speaking, if everything were an object, the
type only defines the MRO (method resolution order) for that object.
x.y first looks at the instance, then the class, then the parent
classes, etc. (this was changed a little in python2.3 to something more
complicated, but it's basically the same).

you can see the mro like this:
==========

[<class '__main__.z'>, <class '__main__.y'>, <class '__main__.x'>,
<type 'object'>]
==========

after all, if we stay out of builtin types, all python objects are
dicts, which support chian-lookup according to the mro. and a method is
just a function that takes the instance as a first argument. so why is
all this type hassle necessary?

if we've taken it that far already, then let's really go over the edge.
I WANT TO DERIVE FROM INSTANCES. not only types.

why? i'm the developer of rpyc (http://rpyc.sf.net), and i got a
request from someone to add support for deriving from remote types. the
concrete example he gave was quite silly, but after i thought about it
a little, i said why not try?

a little intro about rpyc: it gives you proxies (instances) to remote
objects, which can be instances, functions, or classes. and that user
wanted to do something like this:

class my_frame(conn.modules.wx.Frame):
...

so the client was actually creates the graphics on the server. not very
usable, but why not? all it means is, when he does "my_frame.xyz",
python should add the remote type to the mro chain. not too bizar.

but __mro__ is a readonly attribute, and deriving from instances is
impossible (conn.modules.wx.Frame is a PROXY to the class)...

and again -- WHY? these all look like INTENTIONAL limitations. someone
went around and added type checks (which are NOT pythonic) into the
cPython implementation. argh. why do that?

so i thought -- let's be nasty. i created a function that creates a
class that wraps an instance. very ugly. small children and peope with
heart problems should close their eyes.

============
def derive_from(obj):
class cls(object):
def __getattr(self, name):
return getattr(obj, name)
return cls

class my_frame(derive_from(conn.modules.wx.Frame)):
....
============

the actual implementation is quite more complex, but that shows the
concept.
so now i'm experimenting with that little shit. but then i came to the
problem that methods check the type of the first argument... ARGH. dont
check types. DONT. the whole point of duck-typing is you DONT CHECK THE
TYPES. you just work with objects, and instead of TypeError you'd get
AttribiuteError, which is much better. AAARRRRRRGGGHH.

python is EVIL at the low level. the high-level is just fine, but when
you try to go under the hood... you better go with an exorcist.
Take a look at languages like Self. Self was actually the first
prototype-based OO language. You could consider Javascript to be a
prototype-based language as well.

regards
Steve
 
S

Steven Bethard

gangesmaster said:
but __mro__ is a readonly attribute, and deriving from instances is
impossible (conn.modules.wx.Frame is a PROXY to the class)...

Maybe I'm misunderstanding, but why is an instance a proxy to a class?
Why don't you make a class a proxy to the class?

STeVe
 
G

gangesmaster

i dont think it's possible, to create proxy classes, but even if i did,
calling remote methods with a `self` that is not an instance of the
remote class would blow up.


-tomer
 
A

Alan Franzoni

gangesmaster on comp.lang.python said:
TypeError: unbound method __init__() must be called with z instance as
first argument (got x instance instead)
==========

and the question is -- WHY?

I think the answer would be: because it's an instance method. Its
'contract' it's to be bound to an object of a certain class. Would you like
a different behaviour, you could decorate whatever method you need. I.e.,
turn your example into:

class z(object):
@staticmethod
def __init__(self):
self.blah=5

class x(object):
def __init__(self):
z.__init__(self)


y = x()


And this will work as you wish. You could have used classmethod as well
with a properly tuned init, of course.
but __mro__ is a readonly attribute, and deriving from instances is
impossible (conn.modules.wx.Frame is a PROXY to the class)...
and again -- WHY? these all look like INTENTIONAL limitations. someone
went around and added type checks (which are NOT pythonic) into the
cPython implementation. argh. why do that?

I really think this happens because Python was designed to be
casualerror-safe. This approach would probably lead to many programming
errors.

By the way, Python was designed to *discourage* such behaviours, not to
prevent them. By the way, I didn't grasp what you would really like to do.
You're saying you want to derive from instances, but then I see in your
sample code you're creating a *class* derived from an object (I would
expect you would like to derive an instance from an instance, and to
'twist' such new instance methods to your needs, which I think can be done
as well). What's the difference between that and the use of __class__ ?

class z(object):
@staticmethod
def __init__(self):
self.blah=5

@staticmethod
def met_stat(self):
pass

@classmethod
def met_cls(self):
pass

def met_inst(self):
pass



class x(object):
def __init__(self):
z.__init__(self)


y = x()


class q(y.__class__):
pass


r = q()


This work OK to me. Unless you want to do something like making y instance
attributes become q class attributes, or you would like to set y instance
attributes on all q instances, which could require a bit more of code but
surely can be done. This would mix up a bit the class vs instance
behaviour, though, e.g. changing a derived class instance attribute which
is inherited from a parent instance would lead to a global attribute
change, or would 'spawn' a new instance attribute for that particular
instance?
def derive_from(obj):
class cls(object):
def __getattr(self, name):
return getattr(obj, name)
return cls

This seems to work for deriving read-only data from instances (no way to
write back data).
check types. DONT. the whole point of duck-typing is you DONT CHECK THE
TYPES. you just work with objects, and instead of TypeError you'd get
AttribiuteError, which is much better. AAARRRRRRGGGHH.

You don't HAVE TO check types if you don't want. Just use @staticmethod
everywhere in your classes. I mean, a METHOD is supposed to be
class-related, and it's often useful to have it as such, (unexpected errors
and behaviours might rise everywhere if not so), but you're never forced to
use that.


--
Alan Franzoni <[email protected]>
-
Togli .xyz dalla mia email per contattarmi.
Rremove .xyz from my address in order to contact me.
-
GPG Key Fingerprint:
5C77 9DC3 BD5B 3A28 E7BC 921A 0255 42AA FE06 8F3E
 
S

Steven Bethard

gangesmaster said:
i dont think it's possible, to create proxy classes, but even if i did,
calling remote methods with a `self` that is not an instance of the
remote class would blow up.

I don't understand you here. Why can't you just do something like:
.... def __init__(self, name):
.... self.name = name
.... def __repr__(self):
.... return '%s(name=%s)' % (type(self).__name__, self.name)
........ def __init__(self, name):
.... self.remote = RemoteClass(name)
.... def __repr__(self):
.... return repr(self.remote)
....RemoteClass(name=foo)

Note that when I call methods on the remote class, I don't pass them an
instance of the proxy class -- I pass them an instance of the
appropriate, RemoteClass type. Of course my code is simplified because
I'm not actually doing something remote, but assuming things get, say,
pickled and unpickled appropriately, I'm not sure I understand why the
above won't work.

Could you give some more details?

STeVe
 

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

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top