class MyStr(str):
def contains(self, value):
return self.find(value) >= 0
s = MyStr("hello, world!")
s = s.capitalize()
if s.contains('Hello'):
print "Found it!"
It fails with an AttributeError when it calls s.contains(), because
s.capitalize() returned a str instead of a MyStr. Anyone want to take a
whack at defending this as the correct behavior?
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/
"I had lots of reasonable theories about children myself, until I
had some." --Michael Rios
>Consider the following code:
>
>class MyStr(str):
> def contains(self, value):
> return self.find(value) >= 0
>
>s = MyStr("hello, world!")
>s = s.capitalize()
>if s.contains('Hello'):
> print "Found it!"
>
>It fails with an AttributeError when it calls s.contains(), because
>s.capitalize() returned a str instead of a MyStr. Anyone want to take a
>whack at defending this as the correct behavior?
I don't think you could generally coerce base class method results
to subclass instances, so I think it has to be explicit. Maybe it
could be done with a method list for a more compact way (using a metaclass?)
Anyway:
>>> class MyStr(str):
... def contains(self, value):
... return self.find(value) >= 0
... def capitalize(self):
... return MyStr(str.capitalize(self))
...
>>> s = MyStr("hello, world!")
>>> s = s.capitalize()
>>> if s.contains('Hello'):
... print "Found it!"
...
Found it!
Regards,
Bengt Richter
Well, in e.g. C++ this would make perfect sense, since a base class
method can't know the real type of self/this. In Python we can do better
of course:
>>> class A:
... def foo(self):
... return self.__class__()
...
>>> class B(A):
... pass
...
>>> b = B()
>>> b.foo()
<__main__.B instance at 0x00864CC0>
which version is correct is mostly a religious question, but personally
I think that if we _can_ do better than C++ we should <wink>.
File a bug and see what Guido says...
-- bjorn
Looks like a bug to me. How can self be something else then what it is?
Should MySocket return a socket, thus stripping off any additional
functionality added by my derived class?
David LeBlanc
Seattle, WA USA
> Consider the following code:
>
> class MyStr(str):
> def contains(self, value):
> return self.find(value) >= 0
>
> s = MyStr("hello, world!")
> s = s.capitalize()
> if s.contains('Hello'):
> print "Found it!"
>
> It fails with an AttributeError when it calls s.contains(), because
> s.capitalize() returned a str instead of a MyStr. Anyone want to take a
> whack at defending this as the correct behavior?
solving this at the C level would require patching many stingobject factory
functions... e.g. PyString_FromStringAndSize for capitalize(). but it would
indeed be desireable.
i think it would like to have a even more genral mechanism. i would like to
have a possibility to replace the builtin type. e.g. i could replace the
builtin "str" and all strings from now on would be instaces of my class.
but that's clearly impossible in the current implementation.
<hacker warning>
like Bengt already sugested just automated ;-) ...
>>> class mstr(str):
... for name,m in str.__dict__.items():
... if type(m) == type(str.find):
... exec """def %s(*args, **kwargs):
... q = str.%s(*args, **kwargs)
... if type(q) is str: return mstr(q)
... else: return q\n""" % (name, name)
... def __contains__(self, other):
... return str.find(self, other) >= 0
...
>>> s = mstr("hello")
>>> type(s.capitalize())
<class '__main__.mstr'>
>>> 'll' in s.capitalize()
1
</hacker warning>
chris
--
Chris <clie...@gmx.net>
Hmmm...
maybe all methods of builtin types should do:
return self.__class__(return_value)
when returning a new object (like str methods).
-gustavo
class Names(str):
def __init__(self, namelist):
str.__init__(self, ":".join(namelist))
what would you expect
Names([1,2,3]).capitalize()
to return? An exception? I think it's dangerous to assume anything
about the subtyped classes' constructor. You *do* need a constructor
because strings are immutable so 'str.capitalize' can't modify
anything in place.
if-you-subtype-cake-you-gotta-eat-it-all-ly y'rs, holger
oops. sorry. should have checked it better (or at all<self.wink>)...
class Names(str):
def __new__(cls, namelist):
return str.__new__(str, ":".join(namelist))
n=Names(['tim','peter','guido'])
But hopefully my point was understandable that it is hard
to guess a return type for 'n.capitalize()' now ...
> to return? An exception? I think it's dangerous to assume anything
> about the subtyped classes' constructor. You *do* need a constructor
> because strings are immutable so 'str.capitalize' can't modify
> anything in place.
>
> if-you-subtype-cake-you-gotta-eat-it-all-ly y'rs, holger
cheers,
holger
Sounds like a bug to me, but perhaps fixing it at some point was part of the
plan from the beginning.
Editorially speaking, although I hadn't thought of this problem specificially, I
guess it might be another reason to use subclassing to augment behavior, not
change it.
I haven't figured out whether this sort of thing could happen with other, more
usefully subclassed types like list and dict, but I guess it could occur
whenever a built-in type returns its own (er, "parent") type. I bet somebody
can think of an example.
straight-man-ly y'rs,
=g2
_________________________________________________________________________
Grant R. Griffin g...@dspguru.com
Publisher of dspGuru http://www.dspguru.com
Iowegian International Corporation http://www.iowegian.com
Interesting way to go if you can't know except dynamically at run time
what types base class methods will return.
I don't know how you'd fully generalize this process though, and it
seems a shame to have to wrap everything in an extra layer. It would
be nice to be able to specify coercions in the subclass in a way that
base class methods could access quickly to check whether to call a coercion
routine on a result, e.g.,
__coercions__ = (str, mstr), (bool, No_Yes) # just as example with several coercions
Also str.split could even access this, and produce a list of MyStr substrings.
And also deeper bases' methods could check on self.__coercions__
Just OTTOMH, so not very thought through ;-)
BTW, I just thought of a 'where' keyword for 'for' e.g., the above for would become
for name,m in str.__dict__.items() where type(m) == type(str.find):
sort of like sql select ... where ... or the list comprehension if.
Regards,
Bengt Richter
I once had the same problem with subclassing the list type/class: you'd
need to override every single method of the base class to make
subclassing of builtin Python types really useful. I ended up just
implementing the parts of the sequence protocol that I needed in the
particular case.
I'll look at the other answers if there is some clever soluiton using
__getattr__ or a metaclass. One day I'll have to figure out that
metaclass stuff, anyways. I still have no idea what it's all about.
Gerhard
--
This sig powered by Python!
Außentemperatur in München: 17.1 °C Wind: 1.2 m/s
Looks like a waste of performance in about 99 % of the time. Hopefully,
this can be optimized at the C level.
Gerhard
--
This sig powered by Python!
Außentemperatur in München: 17.1 °C Wind: 1.3 m/s
Short course:
http://www.python.org/sf/468887
Long course:
http://www.python.org/sf/460020
Making sure this pisses you off in all cases required one of the biggest
patch sets that went into Python 2.2 <wink>.
why not use if, as in
[ name,m for name,m in str.__dict__.items() if type(m) ==
type(str.find) ]
--
Emile van Sebille
em...@fenx.com
---------
Well, it *was* supposed to be pseudo-code, I'm sure
that at the C level it can be done in a much more
efficient way, without having to resort to Python code.
:-P
:-)
-gustavo
pd: TGIF!!
Inheriting from a class/type with value semantics is usually bad
design. Use containment or helper functions instead.
it-so-happens-that-Python-has-support-for-creating-thusly-flawed-designs-
but-that-doesn't-make-it-a-good-idea-ly y'rs, Anders