473,769 Members | 2,599 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Class Variable Access and Assignment

This has to do with class variables and instances variables.

Given the following:

<code>

class _class:
var = 0
#rest of the class

instance_b = _class()

_class.var=5

print instance_b.var # -> 5
print _class.var # -> 5

</code>

Initially this seems to make sense, note the difference between to last
two lines, one is refering to the class variable 'var' via the class
while the other refers to it via an instance.

However if one attempts the following:

<code>

instance_b.var = 1000 # -> _class.var = 5
_class.var = 9999 # -> _class.var = 9999

</code>

An obvious error occurs. When attempting to assign the class variable
via the instance it instead creates a new entry in that instance's
__dict__ and gives it the value. While this is allowed because of
pythons ability to dynamically add attributes to a instance however it
seems incorrect to have different behavior for different operations.

There are two possible fixes, either by prohibiting instance variables
with the same name as class variables, which would allow any reference
to an instance of the class assign/read the value of the variable. Or
to only allow class variables to be accessed via the class name itself.

Many thanks to elpargo and coke. elpargo assisted in fleshing out the
best way to present this.

perhaps this was intended, i was just wondering if anyone else had
noticed it, and if so what form would you consider to be 'proper'
either referring to class variables via the class itself or via
instances of that class. Any response would be greatly appreciated.
Graham

Nov 3 '05
166 8666
Op 2005-11-03, Magnus Lycka schreef <ly***@carmen.s e>:
Antoon Pardon wrote:
Op 2005-11-03, Steven D'Aprano schreef <st***@REMOVETH IScyber.com.au> :

There are two possible fixes, either by prohibiting instance variables
with the same name as class variables, which would allow any reference
to an instance of the class assign/read the value of the variable. Or
to only allow class variables to be accessed via the class name itself.

There is also a third fix: understand Python's OO model, especially
inheritanc e, so that normal behaviour no longer surprises you.

No matter wat the OO model is, I don't think the following code
exhibits sane behaviour:

class A:
a = 1

b = A()
b.a += 2
print b.a
print A.a

Which results in

3
1


On the other hand:
class C: ... a = [1]
... b=C()
b.a += [2]
b.a [1, 2] C.a

[1, 2]

I can understand that Guido was a bit reluctant to introduce
+= etc into Python, and it's important to understand that they
typically behave differently for immutable and mutable objects.


All fine by me. I won't be using python any less because of this,
because I use class variable very little and you can avoid this
problem by avoiding instance that shadow class variables and
always refer to class variables by class name.

But that doesn't mean we should consider this kind of behaviour
as it should be, just because it is in python.

--
Antoon Pardon
Nov 4 '05 #61
Op 2005-11-03, Steven D'Aprano schreef <st***@REMOVETH IScyber.com.au> :
On Thu, 03 Nov 2005 13:01:40 +0000, Antoon Pardon wrote:
Seems perfectly sane to me.

What would you expect to get if you wrote b.a = b.a + 2?
I would expect a result consistent with the fact that both times
b.a would refer to the same object.


class RedList(list):
colour = "red"

L = RedList(())

What behaviour would you expect from len(L), given that L doesn't have a
__len__ attribute?


Since AFAICT there is no single reference to the __len__ attribute that
will be resolved to two different namespace I don't see the relevance.
Why do you expect
b.a += 2 to give a different result?


I didn't know I did.


It seems to me that you do.

You didn't appear to be objecting to a line like x = b.a assigning the
value of 1 to x (although perhaps you do). If that was the case, then it
is perfectly reasonable to expect b.a = x + 2 to store 3 into b.a, while
leaving b.__class__.a untouched.

Of course, if you object to inheritance, then you will object to x = b.a
as well.


What I object to is that the mentioning of one instance gets resolved
to two different namespaces.
Since ints are immutable objects, you shouldn't expect the value of b.a
to be modified in place, and so there is an assignment to b.a, not A.a.


You are now talking implementation details. I don't care about whatever
explanation you give in terms of implementation details. I don't think
it is sane that in a language multiple occurence of something like b.a
in the same line can refer to different objects


That's an implementation detail only in the sense that "while condition"
is a loop is an implementation detail. It is a *design* detail.

