mutable member, bug or ...
Sambo
sambo at void.com
Mon Jun 12 04:03:46 EDT 2006
Bruno Desthuilliers wrote:
> Sambo a écrit :
>
>> By accident I assigned int to a class member 'count' which was
>> initialized to (empty) string and had no error till I tried to use it
>> as string, obviously. Why was there no error on assignment( near the
>> end ).
>
>
> Python is dynamically typed - which means that it's not the name that
> holds type info, but the object itself. names are just, well, names...
>
Hmm.. so I could have one instance with (int)count and (string)count?
(yay DBase flashback, BRRR)
I was going to initialize the vars in __init__() but somehow it didn't make sense to me( but left couple of them there).
> BTW, I failed to see where you assigned an int to the class attribute
> 'count'. I just saw a try to call a string - which should raise a
> TypeError.
>
I must have fixed it before posting.
gr_info.count = gr_info.first = gr_info.last = 0
??? except ValueError:
gr_info.count(0) ???
not sure what I was thinking there (maybe I was trying to triple fault the CPU hehe)
>> class Cgroup_info:
>
>
> Do yourself (and anyone having to work on or with your code) a favour:
> use new-style classes (ie : inherit from 'object'). And FWIW, the
> convention for class names is CamelCase - preferably without MS-like
> hungarian annotation.
>
Those damn hungarians with their calculators and notations, only later did it occur to me to paste the "class ServerInfo():" statement above.
> this creates a local variable 'group_name', bound to an empty string.
> Using the reference to the current instance (usually named 'self', and
> always passed in as first param) is *not* optional.
>
>> count = "0" #last time checked and processed/retrieved
In __init__() it was an oversight but after the class className()...
I may have thought it unnecessary, otherwise class consists only of a group of functions if as you say any vars should be created/initialized in __init__() hmmm.
> the string module is mostly deprecated. Use str object methods instead -
> or if you just want to create an int from it's representation as a
> string, int(self.count).
>
Are string object methods among others, things like:
words = sentence.split()
This no longer works for me is it because I imported 'string' ,
didn't import something or didn't use "from string import *" instead.
( must be a year since I last played with python.)
>
>> gr_info.group_name = grp
>
>
> Tthis create a new instance attribute "group_name" on the gr_info
> object. This instance attribute will shadow the class attribute of the
> same name.
>
Hmmm . so what is a class attribute good for?
> Also, FWIW, if you always know the value for group_name when
> instanciating a Cgroup_info object, you might as well pass it to the
> initializer.
>
Good point.
>> try:
>> ind = self.group_list.index( grp )
>
>
> The common convention for indices in each and every language is 'i'. If
> you really want a meaningful name, then group_index would be better.
>
lol, well like in a book and increasingly on the net index in used to refer to a list. So... I guess subscribed_group_list_index(_pointer) might be workable.
> Also, for this kind of lookups, dicts are really faster than lists.
>
I am storing group count first last, although I am considering moving the numeric data elsewhere, for about 100 items .. I'll leave dictionaries for future learning.
>> return ( gr_info )
>
>
> parenthesis here are useless (and FWIW, they would be just as useless in
> C++).
>
A habit, true in python , in C, I think I remember reading about return function and statement. I was important at some point in C or perhaps way back in Pascal.
>> print ind
>> if len( self.group_list[ind].split() ) == 4:
>> gr_info.count = self.group_list[ind].split()[1]
>> gr_info.first = self.group_list[ind].split()[2]
>> gr_info.last = self.group_list[ind].split()[3]
>
>
> group_list[ind] is the same as grp, isn't it ? if so, using grp directly
> might be much more efficient *and* much more readable.
>
no grp is the (string) group name that was used earlier to find the right
item in the list.
> Also, you're calling 4 times the same method. This is highly
> inefficient. Try this instead:
> parts = grp.split()
> if len(parts) == 4:
> gr_info.count, gr_info.first, gr_info.last = parts[1:]
>
>
yes I realized that in another function but forgot about the unpacking assignment of a slice.
>> else:
>> gr_info.count = gr_info.first = gr_info.last = "0"
>
>
> This style of "chained assignment" can be a real gotcha in Python. In
> this case, it is safe since "0" is immutable. But using a mutable object
> instead would lead to probably unexpected results. Try this:
>
> a = b = []
> a.append(1)
> print b
I rarely do that even in C particularly when working with struct members,
but now with shorter names it is affordable. barely remembered reading about it.
>
> You have to understand that Python "variables" (the correct name is
> "bindings") are just the association (in a given namespace) of a name
> and a *reference* (kind of a smart pointer) to an object.
>
>> return( gr_info )
>
>
> Here's a possible rewrite of your code. It's certainly not how it should
> be done, but (apart from going into wild guesses) it's difficult to come
> up with anything better without knowing the specs. Anyway, it should
> help you grasp a more pythonic way to do things:
>
> class GroupInfo(object):
>
> def __init__(self, group_name, count="0", first="0", last=""):
> self.group_name = group_name
> self.count = count #last time checked and processed/retrieved
> self.first = first
> self.last = last
>
> self.retrieval_type = "" # always , ask( if more than some
> limit), none
> self.date_checked = ""
> self.time_checked = ""
> self.new_count = ""
> self.new_first = ""
> self.new_last = ""
>
> # local storage maintanance vars
> self.pointer_file = ""
> self.message_file = ""
>
> #maintanance vars
> self.cur_mess_num = 0
> self.cur_mess_id = ""
>
> # if you want to store count as string
> # but retrieve it as an int. The setter will
> # be used by the initializer, and will then create
> # the implementation attribute _count
> def _get_count(self):
> return int(self._count)
>
> def _set_count(self, value):
> self._count = str(value)
>
> count = property(_get_count, _set_count)
>
>
> class ServerInfo(object):
> def __init__(self, ???)
> self._groups = {} # dict lookup is faster
> # ...
> def has_group(self, group_name):
> return self._groups.has_key(group_name)
>
> def get_group_stat(self, group_name):
> if not self.has_group(group_name):
> return GroupInfo(group_name, "0")
>
> parts = group_name.split()
> if len(parts) != 4:
> parts = [None, "0", "0", "0"]
> return GroupInfo(group_name, *(parts[1:4]))
>
>
> As a last point, I'd second Fredrik : don't try to write C++ in Python.
> Learn to write Python instead. The (freely available) "Dive into Python"
> book should be a good place to get started.
>
> HTH
New class style eh, I haven't got a grasp of the old style and exceptions
only out of necessity. Either the Python exception docs were easier to understand or simply since I had to, to use those Inet classes , I finally broke down. I may have to go to C with this, for the GUI and I don't think building list of 100,000 messages is realistic .
Well Thank You for all the good pointers.
More information about the Python-list
mailing list