Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Generic constructors and duplication of internal Python logic

Reply
Thread Tools

Generic constructors and duplication of internal Python logic

 
 
Peter Otten
Guest
Posts: n/a
 
      04-23-2004
Peter Otten wrote:

> But will I stop trying to come up with something better? no way. Here's my
> next try, and I'm likely to present something completely different again
> if you don't like it - not sure if that's a promise or a threat


A threat.

def setLocals(d, selfName="self"):
self = d.pop(selfName)
for n, v in d.iteritems():
setattr(self, n, v)

class Demo(object):
def __init__(self, foo, bar, baz=2, bang=3):
setLocals(locals())


Peter
 
Reply With Quote
 
 
 
 
John J. Lee
Guest
Posts: n/a
 
      04-24-2004
Peter Otten <(E-Mail Removed)> writes:

> Peter Otten wrote:
>
> > But will I stop trying to come up with something better? no way. Here's my
> > next try, and I'm likely to present something completely different again
> > if you don't like it - not sure if that's a promise or a threat

>
> A threat.
>
> def setLocals(d, selfName="self"):
> self = d.pop(selfName)
> for n, v in d.iteritems():
> setattr(self, n, v)
>
> class Demo(object):
> def __init__(self, foo, bar, baz=2, bang=3):
> setLocals(locals())


Perfect! About a hundred times better than my solution. Maybe this
should be a Python Cookbook entry?


John
 
Reply With Quote
 
 
 
 
Sebastien de Menten
Guest
Posts: n/a
 
      04-28-2004
Here is a metaclass for uber-lazy user

Concretely, at the creation of the class it takes the source of the
__init__ function and add, at the first line of __init__, the line
that sets the attributes :
> self.foo, self.bar, self.baz, self.optional1, self.optional2 =
> foo, bar, baz, optional1, optional2



Nothing is done for *args or **kwargs but they could also be assigned
to some attributes of the class (like self.args and self.kwargs ?).
Moreover, for really lazy users, the line for calling the __init__ of
the father of the class (if necessary)
> super(Father, self).__init__()

could also be dynamically added



#----------------------------------------------------
import inspect,re

class autoArgInit(type):
"""
Replace any occurence of xxx in the class by a col version and a
row version and yyy by its complementary row/col
"""
def __new__(cls,classname,bases,classdict):
# get the __init__ function
function_object = classdict["__init__"]

# get the source of the function
function_source = inspect.getsource(function_object)