b is a name, and any reference to b (in the same namespace) will refer
to the same object. At least until you rebind it to another object.
But some namespaces take great care not to allow a rebinding that would
result in the same name being resolved to a different namespace during
this namespace's lifetime.
But b.a is not a name, it is an attribute lookup,
An other implementation detail. b.a is a name search of 'a' in the
namespace b.
and by Python's rules of
inheritance that lookup will look up attributes in the instance, the
class, and finally any superclasses. If you persist in thinking of b.a as a name referring to a single object,
of course you will be confused by the behaviour. But that's not what
attribute lookup does. On the right hand side of an assignment, it will return the first existing
of b.__dict__['a'] or b.__class__.__d ict__['a']. On the left hand of an
assignment, it will store into b.__dict__['a'].


That holly python does it this way, doesn't imply it is reasonable to
do it this way or that all consequences of doing it this way are
reasonable.
I think it even less sane, if the same occurce of b.a refers to two
different objects, like in b.a += 2


Then it seems to me you have some serious design problems. Which would you
prefer to happen?

# Scenario 1
# imaginary pseudo-Python code with no inheritance:
class Paragraph:
ls = '\n' # line separator

para = Paragraph()
para.ls

=> AttributeError - instance has no attribute 'ls'
# Scenario 2
# imaginary pseudo-Python code with special inheritance:
class Paragraph:
ls = '\n' # line separator

linux_para = Paragraph()
windows_para = Paragraph()
windows_para.ls = '\n\r' # magically assigns to the class attribute
linux_para.ls

=> prints '\n\r'

# Scenario 3
# Python code with standard inheritance:
class Paragraph:
ls = '\n' # line separator

linux_para = Paragraph()
windows_para = Paragraph()
windows_para.ls = '\n\r'
linux_para.ls

=> prints '\n'


I don't see the relevance of these pieces of code. In none of them is
there an occurence of an attribute lookup of the same attribute that resolves
to different namespaces.

--
Antoon Pardon
Nov 4 '05 #62
Op 2005-11-03, Steven D'Aprano schreef <st***@REMOVETH IScyber.com.au> :
On Thu, 03 Nov 2005 13:35:35 +0000, Antoon Pardon wrote:
Suppose I have code like this:

for i in xrange(1,11):
b.a = b.a + i

Now the b.a on the right hand side refers to A.a the first time through
the loop but not the next times. I don't think it is sane that which
object is refered to depends on how many times you already went through
the loop.


Well, then you must think this code is *completely* insane too:

py> x = 0
py> for i in range(1, 5):
... x += i
... print id(x)
...
140838200
140840184
140843160
140847128

Look at that: the object which is referred to depends on how many times
you've already been through the loop. How nuts is that?


It is each time the 'x' from the same name space. In the code above
the 'a' is not each time from the same namespace.

I also think you new very well what I meant.

--
Antoon Pardon
Nov 4 '05 #63
Op 2005-11-03, Mike Meyer schreef <mw*@mired.org> :
Antoon Pardon <ap*****@forel. vub.ac.be> writes:
What would you expect to get if you wrote b.a = b.a + 2? I would expect a result consistent with the fact that both times
b.a would refer to the same object.


Except they *don't*. This happens in any language that resolves
references at run time.


Python doesn't resolve references at run time. If it did the following
should work.

a = 1
def f():
a = a + 1

f()

But letting that aside. There is still a difference between resolving
reference at run time and having the same reference resolved twice
with each resolution a different result.
Changing that would be changing a fundamental
- and *important* - feature of Python. Arbitrary restrictions to
prevent a single case of this from doing something people who aren't
used to suvh behavior are kludges, and would constitute a wart on the
language, pure and simple.
Python already has its warts. If you want to argue that fixing this
would make a bigger wart then the wart it is now. Fine I will accept
that.
If you think this is bad, you should consider Jensen's device. It uses
call-by-name, which Python doesn't have.


Actually, I would have thought it very interesting should python
have provided some choice in parameter semantics.

I think it even less sane, if the same occurce of b.a refers to two
different objects, like in b.a += 2


That's a wart in +=, nothing less. The fix to that is to remove +=
from the language, but it's a bit late for that.

<mike


Well we agree that there is a wart somewhere.

