Re: setattr question
TP wrote: > Hi everybody, > > I try to make a "link" (or shortcut, if you want) so that len(b_instance) > computes in fact len(a) (see the code below). I could write a method > __len__ to b, but I wonder if it is possible to make it with a > setattr/getattr trick, as I do below. > > Thanks in advance, > > Julien > > ## > class b( object ): > > def __init__( self ): > > super( b, self ).__init__() > > a = [5,4,7] > b_instance = b() > > setattr( b_instance, "__len__", getattr( a, "__len__") ) Invoking setattr() or getattr() with a constant name is bogus. The above can be written as b_instance.__len__ = a.__len__ > print len( a ) > print id( a.__len__ ) > print hasattr( b_instance, "__len__" ) > print id( b.__len__ ) > print len( b_instance ) > > > I obtain: > $ p test_setattr.py > 3 > 3083822540 > True > Traceback (most recent call last): > File "test_setattr.py", line 14, in > print id( b.__len__ ) > AttributeError: type object 'b' has no attribute '__len__' > Command failure: error 1 ! > __special__ methods in newstyle classes are looked up in the class, not the instance: >>> class B(object): pass ... >>> items = [1,2,3] >>> b = B() >>> len(b) Traceback (most recent call last): File "", line 1, in TypeError: object of type 'B' has no len() >>> B.__len__ = items.__len__ >>> len(b) 3 Now that doesn't make much sense because all instances of B now share the same length. If you want a useful per-instance length function you have to delegate: >>> class B(object): ... def __len__(self): return self._len() ... >>> a = B() >>> b = B() >>> a._len = [1,2,3].__len__ >>> b._len = [].__len__ >>> len(a), len(b) (3, 0) Peter -- http://mail.python.org/mailman/listinfo/python-list
setattr question
Hi everybody, I try to make a "link" (or shortcut, if you want) so that len(b_instance) computes in fact len(a) (see the code below). I could write a method __len__ to b, but I wonder if it is possible to make it with a setattr/getattr trick, as I do below. Thanks in advance, Julien ## class b( object ): def __init__( self ): super( b, self ).__init__() a = [5,4,7] b_instance = b() setattr( b_instance, "__len__", getattr( a, "__len__") ) print len( a ) print id( a.__len__ ) print hasattr( b_instance, "__len__" ) print id( b.__len__ ) print len( b_instance ) I obtain: $ p test_setattr.py 3 3083822540 True Traceback (most recent call last): File "test_setattr.py", line 14, in print id( b.__len__ ) AttributeError: type object 'b' has no attribute '__len__' Command failure: error 1 ! -- python -c "print ''.join([chr(154 - ord(c)) for c in '*9(9&(18%.\ 9&1+,\'Z4(55l4('])" "When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong." (first law of AC Clarke) -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
bruno at modulix wrote: > Gerard Flanagan wrote: > > The functions were kind of related > > and meaningless outside the module they were declared - > > FWIW (and from the snippet I saw), these functions are useless even in > the module !-) > ok, ok... :-) > Unless you want to dynamically choose the concrete class at runtime > based on platform/settings/phase of the moon/whatnot (which seems not to > be te case in the snippet you posted), you don't need these functions, > just instanciating the concrete class is enough. Remember that Python > classes *are* factory already - and that you can freely replace a class > by any callable returning an instance, ie: > > == before refactoring, directly instanciating concrete class == > # myhtmlmodule.py > class HtmlElement(tag, *args, **kw): > # code here > > # myclientmodule.py > from myhtmlmodule import HtmlElement > ul = HtmlElement('ul') > > > == after refactoring, using a factory function == > # myhtmlmodule.py > class _HtmlElement1(tag, *args, **kw): > # code here > > class _HtmlElement2(tag, *args, **kw): > # other code here > > # yes, it's now a function... > def HtmlElement(tag, *args, **kw): > if phase_of_the_moon(): > klass = _HtmlElement1 > else: > klass = _HtmlElement2 > return klass(tag, *args, **kw) > > # myclientmodule.py > # well... nothing changed here !-) > from myhtmlmodule import HtmlElement > ul = HtmlElement('ul') > ah, I'm getting it. > > > I've ditched the factory class in any case: > > > > http://gflanagan.net/site/python/htmlbuilder/HtmlBuilder.py > > (FWIW) > > Seems mostly clean. May I suggest a couple small corrections/improvements ? > > 1/ potential bugfix: > try: > from tidy import parseString > except ImportError: > def parseString(text): > # woops, this function is supposed to return something > #pass > return text > > 2/ safer and cleaner > class HtmlPage(HtmlElement): > # removed class vars, > # replaced with default in __init__ > def __init__(self, title, **kw): > self.title = title > self.stylesheets = kw.get('stylesheets', []) > self.doctype = kw.get('doctype', HTML4_STRICT) > That's much better - thanks very much for taking the time, I'm a little bit wiser! regards Gerard > -- > bruno desthuilliers > python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for > p in '[EMAIL PROTECTED]'.split('@')])" -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
Gerard Flanagan wrote: > bruno at modulix wrote: > [...] > >>I don't know this HtmlElement class, nor where it comes from. >>'to_string()' (or is it toString() ?) is javaish. The pythonic idiom for >>this is implementing the __str__() method and calling str(obj) on the >>obj (which will call obj.__str__()). Hence my (bad) guess about you >>being a Javaer. >> > > > I've made this change, thanks. ( I had a year with C# so maybe that's > why I'm so idiomatically-challenged ! ) Well, C# being somewhat inspired by Java... > >>Not the HtmlElement class, but the HtmlBuilder one. Here again, a class >>defining only staticmethods is a pretty javaish idiom - in Python, we >>just use good old functions !-) (in a separate module if you want a >>separate namespace). >> > > But it's personal preference, no? Well, in Python, there are a lot of things that can be done the way you like it, but are better done the idiomatic way. Python relies quite a lot on conventions and idioms where other languages try to inforce strict rules. > The functions were kind of related > and meaningless outside the module they were declared - FWIW (and from the snippet I saw), these functions are useless even in the module !-) Unless you want to dynamically choose the concrete class at runtime based on platform/settings/phase of the moon/whatnot (which seems not to be te case in the snippet you posted), you don't need these functions, just instanciating the concrete class is enough. Remember that Python classes *are* factory already - and that you can freely replace a class by any callable returning an instance, ie: == before refactoring, directly instanciating concrete class == # myhtmlmodule.py class HtmlElement(tag, *args, **kw): # code here # myclientmodule.py from myhtmlmodule import HtmlElement ul = HtmlElement('ul') == after refactoring, using a factory function == # myhtmlmodule.py class _HtmlElement1(tag, *args, **kw): # code here class _HtmlElement2(tag, *args, **kw): # other code here # yes, it's now a function... def HtmlElement(tag, *args, **kw): if phase_of_the_moon(): klass = _HtmlElement1 else: klass = _HtmlElement2 return klass(tag, *args, **kw) # myclientmodule.py # well... nothing changed here !-) from myhtmlmodule import HtmlElement ul = HtmlElement('ul') You could also do the trick with metaclass black magic, but what, KISS... > but I'll take > it on board, anyway. > > [...] > > >>My experience is that it's far easier to start simple and add >>flexibility where needed than to simplify useless complexity. KISS, >>yagni and all that kind of things... >> > > yagni - I'd never heard that one! You Aint Gonna Need It. Code not written is the best code, so don't write code "just in case". Python is usually dynamic enough to make refactoring easy (cf example above) > I've ditched the factory class in any case: > > http://gflanagan.net/site/python/htmlbuilder/HtmlBuilder.py > (FWIW) Seems mostly clean. May I suggest a couple small corrections/improvements ? 1/ potential bugfix: try: from tidy import parseString except ImportError: def parseString(text): # woops, this function is supposed to return something #pass return text 2/ safer and cleaner class HtmlPage(HtmlElement): # removed class vars, # replaced with default in __init__ def __init__(self, title, **kw): self.title = title self.stylesheets = kw.get('stylesheets', []) self.doctype = kw.get('doctype', HTML4_STRICT) >>BTW, there's also a french speaking python newsgroup at fr.comp.lang.py. > > I wasn't aware of that, I'll have a lurk! see you there !-) >>-- >>bruno desthuilliers >>python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for >>p in '[EMAIL PROTECTED]'.split('@')])" > > -- bruno desthuilliers python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for p in '[EMAIL PROTECTED]'.split('@')])" -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
bruno at modulix wrote: [...] > > I don't know this HtmlElement class, nor where it comes from. > 'to_string()' (or is it toString() ?) is javaish. The pythonic idiom for > this is implementing the __str__() method and calling str(obj) on the > obj (which will call obj.__str__()). Hence my (bad) guess about you > being a Javaer. > I've made this change, thanks. ( I had a year with C# so maybe that's why I'm so idiomatically-challenged ! ) > Not the HtmlElement class, but the HtmlBuilder one. Here again, a class > defining only staticmethods is a pretty javaish idiom - in Python, we > just use good old functions !-) (in a separate module if you want a > separate namespace). > But it's personal preference, no? The functions were kind of related and meaningless outside the module they were declared - but I'll take it on board, anyway. [...] > > My experience is that it's far easier to start simple and add > flexibility where needed than to simplify useless complexity. KISS, > yagni and all that kind of things... > yagni - I'd never heard that one! I've ditched the factory class in any case: http://gflanagan.net/site/python/htmlbuilder/HtmlBuilder.py (FWIW) > > > > Merci bien pour votre reponse. > > > You're welcome. > > BTW, there's also a french speaking python newsgroup at fr.comp.lang.py. > I wasn't aware of that, I'll have a lurk! Thanks again. Gerard > -- > bruno desthuilliers > python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for > p in '[EMAIL PROTECTED]'.split('@')])" -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
Gerard Flanagan wrote: > bruno at modulix wrote: > (snip french) > > I was trying to implement the factory pattern. > The recipe above uses 'apply' which is deprecated according to the > docs, and I suppose I was curious how to do the same sort of thing > without 'apply'. def fun(*args, **kwargs): pass def otherfun(*args, **kwargs): fun(*args, **kwargs) > >>Err... I don't see the point of this class. Why not just calling the >>HtmlPage|Element|Literal classes directly ? >> >> (snip) >>'to_string' ? >>Let's see... 'to_string', a class with only staticmethods in it... >>You're coming from Java, aren't you ?-) >> > > Never been to Java in my life! bad guess. > I don't know if I understand you, HtmlElement has a 'to_string' method I don't know this HtmlElement class, nor where it comes from. 'to_string()' (or is it toString() ?) is javaish. The pythonic idiom for this is implementing the __str__() method and calling str(obj) on the obj (which will call obj.__str__()). Hence my (bad) guess about you being a Javaer. > but no static methods: Not the HtmlElement class, but the HtmlBuilder one. Here again, a class defining only staticmethods is a pretty javaish idiom - in Python, we just use good old functions !-) (in a separate module if you want a separate namespace). > class HtmlElement(list): > > def __init__(self, tag, text=None, **attrib): > self.tag = tag > self.text = text > self.attrib = attrib > > def write(self, writer): > writer.start(self.tag, self.attrib) > if self.text is not None: > writer.data(self.text) > for node in self: > node.write(writer) > writer.end() > > def to_string(self): > out = StringIO() > writer = HtmlWriter(out) > self.write(writer) > ret = out.getvalue() > out.close() > return ret > If it's your own code, you may want to rename this last method __str__(). >> >>>ie. to pass along *args and **kwargs to the HtmlElement constructor. >>>Any suggestions? >> >>yes : pass along *args and **kwargs to the HtmlElement constructor !-) >> >> >>>Or is there a better way to this kind of thing? >> >>yes again : kiss (Keep It Simple Stupid) >> >>There's not enough code to really grasp what you're trying to do, but >>from what I see, I'd say you're having a bad case of arbitrary >>overcomplexification. >> > > My code itself is just a learning project ( etant sans emploi a ce > moment, moi-meme...) and it is no doubt a bit 'over-egged' at the > minute, but it is a first attempt and I can always refactor later. My experience is that it's far easier to start simple and add flexibility where needed than to simplify useless complexity. KISS, yagni and all that kind of things... > > Merci bien pour votre reponse. > You're welcome. BTW, there's also a french speaking python newsgroup at fr.comp.lang.py. -- bruno desthuilliers python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for p in '[EMAIL PROTECTED]'.split('@')])" -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
bruno at modulix wrote: (snip) > Je ne vois pas très bien à quoi sert cette classe (à moins bien sûr > qu'il y ait d'autre code). Pour ce que je vois là, pourquoi ne pas > appeler directement les classes HtmlPage, HtmlElement et HtmlLiteral ? > oops, sorry, forgot to remove this before posting :( -- bruno desthuilliers python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for p in '[EMAIL PROTECTED]'.split('@')])" -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
Gerard Flanagan wrote: > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/86900 > > mais il utilise 'apply', qui est...blah > > I was trying to implement the factory pattern. > The recipe above uses 'apply' which is deprecated according to the > docs, and I suppose I was curious how to do the same sort of thing > without 'apply'. Apply has been replaced by 'extended call syntax', that is why it is deprecated. Instead of return apply(self._function,_args,_kargs) write return self._function(*_args, **_kargs) Kent -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
Fredrik Lundh wrote: > Gerard Flanagan wrote: > > > I have the following code: > > > > builder.py # > > class HtmlBuilder(object): > > > > @staticmethod > > def page(title=''): > > return HtmlPage(title) > > > > @staticmethod > > def element(tag, text=None, **attribs): > > return HtmlElement(tag, text, **attribs) > > > > @staticmethod > > def literal(text): > > return HtmlLiteral(text) > > just curious, but what's the purpose of this class, and what gave > you the idea to structure your program in this way ? > > In my defense, I can only quote Albert Einstein: "If we knew what it was we were doing, it would not be called research, would it?" I'm writing a script to generate a few relatively static webpages and upload them to a server, but it's as much a learning exercise as anything else - I have no formal programming education. I thought the Factory pattern would be appropriate here; the class you quote was a first attempt and i knew it was undoubtedly the wrong approach, so that's why i asked the group... Gerard -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
bruno at modulix wrote: > Gerard Flanagan wrote: > > Hello > > > > I have the following code: > > > > builder.py # > > class HtmlBuilder(object): > > > > @staticmethod > > def page(title=''): > > return HtmlPage(title) > > > > @staticmethod > > def element(tag, text=None, **attribs): > > return HtmlElement(tag, text, **attribs) > > > > @staticmethod > > def literal(text): > > return HtmlLiteral(text) > > Je ne vois pas très bien à quoi sert cette classe (à moins bien sûr > qu'il y ait d'autre code). Pour ce que je vois là, pourquoi ne pas > appeler directement les classes HtmlPage, HtmlElement et HtmlLiteral ? > C'est une vaine tentative d'appliquer "the Factory Pattern" ! J'ai eu commence d'ecrire les classes 'ul(HtmlElement), li(HtmlElement), etc ', et le but de 'HtmlElementFactory' etait d'eviter ceci (cela?). Il y a une recette ici: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/86900 mais il utilise 'apply', qui est...blah I was trying to implement the factory pattern. The recipe above uses 'apply' which is deprecated according to the docs, and I suppose I was curious how to do the same sort of thing without 'apply'. > Err... I don't see the point of this class. Why not just calling the > HtmlPage|Element|Literal classes directly ? > > > class HtmlElementFactory(object): > > > > def __init__(self): > > for tag in ['li', 'ul']: > > setattr( self, tag, HtmlBuilder.element(tag) ) > > > > # > > > > and so I can do the following: > > > > html = HtmlElementFactory() > > ul = html.ul > > ul.attrib['class'] = 'default' > > for i in range(3): > > li = html.li > > li.text = 'ghfhj' > > ul.append(li) > > print ul.to_string() > > > > but what I'd like to do is: > > > > html = HtmlElementFactory() > > ul = html.ul( class='default' ) > > > > > for i in range(3): > > ul.append( html.li( 'ghfhj' ) > > print ul.to_string() > > 'to_string' ? > Let's see... 'to_string', a class with only staticmethods in it... > You're coming from Java, aren't you ?-) > Never been to Java in my life! I don't know if I understand you, HtmlElement has a 'to_string' method but no static methods: class HtmlElement(list): def __init__(self, tag, text=None, **attrib): self.tag = tag self.text = text self.attrib = attrib def write(self, writer): writer.start(self.tag, self.attrib) if self.text is not None: writer.data(self.text) for node in self: node.write(writer) writer.end() def to_string(self): out = StringIO() writer = HtmlWriter(out) self.write(writer) ret = out.getvalue() out.close() return ret > (if yes, google for "python is not java", it may be helpful) > > > ie. to pass along *args and **kwargs to the HtmlElement constructor. > > Any suggestions? > > yes : pass along *args and **kwargs to the HtmlElement constructor !-) > > > > Or is there a better way to this kind of thing? > > yes again : kiss (Keep It Simple Stupid) > > There's not enough code to really grasp what you're trying to do, but > from what I see, I'd say you're having a bad case of arbitrary > overcomplexification. > My code itself is just a learning project ( etant sans emploi a ce moment, moi-meme...) and it is no doubt a bit 'over-egged' at the minute, but it is a first attempt and I can always refactor later. > What's wrong with: > > # nb: class is a reserved word in Python > ul = HtmlElement('ul', css_class='default') > for i in range(3): > ul.append(HtmlElement('li', 'baaz%d' % i) > > # nb2: use the __str__() method of HtmlElement > print str(ul) > > Python's philosophy is to make simple things simple (don't worry, > there's still space for complex things -> descriptors, metaclasses etc). > > HTH > -- > bruno desthuilliers > python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for > p in '[EMAIL PROTECTED]'.split('@')])" Merci bien pour votre reponse. Gerard -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
Gerard Flanagan wrote: > I have the following code: > > builder.py # > class HtmlBuilder(object): > > @staticmethod > def page(title=''): > return HtmlPage(title) > > @staticmethod > def element(tag, text=None, **attribs): > return HtmlElement(tag, text, **attribs) > > @staticmethod > def literal(text): > return HtmlLiteral(text) just curious, but what's the purpose of this class, and what gave you the idea to structure your program in this way ? -- http://mail.python.org/mailman/listinfo/python-list
Re: setattr question
Gerard Flanagan wrote: > Hello > > I have the following code: > > builder.py # > class HtmlBuilder(object): > > @staticmethod > def page(title=''): > return HtmlPage(title) > > @staticmethod > def element(tag, text=None, **attribs): > return HtmlElement(tag, text, **attribs) > > @staticmethod > def literal(text): > return HtmlLiteral(text) Je ne vois pas très bien à quoi sert cette classe (à moins bien sûr qu'il y ait d'autre code). Pour ce que je vois là, pourquoi ne pas appeler directement les classes HtmlPage, HtmlElement et HtmlLiteral ? Err... I don't see the point of this class. Why not just calling the HtmlPage|Element|Literal classes directly ? > class HtmlElementFactory(object): > > def __init__(self): > for tag in ['li', 'ul']: > setattr( self, tag, HtmlBuilder.element(tag) ) > > # > > and so I can do the following: > > html = HtmlElementFactory() > ul = html.ul > ul.attrib['class'] = 'default' > for i in range(3): > li = html.li > li.text = 'ghfhj' > ul.append(li) > print ul.to_string() > > but what I'd like to do is: > > html = HtmlElementFactory() > ul = html.ul( class='default' ) > for i in range(3): > ul.append( html.li( 'ghfhj' ) > print ul.to_string() 'to_string' ? Let's see... 'to_string', a class with only staticmethods in it... You're coming from Java, aren't you ?-) (if yes, google for "python is not java", it may be helpful) > ie. to pass along *args and **kwargs to the HtmlElement constructor. > Any suggestions? yes : pass along *args and **kwargs to the HtmlElement constructor !-) > Or is there a better way to this kind of thing? yes again : kiss (Keep It Simple Stupid) There's not enough code to really grasp what you're trying to do, but from what I see, I'd say you're having a bad case of arbitrary overcomplexification. What's wrong with: # nb: class is a reserved word in Python ul = HtmlElement('ul', css_class='default') for i in range(3): ul.append(HtmlElement('li', 'baaz%d' % i) # nb2: use the __str__() method of HtmlElement print str(ul) Python's philosophy is to make simple things simple (don't worry, there's still space for complex things -> descriptors, metaclasses etc). HTH -- bruno desthuilliers python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for p in '[EMAIL PROTECTED]'.split('@')])" -- http://mail.python.org/mailman/listinfo/python-list
setattr question
Hello I have the following code: builder.py # class HtmlBuilder(object): @staticmethod def page(title=''): return HtmlPage(title) @staticmethod def element(tag, text=None, **attribs): return HtmlElement(tag, text, **attribs) @staticmethod def literal(text): return HtmlLiteral(text) class HtmlElementFactory(object): def __init__(self): for tag in ['li', 'ul']: setattr( self, tag, HtmlBuilder.element(tag) ) # and so I can do the following: html = HtmlElementFactory() ul = html.ul ul.attrib['class'] = 'default' for i in range(3): li = html.li li.text = 'ghfhj' ul.append(li) print ul.to_string() but what I'd like to do is: html = HtmlElementFactory() ul = html.ul( class='default' ) for i in range(3): ul.append( html.li( 'ghfhj' ) print ul.to_string() ie. to pass along *args and **kwargs to the HtmlElement constructor. Any suggestions? Or is there a better way to this kind of thing? thanks Gerard -- http://mail.python.org/mailman/listinfo/python-list