Can't do a multiline assignment!

S

s0suk3

I was shocked a while ago when a discovered that in Python you can't
do a multiline assignment
with comments between the lines.

For example, let's say I want to assign a bunch of variables to an
initial, single value. In C or a similar language you would do:

CONSTANT1 =
/* This is some constant */
CONSTANT2 =
CONSTANT3 =

/*This is yet some other constant */
CONSTANT =

1;

In Python, you usually can use parentheses to split something over
several lines. But you can't use parentheses for an assignment of
several lines. For that, you can use the line continuation character
('\'):

CONSTANT1 = \
CONSTANT2 = \
CONSTANT3 = \
1

But I realized that you can't do this:

CONSTANT1 = \
# Oops... syntax error
CONSTANT2 = \
CONSTANT3 = \ # This is also a syntax error
# And this too \
1

Does anyone know of a way to put the comments between lines like that?
I find this limitation very annoying.
 
G

Gary Herron

I was shocked a while ago when a discovered that in Python you can't
do a multiline assignment
with comments between the lines.

For example, let's say I want to assign a bunch of variables to an
initial, single value. In C or a similar language you would do:

CONSTANT1 =
/* This is some constant */
CONSTANT2 =
CONSTANT3 =

/*This is yet some other constant */
CONSTANT =

1;

Yuck! No way!! If you *want* to make your code that hard to read, I'm
sure you can find lots of ways to do so, even in Python, but don't
expect Python to change to help you toward such a dubious goal.

Seriously, examine your motivations for wanting such a syntax. Does it
make the code more readable? (Absolutely not.) Does it make it more
maintainable. (Certainly not -- consider it you needed to change
CONSTANT2 to a different value some time in the future.)

Gary Herron
 
S

s0suk3

Yuck! No way!! If you *want* to make your code that hard to read, I'm
sure you can find lots of ways to do so, even in Python, but don't
expect Python to change to help you toward such a dubious goal.

Well, my actual code doesn't look like that. Trust me, I like clean
code.
Seriously, examine your motivations for wanting such a syntax. Does it
make the code more readable? (Absolutely not.) Does it make it more
maintainable. (Certainly not -- consider it you needed to change
CONSTANT2 to a different value some time in the future.)

Yes, it makes it more readable. And yes, it does make it (a lot) more
maintainable. Mainly because I don't have those four variables, I have
about thirty. And I think I won't need to one or two of them, but
maybe all of them at once.
 
M

Marco Mariani

Yes, it makes it more readable. And yes, it does make it (a lot) more
maintainable. Mainly because I don't have those four variables, I have
about thirty. And I think I won't need to one or two of them, but
maybe all of them at once.

have fun with locals(), then (but please feel dirty :)

loc = locals()
for var in [
'foo', # INSERT
'bar', # COMMENT
'baz' # HERE
]:
loc[var] = 42
 
C

colas.francis

Well, my actual code doesn't look like that. Trust me, I like clean
code.


Yes, it makes it more readable. And yes, it does make it (a lot) more
maintainable. Mainly because I don't have those four variables, I have
about thirty. And I think I won't need to one or two of them, but
maybe all of them at once.

Out of sheer curiosity, why do you need thirty (hand-specified and
dutifully commented) names to the same constant object if you know
there will always be only one object?
 
S

s0suk3

On 17 avr, 17:40, (e-mail address removed) wrote:

Out of sheer curiosity, why do you need thirty (hand-specified and
dutifully commented) names to the same constant object if you know
there will always be only one object?

I'm building a web server. The many variables are names of header
fields. One part of the code looks like this (or at least I'd like it
to):

class RequestHeadersManager:

# General header fields
Cache_Control = \
Connection = \
Date = \
Pragma = \
Trailer = \
Transfer_Encoding = \
Upgrade = \
Via = \
Warning = \

# Request header fields
Accept = \
Accept_Charset = \
Accept_Encoding = \
Accept_Language = \
Authorization = \
....

Etc etc etc. At the end they'll all be assign to None. Then, when
initialized, __init__() will the the string of headers, parse them,
and use those variables shown above to assign to the header values. Of
course a normal request won't include all of those headers, so the
others will remain None. That's what I want.
 
D

D'Arcy J.M. Cain

On Thu, 17 Apr 2008 09:19:32 -0700 (PDT)
I'm building a web server. The many variables are names of header
fields. One part of the code looks like this (or at least I'd like it
to):

class RequestHeadersManager:

# General header fields
Cache_Control = \
Connection = \
Date = \
Pragma = \
Trailer = \
Transfer_Encoding = \
Upgrade = \
Via = \
Warning = \

# Request header fields
Accept = \
Accept_Charset = \
Accept_Encoding = \
Accept_Language = \
Authorization = \
...

Etc etc etc. At the end they'll all be assign to None. Then, when
initialized, __init__() will the the string of headers, parse them,
and use those variables shown above to assign to the header values. Of
course a normal request won't include all of those headers, so the
others will remain None. That's what I want.

So basically you want a class that has a dict of headers which __init__
assigns to and to get a header you basically return O.get(header).
 
C

colas.francis

I'm building a web server. The many variables are names of header
fields. One part of the code looks like this (or at least I'd like it
to):

class RequestHeadersManager:

# General header fields
Cache_Control = \
Connection = \
Date = \
Pragma = \
Trailer = \
Transfer_Encoding = \
Upgrade = \
Via = \
Warning = \

# Request header fields
Accept = \
Accept_Charset = \
Accept_Encoding = \
Accept_Language = \
Authorization = \
...

Etc etc etc. At the end they'll all be assign to None. Then, when
initialized, __init__() will the the string of headers, parse them,
and use those variables shown above to assign to the header values. Of
course a normal request won't include all of those headers, so the
others will remain None. That's what I want.

Ah, so they are not constant, I was mislead by the name 'CONSTANTn' in
your OP.

But why would you insist on:
"""
# helpful comment
CONSTANT1 = \
# there too
CONSTANT2 = \
CONSTANT3 = \
None
"""
rather than:
"""
# helpful comment
CONSTANT1 = None
# there too
CONSTANT2 = None
CONSTANT3 = None
"""
or even:
"""
CONSTANT = None
# helpful comment
CONSTANT1 = CONSTANT
# there too
CONSTANT2 = CONSTANT
CONSTANT3 = CONSTANT
"""

(hopefully you don't consider those names in your code. ^ ^)
 
G

Gary Herron

I'm building a web server. The many variables are names of header
fields. One part of the code looks like this (or at least I'd like it
to):

class RequestHeadersManager:

# General header fields
Cache_Control = \
Connection = \
Date = \
Pragma = \
Trailer = \
Transfer_Encoding = \
Upgrade = \
Via = \
Warning = \

# Request header fields
Accept = \
Accept_Charset = \
Accept_Encoding = \
Accept_Language = \
Authorization = \
...

But. *What's the point* of doing it this way. I see 14 variables
being assigned a value, but I don't see the value, they are getting.
Reading this bit if code provides no useful information unless I'm
willing to scan down the file until I find the end of this mess. And in
that scanning I have to make sure I don't miss the one single line that
does not end in a backslash. (Your ellipsis conveniently left out the
*one* important line needed to understand what this code is doing, but
even if you had included it, I'd have to scan *all* lines to understand
what a single value is being assigned.

There is *no way* you can argue that code is clearer than this:

# General header fields
Cache_Control = None
Connection = None
Date = None
Pragma = None
....

Gary Herron
 
A

Arnaud Delobelle

I'm building a web server. The many variables are names of header
fields. One part of the code looks like this (or at least I'd like it
to):

class RequestHeadersManager:

    # General header fields
    Cache_Control               = \
    Connection                  = \
    Date                        = \
    Pragma                      = \
    Trailer                     = \
    Transfer_Encoding           = \
    Upgrade                     = \
    Via                         = \
    Warning                     = \

    # Request header fields
    Accept                      = \
    Accept_Charset              = \
    Accept_Encoding             = \
    Accept_Language             = \
    Authorization               = \
...

Etc etc etc. At the end they'll all be assign to None. Then, when
initialized, __init__() will the the string of headers, parse them,
and use those variables shown above to assign to the header values. Of
course a normal request won't include all of those headers, so the
others will remain None. That's what I want.

Why not do something like:

class RequestHeadersManager:

def __init__(self, string):
self._fields = {}
# Populate self.fields with fields defined in 'string'

def __getitem__(self, fieldname):
return self._fields.get(fieldname, None)

This way you don't need to prebind all possible fields to None, and a
field is accessible by its actual name, which should be easier to
remember than an identifier derived from a field name. Moreover you
can more easily do some group manipulation of fields (e.g. print them
all

def print_fields(self):
for name, value in self._fields.iteritems():
print "%s: %s" % (name, value)
)
 
S

s0suk3

But. *What's the point* of doing it this way. I see 14 variables
being assigned a value, but I don't see the value, they are getting.
Reading this bit if code provides no useful information unless I'm
willing to scan down the file until I find the end of this mess. And in
that scanning I have to make sure I don't miss the one single line that
does not end in a backslash. (Your ellipsis conveniently left out the
*one* important line needed to understand what this code is doing, but
even if you had included it, I'd have to scan *all* lines to understand
what a single value is being assigned.

There is *no way* you can argue that code is clearer than this:

# General header fields
Cache_Control = None
Connection = None
Date = None
Pragma = None

class RequestHeadersManager:

# General header fields
Cache_Control = \
Connection = \
Date = \
Pragma = \
Trailer = \
Transfer_Encoding = \
Upgrade = \
Via = \
Warning = \

# Request header fields
Accept = \
Accept_Charset = \
Accept_Encoding = \
Accept_Language = \
Authorization = \
Expect = \
From = \
Host = \
If_Match = \
If_Modified_Since = \
If_None_Match = \
If_Range = \
If_Unmodified_Since = \
Max_Forwards = \
Proxy_Authorization = \
Range = \
Referer = \
TE = \
User_Agent = \

# Entity header fields
Allow = \
Content_Encoding = \
Content_Language = \
Content_Length = \
Content_Location = \
Content_MD5 = \
Content_Range = \
Content_Type = \
Expires = \
Last_Modified = \

None

def __init__(self, headers, linesep):
headersDict = parse_headers(headers, linesep)

for header in headersDict.keys():
charsLength = len(header)

if charsLength == 10:
if header == "connection":
self.Connection = headersDict["connection"]
elif header == "user-agent":
self.User_Agent = headersDict["user-agent"]

elif charsLength == 15:
if header == "accept-encoding":
self.Accept_Encoding = headersDict["accept-
encoding"]
elif header == "accept-language":
self.Accept_Language = headersDict["accept-
language"]

elif charsLength == 17:
if header == "if-modified-since":
self.If_Modified_Since = headersDict["if-modified-
since"]
elif header == "transfer-encoding":
self.Transfer_Encoding = headersDict["transfer-
encoding"]

elif charsLength == 2:
if header == "te":
self.TE = headersDict["te"]

elif charsLength == 3:
if header == "via":
self.Via = headersDict["via"]

elif charsLength == 4:
if header == "date":
self.Date = headersDict["date"]
elif header == "host":
self.Host = headersDict["host"]
elif header == "from":
self.From = headersDict["from"]

elif charsLength == 5:
if header == "allow":
self.Allow = headersDict["allow"]
elif header == "range":
self.Range = headersDict["range"]

elif charsLength == 6:
if header == "accept":
self.Accept = headersDict["accept"]
elif header == "expect":
self.Expect = headersDict["expect"]
elif header == "pragma":
self.Pragma = headersDict["pragma"]

elif charsLength == 7:
if header == "expires":
self.Expires = headersDict["expires"]
elif header == "referer":
self.Referer = headersDict["referer"]
elif header == "trailer":
self.Trailer = headersDict["trailer"]
elif header == "upgrade":
self.Upgrade = headersDict["upgrade"]
elif header == "warning":
self.Warning = headersDict["warning"]

elif charsLength == 8:
if header == "if-match":
self.If_Match = headersDict["if-match"]
elif header == "if-range":
self.If_Range = headersDict["if-range"]

elif charsLength == 11:
if header == "content-md5":
self.Content_MD5 = headersDict["content-md5"]

elif charsLength == 12:
if header == "content-type":
self.Content_Type = headersDict["content-type"]
elif header == "max-forwards":
self.Max_Forwards = headersDict["max-forwards"]

elif charsLength == 13:
if header == "authorization":
self.Authorization = headersDict["authorization"]
elif header == "cache-control":
self.Cache_Control = headersDict["cache-control"]
elif header == "content-range":
self.Content_Range = headersDict["content-range"]
elif header == "if-none-match":
self.If_None_Match = headersDict["if-none-match"]
elif header == "last-modified":
self.Last_Modified = headersDict["last-modified"]

elif charsLength == 14:
if header == "accept-charset":
self.Accept_Charset = headersDict["accept-
charset"]
elif header == "content-length":
self.Content_Length = headersDict["content-
length"]

elif charsLength == 16:
if header == "content-encoding":
self.Content_Encoding = headersDict["content-
encoding"]
elif header == "content-language":
self.Content_Language = headersDict["content-
language"]
elif header == "content-location":
self.Content_Location = headersDict["content-
location"]

elif charsLength == 19:
if header == "if-unmodified-since":
self.If_Unmodified_Since = headersDict["if-
unmodified-since"]
elif header == "proxy-authorization":
self.Proxy_Authorization = headersDict["proxy-
authorization"]

There! That's the whole code. I guess the way you suggest is simpler
and a bit more intuitive, but I was figuring that the way I suggested
it is more stylish.
 
S

s0suk3

Why not do something like:

class RequestHeadersManager:

def __init__(self, string):
self._fields = {}
# Populate self.fields with fields defined in 'string'

def __getitem__(self, fieldname):
return self._fields.get(fieldname, None)

This way you don't need to prebind all possible fields to None, and a
field is accessible by its actual name, which should be easier to
remember than an identifier derived from a field name. Moreover you
can more easily do some group manipulation of fields (e.g. print them
all

def print_fields(self):
for name, value in self._fields.iteritems():
print "%s: %s" % (name, value)
)

I do it with all the separate variables mainly for performance. If I
had the headers in a dict, I'd be looking up a string in a list of
strings (the keys of the dict) everytime I check for a header. Not
that that's going to take more that 0.1 seconds, but the program is
still small and simple. As it gets bigger, more features are gonna
slow things down.
 
S

Sion Arrowsmith

In Python, you usually can use parentheses to split something over
several lines. But you can't use parentheses for an assignment of
several lines.

Yes you can, you just need an iterable of the right length on
the other side for the tuple unpacking to work:
.... # This isn't a syntax error
.... CONSTANT2,
.... CONSTANT3, #and neither is this
.... CONSTANT) = [1] * 4
[ (k, v) for k, v in locals().items() if k.startswith("CONSTANT") ] [('CONSTANT', 1), ('CONSTANT1', 1), ('CONSTANT3', 1), ('CONSTANT2', 1)]
 
M

Michael Torrie

<code snipped>
There! That's the whole code. I guess the way you suggest is simpler
and a bit more intuitive, but I was figuring that the way I suggested
it is more stylish.

Umm, doesn't defining all those members in the class lead to class
variables, not instance variables? I believe the recommended way of
making it clear what instance variables to expect is to initialize them
all in __init__. Currently in your implementation, each instance of
your class is going to share the same variables for all those fields you
defined, which probably isn't what you want.

consider:

class myclass(object):
classvar1=None
classvar2=None

def __init__(self,test):
self.instancevar1=test
6

Also, your idea of checking the length of the headers to reduce the
number of string comparisons is a great case of premature optimization.
First it does not clarify the code, making it harder to follow.
Second, since web servers are I/O bound, it likely does nothing to
improve speed.

So my recommendation is to use a bunch of self.HEADER_NAME=None
declarations in __init__(). This is the expected way of doing it and
all python programmers who are looking at your code will immediately
recognize that they are instance variables.
 
S

s0suk3

In Python, you usually can use parentheses to split something over
several lines. But you can't use parentheses for an assignment of
several lines.

Yes you can, you just need an iterable of the right length on
the other side for the tuple unpacking to work:

... # This isn't a syntax error
... CONSTANT2,
... CONSTANT3, #and neither is this
... CONSTANT) = [1] * 4>>> [ (k, v) for k, v in locals().items() if k.startswith("CONSTANT") ]

[('CONSTANT', 1), ('CONSTANT1', 1), ('CONSTANT3', 1), ('CONSTANT2', 1)]

That's not the same kind of multiple assignment. There, you're just
unpacking several items from a sequence into several variables on the
left. Some would say that's a list assignment.
 
M

Michael Torrie

I do it with all the separate variables mainly for performance. If I
had the headers in a dict, I'd be looking up a string in a list of
strings (the keys of the dict) everytime I check for a header. Not
that that's going to take more that 0.1 seconds, but the program is
still small and simple. As it gets bigger, more features are gonna
slow things down.

As I just said in my other post, this is all premature optimization.
Make your program simple and clear up front, and then work on
spot-optimizations in the places that your code really is slow.
Premature optimization can kill you in terms of code reliability and
maintainability. The rule of thumb is that 80% of your program's
execution time will be in 20% of the code. Therefore you have to
profile the code and fine out exactly where this 20% is. Then you can
optimize it.

Another thing to consider is that referencing a member of a class or
instance already *is* a dictionary lookup. It's how python works. Thus
dictionaries are optimized to be fast. Since strings are immutable,
python hashes them into a fast lookup pointer. So every time you say
mydict["mykey"], it already knows the lookup pointer (hash) for "mykey"
(the string) and can find the dictionary entry very quickly, ideally in
O(1) time (well maybe log(N)). Thus putting your headers in a
dictionary is actually a really good idea for performance reasons.
 
A

Arnaud Delobelle

On Apr 17, 6:02 pm, (e-mail address removed) wrote:
[...]
I do it with all the separate variables mainly for performance. If I
had the headers in a dict, I'd be looking up a string in a list of
strings (the keys of the dict) everytime I check for a header. Not
that that's going to take more that 0.1 seconds, but the program is
still small and simple. As it gets bigger, more features are gonna
slow things down.

- Have you measured the difference in performance?

- Are you aware that attribute access is implemented as string lookup
in a dictionary?

i.e. when you write foo.bar, the interpreter looks for 'bar' in
foo.__dict__, and if it doesn't find it, then proceeds to look in
type(foo).__dict__. So in your code, if a header (with manager rhm)
has no 'allow' field and you do:

rhm.Allow

the interpreter looks up *two* dictionaries (rhm.__dict__ then
RequestHeadersManager.__dict__).
 
P

Peter Otten

Michael Torrie wrote:

That's not how Python actually works:

What actually happens is that the a.classvar1 = 9 assignment creates an
instance variable that shades the classvar:
.... alpha = 1
....1

So everything works as expected (until you start modifying mutable
classvars).

Peter
 
S

Steve Holden

Marco said:
Yes, it makes it more readable. And yes, it does make it (a lot) more
maintainable. Mainly because I don't have those four variables, I have
about thirty. And I think I won't need to one or two of them, but
maybe all of them at once.

have fun with locals(), then (but please feel dirty :)

loc = locals()
for var in [
'foo', # INSERT
'bar', # COMMENT
'baz' # HERE
]:
loc[var] = 42
And bear in mind there is an explicit notification of the danger of this
course of action in the CPython documentation, which refuses to
guarantee that changes made to the object returns by locals() will ve
reflected in the local namespace.

You have been warned.

regards
Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,836
Latest member
login dogas

Latest Threads

Top