--
Antoon Pardon
Nov 4 '05 #64
Op 2005-11-04, Steve Holden schreef <st***@holdenwe b.com>:
Antoon Pardon wrote:
Op 2005-11-03, Stefan Arentz schreef <st***********@ gmail.com>:
Antoon Pardon <ap*****@forel. vub.ac.be> writes:

...
>>No matter wat the OO model is, I don't think the following code
>>exhibit s sane behaviour:
>>
>>class A:
>> a = 1
>>
>>b = A()
>>b.a += 2
>>print b.a
>>print A.a
>>
>>Which results in
>>
>>3
>>1
>
>I find it confusing at first, but I do understand what happens :-)

I understand what happens too, that doesn't make it sane behaviour.
>But really, what should be done different here?

I don't care what should be different. But a line with only one
referent to an object in it, shouldn't be referring to two different
objects.

It doesn't.

Yes it does. If the b.a refers to the instance variable, then an
AttributeError should be raised, because the instance variable doesn't
exist yet, so you can't add two to it.

Excuse me. The statement

a += 2

causes a to refer to a different object after the assignment than it did
before. So does the statement


But the 'a' is both times in the same namespace.
self.a += 2
In this case the 'a' is not necessarily both times in the same
name space.
So why are you so concerned that the pre-assignment reference comes from
a different scope to the post-assignment reference? The fact remains
that after both assignments the rebound name can no longer (ever) be
used to refer to its former referent without a further rebinding taking
place.
I concerned with the a refering to different variables. A variable being
a name in a specific namespace.
If the b.a refers to the class variable then two should be added to it.

Wring, wring, wring. (Sorry, got that wrong :-)
Neither happens instead we get some hybrid in which an instance varible
is created that gets the value of class variable incrented by two.

Yes. So does this mean you also have a problem with

def f(x):
x += 2

g = 3
print f(g)

When the function call executes, the name x is bound to an object in the
call's containing scope. Is it then your contention that the augmented
assignment in the function should add two to that object, changing the
value of g?


Whether I have a problem with this specific behaviour or not is
irrelevant. In this case we have only one namespace with an 'x'.
So searching for 'x' will not result in different variables being
found.
It doesn't, it simply proceeds along the lines of all Python assignments
and resolves the name as a reference to a specific object. It then
computes a new value from the referenced object and the augmented
assignment operator's right operand, and rebinds the name to the
newly-computed value.

Please stop talking about variables.
No I think variable is the right term here. It refers to a name
in a specific namespace.
Although augmented assignment operators have the *option* of updating
objects in place, surely not even you can require that they do so when
they are bound to an immutable object such as an integer.
No but I can require that the namespace to which a name is resolved,
doesn't change during the operation.
It doesn't touch the *class variable* A.a which is still 1.

Why "should" it? Why, why, why? And gain, just for good measure, why?
Augmented assignment to a function argument doesn't modify the passed
object when immutable, and you have no problem with that (I know as I
write that this is just asking for trouble, and it will turn out that
you also find that behavior deeply controversial ...)

But it accesses the class variable.

Repeat after me: "Python assignment binds values to names".


But not just to a name, it binds a name in a specific namespace.
When I write

class something:
a = 1
def __init__(self, val=None):
if val:
self.a += val

then in the last statement the augmented assignment rebinds "self.a"
from the class "variable" to a newly-created instance "variable". I am
of course using the word "variable" here in a Pythonic sense, rather
than in the sense that, say, a C programmer would use. In Python I
prefer to talk about binding names because talking of variables leads
people to expect that a name is bound to an area of memory whose value
is modified by assignment, but this is in fact not so.

The initial access to self.a uses the defined name resolution order to
locate a value that was bound to the name "a" in class scope. So what?
This is a long-documented fact of Python life. It's *supposed* to be
that way, dammit.
That it is documented, doesn't make it sane behaviour. Otherwise
all companies had to do was to document there bugs.

In a line like b.a += 2, you only have one reference to a name
to be resolved in a spefied namespace (hierarchy). Since there
is only one reference I don't think it is sane that two resolutions
are done with two different variables as a result.
I fail to understand why this is such a problem for you. But then it's
clear from long past experience that our perceptions of Python's
execution model differ quite radically, and that I seem to find it quite
satisfactory overall, whereas you are forever banging on about what
"should" be true of Python and what Python "should" do. Which, as is
probably obvious by now, I sometimes find just a teeny bit irritating.
Kindly pardon my tetchiness.

