On Monday, July 29, 2013 1:43:39 AM UTC-4, Steven D'Aprano wrote: > On Sun, 28 Jul 2013 18:38:10 -0700, Tim O'Callaghan wrote: > > > > > Hi, > > > > > > I hope that this hasn't been asked for the millionth time, so my > > > apologies if it has. > > [...] > > > I hope that this was clear enough, apologies if it wasn't. > > > > Clear as mud. > Alright, let me see if I can clear this up. And by the way, thanks for chiming in on this. It's appreciated.
I have a 3rd party api definition that I'm using to generate python classes from so that I can access this api using python. The api definition currently changes, so what I've done is saved a local copy of the html (the api definition from the vendor) and screen scraped the categories, and methods for this api. So when the api changes, I can just get a fresh definition from the vendors site, parse the html, and generate the classes again. This screen scape is saved to a json object in the format I originally mentioned: returned from json from screen scrape: {"Whatever": [{"method1": "Some Default", "async": "True"},{"method2": "Some Other Default", "async": "True"}]} **note: "method1": "Some Default" "method2": "Some Other Default" are just dummy values. ** > > > > It's late(ish), I'm tired and borderline frustrated :) > > > > I see your smiley, but perhaps you would get better results by waiting > > until you can make a better post. > > > > It *really* helps if you post actual "working" (even if "working" means > > "fails in the way I said"), *short*, *simple* code. Often you'll find > > that trying to simplify the problem gives you the insight to solve the > > problem yourself. > > > > http://www.sscce.org/ > I would normally post 'working' code, but I'm really not there yet. All I've been doing up until this point is basically proof of concept. > > > I'm going to try to guess what you're attempting, but I may get it > > completely wrong. Sorry if I do, but hopefully you'll get some insight > > even from my misunderstandings. > > > > > > > I have a base class (BaseClass - we'll call it for this example) with an > > > http call that i would like to inherit into a dynamic class at runtime. > > > We'll call that method in BaseClass; 'request'. > > > > If I read this literally, you want to do this: > > > > class BaseClass(DynamicParent): > > def request(self): > > ... > > > > except that DynamicParent isn't known until runtime. Am I close? The parent is the stable/static part. That has the http request method to communicate with the vendor api. The request method in BaseClass creates the request(signs and authorizes the call). Right now the BaseClass.request("api_call_to_vendor") will work and return data, but again I would like to separate each api category into classes with the appropriate methods. > > Obviously the above syntax won't work, but you can use a factory: > > > > def make_baseclass(parent): > > class BaseClass(parent): > > def request(self): > > ... > > return BaseClass > > > > class Spam: ... > > > > BaseClass = make_baseclass(Spam) > > > > > > Or you can use the type() constructor directly: > > > > BaseClass = type('BaseClass', (Spam,), dict_of_methods_and_stuff) > This, on the surface is what I'm after. Except the 'dict_of_methods_and_stuff' call would be something like this: Vendor_API_Cateogry = type("Vendor_API_Category", (BaseClass,), {"api_call_from_vendors_category": "call_supers_request_method_passing_in_vendor_call"}) resulting in a call something like this: vendor_category = Vendor_API_Category() vendor_category.api_call_from_vendors_category() > > which is probably far less convenient. But all this assumes I read you > > literally, and reading on, I don't think that's what you are after. > > > > > > > I have a dictionary(json) of key (class name): value(method) that I > > > would like to create inheriting this 'request' method from the > > > BaseClass. So the derived class would look something like this > > > > > > definition in json: > > > {"Whatever": [{"method1": "Some Default", "async": True},{"method2": > > > "Some Other Default", "async": True}]} > > > > > > Pure gobbledygook to me. I don't understand what you're talking about, > > how does a derived class turn into JSON? (Could be worse, it could be > > XML.) Is BaseClass the "derived class", or are you talking about > > inheriting from BaseClass? What's "Some Default"? It looks like a string, > > and it certainly isn't a valid method name, not with a space in it. > > > > Where did async and method2 come from? How do these things relate to > > "request" you talk about above? I think you're too close to the problem > > and don't realise that others don't sharing your knowledge of the problem. Agreed. > > But, moving along, if I've understood you correctly, I don't think > > inheritance is the right solution here. I think that composition or > > delegation may be better. Something like this: > > > > class BaseClass: > > def request(self): > > # Delegate to a method set dynamically, on the instance. > > return self.some_method() > > > > > > a = BaseClass() > > a.some_method = one_thing.method1 > > > > b = BaseClass() > > b.some_method = another_thing.method2 > > > > > > Now you have instance a.request calling method1 of another object, and > > b.request calling method2 of a different object. Does that solve your > > problem, or am I on a wild-goose chase? > > > > > > > Ideally I'd like the class def to look something like this if i were to > > > type it out by hand > > > > > > [excuse the indents] > > > > > > class Whatever(BaseClass): > > > def method1(self): > > > stupid_data = super(Whatever, self).request("method1") > > > return stupid_data > > > > > > def method2(self): > > > stupid_data = super(Whatever, self).request("method1") > > > return stupid_data > > > > > > Since request is not the method you are currently in, the above is > > equivalent to: > > > > class Whatever(BaseClass): > > def method1(self): > > return self.request("method1") > > def method2(self): > > return self.request("method2") > > > > where "request" is defined by BaseClass, and assuming you don't override > > it in the subclass. (I assume "method1" in your code above was a typo.) > > > > > > > Now, I've been trying to do this using the python cli, with out success. > > > > > > So, attempting this at runtime I get a plethora of wonderful errors that > > > I suspect has broken my brain. > > > > > > Here is what i've tried: > > > > > > # trying with just an empty object of type BaseClass > > > obj = type("Object", (BaseClass,), {}) > > > > "obj" here is a class called "Object", inheriting from BaseClass. It > > overrides no methods. Why does it exist? It doesn't do anything. > > 'obj" was just an example. I was trying to inherit from BaseClass (attempting to get the BaseClass.request method into 'obj') and then try and extend that? > > > > whatever = type("WhatEver", (obj,), {"method1": super(WhatEver, > > > self).request("method1")}) > > > > > > but when i try this I get 'NameError: name 'self' is not defined' > > > > This is what you are doing: > > > > * look up names WhatEver and self, in the current scope (i.e. the scope > > where you are running this call to type, which is likely the global > > scope); > > > > * pass those objects (if they exist!) to super(), right now; > > > > * on the object returned, look up the attribute "request", right now; > > > > * call that object with string argument "method1", right now; > > > > * take the result of that sequences of calls, let's call it x, and set it > > in a new dict with key "method1"; > > > > * and then create a new type using dict {'method1': x}. > > > > > > Notice that everything you do is done immediately. You should be getting > > a NameError for WhatEver too, but since you are not, I can only imagine > > that you have already (accidentally?) defined something, anything, with > > that name. > > > > What you actually want (but probably not what you *need*, see above about > > delegation) is to delay evaluation of super() and subsequent calls until > > after your WhatEver class is created and initialised and the method1 > > *method* is called. That means putting it all those calls inside a > > function object, for later use, instead of executing them directly *right > > now*: > > > > def method1(self): > > return super(WhatEver, self).request("method1") > > > > WhatEver = type("WhatEver", (BaseClass,), {"method1": method1}) > > > > You could alternatively use lambda: > > > > WhatEver = type("WhatEver", (BaseClass,), > > {"method1": > > lambda self: super(WhatEver, self).request("method1") > > } > > ) > > > > > > Note that the class name inside super() *must* match the global name the > > class is assigned to, "WhatEver". The internal class __name__ -- the > > first argument to type() -- doesn't have to match, but it should, to > > avoid confusion. > > > > The above should fix the NameError you are getting, and it might even > > work, but I think delegation is a better solution to this problem. > > Was any of this clear? And Steven, thank you again. > > > > -- > > Steven -- http://mail.python.org/mailman/listinfo/python-list