Extending built-in objects/classes

J

Jon Clements

Hi All,

I've reached the point in using Python where projects, instead of being
like 'batch scripts', are becoming more like 'proper' programs.

Therefore, I'm re-designing most of these and have found things in
common which I can use classes for. As I'm only just starting to get
into classes, I see that new style classes are thte way to go, so will
be using those. I come from a C++ background, and understand I need to
adjust my thinking in certain ways - I have read
http://www.geocities.com/foetsch/python/new_style_classes.htm.


As a really simple class, I've decided to make a 'str' to include a
'substr' function. Yes, I know this can be done using slicing, and
effectively this is what substr would do: something like;

class mystr(str):
"""" My rather rubbish but trying to be simple custom string class
"""
def substr(self,start,length,pad=False):
"""
Return str of (up to) _length_ chars, starting at _start_ which
is 1 offset based.
If pad is True, ensure _length_ chars is returned by padding
with trailing whitespace.
""""
return self.<what>[ (start-1): (start-1)+length ]

Ignore the fact pad isn't implemented...

<what> should be the actual string value of the string object: How do I
work out what this is?
Secondly, I'm not 100% sure what I need for the __init__; is str's
__init__ implicitly called, or do I need to call str's __init__ in
mystr's (I seem to remember seeing some code which did this, as well as
calling super()).

Any critiscm is appreciated.

Many thanks,

Jon.
 
C

cmdrrickhunter

My experiance is mostly with old-style classes, but here goes.

first off, the <what> question is actually easier than you think.
After all, self is an instance of a string, so self[3:4] would grab
the slice of characters between 3 and 4 =)

as for __init__, what I have found is that if you do not include an
__init__ function, the parent class's __init__ gets inherited, just
like any other function, so you dont need one. If you have multiple
inheritance, however, you must include an __init__ which calls the
__init__ on every parent, otherwise only the first parent's gets
called.
 
J

Jon Clements

My experiance is mostly with old-style classes, but here goes.

first off, the <what> question is actually easier than you think.
After all, self is an instance of a string, so self[3:4] would grab
the slice of characters between 3 and 4 =)

That's kind of funky - I like it. However, I'd still like to know what
as for __init__, what I have found is that if you do not include an
__init__ function, the parent class's __init__ gets inherited, just
like any other function, so you dont need one. If you have multiple
inheritance, however, you must include an __init__ which calls the
__init__ on every parent, otherwise only the first parent's gets
called.

Thanks for your post: it's most appreciated.

Cheers,

Jon.
 
J

John Machin

My experiance is mostly with old-style classes, but here goes.

first off, the <what> question is actually easier than you think.
After all, self is an instance of a string, so self[3:4] would grab
the slice of characters between 3 and 4 =)

That's kind of funky - I like it. However, I'd still like to know what
<what> technically is - any ideas on how to find out?

You have already been told: you don't need "self.<what>", you just write
"self" ... self *is* a reference to the instance of the mystr class that
is being operated on by the substr method.

You did ask for criticism: here's what's intended to be constructive
criticism: you can often find out answers a lot faster by actually
trying it out yourself. E.g. do I need an __init__() method?

|>> class mystr(str):
.... def substr(self, start, length):
.... return self[start-1:start-1+length]
....
|>> foo = mystr('abcdef')
|>> foo
'abcdef'
|>> foo.substr(2, 3)
'bcd'
|>> mystr.substr(foo, 2, 3)
'bcd'

No __init__(), no <what>, it just works!

HTH,
John
 
J

Jon Clements

John Machin wrote:
(snip)
You have already been told: you don't need "self.<what>", you just write
"self" ... self *is* a reference to the instance of the mystr class that
is being operated on by the substr method.
(snip)

I get that; let me clarify why I asked again.

As far as I'm aware, the actual representation of a string needn't be
the same as its 'physical' value. ie, a string could always appear in
uppercase ('ABCD'), while stored as 'aBcd'. If I need to guarantee that
substr always returned from the physical representation and not the
external appearance, how would I do this? Or, would self, always return
internal representation, (if so, how would I get external appearance?).

Or I could be talking complete _beep_ - in which case I apologise.

Jon.
 
J

John Machin

John Machin wrote:
(snip)
(snip)

I get that; let me clarify why I asked again.

As far as I'm aware, the actual representation of a string needn't be
the same as its 'physical' value. ie, a string could always appear in
uppercase ('ABCD'), while stored as 'aBcd'. If I need to guarantee that
substr always returned from the physical representation and not the
external appearance, how would I do this? Or, would self, always return
internal representation, (if so, how would I get external appearance?).

Or I could be talking complete _beep_ - in which case I apologise.

Jon.
The external appearance of an object is produced by repr and str
methods. These transform the internal value into a human-readable (and
Python-compilable, in the case of repr) format. When you are
subclassing, these methods would normally be inherited.

Let's transpose your question into the realm of floats. A float is
usually a 64-bit gizmoid with about 53 bits of mantissa, a sign bit, and
the rest is for the exponent. The external representations are character
strings like '3.3333333333333333e-021'. You want to subclass float so
that you can add handy methods like squared(). You would like it to be
as simple as:

def squared(self):
return self * self

There are two possibilities:
(a) It just works; e.g. print myfloat(1.1).squared() produces 1.21
(b) It doesn't work, you get some mysterious exception like

TypeError: can't multiply sequence by non-int

which you decode as meaning that it doesn't like you trying to multiply
two character strings together, and you have to code the return
expression as self.__internal__ * self.__internal__ or something like that.

1. Which of these possibilities do you think is more
useful/elegant/plausible?
2. [Stop me if you've heard this one before] When you try it out, what
happens?
3. Have you ever seen any indication in the manuals, tutorials, books,
code published online, etc etc as to which possibility has been implemented?

HTH,
John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top