# detect indentation of the function definition and remove it
such that def __init__ is at beginning of line
indentation_level = re.match("( *)def
(.*)\(",function_source).groups()[0]
function_source =
re.sub("^"+indentation_level,"",function_source)
function_source =
re.sub("\n"+indentation_level,"\n",function_source )

# split the lines to add new lines easely
function_lines = function_source.split("\n")

# detect indentation inside the function
indentation =
re.match("(\s*)\S*",function_lines[1]).groups()[0]

# take argument list without self
args = inspect.getargspec(function_object)[0][1:]

# create the line for assignment
assign_code = indentation + ", ".join(map(lambda s:
"self.%s"%(s),args)) + " = " + ", ".join(args)

# insert it in the code
function_lines.insert(1,assign_code)

# join the code again
new_function_source = "\n".join(function_lines)

# evaluate it and replace the __init__ definition in classdict
exec new_function_source in function_object.func_globals,
classdict

return type.__new__(cls,classname,bases,classdict)

class test(object):
__metaclass__ = autoArgInit
def __init__(self, baz, top, foo=3, r = 5, *args, **kwargs):
assert self.baz == baz
assert self.top == top
assert self.foo == foo
assert self.r == r

test(3,4,6)
#----------------------------------------------------


Seb






http://www.velocityreviews.com/forums/(E-Mail Removed) (John J. Lee) wrote in message news:<(E-Mail Removed)>...
> This is one of those things that I can't quite believe I've never
> needed to do before.
>
> I've got a set classes, each of which has a set of attributes that all
> behave very similarly. So, I have a class attribute (Blah.attr_spec
> below), which is used by a mixin class to implement various methods
> that would otherwise be highly repetitious across these classes. I'd
> like to do the same for the constructor, to avoid this kind of
> nonsense:
>
> class Blah(NamesMixin):
> attr_spec = ["foo", "bar", "baz",
> ("optional1", None), ("optional2", None)]
> def __init__(self, foo, bar, baz,
> optional1=None, optional2=None):
> self.foo, self.bar, self.baz = \
> foo, bar, baz
> self.optional1, self.optional2 = \
> optional1, optional2
>
> So, I wrote a mixin class whose __init__ looks at the attr_spec
> attribute, and uses args and kwds (below) to assign attributes in the
> same sort of way as the special-case code above:
>
> class ArgsMixin:
> def __init__(self, *args, **kwds):
> # set attributes based on arguments passed in, as done
> # manually in Blah.__init__, above
> ... lots of logic already present in Python goes here...
>
> That immediately leads to duplication of Python's internal logic: I
> have to check things like:
>
> -are there too many positional arguments?
> -any unexpected keyword arguments?
> -multiple keyword arguments?
> -any duplication between positional and keyword arguments?
>
> etc.
>
> Surely there's some easy way of making use of Python's internal logic
> here? For some reason, I can't see how. Can anybody see a way?
>
>
> John

 
Reply With Quote
 
Michele Simionato
Guest
Posts: n/a
 
      04-28-2004
(E-Mail Removed) (Sebastien de Menten) wrote in message news:<(E-Mail Removed). com>...
> Here is a metaclass for uber-lazy user
>
> Concretely, at the creation of the class it takes the source of the
> __init__ function and add, at the first line of __init__, the line
> that sets the attributes :
> > self.foo, self.bar, self.baz, self.optional1, self.optional2 =
> > foo, bar, baz, optional1, optional2

>


Unfortunately this approach does not work if the source is not available
(this happens when you are in the interpreter, or when you only have a .pyc
file). I was playing this kind of tricks some time ago, then I decided that
it was best to switch to Lisp/Scheme for this kind of stuff


Michele Simionato
 
Reply With Quote
 
Sebastien de Menten
Guest
Posts: n/a
 
      04-29-2004
> > Here is a metaclass for uber-lazy user
> >
> > Concretely, at the creation of the class it takes the source of the
> > __init__ function and add, at the first line of __init__, the line
> > that sets the attributes :
> > > self.foo, self.bar, self.baz, self.optional1, self.optional2 =
> > > foo, bar, baz, optional1, optional2

> >

>
> Unfortunately this approach does not work if the source is not available
> (this happens when you are in the interpreter, or when you only have a .pyc
> file). I was playing this kind of tricks some time ago, then I decided that
> it was best to switch to Lisp/Scheme for this kind of stuff
>
>
> Michele Simionato


I agree that it is quite low-level. However, 1) I think people are
"very" rarely creationg new classes directly in the interpreter (it's
a pain!) 2) I don't get the point about the .pyc (the metaclass is in
the pyc ? the class is in the pyc ?)
About the List/scheme option, it would be definitely way easier to do
it with macros in those languages but, hey, if i'm working with
python, i need a solutioon in python, don't I ?

Seb
 
Reply With Quote
 
Michele Simionato
Guest
Posts: n/a
 
      04-29-2004
(E-Mail Removed) (Sebastien de Menten) wrote in message news:<(E-Mail Removed) om>...
> 2) I don't get the point about the .pyc


inspect.getsource look at the .py file; in some situations (i.e. trying to
obfuscate code) you may want to ship the .pyc file only; so inspect.getsource
cannot work (unless you decompile the .pyc file and restore .py).

For instance try

$ cat example.py
import inspect,sys

print inspect.getsource(sys.modules["__main__" ])

run it and then remove example.py.

Also, the approach breaks down if the code is executed dynamically;
for instance C-c C-c in emacs would not work.


Michele Simionato
 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      04-29-2004
John J. Lee wrote:

>> Peter Otten wrote:


>> def setLocals(d, selfName="self"):
>> self = d.pop(selfName)
>> for n, v in d.iteritems():
>> setattr(self, n, v)
>>
>> class Demo(object):
>> def __init__(self, foo, bar, baz=2, bang=3):
>> setLocals(locals())

