By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,548 Members | 1,496 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,548 IT Pros & Developers. It's quick & easy.

My fight with classes :)

P: n/a
Hi,
I'm very new with classes. I still reading something around ;)

I got started to try a concatenation of 2 type of string, which have a
particular property to start with A or D.

My class here:
""" Small class to join some strings according to the leading first
letter"""

def __init__(self):
self.valueA= ''
self.valueD= ''

def __add__(self, value):
if not isinstance(value, str): return
if value.lower().startswith('a'):
self.valueA += value
if value.lower().startswith('d'):
self.valueD += value
return self.valueA ,self.valueD

__call__= __add__
__iadd__= __add__

my test on the shell:
>>from utilities import StrJoin as zx
k= zx()
k
<utilities.StrJoin instance at 0x9dc7ccc>
>>k +'aks'
('aks', '')
>>k +'daks'
('aks', 'daks')
>>k +'hdaks'
('aks', 'daks')
>>k +'dhks'
('aks', 'daksdhks')
>>j('boi')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'j' is not defined
>>k('boi')
('aks', 'daksdhks')
>>k('aboi')
('aksaboi', 'daksdhks')
>>k('duboi')
('aksaboi', 'daksdhksduboi')
>>k += 'liu'
k += 'aliu'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate tuple (not "str") to tuple
>>k
('aksaboi', 'daksdhksduboi')

Do I miss something?

I'd rather like to avoid class, but a function won't allow me to store so
easily data between several call.
Mostly I'd expect to pass to the built instance in a more elaborated
function. Then I mean call will be the primer goal.

--
Mailsweeper Home : http://it.geocities.com/call_me_not_now/index.html
Jun 27 '08 #1
Share this Question
Share on Google+
5 Replies


P: n/a
On Wed, 11 Jun 2008 22:16:56 +0800, TheSaint <fc********@icqmail.comwrote:
Hi,
I'm very new with classes. I still reading something around ;)

I got started to try a concatenation of 2 type of string, which have a
particular property to start with A or D.

My class here:
""" Small class to join some strings according to the leading first
letter"""

def __init__(self):
self.valueA= ''
self.valueD= ''

def __add__(self, value):
if not isinstance(value, str): return
if value.lower().startswith('a'):
self.valueA += value
if value.lower().startswith('d'):
self.valueD += value
return self.valueA ,self.valueD

__call__= __add__
__iadd__= __add__

my test on the shell:
[snip]
>>>k +'aks'
('aks', '')
>>>k +'daks'
('aks', 'daks')
[snip]
>>>k += 'liu'
k += 'aliu'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate tuple (not "str") to tuple
You have designed your class in a confusing way, and then you
were confused by it.

It was confusing to design your class in such a way that "k+'aks'"
modifies k, because "k+'aks'" appears to be just an expression.
Changing k as a side-effect of evaluating that expression is
unnecessarily confusing. See if you can figure out how to design
your class so that you modify k either by writing "k.append( 'aks' )"
or "k += 'aks'".

Speaking of which, you discovered that "k += 'liu';
k += 'aliu'" fails. It fails because "k += 'liu'" replaces k
with a tuple (because you return a tuple from your __add__
function), so k is no longer an instance of your class.

Do I miss something?

I'd rather like to avoid class, but a function won't allow me to store so
easily data between several call.
Classes are wonderfully useful, and it would be sad for you to
use Python while shunning classes. I strongly recommend looking
at some good examples of simple class programming; I apologize
for having no specific recommendations.

--
To email me, substitute nowhere->spamcop, invalid->net.
Jun 27 '08 #2

P: n/a

"TheSaint" <fc********@icqmail.comwrote in message
news:48********@news.tm.net.my...
| Hi,
| I'm very new with classes. I still reading something around ;)
|
| I got started to try a concatenation of 2 type of string, which have a
| particular property to start with A or D.
|
| My class here:
| """ Small class to join some strings according to the leading first
| letter"""

You left out the class statement.

| def __init__(self):
| self.valueA= ''
| self.valueD= ''
|
| def __add__(self, value):

I agree with P. Pearson that 'add' methods should generaly not be used for
mutation. Certainly, they are generally used to combine two objects of the
same or compatible classes, even if the result replaces one of them. This
method is equivalent to list.append.

| if not isinstance(value, str): return

Do you really want to just return None when there is bad input?