I suppose ultimately I'm just more pragmatic than you.
It has nothing to do with being more pragmatic. Being pragmatic
is about how you handle things with real life projects. It has
little to do with the degree in which you agree with the design
of the tool you have to work with. I would say I am more pragmatic
than most defenders of python, because when it comes done to
do my work, I just use python as best as I can, while a lot
of people here seem to think that every little criticism I have
is enough to go and look for a different language.
Plus I started
using Icon, whose assignment semantics are very similar, back in the
1970's, so Python's way of doing things fits my brain quite nicely,
thank you.


So, people can probably say that about any language they started with.
That a language suits a certain persons brain, may say more about
the person than about the language.

--
Antoon Pardon
Nov 4 '05 #65
Antoon Pardon wrote:
Because b.a += 2 expands to b.a = b.a + 2. Why would you want b.a =
<something> to correspond to b.__class__.a = <something>?

That is an implemantation detail. The only answer that you are given
means nothing more than: because it is implemented that way.


Something that is written in the language reference is not
an implementation detail. Every implementation that aims to
be Python must follow this. It's a design decision.

Whether you like it or not, you will find out that the behaviour
of Python is largely based on an idea of an underlying structure.
A lot of the syntax is basically just convenient ways to access
this structure, and there is a strong tradition to avoid magic.

The explicit use of self might be the most obvious example of that,
but you can find a lot of other things in Python that shows you
this, __dict__ for instance.

I agree that the behaviour you are questioning isn't completely
unsurprising for someone who stumbles over it the first time, but
considering how things work in Python classes, where the class
scope is searched if a name isn't found in the instance scope
(self.__dict__) , any other solution would involve more magic, and
be more surprising to someone who actually knows what is going on.

It's possible that a oldie like me, who started coding Python in
1996 is just blind to the warts in Python by now, but no language
is perfect, and whatever design decisions you make, they will have
both positive and negative consequences.

I frankly don't understand what you are after Antoon. Just to
vent your frustrations? If you want to use Python in an effective
way, try to learn how to use the language that actually exists.

Asking questions in this forum is clearly a part of that, but
your confrontational style, and idea that everything that bothers
you is a language bug that needs to be fixed is not the most
constructive approach. I'm pretty sure that it doesn't really solve
your coding problems, instead it leads the discussion away from the
practical solutions.

If you really want to improve the Python language, your approach
is completely off target. First of all, this isn't really the right
forum for that, and secondly, improvements to Python requires a
lot of cooperation and substantial contributions of work, not just
complaints, even if you might have a point now and then.
Nov 4 '05 #66
Antoon Pardon <ap*****@forel. vub.ac.be> writes:

....
Would it be too much to ask that in a line like.

x = x + 1.

both x's would resolve to the same namespace?


This is starting to look more like a nagging contest than a real
discussion imo.

Consider changing the semantics of what you are proposing and
think about all those Python projects that will break because they
depend on the above behaviour and even take advantage of it.

So in short: yes, it would be too much to ask :-)

But, you can fix it in your own code. Simply make sure that your
class variables have different names or a prefix.

S.
Nov 4 '05 #67
Antoon Pardon <ap*****@forel. vub.ac.be> writes:
Op 2005-11-03, Mike Meyer schreef <mw*@mired.org> :
Antoon Pardon <ap*****@forel. vub.ac.be> writes:
What would you expect to get if you wrote b.a = b.a + 2?
I would expect a result consistent with the fact that both times
b.a would refer to the same object.


Except they *don't*. This happens in any language that resolves
references at run time.


Python doesn't resolve references at run time. If it did the following
should work.

a = 1
def f():
a = a + 1

f()


No that has nothing to do with resolving things at runtime. Your example
does not work because the language is very specific about looking up
global variables. Your programming error, not Python's shortcoming.

S.
Nov 4 '05 #68
Op 2005-11-04, Stefan Arentz schreef <st***********@ gmail.com>:
Antoon Pardon <ap*****@forel. vub.ac.be> writes:

...
> Ah yes. Well, good luck with that. You seem to have decided that it is not
> sane and who am I to argue with that. It depends on your state of mind :-)
I can just say the opposite, that you seem to have decided that it is
sane.


