cgi, classes and their instances

Paul Boddie paul at boddie.net
Wed Jul 14 12:38:44 EDT 2004


klaus_neuner82 at yahoo.de (Klaus Neuner) wrote in message news:<3e96ebd7.0407130023.586cfb88 at posting.google.com>...
> Hello,
> 
> code (1) works, code (2) doesn't.
> 
> (1)
> data = cgi.FieldStorage()
> comment = data.getvalue("comment")
> user_name = data.getvalue("user_name")
> 
> (2)
> data = cgi.FieldStorage()
> comment = cgi.FieldStorage().getvalue("comment")
> user_name = cgi.FieldStorage().getvalue("user_name")

The only response to this that I've seen so far covers the
"accidental" properties that the second case has in the context of the
cgi library. But what's actually going on here is that you're creating
a new instance of FieldStorage for each value you're trying to access:

  cgi.FieldStorage() # This creates a new object.

And since you've already obtained such an object, there's no point in
creating more of them. In the context of the cgi library, you observe
that not all such objects contain the same data, too. Regardless of
whether you think this is a bad thing, it is useful to consider the
potential source of your confusion...

> This doesn't seem to be caused by general properties of objecthood
> in Python. Cf. (3).
> 
> (3)
> class TestClass:
>     x = "bar"
>     y = "foo"
> print TestClass().x
> print TestClass().y

The x and y attributes are class attributes - they are shared between
all instances of TestClass. When you instantiate TestClass...

  TestClass() # This is a new TestClass object.

...you can access these class attributes and observe that they are
shared between the separate instances:

  TestClass().x == TestClass().x # Is true, since we're referring
                                 # to the same thing.

You can actually access them directly on the class, too:

  TestClass.x

However, these attributes are not instance attributes and can
therefore not be described as being covered by the "properties of
objecthood". Instead, you should write something like this:

  class TestClass:
    def __init__(self, x, y):
      self.x = x
      self.y = y

And to deal with instances of this class (ie. objects):

  obj = TestClass("bar", "foo")
  print obj.x
  print obj.y

You could actually omit the constructor and just assign directly to
the instance attributes:

  class TestClass:
    pass

  obj = TestClass()
  obj.x = "bar" # Note that this is on the object, not the class.
  obj.y = "foo"
  print obj.x
  print obj.y

But if you were to casually create two such objects without setting
the same values on the instance attributes, comparing those attributes
could easily produce a non-true result.

  obj2 = TestClass()
  obj2.x = "pub"
  print obj2.x
  obj.x == obj2.x # Is false.

> So, what is the reason for the difference between (1) and (2)?

Now, you're probably about to respond to this with a remark about how
you knew all this already. ;-) But it is interesting to consider why
the FieldStorage object uses instance attributes to store its data, as
it clearly must do if the second example doesn't work. If you look at
the definition of the FieldStorage class (by digging inside the Lib
directory in your Python installation), you'll see that there are a
lot of "hidden", optional parameters to the initialiser, and the most
interesting one is that which takes a stream from which data will be
read in order to produce the conveniently accessible form field
values.

When you instantiate FieldStorage, the results of reading from the
specified stream will be stored as instance attributes. On subsequent
instantiations (looking at your second example), that stream will not
yield any useful information, and the resulting instance attributes
will not be set (or at least not in the same, meaningful way) on the
subsequent instances of FieldStorage. Therefore, querying each
subsequent object will produce different results from any querying of
the first object that was created.

Now I suppose you could suggest that FieldStorage should employ class
attributes to store form field values, but consider that stream
parameter again - while you might be using FieldStorage in a CGI
environment (where the default stream is sys.stdin and where there is
only one source of such values), FieldStorage can potentially be used
in other environments. Certainly, the use of class attributes would be
limiting in such environments, and the usage pattern depicted in the
second example, being a highly unusual approach in the simple CGI
case, would possibly be quite inappropriate in those other
environments.

Although verbose, I hope that this explanation makes the observed
behaviour more obvious.

Paul



More information about the Python-list mailing list