| if value.lower().startswith('a'):
| self.valueA += value
| if value.lower().startswith('d'):
| self.valueD += value
| return self.valueA ,self.valueD

List mutation methods return None so one cannot forget that they mutate.
In any case, the alternative is to return self. You seem to be returning
this tuple because you did not write an __str__ method. Doing two
different things in one method is what got you in trouble. So return None
or self and add

def __str__(self): return self.valueA + ', ' + self.valueB

| __call__= __add__
| __iadd__= __add__

This requires that __add__ return self. Better to use .append() and

def __iadd__(self, val):
self.append(val)
return self

| my test on the shell:
[snip good tests]
| >>k += 'liu'

k is now a tuple!
Hence the below

| >>k += 'aliu'
| Traceback (most recent call last):
| File "<stdin>", line 1, in <module>
| TypeError: can only concatenate tuple (not "str") to tuple
| >>k
| ('aksaboi', 'daksdhksduboi')

| Do I miss something?

That augmented assignment is assigment. Always.
You are not the first ;-)/

| I'd rather like to avoid class, but a function won't allow me to store so
| easily data between several call.

Classes are the general mechanism for bundling stored data and functions.
You can easily bundle *one* function and stored data with a nested
function.

def makeappender():
data = ['','']
def appender(val):
<code that mutates data>
return appender

For multiple functions, use classes.

| Mostly I'd expect to pass to the built instance in a more elaborated
| function. Then I mean call will be the primer goal.

__call__ can be an alias for append just as well as for __add__.

Terry Jan Reedy

Jun 27 '08 #3

P: n/a
TheSaint a écrit :
On 04:51, giovedì 12 giugno 2008 Terry Reedy wrote:

First of all a big thank you, all.
>def makeappender():
data = ['','']
def appender(val):
<code that mutates data>
return appender

I'll give it a try. I just doubting if the data will be shared outside the
function.
Each time makeappender is called, it returns a new appender function
object with it's own 'data' object. So 'data' won't be shared between
different instances of the appender function.
Actually, my practice goes to send all variables to the functions and
expecting a returned value.
Mostly a sane, sound and sensible approach IMHO - but doesn't work that
well when the function needs to maintain own state between calls.
Usually I'm not relying on that module's
variables are read inside a function. Probably I got wrong learning or
experiences.
As long as you only *read* module's globals from within a function,
that's mostly ok. When you start *writing* them it may be time to
reconsider the design (not that it's necessarily bad, but it's a
possible signal that something is wrong).
>For multiple functions, use classes.
Well... Closures are poor men's objects, or so they say (or is that the
other way round ?-).

def make_person(name, age):
state = dict(name=name, age=age)
def set_name(new_name=None):
state['name'] = new_name
def get_name():
return state['name']
def grow():
state['age'] += 1
def get_age()
return state['age']
return set_name, get_name, grow, get_age

(toto_set_name,
toto_get_name,
toto_grow,
toto_get_age) = make_person('toto', 42)

A bit cumbersome, indeed !-)
Jun 27 '08 #4

P: n/a
On 17:47, giovedì 12 giugno 2008 Bruno Desthuilliers wrote:
>>For multiple functions, use classes.
Well... Closures are poor men's objects, or so they say (or is that the
other way round ?-).
Well, I'd like to know what could be the reason to design a single-callclass
instead of a similar function.
def make_person(name, age):
state = dict(name=name, age=age)
def set_name(new_name=None):
I'm going to get a deeper thinking about a function's function :)

--
Mailsweeper Home : http://it.geocities.com/call_me_not_now/index.html
Jun 27 '08 #5

P: n/a
TheSaint a écrit :
On 17:47, giovedì 12 giugno 2008 Bruno Desthuilliers wrote:
>>>For multiple functions, use classes.
Well... Closures are poor men's objects, or so they say (or is that the
other way round ?-).

Well, I'd like to know what could be the reason to design a single-call class
instead of a similar function.
Convenience. FWIW, in Python, functions are objects, and when you use a
closure to maintain state, you in fact already use the function's class
features. Sometimes, it's just simpler and more straightforward to use a
custom callable object than closures. Two common examples are function
decorators taking arguments (which require "two levels" closures if you
want to define them as functions, something that the instanciation/call
scheme of a callable class handles naturally) and partial application.

Jun 27 '08 #6

This discussion thread is closed

Replies have been disabled for this discussion.