>
> Perfect! About a hundred times better than my solution. Maybe this
> should be a Python Cookbook entry?


Did that:

http://aspn.activestate.com/ASPN/Coo.../Recipe/280381

Peter
 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      04-29-2004
Michele Simionato wrote:

> (E-Mail Removed) (Sebastien de Menten) wrote in message
> news:<(E-Mail Removed). com>...
>> Here is a metaclass for uber-lazy user
>>
>> Concretely, at the creation of the class it takes the source of the
>> __init__ function and add, at the first line of __init__, the line
>> that sets the attributes :
>> > self.foo, self.bar, self.baz, self.optional1, self.optional2 =
>> > foo, bar, baz, optional1, optional2

>>

>
> Unfortunately this approach does not work if the source is not available
> (this happens when you are in the interpreter, or when you only have a
> .pyc file). I was playing this kind of tricks some time ago, then I
> decided that it was best to switch to Lisp/Scheme for this kind of stuff
>


Here's a variant that operates on the byte code:

import opcode

class List(list):
def ensure(self, value):
try:
return self.index(value)
except ValueError:
self.append(value)
return len(self)-1

class Recorder(object):
def __init__(self, code):
self.func_code = code
self._code = map(ord, code.co_code)[:-4]
self._names = List(code.co_names)

def __getattr__(self, name):
opc = opcode.opmap[name.upper()]
def record(self, arg=None):
# XXX limit name resolution/addition to the proper opcodes
if isinstance(arg, str):
arg = self._names.ensure(arg)
self._code.append(opc)
if arg is not None:
self._code.append(arg & 0xff)
self._code.append(arg >>
setattr(self.__class__, name, record)
return getattr(self, name)

def code(self):
return ''.join(map(chr, self._code))
def names(self):
return tuple(self._names)

def autoinit(f):
co = f.func_code

r = Recorder(co)
for i in range(1, co.co_argcount):
r.load_fast(i)
r.load_fast(0) # self
r.store_attr(co.co_varnames[i])
r.load_const(0) # None
r.return_value()

new_names = r.names()
new_code = r.code()

codeobj = type(co)(co.co_argcount, co.co_nlocals, co.co_stacksize,
co.co_flags, new_code, co.co_consts, new_names,
co.co_varnames, co.co_filename, co.co_name,
co.co_firstlineno, co.co_lnotab, co.co_freevars,
co.co_cellvars)
return type(f)(codeobj, f.func_globals, f.func_name, f.func_defaults,
f.func_closure)

class AutoInit(type):
def __new__(cls, classname, bases, classdict):
classdict["__init__"] = autoinit(classdict["__init__"])
return type.__new__(cls, classname, bases, classdict)

class Demo(object):
__metaclass__ = AutoInit
def __init__(self, baz, top, foo=3, r=None):
if r is None:
r = ["default"]
foo *= 2
baz *= 3
helper = 42 #ignored

def __str__(self):
return ("Demo(baz=%(baz)r, top=%(top)r, foo=%(foo)r, r=%(r)r)"
% self.__dict__)


if __name__ == "__main__":
print Demo(1, 2)
print Demo(10, 20, 30, r=["other"])
print Demo(100, foo="other", top=200)

I guess that was just a complicated way to fail the sanity check

Peter

 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      04-29-2004
Turns out it has already been done with more magic (no explicit locals()
call) in http://aspn.activestate.com/ASPN/Coo.../Recipe/157572

Peter


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Python Logic Map/Logic Flow Chart. (Example Provided) spike Python 8 02-09-2010 12:31 PM
Is the possible to have all the public constructors of the publicbase class as the constructors of a derived class? Peng Yu C++ 5 09-19-2008 10:19 AM
compiler synthesized constructors/copy constructors/assignment operators Jess C++ 5 06-07-2007 11:09 AM
Copy constructors, de/constructors and reference counts Jeremy Smith C++ 2 08-02-2006 11:25 PM
Constructors that call other Constructors Dave Rudolf C++ 12 02-06-2004 03:26 PM



Advertisments