So .. here's another class / meta patch. This one combines the "best of the best" from all the previous approaches.
- In python code, you can write really clean class interfaces (like in the python style patch). - You also get a getmeta / setmeta function which you can use to change the "class" of an object. Or even change the parent class of a class. Or whatever. - You can change methods on a class "real-time" and the objects will "reflect" those changes since methods are looked-up at request. - Memory use is reduced for objects with dozens of methods as these methods aren't all created upon instantiation of an object. - Speed increase is only 10%, which is quite good. - Internally dicts can be in any of 3 states: "default" which will check its meta on a get. "object" which will check its metas do various meta actions for you and will return found functions as methods. "raw" which ignores its meta. (There might be some bugs in my differentiation of "object" vs "default" .. these will have to be fixed.)
Feedback requested before I commit this. I'm thinking this one is looking pretty good ...
I've patched the hole I alluded to in the previous post ... I think the three "kinds" of dicts are now properly distinct.
Allefant - take a good look at this patch, I think it does everything you want, cleanly and quickly.
-Phil
--- On Tue, 6/10/08, Phil Hassey <philhas...@yahoo.com> wrote: From: Phil Hassey <philhas...@yahoo.com> Subject: [tinypy] Final meta patch To: tinypy@googlegroups.com Date: Tuesday, June 10, 2008, 6:49 PM
Hey,
So .. here's another class / meta patch. This one combines the "best of the best" from all the previous approaches.
- In python code, you can write really clean class interfaces (like in the python style patch). - You also get a getmeta / setmeta function which you can use to change the "class" of an object. Or even change the parent class of a class. Or whatever. - You can change methods on a class "real-time" and the objects will "reflect" those changes since methods are looked-up at request. - Memory use is reduced for objects with dozens of methods as these methods aren't all created upon instantiation of an object. - Speed increase is only 10%, which is quite good. - Internally dicts can be in any of 3 states: "default" which will check its meta on a get. "object" which will check its metas do various meta actions for you and will return found functions as methods. "raw" which ignores its meta. (There might be some bugs in my differentiation of "object" vs "default" .. these will have to be fixed.)
Feedback requested before I commit this. I'm thinking this one is looking pretty good ...
-Phil
Index: tinypy/ops.c =================================================================== --- tinypy/ops.c (revision 49) +++ tinypy/ops.c (working copy) @@ -1,13 +1,3 @@ -#define TP_META_BEGIN(self,name) \ - if (self.dict.dtype && self.dict.val->meta.type != TP_NONE) { \ - int n = _tp_dict_find(tp,self.dict.val->meta.dict.val,tp_string(name)); \ - if (n != -1) { \ - tp_obj meta = self.dict.val->meta.dict.val->items[n].val; - -#define TP_META_END \ - } \ - } - tp_obj tp_str(TP,tp_obj self) { int type = self.type; if (type == TP_STRING) { return self; } @@ -80,8 +70,9 @@ tp_obj r; if (type == TP_DICT) { TP_META_BEGIN(self,"__get__"); - return tp_call(tp,meta,tp_params_v(tp,2,self,k)); + return tp_call(tp,meta,tp_params_v(tp,1,k)); TP_META_END; + if (self.dict.dtype && _tp_lookup(tp,self,k,&r)) { return r; } return _tp_dict_get(tp,self.dict.val,k,"tp_get"); } else if (type == TP_LIST) { if (k.type == TP_NUMBER) { @@ -176,7 +167,7 @@
- #test that you can make a callable meta object + #various class construct use tests t_render(""" -class TestMeta: +class C: + def __init__(self,data): self.data = data + def print(self): print(self.data) +C("OK").print() +""" +,"OK") + + t_render(""" +class X: + pass +y = X() +print("OK") +""","OK") + + t_render(""" +class X: pass +def test(): y = X() +test() +print("OK") +""","OK") + + t_render(["class X: pass\ndef test(): y = X()","import tmp1\ntmp1.test();print('OK')"],"OK") + + t_render(""" +class A: + def __init__(self): + self.a = 'O' + self.b = 'x' + def test(self): + print("KO") +class B(A): + def __init__(self): + A.__init__(self) + self.b = 'K' + def test(self): + print(self.a+self.b) +B().test() +""","OK") + + t_render(""" +class A: + def test(self): + print(self) +A.test("OK") +""","OK") + + + #test that you can make a callable object + t_render(""" +class Test: + def __init__(self,v): + self.value = v def __call__(self): - self = getraw(self) print(self.value)
-class Test: - def __init__(self,value): - self.value = value - setmeta(self,TestMeta) - x = Test('OK') x() ""","OK")
+ #test that you can use a __get__ + t_render(""" +class Test: + def __get__(self,k): + return k+"K" +x = Test() +print(x.O) +""","OK") + #test that you can use __set__ + t_render(""" +class Test: + def __set__(self,k,v): + getraw(self)[k] = "O"+v +x = Test() +x.v = "K" +print(x.v) +""","OK") + #test that exceptions are cleared after they are caught #and not repeated t_render(""" @@ -845,6 +838,35 @@ pass ""","OK")
+ #check that missing attributes throw an error + t_render(""" +class A: pass +try: + A().x +except: + print('OK') +""","OK") + + #check that a changed attribute gets changed + t_render(""" +class A: + def x(self): pass +a = A() +a.x = "OK" +print(a.x) +""","OK") + + #test that you can use a __get__ gets inherited + t_render(""" +class A: + def __get__(self,k): + return k+"K" +class B(A): + pass +x = B() +print(x.O) +""","OK") + ########################################################################### #####
--- On Tue, 6/10/08, Phil Hassey <philhas...@yahoo.com> wrote: From: Phil Hassey <philhas...@yahoo.com> Subject: [tinypy] Re: Final meta patch To: tinypy@googlegroups.com Date: Tuesday, June 10, 2008, 8:47 PM
I've patched the hole I alluded to in the previous post ... I think the three "kinds" of dicts are now properly distinct.
Allefant - take a good look at this patch, I think it does everything you want, cleanly and quickly.
-Phil
--- On Tue, 6/10/08, Phil Hassey <philhas...@yahoo.com> wrote: From: Phil Hassey <philhas...@yahoo.com> Subject: [tinypy] Final meta patch To: tinypy@googlegroups.com Date: Tuesday, June 10, 2008, 6:49 PM
Hey,
So .. here's another class / meta patch. This one combines the "best of the best" from all the previous approaches.
- In python code, you can write really clean class interfaces (like in the python style patch). - You also get a getmeta / setmeta function which you can use to change the "class" of an object. Or even change the parent class of a class. Or whatever. - You can change methods on a class "real-time" and the objects will "reflect" those changes since methods are looked-up at request. - Memory use is reduced for objects with dozens of methods as these methods aren't all created upon instantiation of an object. - Speed increase is only 10%, which is quite good. - Internally dicts can be in any of 3 states: "default" which will check its meta on a get. "object" which will check its metas do various meta actions for you and will return found functions as methods. "raw" which ignores its meta. (There might be some bugs in my differentiation of "object" vs "default" .. these will have to be fixed.)
Feedback requested before I commit this. I'm thinking this one is looking pretty good ...
-Phil
Index: tinypy/ops.c =================================================================== --- tinypy/ops.c (revision 49) +++ tinypy/ops.c (working copy) @@ -1,13 +1,3 @@ -#define TP_META_BEGIN(self,name) \ - if (self.dict.dtype && self.dict.val->meta.type != TP_NONE) { \ - int n = _tp_dict_find(tp,self.dict.val->meta.dict.val,tp_string(name)); \ - if (n != -1) { \ - tp_obj meta = self.dict.val->meta.dict.val->items[n].val; - -#define TP_META_END \ - } \ - } - tp_obj tp_str(TP,tp_obj self) { int type = self.type; if (type == TP_STRING) { return self; } @@ -80,8 +70,9 @@ tp_obj r; if (type == TP_DICT) { TP_META_BEGIN(self,"__get__"); - return tp_call(tp,meta,tp_params_v(tp,2,self,k)); + return tp_call(tp,meta,tp_params_v(tp,1,k)); TP_META_END; + if (self.dict.dtype && _tp_lookup(tp,self,k,&r)) { return r; } return _tp_dict_get(tp,self.dict.val,k,"tp_get"); } else if (type == TP_LIST) { if (k.type == TP_NUMBER) { @@ -176,7 +167,7 @@
- #test that you can make a callable meta object + #various class construct use tests t_render(""" -class TestMeta: +class C: + def __init__(self,data): self.data = data + def print(self): print(self.data) +C("OK").print() +""" +,"OK") + + t_render(""" +class X: + pass +y = X() +print("OK") +""","OK") + + t_render(""" +class X: pass +def test(): y = X() +test() +print("OK") +""","OK") + + t_render(["class X: pass\ndef test(): y = X()","import tmp1\ntmp1.test();print('OK')"],"OK") + + t_render(""" +class A: + def __init__(self): + self.a = 'O' + self.b = 'x' + def test(self): + print("KO") +class B(A): + def __init__(self): + A.__init__(self) + self.b = 'K' + def test(self): + print(self.a+self.b) +B().test() +""","OK") + + t_render(""" +class A: + def test(self): + print(self) +A.test("OK") +""","OK") + + + #test that you can make a callable object + t_render(""" +class Test: + def __init__(self,v): + self.value = v def __call__(self): - self = getraw(self) print(self.value)
-class Test: - def __init__(self,value): - self.value = value - setmeta(self,TestMeta) - x = Test('OK') x() ""","OK")
+ #test that you can use a __get__ + t_render(""" +class Test: + def __get__(self,k): + return k+"K" +x = Test() +print(x.O) +""","OK") + #test that you can use __set__ + t_render(""" +class Test: + def __set__(self,k,v): + getraw(self)[k] = "O"+v +x = Test() +x.v = "K" +print(x.v) +""","OK") + #test that exceptions are cleared after they are caught #and not repeated t_render(""" @@ -845,6 +838,35 @@ pass ""","OK")
+ #check that missing attributes throw an error + t_render(""" +class A: pass +try: + A().x +except: + print('OK') +""","OK") + + #check that a changed attribute gets changed + t_render(""" +class A: + def x(self): pass +a = A() +a.x = "OK" +print(a.x) +""","OK") + + #test that you can use a __get__ gets inherited + t_render(""" +class A: + def
...
On Jun 11, 4:47 am, Phil Hassey <philhas...@yahoo.com> wrote:
> I've patched the hole I alluded to in the previous post ... I think the three "kinds" of dicts are now properly distinct.
> Allefant - take a good look at this patch, I think it does everything you want, cleanly and quickly.
Yes, this is just what I wanted :) I.e., Python style run-time
lookup. But I think, I shouldn't be the one to approve it or not,
others here most likely know a lot more about Python and scripting
languages. But then, I guess being closer to Python generally will be
considered good :)
Btw., What did you change to have it work faster? Looking at the
patch, there's apparently no trick like caching anything involved this
time..
About the setmeta, do I understand this right..
- for a class, it will set the parent class
- for an object, it will set the class
?
In which case, it seems to be an ideal solution. I think I remember
that someone already hinted about a solution like this at some point,
when asking about the difference of __class__ and __parent__...
Hmn, maybe you could file a complaint with google about how the google groups web interface works? Or subscribe as a mailing list?
In my previous python style patch, the class / parent were actually members of the dictionary, so all lookups took 2-3x as many checks to resolve. By having a "meta" variable in the dict structure, it cuts out a lot of nonsense.
-Phil
--- On Thu, 6/12/08, allefant <allef...@gmail.com> wrote: From: allefant <allef...@gmail.com> Subject: [tinypy] Re: Final meta patch To: "tinypy" <tinypy@googlegroups.com> Date: Thursday, June 12, 2008, 10:24 AM
On Jun 11, 4:47 am, Phil Hassey <philhas...@yahoo.com> wrote: > I've patched the hole I alluded to in the previous post ...&nbsp; I think the three "kinds" of dicts are now properly distinct. > > Allefant - take a good look at this patch, I think it does everything you want, cleanly and quickly. >
Yes, this is just what I wanted :) I.e., Python style run-time lookup. But I think, I shouldn't be the one to approve it or not, others here most likely know a lot more about Python and scripting languages. But then, I guess being closer to Python generally will be considered good :)
Btw., What did you change to have it work faster? Looking at the patch, there's apparently no trick like caching anything involved this time..
About the setmeta, do I understand this right.. - for a class, it will set the parent class - for an object, it will set the class ?
In which case, it seems to be an ideal solution. I think I remember that someone already hinted about a solution like this at some point, when asking about the difference of __class__ and __parent__...
> Hmn, maybe you could file a complaint with google about how the google groups web interface works? Or subscribe as a mailing list?
> In my previous python style patch, the class / parent were actually members of the dictionary, so all lookups took 2-3x as many checks to resolve. By having a "meta" variable in the dict structure, it cuts out a lot of nonsense.