I have. I like the Python model.


Fine good for you.
> The model makes sense in my opinion. If you don't like it then there are
> plenty of other languages to choose from that have decided to implement
> things differently.


And again this argument. Like it or leave it, as if one can't in general
like the language, without being blind for a number of shortcomings.


Personally I don't see it as a shortcoming.


Which isn't the point.
It is this kind of recations that make me think a number of people is
blindly devoted to the language to the point that any criticism of
the language becomes intollerable.


No not at all. Just look at all the PEPs and the changes in the language
that have been made in the past. Python is very much community driven and
that shows in it's progress.

You on the other hand keep talking about emo things like 'sane' and
'madness' without giving any technical backing about these problems
that you are having with the language.


That you took those emotionally, is not my responsibility. Would you
prefered it, had I called it a wart? As far as I see it, any negative
comment on python is reacted to in pretty much the same way. So
don't blame it on me using emotional language.

--
Antoon Pardon
Nov 4 '05 #69
Stefan Arentz <st***********@ gmail.com> writes:
Would it be too much to ask that in a line like.
x = x + 1.
both x's would resolve to the same namespace?

...
Consider changing the semantics of what you are proposing and
think about all those Python projects that will break because they
depend on the above behaviour and even take advantage of it.


Are you seriously saying there's lots of Python projects that would
break if this particular weirdness were fixed?
Nov 4 '05 #70

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

Similar topics

106
5600
by: A | last post by:
Hi, I have always been taught to use an inialization list for initialising data members of a class. I realize that initialsizing primitives and pointers use an inialization list is exactly the same as an assignment, but for class types it has a different effect - it calls the copy constructor. My question is when to not use an initalisation list for initialising data members of a class?
5
2149
by: xuatla | last post by:
Hi, I encountered the following compile error of c++ and hope to get your help. test2.cpp: In member function `CTest CTest::operator+=(CTest&)': test2.cpp:79: error: no match for 'operator=' in '*this = CTest::operator+(CTest&)((+t2))' test2.cpp:49: error: candidates are: CTest CTest::operator=(CTest&) make: *** Error 1
5
8732
by: Chris | last post by:
Hi, I don't get the difference between a struct and a class ! ok, I know that a struct is a value type, the other a reference type, I understand the technical differences between both, but conceptually speaking : when do I define something as 'struct' and when as 'class' ? for example : if I want to represent a 'Time' thing, containing : - data members : hours, mins, secs
9
1930
by: NevilleDNZ | last post by:
Can anyone explain why "begin B: 123" prints, but 456 doesn't? $ /usr/bin/python2.3 x1x2.py begin A: Pre B: 123 456 begin B: 123 Traceback (most recent call last): File "x1x2.py", line 13, in ? A() File "x1x2.py", line 11, in A
14
2643
by: lovecreatesbea... | last post by:
Could you tell me how many class members the C++ language synthesizes for a class type? Which members in a class aren't derived from parent classes? I have read the book The C++ Programming Language, but there isn't a detail and complete description on all the class members, aren't they important to class composing? Could you explain the special class behavior in detail? Thank you very much.
20
4043
by: tshad | last post by:
Using VS 2003, I am trying to take a class that I created to create new variable types to handle nulls and track changes to standard variable types. This is for use with database variables. This tells me if a variable has changed, give me the original and current value, and whether the current value and original value is/was null or not. This one works fine but is recreating the same methods over and over for each variable type. ...
20
1482
by: d.s. | last post by:
I've got an app with two classes, and one class (InventoryInfoClass) is an object within the other class (InventoryItem). I'm running into problems with trying to access (get/set) a private variable within the included class (InventoryInfo) from the "including" class (InventoryItem). Here's the code, trimmed down. I've included ********* at the start of the first line that's blowing up on me. I'm sure others that try to access the...
16
3448
by: John Doe | last post by:
Hi, I wrote a small class to enumerate available networks on a smartphone : class CNetwork { public: CNetwork() {}; CNetwork(CString& netName, GUID netguid): _netname(netName), _netguid(netguid) {}
0
9589
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9423
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10212
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10047
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9995
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
7410
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5304
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5447
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3563
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.