Re: substitution

2010-01-22 Thread Duncan Booth
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

2010-01-21 Thread Wilbert Berendsen
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

2010-01-21 Thread MRAB

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

2010-01-21 Thread Iain King
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

2010-01-21 Thread Wilbert Berendsen
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

2010-01-21 Thread Anthra Norell

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

2010-01-20 Thread Peter Otten
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

2010-01-19 Thread Wyrmskull


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

2010-01-19 Thread Peter Otten
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

2010-01-19 Thread Wyrmskull

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

2010-01-19 Thread Wyrmskull
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

2010-01-18 Thread superpollo

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

2010-01-18 Thread Peter Otten
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

2010-01-18 Thread Steven D'Aprano
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

2010-01-18 Thread Anthra Norell

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

2010-01-18 Thread Iain King
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

2010-01-18 Thread Iain King
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

2010-01-18 Thread Peter Otten
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

2010-01-18 Thread superpollo
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

2010-01-18 Thread Iain King
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

2010-01-18 Thread Mel
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

2010-01-18 Thread Nobody
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

2010-01-18 Thread Anthra Norell

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

2010-01-18 Thread Duncan Booth
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

2010-01-18 Thread Anthra Norell

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

2010-01-18 Thread Steven D'Aprano
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

2010-01-18 Thread Iain King
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

2010-01-18 Thread Adi Eyal
 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

2008-10-24 Thread Duncan Booth
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

2008-10-23 Thread Christian Heimes

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

2008-10-23 Thread Diez B. Roggisch
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

2008-10-23 Thread Diez B. Roggisch
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

2008-10-23 Thread Bruno Desthuilliers

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

2008-10-23 Thread Bruno Desthuilliers

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

2008-10-23 Thread Steven D'Aprano
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

2008-10-22 Thread Terry Reedy

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

2008-10-22 Thread George Sakkis
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

2008-10-22 Thread Bruno Desthuilliers

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

2008-10-22 Thread netimen
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

2008-10-22 Thread Terry Reedy

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

2008-10-22 Thread netimen
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

2008-10-22 Thread Bruno Desthuilliers

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

2008-10-22 Thread netimen
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

2008-07-18 Thread Wolfram Kraus

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

2008-07-18 Thread [EMAIL PROTECTED]
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