473,387 Members | 1,575 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Confounded by Python objects

Hello group,

take a look at the code snippet below. What I want to do is initialize
two separate Channel objects and put some data in them. However,
although two different objects are in fact created (as can be seen
from the different names they spit out with the "diag()" method), the
data in the "sample" member is the same although I stick different
values in.

Thanks,
robert
(Sorry for Google Groups, but I don't have NNTP at work)

Here's the code:

#!/usr/bin/python

class Channel:
name = ''
sample = []

def __init__(self, name):
self.name = name

def append(self, time, value):
self.sample.append((time, value))
self.diag()

def diag(self):
print (self.name, self.sample)
chA = Channel('A')
chB = Channel('B')

chA.append(1, 1.1)
chB.append(2, 2.1)
chA.append(3, 1.2)
chB.append(4, 2.2)

print 'Result:'

chA.diag()
chB.diag()

------------------------------------
and here's the output:

('A', [(1, 1.1000000000000001)])
('B', [(1, 1.1000000000000001), (2, 2.1000000000000001)])
('A', [(1, 1.1000000000000001), (2, 2.1000000000000001), (3, 1.2)])
('B', [(1, 1.1000000000000001), (2, 2.1000000000000001), (3, 1.2), (4,
2.2000000000000002)])
Result:
('A', [(1, 1.1000000000000001), (2, 2.1000000000000001), (3, 1.2), (4,
2.2000000000000002)])
('B', [(1, 1.1000000000000001), (2, 2.1000000000000001), (3, 1.2), (4,
2.2000000000000002)])

What I'd like to see, however, is 2 tuples per Channel object, like
this:
('A', [(1, 1.1000000000000001)])
('B', [(2, 2.1000000000000001)])
('A', [(1, 1.1000000000000001), (3, 1.2)])
('B', [(2, 2.1000000000000001), (4, 2.2000000000000002)])
Result:
('A', [(1, 1.1000000000000001), (3, 1.2)])
('B', [(2, 2.1000000000000001), (4, 2.2000000000000002)])

Jul 24 '08 #1
8 867
bo*******@googlemail.com wrote:
take a look at the code snippet below. What I want to do is initialize
two separate Channel objects and put some data in them. However,
although two different objects are in fact created (as can be seen
from the different names they spit out with the "diag()" method), the
data in the "sample" member is the same although I stick different
values in.
that's because you only have one sample object -- the one owned by
the class object.

since you're modifying that object in place (via the append method),
your changes will be shared by all instances. python never copies
attributes when it creates an instance; if you want a fresh object,
you have to create it yourself.
class Channel:
tip: if you're not 100% sure why you would want to put an attribute
on the class level, don't do it. instead, just create all attributes
inside the __init__ method:
def __init__(self, name):
self.name = name
self.sample = [] # create fresh container for instance
def append(self, time, value):
self.sample.append((time, value))
self.diag()

def diag(self):
print (self.name, self.sample)
hope this helps!

</F>

Jul 24 '08 #2
On Jul 24, 7:45 pm, "boblat...@googlemail.com"
<boblat...@googlemail.comwrote:
class Channel:
name = ''
sample = []

def __init__(self, name):
self.name = name

def append(self, time, value):
self.sample.append((time, value))
self.diag()

def diag(self):
print (self.name, self.sample)
Okay, the problem is you're appending to a _class_ attribute, not to
an instance attribute.

If you change your class definition to this, it should work:

class Channel:
def __init__(self, name):
self.name = name
self.sample = []

That will provide each instance with its own version of the sample
attribute.

The 'self.name = name' in the __init__ for your original code binds a
new attribute to the instance, whereas 'self.sample.append(...' in the
class's append was appending to the class attribute instead.

Hope this helps.

- alex23
Jul 24 '08 #3
In message
<33**********************************@z66g2000hsc. googlegroups.com>,
bo*******@googlemail.com wrote:
class Channel:
name = ''
sample = []
These are class variables, not instance variables. Take them out, and ...
def __init__(self, name):
self.name = name
.... add this line to the above function

self.sample = []

Jul 24 '08 #4
On Jul 24, 11:59 am, Fredrik Lundh <fred...@pythonware.comwrote:
tip: if you're not 100% sure why you would want to put an attribute
on the class level, don't do it.
The reason I did it was sort of C++ish (that's where I come from): I
somehow wanted a list of attributes on the class level. More for
readibility than anything elase, really.
hope this helps!
Yup, did the trick. Thanks!
robert
Jul 24 '08 #5
On Jul 24, 6:10*pm, "boblat...@googlemail.com"
<boblat...@googlemail.comwrote:
On Jul 24, 11:59 am, Fredrik Lundh <fred...@pythonware.comwrote:
tip: if you're not 100% sure why you would want to put an attribute
on the class level, don't do it.

The reason I did it was sort of C++ish (that's where I come from): I
somehow wanted a list of attributes on the class level. More for
readibility than anything elase, really.
hope this helps!

Yup, did the trick. Thanks!
robert
yes, i thought your code is kind of static, so it didn't work for a
dynamic language like python.
in python, you don't have to say "static" to make an variable a class
variable, so the "name" and "sample" you kind of "declared" is indeed
class variables.
you may wonder why then the two instaces of "Channel" has different
names, that's because you assign to name in "__init__" and make it an
instance variable that shared the name "name" with a class variable.
As to "sample", it never get assigned to and when you say "append" the
class variable is changed in place.
hope my explaination helps.
Jul 25 '08 #6
satoru wrote:
As to "sample", it never get assigned to and when you say "append" the
class variable is changed in place.
hope my explaination helps.
Sure does, thanks a lot.

Here's an interesting side note: After fixing my "Channel" thingy the
whole project behaved as expected. But there was an interesting hitch.
The main part revolves around another class, "Sequence", which has a
list of Channels as attribute. I was curious about the performance of my
script, because eventually this construct is supposed to handle
megabytes of data. So I wrote a simple loop that creates a new Sequence,
fills all the Channels with data, and repeats.

Interistingly, the first couple of dozens iterations went satisfactorily
quickly (took about 1 second total), but after a hundred or so times it
got really slow -- like a couple of seconds per iteration.

Playing around with the code, not really knowing what to do, I found
that in the "Sequence" class I had again erroneously declared a class-level
attribute -- rather harmlessly, just a string, that got assigned to once in each
iteration on object creation.

After I had deleted that, the loop went blindingly fast without slowing
down.

What's the mechanics behind this behavior?

robert
Jul 26 '08 #7
On Sat, 26 Jul 2008 18:54:22 +0000, Robert Latest wrote:
Here's an interesting side note: After fixing my "Channel" thingy the
whole project behaved as expected. But there was an interesting hitch.
The main part revolves around another class, "Sequence", which has a
list of Channels as attribute. I was curious about the performance of my
script, because eventually this construct is supposed to handle
megabytes of data. So I wrote a simple loop that creates a new Sequence,
fills all the Channels with data, and repeats.

Interistingly, the first couple of dozens iterations went satisfactorily
quickly (took about 1 second total), but after a hundred or so times it
got really slow -- like a couple of seconds per iteration.

Playing around with the code, not really knowing what to do, I found
that in the "Sequence" class I had again erroneously declared a
class-level attribute -- rather harmlessly, just a string, that got
assigned to once in each iteration on object creation.

After I had deleted that, the loop went blindingly fast without slowing
down.

What's the mechanics behind this behavior?
Without actually seeing the code, it's difficult to be sure, but my guess
is that you were accidentally doing repeated string concatenation. This
can be very slow.

In general, anything that looks like this:

s = ''
for i in range(10000): # or any big number
s = s + 'another string'

can be slow. Very slow. The preferred way is to build a list of
substrings, then put them together in one go.

L = []
for i in range(10000):
L.append('another string')
s = ''.join(L)
It's harder to stumble across the slow behaviour these days, as Python
2.4 introduced an optimization that, under some circumstances, makes
string concatenation almost as fast as using join(). But be warned: join()
is still the recommended approach. Don't count on this optimization to
save you from slow code.

If you want to see just how slow repeated concatenation is compared to
joining, try this:

>>import timeit
t1 = timeit.Timer('for i in xrange(1000): x=x+str(i)+"a"', 'x=""')
t2 = timeit.Timer('"".join(str(i)+"a" for i in xrange(1000))', '')

t1.repeat(number=30)
[0.8506159782409668, 0.80239105224609375, 0.73254203796386719]
>>t2.repeat(number=30)
[0.052678108215332031, 0.052067995071411133, 0.052803993225097656]

Concatenation is more than ten times slower in the example above, but it
gets worse:
>>t1.repeat(number=40)
[1.5138671398162842, 1.5060651302337646, 1.5035550594329834]
>>t2.repeat(number=40)
[0.072292804718017578, 0.070636987686157227, 0.070624113082885742]

And even worse:
>>t1.repeat(number=50)
[2.7190279960632324, 2.6910948753356934, 2.7089321613311768]
>>t2.repeat(number=50)
[0.087616920471191406, 0.088094949722290039, 0.087819099426269531]

--
Steven
Jul 27 '08 #8
On Sun, 27 Jul 2008 20:04:27 +0200, Bruno Desthuilliers wrote:
>In general, anything that looks like this:

s = ''
for i in range(10000): # or any big number
s = s + 'another string'

can be slow. Very slow.

But this is way faster:

s = ''
for i in range(10000): # or any big number
s += 'another string'
Actually, no, for two reasons:

(1) The optimizer works with both s = s+t and s += t, so your version is
no faster than mine.

(2) The optimization isn't part of the language. It only happens if you
are using CPython versions better than 2.4, and even then not guaranteed.

People forget that CPython isn't the language, it's just one
implementation of the language, like Jython and IronPython. Relying on
the optimization is relying on an implementation-specific trick.
yeps : using augmented assignment (s =+ some_string) instead of
concatenation and rebinding (s = s + some_string).
Both are equally optimized.
>>timeit.Timer('s+=t', 's,t="xy"').repeat(number=100000)
[0.027187108993530273, 0.026471138000488281, 0.027689933776855469]
>>timeit.Timer('s=s+t', 's,t="xy"').repeat(number=100000)
[0.026300907135009766, 0.02638697624206543, 0.02637791633605957]

But here's a version without it:
>>timeit.Timer('s=t+s', 's,t="xy"').repeat(number=100000)
[2.1038830280303955, 2.1027638912200928, 2.1031770706176758]

--
Steven
Jul 27 '08 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
by: Berthold Hoellmann | last post by:
Hello, When I use ./configure --with-thread --with-fpectl --with-signal-module \ --with-pymalloc --enable-shared --with-cxx=g++ make test on 2.3.3 I get
2
by: Olaf Meyer | last post by:
I'm having some problems compiling Python 2.3.3 on HP-UX (B.11.00). I've tried sevral different options for the configure script (e.g. enabling/disabling gcc, aCC) but I always get the same problem...
1
by: Jerald | last post by:
Running python 2.3.4 on valgrind (a tool like purify which checks the use of uninitialized memory, etc), gives a lot of errors. See below. jfj@cluster:~/> python -V Python 2.3.4...
1
by: Karalius, Joseph | last post by:
Can anyone explain what is happening here? I haven't found any useful info on Google yet. Thanks in advance. mmagnet:/home/jkaralius/src/zopeplone/Python-2.3.5 # make gcc -pthread -c...
1
by: Justin Johnson | last post by:
Hello, I'm trying to build Python 2.5.0 on AIX 5.3 using IBM's compiler (VisualAge C++ Professional / C for AIX Compiler, Version 6). I run configure and make, but makes fails with undefined...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.