Re: substitution
Wilbert Berendsen wbs...@xs4all.nl wrote: # sort the keys, longest first, so 'aa' gets matched before 'a', because # in Python regexps the first match (going from left to right) in a # |-separated group is taken keys = sorted(mapping.keys(), key=len, reverse=True) This would do just as well (although see Iain King's response for the correct answer): keys = sorted(mapping, reverse=True) You don't need to specify key=len because the default sorting for two strings where one is a prefix of the other will always sort them that way anyway, and you don't need to call mapping.keys() because that's what sorted will sort anyway. -- Duncan Booth http://kupuguy.blogspot.com -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Op maandag 18 januari 2010 schreef Adi: keys = [(len(key), key) for key in mapping.keys()] keys.sort(reverse=True) keys = [key for (_, key) in keys] pattern = (%s) % |.join(keys) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux re.subn(pattern, repl, s) I managed to make it even shorted, using the key argument for sorted, not putting the whole regexp inside parentheses and pre-compiling the regular expression: import re mapping = { foo : bar, baz : quux, quuux : foo } # sort the keys, longest first, so 'aa' gets matched before 'a', because # in Python regexps the first match (going from left to right) in a # |-separated group is taken keys = sorted(mapping.keys(), key=len) rx = re.compile(|.join(keys)) repl = lambda x: mapping[x.group()] s = fooxxxbazyyyquuux rx.sub(repl, s) One thing remaining: if the replacement keys could contain non-alphanumeric characters, they should be escaped using re.escape: rx = re.compile(|.join(re.escape(key) for key in keys)) Met vriendelijke groet, Wilbert Berendsen -- http://www.wilbertberendsen.nl/ You must be the change you wish to see in the world. -- Mahatma Gandhi -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Wilbert Berendsen wrote: Op maandag 18 januari 2010 schreef Adi: keys = [(len(key), key) for key in mapping.keys()] keys.sort(reverse=True) keys = [key for (_, key) in keys] pattern = (%s) % |.join(keys) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux re.subn(pattern, repl, s) I managed to make it even shorted, using the key argument for sorted, not putting the whole regexp inside parentheses and pre-compiling the regular expression: import re mapping = { foo : bar, baz : quux, quuux : foo } # sort the keys, longest first, so 'aa' gets matched before 'a', because # in Python regexps the first match (going from left to right) in a # |-separated group is taken keys = sorted(mapping.keys(), key=len) For longest first you need: keys = sorted(mapping.keys(), key=len, reverse=True) rx = re.compile(|.join(keys)) repl = lambda x: mapping[x.group()] s = fooxxxbazyyyquuux rx.sub(repl, s) One thing remaining: if the replacement keys could contain non-alphanumeric characters, they should be escaped using re.escape: Strictly speaking, not all non-alphanumeric characters, but only the special ones. rx = re.compile(|.join(re.escape(key) for key in keys)) -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
On Jan 21, 2:18 pm, Wilbert Berendsen wbs...@xs4all.nl wrote: Op maandag 18 januari 2010 schreef Adi: keys = [(len(key), key) for key in mapping.keys()] keys.sort(reverse=True) keys = [key for (_, key) in keys] pattern = (%s) % |.join(keys) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux re.subn(pattern, repl, s) I managed to make it even shorted, using the key argument for sorted, not putting the whole regexp inside parentheses and pre-compiling the regular expression: import re mapping = { foo : bar, baz : quux, quuux : foo } # sort the keys, longest first, so 'aa' gets matched before 'a', because # in Python regexps the first match (going from left to right) in a # |-separated group is taken keys = sorted(mapping.keys(), key=len) rx = re.compile(|.join(keys)) repl = lambda x: mapping[x.group()] s = fooxxxbazyyyquuux rx.sub(repl, s) One thing remaining: if the replacement keys could contain non-alphanumeric characters, they should be escaped using re.escape: rx = re.compile(|.join(re.escape(key) for key in keys)) Met vriendelijke groet, Wilbert Berendsen --http://www.wilbertberendsen.nl/ You must be the change you wish to see in the world. -- Mahatma Gandhi Sorting it isn't the right solution: easier to hold the subs as tuple pairs and by doing so let the user specify order. Think of the following subs: fooxx - baz oxxx - bar does the user want bazxbazyyyquuux or fobarbazyyyquuux? Iain -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Op donderdag 21 januari 2010 schreef MRAB: For longest first you need: keys = sorted(mapping.keys(), key=len, reverse=True) Oh yes, I cut/pasted the wrong line :-) Just for clarity: import re mapping = { foo : bar, baz : quux, quuux : foo } # sort the keys, longest first, so 'aa' gets matched before 'a', because # in Python regexps the first match (going from left to right) in a # |-separated group is taken keys = sorted(mapping.keys(), key=len, reverse=True) rx = re.compile(|.join(keys)) repl = lambda x: mapping[x.group()] s = fooxxxbazyyyquuux rx.sub(repl, s) One thing remaining: if the replacement keys could contain non-alphanumeric characters, they should be escaped using re.escape: rx = re.compile(|.join(re.escape(key) for key in keys)) Strictly speaking, not all non-alphanumeric characters, but only the special ones. True, although the re.escape function simply escapes all non-alphanumeric characters :) And here is a factory function that returns a translator given a mapping. The translator can be called to perform replacements in a string: import re def translator(mapping): keys = sorted(mapping.keys(), key=len, reverse=True) rx = re.compile(|.join(keys)) repl = lambda m: mapping[m.group()] return lambda s: rx.sub(repl, s) #Usage: t = translator(mapping) t('fooxxxbazyyyquuux') 'barxxxquuxyyyfoo' w best regards, Wilbert Berendsen -- http://www.wilbertberendsen.nl/ -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Iain King wrote: On Jan 21, 2:18 pm, Wilbert Berendsen wbs...@xs4all.nl wrote: Op maandag 18 januari 2010 schreef Adi: keys = [(len(key), key) for key in mapping.keys()] keys.sort(reverse=True) keys = [key for (_, key) in keys] pattern = (%s) % |.join(keys) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux re.subn(pattern, repl, s) I managed to make it even shorted, using the key argument for sorted, not putting the whole regexp inside parentheses and pre-compiling the regular expression: import re mapping = { foo : bar, baz : quux, quuux : foo } # sort the keys, longest first, so 'aa' gets matched before 'a', because # in Python regexps the first match (going from left to right) in a # |-separated group is taken keys = sorted(mapping.keys(), key=len) rx = re.compile(|.join(keys)) repl = lambda x: mapping[x.group()] s = fooxxxbazyyyquuux rx.sub(repl, s) One thing remaining: if the replacement keys could contain non-alphanumeric characters, they should be escaped using re.escape: rx = re.compile(|.join(re.escape(key) for key in keys)) Met vriendelijke groet, Wilbert Berendsen --http://www.wilbertberendsen.nl/ You must be the change you wish to see in the world. -- Mahatma Gandhi Sorting it isn't the right solution: easier to hold the subs as tuple pairs and by doing so let the user specify order. Think of the following subs: fooxx - baz oxxx - bar does the user want bazxbazyyyquuux or fobarbazyyyquuux? Iain There is no way you can automate a user's choice. If he wants the second choice (oxxx-bar) he would have to add a third pattern: fooxxx - fobar. In general, the rules 'upstream over downstream' and 'long over short' make sense in practically all cases. With all but simple substitution runs whose functionality is obvious, the result needs to be checked for unintended hits. To use an example from my SE manual which runs a (whimsical) text through a set of substitutions concentrating overlapping targets: substitutions = [['be', 'BE'], ['being', 'BEING'], ['been', 'BEEN'], ['bee', 'BEE'], ['belong', 'BELONG'], ['long', 'LONG'], ['longer', 'LONGER']] T = Translator (substitutions) # Code further up in this thread handling precedence by the two rules mentioned text = There was a bee named Mabel belonging to hive nine longing to be a beetle and thinking that being a bee was okay, but she had been a bee long enough and wouldn't be one much longer. print T (text) There was a BEE named MaBEl BELONGing to hive nine LONGing to BE a BEEtle and thinking that BEING a BEE was okay, but she had BEEN a BEE LONG enough and wouldn't BE one much LONGER. All word-length substitutions resolve correctly. There are four unintended translations, though: MaBEl, BELONGing, LONGing and BEEtle. Adding the substitution Mabel-Mabel would prevent the first miss. The others could be taken care of similarly by replacing the target with itself. With large substitution sets and extensive data, this amounts to an iterative process of running, checking and fixing, many times over. That just isn't practical and may have to be abandoned when the substitutions catalog grows out of reasonable bounds. Dependable are runs where the targets are predictably singular, such as long id numbers that cannot possibly match anything but id numbers. Frederic -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Wyrmskull wrote: Your flowing pythonicity (if len(x):) gave me lots of inspiration. Actually, instead of if len(pairs): ... that should have been just if pairs: ... When I started writing the function I initially wanted to special-case len(pairs) == 1. The len() call is a superfluous leftover. Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Peter Otten wrote: def replace_many(s, pairs): if len(pairs): a, b = pairs[0] rest = pairs[1:] return b.join(replace_many(t, rest) for t in s.split(a)) else: return s - Proves wrong, this way x - y - z. You call replace_many again on the central part of the split Specifics indicate that x - y in the end. Your flowing pythonicity (if len(x):) gave me lots of inspiration. I bet this will win the prize ;) - def mySubst(reps,string): if not(len(reps)): return string a,b,c = string.partition(reps[0][0]) if b: return mySubst(reps,a) + reps[0][1] + mySubst (reps,c) else: return mySubst(reps[1:],string) print mySubst( ( ('foo','bar'), ('bar','qux'), ('qux','foo') ), 'foobarquxfoo') --- Wyrmskull lordkran...@gmail.com -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Wyrmskull wrote: Peter Otten wrote: def replace_many(s, pairs): if len(pairs): a, b = pairs[0] rest = pairs[1:] return b.join(replace_many(t, rest) for t in s.split(a)) else: return s Proves wrong, this way x - y - z. You call replace_many again on the central part of the split Specifics indicate that x - y in the end. Sorry, I don't understand what you want to say with the above. Try with this: def mySubst(reps,string): if not(len(reps)): return string current = reps[0][0] a,b,c = string.partition(current) if b: return mySubst(reps,a) + reps[0][1] + mySubst (reps,c) else: return mySubst(reps[1:],string) print mySubst( ( ('foo','bar'), ('bar','qux'), ('qux','foo') ), 'foobarquxfoo') --- Wyrmskull lordkran...@gmail.com I don't see at first glance where the results of replace_many() and mySubst() differ. Perhaps you could give an example? Peter PS: Please keep the conversation on-list -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Cleaned. You can remove the 'else's if you want, because 'return' breaks the instruction flow. Should also work with other sequence types. def mySubst(reps,seq): if reps: a,b,c = string.partition(reps[0][0]) if b: return mySubst(reps,a) + reps[0][1] + mySubst (reps,c) else: return mySubst(reps[1:], seq) else: return seq print mySubst( ( ('foo','bar'), ('bar','qux'), ('qux','foo') ), 'foobarquxfoo') print mySubst( ( ('foo','bar'), ('bar','qux'), ('qux','foo') ), 'foobarquxxxfoo') --- Wyrmskull -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Nvm, my bad, I misunderstood the split instruction. No difference :) --- Wyrmskull P.S Sorry about the P.M., I misclicked on a GUI -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
superpollo ha scritto: hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo bye i explain better: say the subs are: quuux -- foo foo -- bar baz -- quux then i cannot apply the subs in sequence (say, .replace() in a loop), otherwise: fooxxxbazyyyquuux -- fooxxxbazyyyfoo -- barxxxbazyyybar -- barxxxquuxyyybar not as intended... -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
superpollo wrote: superpollo ha scritto: hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo bye i explain better: say the subs are: quuux -- foo foo -- bar baz -- quux then i cannot apply the subs in sequence (say, .replace() in a loop), otherwise: fooxxxbazyyyquuux -- fooxxxbazyyyfoo -- barxxxbazyyybar -- barxxxquuxyyybar not as intended... If you want to avoid regular expressions: def replace_many(s, pairs): if len(pairs): a, b = pairs[0] rest = pairs[1:] return b.join(replace_many(t, rest) for t in s.split(a)) else: return s assert replace_many(abc, [ab, bc, ca]) == bca assert (replace_many(fooxxxbazyyyquuux, [(quuux, foo), (foo, bar), (baz, quux)]) == barxxxquuxyyyfoo) Not tested. Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
On Mon, 18 Jan 2010 11:15:37 +0100, superpollo wrote: hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo For simple cases, just use replace: s = 'fooxxxbazyyyquuux' s = s.replace('foo', 'bar') s = s.replace('baz', 'quux') s = s.replace('quuux', 'foo') s == 'barxxxquuxyyyfoo' True In complicated cases, such as if there are conflicts or overlaps between strings, you may need to use a regular expression, or even parse the string yourself. The problem is that substitute multiple strings is not well defined, because in general it depends on the order you perform them. You can define a function to do the replacements in one order, but for another use you might need a different order. E.g.: replacing a - X and aa - Y, if you have the string aaa what result do you expect? You could get XXX, XY or YX. None of these are wrong, it depends on which you prefer. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
superpollo wrote: hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo bye Try the code below the dotted line. It does any number of substitutions and handles overlaps correctly (long over short) Your case: substitutions = (('foo', 'bar'), ('baz', 'quux'), ('quuux', 'foo')) # Sequence of doublets T = Translator (substitutions) # Compile substitutions - translator s = 'fooxxxbazyyyquuux' # Your source string d = 'barxxxquuxyyyfoo'# Your destination string print T (s) barxxxquuxyyyfoo print T (s) == d True Frederic - class Translator: r Will translate any number of targets, handling them correctly if some overlap. Making Translator T = Translator (definitions, [eat = 1]) 'definitions' is a sequence of pairs: ((target, substitute),(t2, s2), ...) 'eat' says whether untargeted sections pass (translator) or are skipped (extractor). Makes a translator by default (eat = False) T.eat is an instance attribute that can be changed at any time. Definitions example: (('a','A'),('b','B'),('ab','ab'),('abc','xyz') # ('ab','ab') see Tricks. ('\x0c', 'page break'), ('\r\n','\n'), (' ','\t')) Order doesn't matter. Running translation = T (source) Tricks Deletion: ('target', '') Exception: (('\n',''), ('\n\n','\n\n')) # Eat LF except paragraph breaks. Exception: (('\n', '\r\n'), ('\r\n',\r\n')) # Unix to DOS, would leave DOS unchanged Translation cascade: # Rejoin text lines per paragraph Unix or DOS, inserting inter-word space if missing Mark_LF = Translator ((('\n','+LF+'),('\r\n','+LF+'),('\r\n\r\n','\r\n\r\n'),('\n\n','\n\n'))) # Pick positively identifiable mark for Unix and DOS end of lines Single_Space_Mark = Translator (((' +LF+', ' '),('+LF+', ' '),('-+LF+', ''))) no_lf_text = Single_Space_Mark (Mark_LF (text)) Translation cascade: # Nesting calls reptiles = T_latin_english (T_german_latin (reptilien)) Limitations 1. The number of substitutions and the maximum size of input depends on the respective capabilities of the Python re module. 2. Regular expressions will not work as such. Author: Frederic Rentsch (anthra.nor...@bluewin.ch). def __init__ (self, definitions, eat = 0): ''' definitions: a sequence of pairs of strings. ((target, substitute), (t, s), ...) eat: False (0) means translate: unaffected data passes unaltered. True (1) means extract: unaffected data doesn't pass (gets eaten). Extraction filters typically require substitutes to end with some separator, else they fuse together. (E.g. ' ', '\t' or '\n') 'eat' is an attribute that can be switched anytime. ''' self.eat = eat self.compile_sequence_of_pairs (definitions) def compile_sequence_of_pairs (self, definitions): ''' Argument 'definitions' is a sequence of pairs: (('target 1', 'substitute 1'), ('t2', 's2'), ...) Order doesn't matter. ''' import re self.definitions = definitions targets, substitutes = zip (*definitions) re_targets = [re.escape (item) for item in targets] re_targets.sort (reverse = True) self.targets_set = set (targets) self.table = dict (definitions) regex_string = '|'.join (re_targets) self.regex = re.compile (regex_string, re.DOTALL) def __call__ (self, s): hits = self.regex.findall (s) nohits = self.regex.split (s) valid_hits = set (hits) self.targets_set # Ignore targets with illegal re modifiers. if valid_hits: substitutes = [self.table [item] for item in hits if item in valid_hits] + [] # Make lengths equal for zip to work right if self.eat: return ''.join (substitutes) else: zipped = zip (nohits, substitutes) return ''.join (list (reduce (lambda a, b: a + b, [zipped][0]))) + nohits [-1] else: if self.eat: return '' else: return s -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
On Jan 18, 10:21 am, superpollo ute...@esempio.net wrote: superpollo ha scritto: hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo bye i explain better: say the subs are: quuux -- foo foo -- bar baz -- quux then i cannot apply the subs in sequence (say, .replace() in a loop), otherwise: fooxxxbazyyyquuux -- fooxxxbazyyyfoo -- barxxxbazyyybar -- barxxxquuxyyybar not as intended... Not sure if it's the most pythonic, but I'd probably do it like this: def token_replace(string, subs): subs = dict(subs) tokens = {} for i, sub in enumerate(subs): tokens[sub] = i tokens[i] = sub current = [string] for sub in subs: new = [] for piece in current: if type(piece) == str: chunks = piece.split(sub) new.append(chunks[0]) for chunk in chunks[1:]: new.append(tokens[sub]) new.append(chunk) else: new.append(piece) current = new output = [] for piece in current: if type(piece) == str: output.append(piece) else: output.append(subs[tokens[piece]]) return ''.join(output) token_replace(fooxxxbazyyyquuux, [(quuux, foo), (foo, bar), (baz, quux)]) 'barxxxquuxyyyfoo' I'm sure someone could whittle that down to a handful of list comps... Iain -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
On Jan 18, 12:41 pm, Iain King iaink...@gmail.com wrote: On Jan 18, 10:21 am, superpollo ute...@esempio.net wrote: superpollo ha scritto: hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo bye i explain better: say the subs are: quuux -- foo foo -- bar baz -- quux then i cannot apply the subs in sequence (say, .replace() in a loop), otherwise: fooxxxbazyyyquuux -- fooxxxbazyyyfoo -- barxxxbazyyybar -- barxxxquuxyyybar not as intended... Not sure if it's the most pythonic, but I'd probably do it like this: def token_replace(string, subs): subs = dict(subs) tokens = {} for i, sub in enumerate(subs): tokens[sub] = i tokens[i] = sub current = [string] for sub in subs: new = [] for piece in current: if type(piece) == str: chunks = piece.split(sub) new.append(chunks[0]) for chunk in chunks[1:]: new.append(tokens[sub]) new.append(chunk) else: new.append(piece) current = new output = [] for piece in current: if type(piece) == str: output.append(piece) else: output.append(subs[tokens[piece]]) return ''.join(output) token_replace(fooxxxbazyyyquuux, [(quuux, foo), (foo, bar), (baz, quux)]) 'barxxxquuxyyyfoo' I'm sure someone could whittle that down to a handful of list comps... Iain Slightly better (lets you have overlapping search strings, used in the order they are fed in): def token_replace(string, subs): tokens = {} if type(subs) == dict: for i, sub in enumerate(subs): tokens[sub] = i tokens[i] = subs[sub] else: s = [] for i, (k,v) in enumerate(subs): tokens[k] = i tokens[i] = v s.append(k) subs = s current = [string] for sub in subs: new = [] for piece in current: if type(piece) == str: chunks = piece.split(sub) new.append(chunks[0]) for chunk in chunks[1:]: new.append(tokens[sub]) new.append(chunk) else: new.append(piece) current = new output = [] for piece in current: if type(piece) == str: output.append(piece) else: output.append(tokens[piece]) return ''.join(output) -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Iain King wrote: Not sure if it's the most pythonic, but I'd probably do it like this: def token_replace(string, subs): subs = dict(subs) tokens = {} for i, sub in enumerate(subs): tokens[sub] = i tokens[i] = sub current = [string] for sub in subs: new = [] for piece in current: if type(piece) == str: chunks = piece.split(sub) new.append(chunks[0]) for chunk in chunks[1:]: new.append(tokens[sub]) new.append(chunk) else: new.append(piece) current = new output = [] for piece in current: if type(piece) == str: output.append(piece) else: output.append(subs[tokens[piece]]) return ''.join(output) token_replace(fooxxxbazyyyquuux, [(quuux, foo), (foo, bar), (baz, quux)]) 'barxxxquuxyyyfoo' I'm sure someone could whittle that down to a handful of list comps... I tried, but failed: def join(chunks, separator): chunks = iter(chunks) yield next(chunks) for chunk in chunks: yield separator yield chunk def token_replace(string, subs): tokens = {} current = [string] for i, (find, replace) in enumerate(subs): tokens[i] = replace new = [] for piece in current: if piece in tokens: new.append(piece) else: new.extend(join(piece.split(find), i)) current = new return ''.join(tokens.get(piece, piece) for piece in current) You could replace the inner loop with sum(..., []), but that would be really ugly. Peter -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
it looked simpler when i posted, but i realize that the problem is non trivial. thanks to everybody. i guess that the algorithm would be easier if it was known in advance that the string to substitute must have some specific property, say: 1) they all must start with XYZ 2) they all have the same length N (e.g. 5) like this: qweXYZ12asdXYZ1345XYZ --- qweIWAS12asdIWAS1345XYZ bye -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
On Jan 18, 2:17 pm, Adi Eyal a...@digitaltrowel.com wrote: From: superpollo ute...@esempio.net To: Date: Mon, 18 Jan 2010 11:15:37 +0100 Subject: substitution hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo bye Using regular expressions the answer is short (and sweet) mapping = { foo : bar, baz : quux, quuux : foo } pattern = (%s) % |.join(mapping.keys()) repl = lambda x : mapping.get(x.group(1), x.group(1)) s = fooxxxbazyyyquuux re.subn(pattern, repl, s) Winner! :) Iain -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
superpollo wrote: hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo This is simple -- maybe a bit brutal -- and if the strings get long it will be slow: def replaced (input, replacements): output = [] while input: for target in replacements: if input.startswith (target): output.append (replacements [target]) input = input [len (target):] break else: output.append (input[0]) input = input [1:] return ''.join (output) original = 'fooxxxbazyyyquux' replacements = {'quux':'foo', 'foo':'bar', 'baz':'quux'} print original, '--', replaced (original, replacements) Mel. -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
On Mon, 18 Jan 2010 11:21:54 +0100, superpollo wrote: what is the most pythonic way to substitute substrings? say the subs are: quuux -- foo foo -- bar baz -- quux then i cannot apply the subs in sequence (say, .replace() in a loop), otherwise: fooxxxbazyyyquuux -- fooxxxbazyyyfoo -- barxxxbazyyybar -- barxxxquuxyyybar not as intended... Are there any characters which are guaranteed never to occur in the string? If so: s = s.replace('quuux', '@1').replace('foo', '@2').replace('baz', '@3') s = s.replace('@1', 'foo').replace('@2', 'bar').replace('@3', 'quux') E.g.: def replace(subs, s): for i, (src, dst) in enumerate(subs): s = s.replace(src, '@%06d' % i) for i, (src, dst) in enumerate(subs): s = s.replace('@%06d' % i, dst) return s Not the most efficient solution (and problematic if there aren't any unused characters), but somewhat shorter than the other solutions. -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Anthra Norell wrote: superpollo wrote: hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo bye So it goes. The more it matters, the sillier the misatakes. The method __init__ () was incomplete and __call__ () was missing, Sorry abount that. Here the whole thing again: class Translator: r Will translate any number of targets, handling them correctly if some overlap. Making Translator T = Translator (definitions, [eat = 1]) 'definitions' is a sequence of pairs: ((target, substitute),(t2, s2), ...) 'eat' says whether untargeted sections pass (translator) or are skipped (extractor). Makes a translator by default (eat = False) T.eat is an instance attribute that can be changed at any time. Definitions example: (('a','A'),('b','B'),('ab','ab'),('abc','xyz') # ('ab','ab') see Tricks. ('\x0c', 'page break'), ('\r\n','\n'), (' ','\t')) Order doesn't matter. Running translation = T (source) Tricks Deletion: ('target', '') Exception: (('\n',''), ('\n\n','\n\n')) # Eat LF except paragraph breaks. Exception: (('\n', '\r\n'), ('\r\n',\r\n')) # Unix to DOS, would leave DOS unchanged Translation cascade: # Rejoin text lines per paragraph Unix or DOS, inserting inter-word space if missing Mark_LF = Translator ((('\n','+LF+'),('\r\n','+LF+'),('\r\n\r\n','\r\n\r\n'),('\n\n','\n\n'))) # Pick positively identifiable mark for Unix and DOS end of lines Single_Space_Mark = Translator (((' +LF+', ' '),('+LF+', ' '),('-+LF+', ''))) no_lf_text = Single_Space_Mark (Mark_LF (text)) Translation cascade: # Nesting calls reptiles = T_latin_english (T_german_latin (reptilien)) Limitations 1. The number of substitutions and the maximum size of input depends on the respective capabilities of the Python re module. 2. Regular expressions will not work as such. Author: Frederic Rentsch (anthra.nor...@bluewin.ch). def __init__ (self, definitions, eat = 0): ''' definitions: a sequence of pairs of strings. ((target, substitute), (t, s), ...) eat: False (0) means translate: unaffected data passes unaltered. True (1) means extract: unaffected data doesn't pass (gets eaten). Extraction filters typically require substitutes to end with some separator, else they fuse together. (E.g. ' ', '\t' or '\n') 'eat' is an attribute that can be switched anytime. ''' self.eat = eat self.compile_sequence_of_pairs (definitions) def compile_sequence_of_pairs (self, definitions): ''' Argument 'definitions' is a sequence of pairs: (('target 1', 'substitute 1'), ('t2', 's2'), ...) Order doesn't matter. ''' import re self.definitions = definitions targets, substitutes = zip (*definitions) re_targets = [re.escape (item) for item in targets] re_targets.sort (reverse = True) self.targets_set = set (targets) self.table = dict (definitions) regex_string = '|'.join (re_targets) self.regex = re.compile (regex_string, re.DOTALL) def __call__ (self, s): hits = self.regex.findall (s) nohits = self.regex.split (s) valid_hits = set (hits) self.targets_set # Ignore targets with illegal re modifiers. if valid_hits: substitutes = [self.table [item] for item in hits if item in valid_hits] + [] # Make lengths equal for zip to work right if self.eat: return ''.join (substitutes) else: zipped = zip (nohits, substitutes) return ''.join (list (reduce (lambda a, b: a + b, [zipped][0]))) + nohits [-1] else: if self.eat: return '' else: return s -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
Adi Eyal a...@digitaltrowel.com wrote: Using regular expressions the answer is short (and sweet) mapping = { foo : bar, baz : quux, quuux : foo } pattern = (%s) % |.join(mapping.keys()) repl = lambda x : mapping.get(x.group(1), x.group(1)) s = fooxxxbazyyyquuux re.subn(pattern, repl, s) I'd use a def as being IMHO clearer than the lambda but YMMV. More importantly I'd also escape the keys in case they contain any characters special to regular expressions: mapping = { foo : bar, baz : quux, quuux : foo } import re pattern = (%s) % |.join(re.escape(k) for k in mapping) def repl(x): return mapping[x.group(1)] s = fooxxxbazyyyquuux re.subn(pattern, repl, s) ('barxxxquuxyyyfoo', 3) re.sub(pattern, repl, s) 'barxxxquuxyyyfoo' -- Duncan Booth http://kupuguy.blogspot.com -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
superpollo wrote: hi. what is the most pythonic way to substitute substrings? eg: i want to apply: foo -- bar baz -- quux quuux -- foo so that: fooxxxbazyyyquuux -- barxxxquuxyyyfoo bye Third attempt. Clearly something doesn't work right. My code gets clipped on the way up. I have to send it as an attachment. Here's again what it does: substitutions = (('foo', 'bar'), ('baz', 'quux'), ('quuux', 'foo')) # Sequence of doublets T = Translator (substitutions) # Compile substitutions - translator s = 'fooxxxbazyyyquuux' # Your source string d = 'barxxxquuxyyyfoo'# Your destination string print T (s) barxxxquuxyyyfoo print T (s) == d True Code attached Regards Frederic class Translator: r Will translate any number of targets, handling them correctly if some overlap. Making Translator T = Translator (definitions, [eat = 1]) 'definitions' is a sequence of pairs: ((target, substitute),(t2, s2), ...) 'eat = True' will make an extraction filter that lets only the replaced targets pass. Definitions example: (('a','A'),('b','B'),('ab','ab'),('abc','xyz'), ('\x0c', 'page break'), ('\r\n','\n'), (' ','\t')) # ('ab','ab') see Tricks. Order doesn't matter. Running translation = T (source) Tricks Deletion: ('target', '') Exception: (('\n',''), ('\n\n','\n\n')) # Eat LF except paragraph breaks. Exception: (('\n', '\r\n'), ('\r\n',\r\n')) # Unix to DOS, would leave DOS unchanged Translation cascade: # Unwrap paragraphs, Unix or DOS, restoring inter-word space if missing, Mark_LF = Translator ((('\n','+LF+'),('\r\n','+LF+'),('\n\n','\n\n'),('\r\n\r\n','\r\n\r\n'))) # Pick any positively identifiable mark for end of lines in either Unix or MS-DOS. Single_Space_Mark = Translator (((' +LF+', ' '),('+LF+', ' '),('-+LF+', ''))) no_lf_text = Single_Space_Mark (Mark_LF (text)) Translation cascade: # Nested calls reptiles = T_latin_english (T_german_latin (reptilien)) Limitations 1. The number of substitutions and the maximum size of input depends on the respective capabilities of the Python re module. 2. Regular expressions will not work as such. Author: Frederic Rentsch (i...@anthra-norell.ch). def __init__ (self, definitions, eat = 0): ''' definitions: a sequence of pairs of strings. ((target, substitute), (t, s), ...) eat: False (0) means translate: unaffected data passes unaltered. True (1) means extract: unaffected data doesn't pass (gets eaten). Extraction filters typically require substitutes to end with some separator, else they fuse together. (E.g. ' ', '\t' or '\n') 'eat' is an attribute that can be switched anytime. ''' self.eat = eat self.compile_sequence_of_pairs (definitions) def compile_sequence_of_pairs (self, definitions): ''' Argument 'definitions' is a sequence of pairs: (('target 1', 'substitute 1'), ('t2', 's2'), ...) Order doesn't matter. ''' import re self.definitions = definitions targets, substitutes = zip (*definitions) re_targets = [re.escape (item) for item in targets] re_targets.sort (reverse = True) self.targets_set = set (targets) self.table = dict (definitions) regex_string = '|'.join (re_targets) self.regex = re.compile (regex_string, re.DOTALL) def __call__ (self, s): hits = self.regex.findall (s) nohits = self.regex.split (s) valid_hits = set (hits) self.targets_set # Ignore targets with illegal re modifiers. if valid_hits: substitutes = [self.table [item] for item in hits if item in valid_hits] + [] #
Re: substitution
On Mon, 18 Jan 2010 06:23:44 -0800, Iain King wrote: On Jan 18, 2:17 pm, Adi Eyal a...@digitaltrowel.com wrote: [...] Using regular expressions the answer is short (and sweet) mapping = { foo : bar, baz : quux, quuux : foo } pattern = (%s) % |.join(mapping.keys()) repl = lambda x : mapping.get(x.group(1), x.group(1)) s = fooxxxbazyyyquuux re.subn(pattern, repl, s) Winner! :) What are the rules for being declared Winner? For the simple case given, calling s.replace three times is much faster: more than twice as fast. But a bigger problem is that the above winner may not work correctly if there are conflicts between the target strings (e.g. 'a'-'X', 'aa'-'Y'). The problem is that the result you get depends on the order of the searches, BUT as given, that order is non-deterministic. dict.keys() returns in an arbitrary order, which means the caller can't specify the order except by accident. For example: repl = lambda x : m[x.group(1)] m = {'aa': 'Y', 'a': 'X'} pattern = (%s) % |.join(m.keys()) subn(pattern, repl, 'aaa') # expecting 'YX' ('XXX', 3) The result that you get using this method will be consistent but arbitrary and unpredictable. For those who care, here's my timing code: from timeit import Timer setup = mapping = {foo : bar, baz : quux, quuux : foo} pattern = (%s) % |.join(mapping.keys()) repl = lambda x : mapping.get(x.group(1), x.group(1)) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux from re import subn t1 = Timer(subn(pattern, repl, s), setup) t2 = Timer( s.replace('foo', 'bar').replace('baz', 'quux').replace('quuux', 'foo'), s = 'fooxxxbazyyyquuux') And the results on my PC: min(t1.repeat(number=10)) 1.1273870468139648 min(t2.repeat(number=10)) 0.49491715431213379 -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
On Jan 18, 4:26 pm, Steven D'Aprano st...@remove-this- cybersource.com.au wrote: On Mon, 18 Jan 2010 06:23:44 -0800, Iain King wrote: On Jan 18, 2:17 pm, Adi Eyal a...@digitaltrowel.com wrote: [...] Using regular expressions the answer is short (and sweet) mapping = { foo : bar, baz : quux, quuux : foo } pattern = (%s) % |.join(mapping.keys()) repl = lambda x : mapping.get(x.group(1), x.group(1)) s = fooxxxbazyyyquuux re.subn(pattern, repl, s) Winner! :) What are the rules for being declared Winner? For the simple case given, calling s.replace three times is much faster: more than twice as fast. But a bigger problem is that the above winner may not work correctly if there are conflicts between the target strings (e.g. 'a'-'X', 'aa'-'Y'). The problem is that the result you get depends on the order of the searches, BUT as given, that order is non-deterministic. dict.keys() returns in an arbitrary order, which means the caller can't specify the order except by accident. For example: repl = lambda x : m[x.group(1)] m = {'aa': 'Y', 'a': 'X'} pattern = (%s) % |.join(m.keys()) subn(pattern, repl, 'aaa') # expecting 'YX' ('XXX', 3) The result that you get using this method will be consistent but arbitrary and unpredictable. For those who care, here's my timing code: from timeit import Timer setup = mapping = {foo : bar, baz : quux, quuux : foo} pattern = (%s) % |.join(mapping.keys()) repl = lambda x : mapping.get(x.group(1), x.group(1)) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux from re import subn t1 = Timer(subn(pattern, repl, s), setup) t2 = Timer( s.replace('foo', 'bar').replace('baz', 'quux').replace('quuux', 'foo'), s = 'fooxxxbazyyyquuux') And the results on my PC: min(t1.repeat(number=10)) 1.1273870468139648 min(t2.repeat(number=10)) 0.49491715431213379 -- Steven Adi elicited that response from me because his solution was vastly more succinct than everything else that had appeared up til that point while still meeting the OP's requirements. The OP never cared about overlap between 2 'find' strings, just between the 'find' and 'replace' strings (though I did take it into account in my second post for the sake of completeness). His code could have been a little cleaner, I'd have trimmed it to: mapping = {foo: bar, baz: quux, quuux: foo} pattern = (%s) % |.join(mapping) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux re.subn(pattern, repl, s) but apart from that was very pythonic: explicit, succinct, and all the heavy work is done by the module (i.e. in compiled c code in the majority case of CPython). It can be 'upgraded' to cover the find- find overlap if you really want (I *believe* regexps will match the leftmost option in a group first): subs = [(foo, bar), (baz, quux), (quuux, foo)] pattern = (%s) % |.join((x[0] for x in subs)) mapping = dict(subs) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux re.subn(pattern, repl, s) Anyway, there's no prize for winning, but by all means: if you think someone else's code and not a variation on this should win for most pythonic, then make your nomination :) Iain -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution
From: Steven D'Aprano st...@remove-this-cybersource.com.au To: python-l...@python.org Date: 18 Jan 2010 16:26:48 GMT Subject: Re: substitution On Mon, 18 Jan 2010 06:23:44 -0800, Iain King wrote: On Jan 18, 2:17 pm, Adi Eyal a...@digitaltrowel.com wrote: [...] Using regular expressions the answer is short (and sweet) mapping = { foo : bar, baz : quux, quuux : foo } pattern = (%s) % |.join(mapping.keys()) repl = lambda x : mapping.get(x.group(1), x.group(1)) s = fooxxxbazyyyquuux re.subn(pattern, repl, s) Winner! :) What are the rules for being declared Winner? For the simple case given, calling s.replace three times is much faster: more than twice as fast. :) - The solution above is short and easy to read and digest. It is also easy to maintain - you simply need to add additional entries to the mapping dict if you need to add additional strings. Calling replace 3 times in a row doesn't work correctly e.g. foo = bar bar = baz foo.replace(foo, bar).replace(bar, baz) But a bigger problem is that the above winner may not work correctly if there are conflicts between the target strings (e.g. 'a'-'X', 'aa'-'Y'). The problem is that the result you get depends on the order of the searches, BUT as given, that order is non-deterministic. dict.keys() returns in an arbitrary order, which means the caller can't specify the order except by accident. For example: repl = lambda x : m[x.group(1)] m = {'aa': 'Y', 'a': 'X'} pattern = (%s) % |.join(m.keys()) subn(pattern, repl, 'aaa') # expecting 'YX' ('XXX', 3) The result that you get using this method will be consistent but arbitrary and unpredictable. That's a simple fix import re mapping = { foo : bar, baz : quux, quuux : foo } keys = [(len(key), key) for key in mapping.keys()] keys.sort(reverse=True) keys = [key for (_, key) in keys] pattern = (%s) % |.join(keys) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux re.subn(pattern, repl, s) With regards to timing - I suspect that as the input string grows, the ratio of the regexp solution to the string solution will grow. If the map grows, the regexp solution seems faster (see below). Python's regular expression state machine is very inefficient with lots of disjunctions since it involves a lot of backtracking - this can be hand optimised for a much greater speed improvement. N = 1000 alphabet = abcdefghijklmnopqrstuvwxyz make_token = lambda : .join(sample(alphabet, 5)) mapping = dict([(make_token(), make_token()) for i in range(N)]) keys = [(len(key), key) for key in mapping.keys()] keys.sort(reverse=True) keys = [key for (_, key) in keys] pattern = (%s) % |.join(keys) replace_strs = [replace('%s', '%s') % (key, mapping[key]) for key in keys] command = s. + ..join(replace_strs) setup = import re regexp = re.compile(%s) repl = lambda x : mapping[x.group(1)] s = fooxxxbazyyyquuux % pattern t1 = Timer(regexp.subn(repl, s), setup) t2 = Timer(command, s = 'fooxxxbazyyyquuux') res1 = sum(t1.repeat(number=1000)) res2 = sum(t2.repeat(number=1000)) print res1 / res2 on my machine this comes to 0.316323109737 -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution __str__ method of an instance
Steven D'Aprano [EMAIL PROTECTED] wrote: However, you can dispatch back to the instance if you really must: class MyObj(object): def __init__(self): self.__str__ = lambda self: I'm an object! def __str__(self): return self.__str__(self) But honestly, this sounds like a bad idea. If instances of the one class have such radically different methods that they need to be treated like this, I question whether they actually belong in the same class. Another option would be to just change the class of the object: class C(object): pass c = C() print c __main__.C object at 0x01180C70 def wrapstr(instance, fn=None): if fn is None: def fn(self): return I'm an object Wrapper = type(instance.__class__.__name__, (instance.__class__,), {'__str__':fn}) instance.__class__ = Wrapper wrapstr(c) print c I'm an object isinstance(c, C) True type(c) class '__main__.C' wrapstr(c, lambda s: object %s at %s % (type(s).__name__, id(s))) print c object C at 18353264 (I'll leave enhancing wrapstr so that it avoids multiple levels of wrapping as an exercise for anyone who actually wants to use it.) -- Duncan Booth http://kupuguy.blogspot.com -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution __str__ method of an instance
netimen wrote: How can I substitute __str__ method of an instance? It's not possible. For performance and other reasons most __*__ methods are looked up on the type only. Christian -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution __str__ method of an instance
netimen wrote: I couldn't substitute __str__ method of an instance. Though I managed to substitute ordinary method of an instance: from types import MethodType class Foo(object): pass class Printer(object): def __call__(self, obj_self): return 'printed' f = Foo() f.printer = MethodType(Printer(), f, Foo) print f.printer() # works fine - I get: 'printed' print f # get: __main__.Foo object at 0x00D69C10 f.__str__ = MethodType(Printer(), f, Foo) print f # still get: __main__.Foo object at 0x00D69C10. Why? Foo.__str__ = MethodType(Printer(), None, Foo) print f # works fine - I get: 'printed' How can I substitute __str__ method of an instance? You can't. Special methods are only looked up on classes. Diez -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution __str__ method of an instance
Christian Heimes wrote: netimen wrote: How can I substitute __str__ method of an instance? It's not possible. For performance and other reasons most __*__ methods are looked up on the type only. Is that documented somewhere? I *know* it is that way, yet I'd like to have place to read up on it (and point to when this question pops up) Diez -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution __str__ method of an instance
netimen a écrit : I couldn't substitute __str__ method of an instance. Though I managed to substitute ordinary method of an instance: from types import MethodType class Foo(object): pass class Printer(object): def __call__(self, obj_self): return 'printed' f = Foo() f.printer = MethodType(Printer(), f, Foo) print f.printer() # works fine - I get: 'printed' print f # get: __main__.Foo object at 0x00D69C10 f.__str__ = MethodType(Printer(), f, Foo) print f # still get: __main__.Foo object at 0x00D69C10. Why? Foo.__str__ = MethodType(Printer(), None, Foo) print f # works fine - I get: 'printed' How can I substitute __str__ method of an instance? Now that others told you you couldn't do so, there's eventually a workaround - that is, if you have the hand on class Foo: class Foo(object): def __str__(self): printer = getattr(self, 'printer', super(Foo, self).__str__) return printer() HTH -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution __str__ method of an instance
Diez B. Roggisch a écrit : Christian Heimes wrote: netimen wrote: How can I substitute __str__ method of an instance? It's not possible. For performance and other reasons most __*__ methods are looked up on the type only. Is that documented somewhere? I *know* it is that way, yet I'd like to have place to read up on it (and point to when this question pops up) http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution __str__ method of an instance
On Thu, 23 Oct 2008 10:55:56 +0200, Christian Heimes wrote: netimen wrote: How can I substitute __str__ method of an instance? It's not possible. For performance and other reasons most __*__ methods are looked up on the type only. Christian However, you can dispatch back to the instance if you really must: class MyObj(object): def __init__(self): self.__str__ = lambda self: I'm an object! def __str__(self): return self.__str__(self) But honestly, this sounds like a bad idea. If instances of the one class have such radically different methods that they need to be treated like this, I question whether they actually belong in the same class. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of a method by a callable object
netimen wrote: Can I substitute a method of a class by a callable object (not a function)? I can very easy insert my function in a class as a method, but an object - can't. Yes you can and did. class Foo(object): pass class Obj(object): def __call__(self, obj_self): print 'Obj' def func(self): print 'func' f = Foo() Foo.meth = func f.meth() # all goes OK Foo.meth = Obj() f.meth() # I get TypeError: __call__() takes exactly 2 arguments (1 given) So either remove the unused obj_self parameter from __call__ or pass something -- anything -- to be bound to it. f.meth(1) for instance, works fime (in 3.0 at least) -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of a method by a callable object
On Oct 22, 12:13 pm, netimen [EMAIL PROTECTED] wrote: Can I substitute a method of a class by a callable object (not a function)? I can very easy insert my function in a class as a method, but an object - can't. I have the following: class Foo(object): pass class Obj(object): def __call__(self, obj_self): print 'Obj' def func(self): print 'func' f = Foo() Foo.meth = func f.meth() # all goes OK Foo.meth = Obj() f.meth() # I get TypeError: __call__() takes exactly 2 arguments (1 given) You have to wrap it as an (unbound) instance method explicitly: from types import MethodType Foo.meth = MethodType(Obj(), None, Foo) f.meth() For normal functions this seems to be done implicitly (of course you can do it explicitly if you want): Foo.meth = func print Foo.meth unbound method Foo.func George -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of a method by a callable object
netimen a écrit : Can I substitute a method of a class by a callable object (not a function)? I can very easy insert my function in a class as a method, but an object - can't. functions implement the descriptor protocol so when looked up as class attributes, the lookup invoke their __get__ method, which in turn returns a method object (which is a thin wrapper around the function, the class and the instance). You can either build the method manually (as Georges explained), or make your own Obj class a proper descriptor: from types import MethodType class Obj(object): __name__ = Obj # for Method.__repr_ def __call__(self, obj_self): print 'Obj' def __get__(self, instance, cls): return MethodType(self, instance, cls) HTH -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of a method by a callable object
On 22 окт, 20:46, Bruno Desthuilliers [EMAIL PROTECTED] wrote: netimen a écrit : Can I substitute a method of a class by a callable object (not a function)? I can very easy insert my function in a class as a method, but an object - can't. functions implement the descriptor protocol so when looked up as class attributes, the lookup invoke their __get__ method, which in turn returns a method object (which is a thin wrapper around the function, the class and the instance). You can either build the method manually (as Georges explained), or make your own Obj class a proper descriptor: from types import MethodType class Obj(object): __name__ = Obj # for Method.__repr_ def __call__(self, obj_self): print 'Obj' def __get__(self, instance, cls): return MethodType(self, instance, cls) HTH thanks! -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of a method by a callable object
George Sakkis wrote: On Oct 22, 12:13 pm, netimen [EMAIL PROTECTED] wrote: Can I substitute a method of a class by a callable object (not a function)? I can very easy insert my function in a class as a method, but an object - can't. I have the following: class Foo(object): pass class Obj(object): def __call__(self, obj_self): print 'Obj' def func(self): print 'func' f = Foo() Foo.meth = func f.meth() # all goes OK Foo.meth = Obj() f.meth() # I get TypeError: __call__() takes exactly 2 arguments (1 given) You have to wrap it as an (unbound) instance method explicitly: Nope. As the error message says, the method was called with nothing provided to be bound to the extraneous parameter obj_self. Either provide an arg, such as with f.meth(1), *or* delete obj_self and 'Obj' is printed, with both 2.5 and 3.0. -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of a method by a callable object
On 23 окт, 00:34, Terry Reedy [EMAIL PROTECTED] wrote: George Sakkis wrote: On Oct 22, 12:13 pm, netimen [EMAIL PROTECTED] wrote: Can I substitute a method of a class by a callable object (not a function)? I can very easy insert my function in a class as a method, but an object - can't. I have the following: class Foo(object): pass class Obj(object): def __call__(self, obj_self): print 'Obj' def func(self): print 'func' f = Foo() Foo.meth = func f.meth() # all goes OK Foo.meth = Obj() f.meth() # I get TypeError: __call__() takes exactly 2 arguments (1 given) You have to wrap it as an (unbound) instance method explicitly: Nope. As the error message says, the method was called with nothing provided to be bound to the extraneous parameter obj_self. Either provide an arg, such as with f.meth(1), *or* delete obj_self and 'Obj' is printed, with both 2.5 and 3.0. OK, I have implemented Bruno Desthuilliers example. But there is another question: can I having a method determine if it is an instance of given class. So: class Obj(object): __name__ = Obj # for Method.__repr_ def __call__(self, obj_self): print 'Obj' def __get__(self, instance, cls): return MethodType(self, instance, cls) class Foo(object): pass Foo.meth = Obj() ## in some another place of code if isinstance(Foo.meth, Obj): # doesn't work because type(Foo.meth) is now 'instancemethod' ... Can I determine that? -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of a method by a callable object
netimen a écrit : (snip) OK, I have implemented Bruno Desthuilliers example. But there is another question: can I having a method determine if it is an instance of given class. So: As the name imply, a method is usually, well, an instance of type 'method' !-) class Obj(object): (snip) class Foo(object): pass Foo.meth = Obj() ## in some another place of code if isinstance(Foo.meth, Obj): # doesn't work because type(Foo.meth) is now 'instancemethod' Indeed. I suppose what you want is to know if the callable wrapped by the method is an instance of Obj ? Can I determine that? Yeps. Test the im_func attribute of the method: if isinstance(Foo.meth.im_func, Obj): print yadda But you'd better put this in a try/except block, because a callable attribute of a class is not necessarily a method - and so it may not have an im_func attribute. Also, may I ask why you want to check this ? Not that it's necessarily wrong, but real use case for typechecking are pretty rare. -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of a method by a callable object
On 23 окт, 00:26, Bruno Desthuilliers [EMAIL PROTECTED] wrote: netimen a écrit : (snip) OK, I have implemented Bruno Desthuilliers example. But there is another question: can I having a method determine if it is an instance of given class. So: As the name imply, a method is usually, well, an instance of type 'method' !-) class Obj(object): (snip) class Foo(object): pass Foo.meth = Obj() ## in some another place of code if isinstance(Foo.meth, Obj): # doesn't work because type(Foo.meth) is now 'instancemethod' Indeed. I suppose what you want is to know if the callable wrapped by the method is an instance of Obj ? Can I determine that? Yeps. Test the im_func attribute of the method: if isinstance(Foo.meth.im_func, Obj): print yadda But you'd better put this in a try/except block, because a callable attribute of a class is not necessarily a method - and so it may not have an im_func attribute. Also, may I ask why you want to check this ? Not that it's necessarily wrong, but real use case for typechecking are pretty rare. Thanks! I have wasted much time playing with different Foo.meth trying to get to Obj through them. But im_func was one of the fields I haven't checked ) Indeed, I have managed already without that. The task was to substitute __str__ method by a complex formatter. It called a low- level formatter, a function wich returned simple str(self). That function could be called with objects with substituted formatters and with simple objects. So to avoid recursion I wanted to check wether the formatter of my object was substituted. -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of list elements
Am 18.07.2008 14:33, antar2 schrieb: I want to replace each first element in list 5 that is equal to the first element of the list of lists4 by the fourth element. I wrote following code that does not work: list4 = [['1', 'a', 'b', 'c'], ['2', 'd', 't', 'e'], ['8', 'g', 'q', 'f']] list5 = ['1', '2', '3'] for j in list4: for k in list5: for i,k in enumerate(list5): if j[0] == k: k = j[3] list5[i] = j[3] print list5 Wanted result: ['c', 'e', '3'] thanks! You didn't replace the list element itself. HTH, Wolfram -- http://mail.python.org/mailman/listinfo/python-list
Re: substitution of list elements
On 18 juil, 14:33, antar2 [EMAIL PROTECTED] wrote: I want to replace each first element in list 5 that is equal to the first element of the list of lists4 by the fourth element. I wrote following code that does not work: list4 = [['1', 'a', 'b', 'c'], ['2', 'd', 't', 'e'], ['8', 'g', 'q', 'f']] list5 = ['1', '2', '3'] for j in list4: for k in list5: if j[0] == k: k = j[3] print list5 Wanted result: ['c', 'e', '3'] thanks! select = lambda item, lst: (item, lst[3])[item == lst[0]] list5[:] = [select(*pair) for pair in zip(list5, list4)] # or if you prefer a more procedural solution: for index, (item, lst) in enumerate(zip(list5, list4)): if item == lst[0]: list5[index] = lst[3] -- http://mail.python.org/mailman/listinfo/python-list