My fight with classes :)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • TheSaint

    My fight with classes :)

    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(valu e, str): return
    if value.lower().s tartswith('a'):
    self.valueA += value
    if value.lower().s tartswith('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.StrJ oin 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
  • Peter Pearson

    #2
    Re: My fight with classes :)

    On Wed, 11 Jun 2008 22:16:56 +0800, TheSaint <fc14301589@icq mail.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(valu e, str): return
    if value.lower().s tartswith('a'):
    self.valueA += value
    if value.lower().s tartswith('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.

    Comment

    • Terry Reedy

      #3
      Re: My fight with classes :)


      "TheSaint" <fc14301589@icq mail.comwrote in message
      news:484fde63_1 @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(valu e, str): return

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

      | if value.lower().s tartswith('a'):
      | self.valueA += value
      | if value.lower().s tartswith('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



      Comment

      • Bruno Desthuilliers

        #4
        Re: My fight with classes :)

        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(nam e, age):
        state = dict(name=name, age=age)
        def set_name(new_na me=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('to to', 42)

        A bit cumbersome, indeed !-)


        Comment

        • TheSaint

          #5
          Re: My fight with classes :)

          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(nam e, age):
          state = dict(name=name, age=age)
          def set_name(new_na me=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

          Comment

          • Bruno Desthuilliers

            #6
            Re: My fight with classes :)

            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.

            Comment

            Working...