Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

creating class objects inside methods

3 views
Skip to first unread message

horos11

unread,
Oct 3, 2009, 11:32:24 PM10/3/09
to
All,

I've got a strange one..

I'm trying to create a class object inside another class object by
using the code template below (note.. this isn't the exact code.. I'm
having difficulty reproducing it without posting the whole thing)

Anyways, the upshot is that the first time the Myclass() constructor
is called, the __init__ function gets executed.. The second time, it
calls the '__call__' method (and dies, because I don't have a call
method defined).

To get around this, I've made __call__ a synonym of __init__, which is
a horrid hack, and doesn't help me much (since I don't have a good
idea what's going on).

So - anyone have an idea of what's going on here? It looks like the
second time, the Myclass() call is interpreted as a class instance,
not a class object, but that seems odd to me.. Is this a python bug?
I'm seeing it in 2.6..If necessary, I can post the whole piece of
code..

Ed

class Myclass:

def __init__(self, b='default1', c='default2'):

self.b = b;
self.c = c;

def function(self):

other = Myclass();
return(other)

a = Myclass();

b = a.function()

Simon Forman

unread,
Oct 3, 2009, 11:48:00 PM10/3/09
to horos11, pytho...@python.org
> --
> http://mail.python.org/mailman/listinfo/python-list
>


class Myclass:
def __init__(self, b='default1', c='default2'):
self.b = b
self.c = c

def function(self):
other = Myclass()

return other

a = Myclass()
b = a.function()


>>> a
<__main__.Myclass instance at 0x95cd3ec>
>>> b
<__main__.Myclass instance at 0x95cd5ac>


What's the problem?


(Also, you can leave out the ';' at the end of statements. And
'return' isn't a function, you can leave out the ()'s.

horos11

unread,
Oct 4, 2009, 1:12:37 AM10/4/09
to

> >>> a
>
> <__main__.Myclass instance at 0x95cd3ec>>>> b
>
> <__main__.Myclass instance at 0x95cd5ac>
>
> What's the problem?

Like I said, the code was a sample of what I was trying to do, not the
entire thing.. I just wanted to see if the metaphor was kosher.

It sounds to me from your answer that this is unexpected behavior, so
I'll go ahead and post the whole thing. My guess is that it is a
python bug..

Run it (a simple puzzle game solved by breadth first search), and the
first time state() is called inside the method, it calls __init__.
Second time, and therafter, it calls __call__. I've highlighted where
the code fails by putting a pdb.set_trace().

Anyways, I've got a workaround (simply pass in any new objects needed
from the caller), but it is truly annoying that python is either
misleading or broken in this way.

Attached find code, does not work vs. 2.6..


Ed

----

from collections import deque
import copy
import pdb

class state:

def default_board():

return [
[ 1, 'x', 'x', 0 ],
[ 2, 2, 3, 4 ],
[ 5, 6, 6, 7 ],
[ 5, 6, 6, 7 ],
[ 8, 9, 10, 10 ],
[ 0, 'x', 'x', 0 ]
]

def default_types():

return {
1 : [ 0, 0 ],
2 : [ 0, 0, 0, 1 ],
3 : [ 0, 0 ],
4 : [ 0, 0 ],
5 : [ 0, 0, 1, 0 ],
6 : [ 0, 0, 1, 0, 0, 1, 1, 1 ],
7 : [ 0, 0, 1, 0 ],
8 : [ 0, 0 ],
9 : [ 0, 0 ],
10 : [ 0, 0, 0, 1 ]
}

def default_moves():

return []

def print_move(self, moveno, move):
print str(moveno) + ": " + str(move) + "\n"


def __init__(self, _board=default_board(), _moves=default_moves(),
_types=default_types()):

self.board = _board
self.moves = _moves
self.types = _types

def possible_moves(self):

moves_so_far = set()
moves_so_far.add('x')
moves_so_far.add(0)
ret = []
for y_idx in range(0, len(self.board)):
for x_idx in range(0, len(self.board[y_idx])):

piece = self.board[y_idx][x_idx]

if not piece in moves_so_far:

moves = self.legal_moves(y_idx, x_idx)
moves_so_far.add(piece)

if moves:
ret.extend(moves)

return ret

def is_answer(self):

if self.board[5][3] == 1:
return True
else:
return False

def legal_moves(self, ycoord, xcoord):

ret = []
for dir in [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ]:
ret.extend(self.addmove(dir[0], dir[1], ycoord, xcoord))

return ret

def empty(self, type, ycoord, xcoord, pieceno):

for itr in range(0, len(type), 2):

yy = type[itr]
xx = type[itr+1]

if not (len(self.board) > (yy+ycoord) >= 0) or not (len
(self.board[yy+ycoord]) > xx+xcoord >= 0):
return False

if not self.board[yy+ycoord][xx+xcoord] in [ 0, pieceno ]:
return False

return True

def addmove(self, ymult, xmult, ycoord, xcoord):

ret = []
pieceno = self.board[ycoord][xcoord]
type = self.types[pieceno]

if xmult != 0:
for xx in range(xcoord + xmult, -1 if xmult < 0 else 4, -1
if xmult < 0 else 1):
# if xx == 0:
# continue
if self.empty(type, ycoord, xx, pieceno):
ret.append(self.newmove(ycoord, xcoord, ycoord,
xx ))
else:
break

if ymult != 0:
for yy in range(ycoord + ymult, -1 if ymult < 0 else 6, -1
if ymult < 0 else 1):
# if yy == 0:
# continue
if self.empty(type, yy, xcoord, pieceno):
ret.append(self.newmove(ycoord, xcoord, yy,
xcoord))
else:
break

return ret

def newmove(self, fromy, fromx, toy, tox):

move = {
'fromx' : fromx,
'fromy' : fromy,
'toy' : toy,
'tox' : tox,
'piece' : self.board[fromy][fromx]
}

return move

def printout_path(self):

# print self
pdb.set_trace()
answer = state()

moveno = 0
print "\n==========================\n"

for moveno in range(0, len(self.moves)):
move = self.moves[moveno]
self.print_move(moveno, move)
answer.apply_move(move)
answer.print_board()
print "\n==========================\n"

def print_board(self):

for xx in self.board:

print ": ".join([ "%2s" % str(ii) for ii in xx ])

def to_string(self):

return str(self.board)

def apply_move(self, move):

self.moves.append(move)
num = self.board[move['fromy']][move['fromx']]
type = self.types[num]

for idx in range(0,len(type),2):
yy_delta = type[idx]
xx_delta = type[idx+1]
self.board[move['fromy']+ yy_delta][move['fromx']+
xx_delta] = 0

for idx in range(0,len(type),2):
yy_delta = type[idx]
xx_delta = type[idx+1]
self.board[move['toy']+ yy_delta][move['tox']+ xx_delta] =
num

def next_states(self):

ret = []
for move in self.possible_moves():
newstate = copy.deepcopy(self)
newstate.apply_move(move)
ret.append(newstate)

# pdb.set_trace()
# for xx in ret:
# print xx.__dict__
# print "\n"

return ret

seen_states = set()

start = state()
dq = deque()

dq.append(start)


while len(dq):

curstate = dq.popleft()
print "HERE " + str(curstate) + " => " + curstate.to_string() +
"\n"
curstate.printout_path()

if curstate.is_answer():
curstate.printout_path()

elif curstate.to_string() in seen_states:
print "DUP " + curstate.to_string()

else:
seen_states.add(curstate.to_string())
for state in curstate.next_states():
if not state.to_string() in seen_states:
dq.append(state)

print "Trying..\n"
state.print_board()
print "\n"

horos11

unread,
Oct 4, 2009, 1:34:13 AM10/4/09
to
Anyways, I see what's going on here:

With the line,

for state in curstate.next_states():
if not state.to_string() in seen_states:
dq.append(state)

Inadvertently using the name of a module as a variable seems to be
causing this.

In any case, this shouldn't cause issues with constructors, so I'd
call this a bug..

Ed

Carl Banks

unread,
Oct 4, 2009, 2:03:01 AM10/4/09
to
On Oct 3, 10:12 pm, horos11 <horo...@gmail.com> wrote:
> > >>> a
>
> > <__main__.Myclass instance at 0x95cd3ec>>>> b
>
> > <__main__.Myclass instance at 0x95cd5ac>
>
> > What's the problem?
>
> Like I said, the code was a sample of what I was trying to do, not the
> entire thing.. I just wanted to see if the metaphor was kosher.
>
> It sounds to me from your answer that this is unexpected behavior, so
> I'll go ahead and post the whole thing. My guess is that it is a
> python bug..

Sure.


> Run it (a simple puzzle game solved by breadth first search), and the
> first time state() is called inside the method, it calls __init__.
> Second time, and therafter, it calls __call__. I've highlighted where
> the code fails by putting a pdb.set_trace().
>
> Anyways, I've got a workaround (simply pass in any new objects needed
> from the caller), but it is truly annoying that python is either
> misleading or broken in this way.
>
> Attached find code, does not work vs. 2.6..

[snip]

I don't believe you couldn't reduce that to something simpler.

Anyway, I didn't bother reading all the code or running it, but I had
a suspicion what is was so I looked for it and saw what I was looking
for.

Here's you class statement:


> class state:


Now here's some code that appears much later at the top level:


>     else:
>         seen_states.add(curstate.to_string())
>         for state in curstate.next_states():
>             if not state.to_string() in seen_states:
>                 dq.append(state)
>
>                 print "Trying..\n"
>                 state.print_board()
>                 print "\n"


Whoops. It looks like you rebound the global variable "state" to a
new value, which makes the class no longer accessible by that name.

My immediate suggestion is to change the name of the class, and to
capitalize the first letter. "state" is a terrible name for a class.
Class instances, almost by default, maintain state, so naming a class
"state" says almost nothing about what the class is. Something like
GameState or PlayerState would be better.

Here is some reading material that can help you adjust your coding
style to help avoid such errors in the future:

http://www.python.org/dev/peps/pep-0008


Carl Banks

Carl Banks

unread,
Oct 4, 2009, 2:09:34 AM10/4/09
to
On Oct 3, 10:34 pm, horos11 <horo...@gmail.com> wrote:
> Anyways, I see what's going on here:
>
> With the line,
>
> for state in curstate.next_states():
>     if not state.to_string() in seen_states:
>         dq.append(state)
>
> Inadvertently using the name of a module as a variable seems to be
> causing this.

Nope, unless by "module" you meant "class".


> In any case, this shouldn't cause issues with constructors, so I'd
> call this a bug..

It's not a bug. In Python classes and global variables share the same
namespace.

Don't you think you should learn a bit more about how Python manages
objects and namespaces before going around calling things bugs?


Carl Banks

horos11

unread,
Oct 4, 2009, 2:14:08 AM10/4/09
to
Carl,

Thanks for the info, but a couple of points:

1. it wasn't meant to be production code, simply a way to teach
python.

2. this should either be a compile time or a runtime error.

'Actions at a distance' like this are deadly both to productivity and
to correctness - not only is this a runtime error, it is a *silent*
runtime error. Any other language I know would catch this, whether it
be lua, java, or perl.

Saying that 'whoa, this coding error should be handled by naming
convention' may be the only practical way of getting around this
limitation, but it is a limitation nonetheless, and a pretty big one.

Ed

O

horos11

unread,
Oct 4, 2009, 2:45:39 AM10/4/09
to

> It's not a bug.  In Python classes and global variables share the same
> namespace.
>
> Don't you think you should learn a bit more about how Python manages
> objects and namespaces before going around calling things bugs?
>
> Carl Banks

No, I don't think so..

Say you went to another country, where the people wore lead shoes,
hence not only going slower, but getting lead poisoning from time to
time.

Pointing out that shoes made of fabric might just be better should not
be heresy.

In this case, I think the overall goal was syntax simplicity, but it
sure as hell makes things confusing. No warning, or anything. The sane
behavior IMO would be to disallow the assignment unless put through a
special function, something like:

class(state) = ...

After all, python does have a precedent when you try to join, when:

":".join([1,2])

does not work because [1,2] is an array of ints, whereas

":" . join( str(x) for x in [1,2])

does.

Ed

Carl Banks

unread,
Oct 4, 2009, 3:09:55 AM10/4/09
to
On Oct 3, 11:14 pm, horos11 <horo...@gmail.com> wrote:
> Carl,
>
> Thanks for the info, but a couple of points:
>
>     1. it wasn't meant to be production code, simply a way to teach
> python.

I understand, and if you think it's overkill for your pedagogical
application then feel free not to follow the suggestions I gave you.


>     2. this should either be a compile time or a runtime error.
>
> 'Actions at a distance' like this are deadly both to productivity and
> to correctness - not only is this a runtime error, it is a *silent*
> runtime error. Any other language I know would catch this, whether it
> be lua, java, or perl.

I'm afraid that's just not reasonable given the nature of classes in
Python. Python made a deliberate design trade-off by treating classes
as first-class objects. This decision carries benefits and
drawbacks. You've seen one of the drawbacks. Benefits include
simpler data model and increased opportunities for dynamicism. Perl,
Java, and Lua made the opposite choice, thus they are able to catch
the above mistake.

You could argue that Python made the wrong choice, and that classes
ought not to be first-class objects. Fine. But it didn't, and the
protection you seek is sacrificed.

I suggest looking at tools like PyChecker and PyLint. I don't know if
they'd have found your error in this case, but they can find a lot of
problems Python itself misses.


> Saying that 'whoa, this coding error should be handled by naming
> convention' may be the only practical way of getting around this
> limitation, but it is a limitation nonetheless, and a pretty big one.

I believe it's a miniscule limitation in practice. It seems like a
big deal but doesn't actually happen much. YMMV.


Carl Banks

Dave Angel

unread,
Oct 4, 2009, 3:31:10 AM10/4/09
to horos11, pytho...@python.org
The bug in your code that we're discussing is caused because you rebound
a global attribute to a new value, and lost the original object.. Your
complaint is that when the global name happens to reference a class, and
the new value doesn't, you think the compiler should give an error.

If you would call this a limitation of Python, and think it should be
"fixed," then you clearly do not understand the language or its
philosophy. I can't compare to either lua or perl, but Java is a vastly
different language from Python, and this type of thing is at the heart
of the difference. In Java you must declare the types of everything at
compile time (except they had to make a big hole for collections), and
the compiler is therefore told much about the possible behavior of each
variable.

In Python you declare nothing, and much of the power of the language
comes from the fact that every construct is a first-class object.
Function definitions are fancy literal values for function objects,
class declarations are just one of the ways of making a factory
function, and classes themselves are instances of metaclasses. You can
declare new objects that mimic existing ones without having to define a
new class that derives from the old class (duck-typing). And you can
frequently reuse the runtime semantics intended for one purpose to
accomplish something very different.

Python also deliberately doesn't have a notion of "constant"
declaration, nor "private." It doesn't have the notion of a library (or
class) building a "sealed" implementation which cannot be customized.

What Python offers for many of these is some conventions. Names
starting with leading underscores are "private" by convention. Names
all uppercase are "constant." Names starting with an uppercase letter
are classes. But rather than trying to make a language definition of
each of these terms, it's just a convention, observed among the
consenting adults (?) cooperating in the codebase.

I'm not saying (here) whether Python is better or worse than the
languages which are strongly typed at compile time, but just that it's a
deliberate set of design decisions. And special-casing one or two of
the more obscure danger spots is not in keeping with the Python
philosophy. Further, I don't see that you did anything that the runtime
should disallow. You assigned a new value to the 'state' attribute.
And when you tried to call it, it called the __str__() method of that
object.

DaveA

Hendrik van Rooyen

unread,
Oct 4, 2009, 3:35:15 AM10/4/09
to pytho...@python.org
On Sunday, 4 October 2009 08:14:08 horos11 wrote:

> Saying that 'whoa, this coding error should be handled by naming
> convention' may be the only practical way of getting around this
> limitation, but it is a limitation nonetheless, and a pretty big one.

You misunderstand the dynamic nature of python - YOU rebound the name to
something else - how on earth can the interpreter know that this is not what
you meant?

Could you formulate a rule that the interpreter should follow to be able to
flag what you have done as an error?

- Hendrik

Carl Banks

unread,
Oct 4, 2009, 3:48:48 AM10/4/09
to
On Oct 3, 11:45 pm, horos11 <horo...@gmail.com> wrote:
> > It's not a bug.  In Python classes and global variables share the same
> > namespace.
>
> > Don't you think you should learn a bit more about how Python manages
> > objects and namespaces before going around calling things bugs?
>
> > Carl Banks
>
> No, I don't think so..
>
> Say you went to another country, where the people wore lead shoes,
> hence not only going slower, but getting lead poisoning from time to
> time.
>
> Pointing out that shoes made of fabric might just be better should not
> be heresy.

This analogy is wrong on two counts:

1. Pointing out that the "fabric might be better" is not analogous to
what you did. You claimed that Python's behavior was a bug, which
would be analogous to me saying, "lead shoes should be illegal".

2. I know enough about the properties of fabric and lead to make an
informed complaint over the use of lead for shoes, even if I am new to
the country. However you very clearly have a poor understanding of
Python's namespace and object models, and so you have little standing
to claim that Python is buggy in how it treats its namespaces.

I'd say the strongest claim you have grounds to make, given the level
of understanding you've shown, is "this is very confusing to noobs".

BTW, the Python maintainers are very particular to define "bug" as
"Python behaves differently than it is documentated to", and Python is
most definitely documented as acting the way it does.


> In this case, I think the overall goal was syntax simplicity, but it
> sure as hell makes things confusing. No warning, or anything. The sane
> behavior IMO would be to disallow the assignment unless put through a
> special function, something like:
>
> class(state) = ...
> After all, python does have a precedent when you try to join, when:
>
> ":".join([1,2])
>
> does not work because [1,2] is an array of ints, whereas
>
> ":" . join( str(x) for x in [1,2])
>
> does.

No, it really isn't a precedent. Yes, Python does type-checking quite
a bit, however there is no precedent at all for customizing assignment
to a regular variable. When you write "a = b", a gets bound to the
same object as b is bound to, end of story. You can't customize it,
you can't prevent it, you can hook into it, and neither object is
notified that an assignment is happening. This is true even if a or b
happen to be a class.

And if you say, "Well you should be able to customize assigment", my
answer is, "You were saying there was a precedent, I said there was
not". If you want to argue that it should be possible to customize
assignment, be my guest, but you'll have to do it without the benefit
of a precedent.

(You can customize assignment to an attribute or item, but that is not
what we're talking about, especially since classes are hardly ever
attributes or items.)


Carl Banks

Albert Hopkins

unread,
Oct 4, 2009, 6:12:04 AM10/4/09
to pytho...@python.org
Just by a brief look at your code snippet there are a few things that I
would point out, stylistically, that you may consider changing in your
code as they are generally not considered "pythonic":

* As already mentioned the "state" class is best if given a name
that is capitalized.
* As already mentioned the name "state" is (unintentionally)
re-used within the same scope. This could have been avoided
with the above naming convention change and also if the main
body of the code were in a function, say "main()"
* The "methods" default_board, default_types, and default_moves
appear to be static methods but are not defined as such.
* Also, since the above "methods" have no logic and simply return
a value they are probably best defined as static attributes
rather than methods. But if doing so you would need to alter
your constructor.
* You used a number of built-in names as attribute names (dir,
type). While this is legal Python it is generally not
recommended.
* You use range(0, n). 0 is the default start value for range()
so it is generally left out.
* You define a to_string() method. To have a string representation
of a class, one usually defines a __str__ method. This gives
the advantage whereby "print myobject" or '%s' % myjobject just
work.

Probably others can make more suggestions. You will find a lot of these
suggestions are borrowed from PEP8 [1] but you can peruse other people's
Python code to "learn from the masters".

Hope this helps,
-a


Rhodri James

unread,
Oct 4, 2009, 8:35:47 AM10/4/09
to pytho...@python.org
On Sun, 04 Oct 2009 07:14:08 +0100, horos11 <hor...@gmail.com> wrote:

> Carl,
>
> Thanks for the info, but a couple of points:
>
> 1. it wasn't meant to be production code, simply a way to teach
> python.

Speaking as someone who does teach Python, "Ew, no!" If you start by
teaching people bad habits, every educator who comes along afterwards
will curse your name. That includes teaching yourself.

--
Rhodri James *-* Wildebeest Herder to the Masses

Simon Forman

unread,
Oct 4, 2009, 1:35:18 PM10/4/09
to horos11, pytho...@python.org
On Sun, Oct 4, 2009 at 1:12 AM, horos11 <hor...@gmail.com> wrote:
>
>> >>> a
>>
>> <__main__.Myclass instance at 0x95cd3ec>>>> b
>>
>> <__main__.Myclass instance at 0x95cd5ac>
>>
>> What's the problem?
>
> Like I said, the code was a sample of what I was trying to do, not the
> entire thing.. I just wanted to see if the metaphor was kosher.

Right, but it doesn't help if you post code that doesn't actually
display the unexpected behaviour you're asking about.

> It sounds to me from your answer that this is unexpected behavior, so
> I'll go ahead and post the whole thing. My guess is that it is a
> python bug..

/What/ is unexpected behaviour? I ran the code you posted and worked
exactly like I expected.

Posting the whole thing is better than posting code that doesn't
display the issue, but this is too long. I'd ask you to repost a
minimal version that actually displays the problem you're asking about
but I see from the rest of this thread that you've already figured it
out.

Related to that, two points.

Learn python AS python, don't get caught up in what it does
differently than other languages. IMHO it's hands-down the most
useful. productive language out there for a tremendous number of
problem domains. Treat yourself to it. ;]

And second, please don't /teach/ python until you've learned it...

Regards,
~simon

> --
> http://mail.python.org/mailman/listinfo/python-list
>

horos11

unread,
Oct 4, 2009, 2:44:48 PM10/4/09
to

>
> > Thanks for the info, but a couple of points:
>
> >     1. it wasn't meant to be production code, simply a way to teach
> > python.
>
> Speaking as someone who does teach Python, "Ew, no!"  If you start by
> teaching people bad habits, every educator who comes along afterwards
> will curse your name.  That includes teaching yourself.
>
> --
> Rhodri James *-* Wildebeest Herder to the Masses

No offense, but I disagree. By programming without regards to pre-
existing style or convention I learned far more than I otherwise would
have if I had simply mimicked someone else.

And I still think that unbridled assignment - especially assignment
that can change the operational semantics of surrounding terms, at a
distance no less - is a horrid thing.

It gets even worse because the way python handles assignment. To go
back to my original program: why isn't the state variable that I
defined local to that 'if' loop?

while len(dq):

...
if curstate.is_answer():
...
else:
for state in ...


The answer? Because you can't explicitly declare it. It therefore
looks globally, finds the 'class state:' statement, and runs with it.
I should be able to say:

for my state in curstate.next_states():

to show explicitly what I'm doing.


Anyways, maybe I got off to a bad start, but I'm a bit leery of the
language. In my estimation it's trying to be 'too clever by half', and
this coming from a veteran bash/perl programmer. I mean, free form is
one thing, but too much of a good thing can be harmful to your
programming health. Maybe PyChecker or PyLint will help, I don't know.

Ed

(
ps - an aside, but what was the rationale behind only displaying one
error at a time on trying to run a script? I typically like to run a
compilation phase inside my editor (vim), get a list of errors, and
then go to each one and fix them.

And how do you just check a script's syntax without running it
anyways?
)

Benjamin Kaplan

unread,
Oct 4, 2009, 2:56:36 PM10/4/09
to pytho...@python.org

Because these aren't compile-time errors. Python has no compilation
phase- every statement (including def and class) is an executable
statement and it gets turned into byte code at execution time. Just
like any other language, when Python hits a runtime error, it stops.
> --
> http://mail.python.org/mailman/listinfo/python-list
>

Carl Banks

unread,
Oct 4, 2009, 3:37:11 PM10/4/09
to
On Oct 4, 11:56 am, Benjamin Kaplan <benjamin.kap...@case.edu> wrote:

> On Sun, Oct 4, 2009 at 2:44 PM, horos11 <horo...@gmail.com> wrote:
>
> > (
> > ps - an aside, but what was the rationale behind only displaying one
> > error at a time on trying to run a script? I typically like to run a
> > compilation phase inside my editor (vim), get a list of errors, and
> > then go to each one and fix them.
>
> > And how do you just check a script's syntax without running it
> > anyways?
> > )
>
> Because these aren't compile-time errors. Python has no compilation
> phase- every statement (including def and class) is an executable
> statement and it gets turned into byte code at execution time. Just
> like any other language, when Python hits a runtime error, it stops.

No, there is a compile phase, but the only error that is raised at
compile-time is SyntaxError. Because of Python's dynamicism the
compiler knows hardly anything about the objects at compile-time
(except in a few cases involving constants, which Python takes
advantage of to do some compile-time constant folding).


Carl Banks

Carl Banks

unread,
Oct 4, 2009, 3:40:49 PM10/4/09
to
On Oct 4, 3:12 am, Albert Hopkins <mar...@letterboxes.org> wrote:
>       * You define a to_string() method. To have a string representation
>         of a class, one usually defines a __str__ method.  This gives
>         the advantage whereby "print myobject" or '%s' % myjobject just
>         work.


In fairness, a lot of types define a to_string() method (especially
third-party types like numpy), but it's usually to produce a raw
binary output.

Presumably in Python 3 these methods will be renamed to_bytes.


Carl Banks

Simon Forman

unread,
Oct 4, 2009, 4:00:36 PM10/4/09
to horos11, pytho...@python.org
On Sun, Oct 4, 2009 at 2:44 PM, horos11 <hor...@gmail.com> wrote:
>
>>
>> > Thanks for the info, but a couple of points:
>>
>> >     1. it wasn't meant to be production code, simply a way to teach
>> > python.
>>
>> Speaking as someone who does teach Python, "Ew, no!"  If you start by
>> teaching people bad habits, every educator who comes along afterwards
>> will curse your name.  That includes teaching yourself.
>>
>> --
>> Rhodri James *-* Wildebeest Herder to the Masses
>
> No offense, but I disagree. By programming without regards to pre-
> existing style or convention I learned far more than I otherwise would
> have if I had simply mimicked someone else.

Don't teach newbies bad idiom.

> And I still think that unbridled assignment - especially assignment
> that can change the operational semantics of surrounding terms, at a
> distance no less - is a horrid thing.

That's opinion.

Python allows you to shoot yourself in the foot. It's on us as
programmers to be able to grok our code well enough to prevent nasty
errors. "With great power comes great responsibility." and all that.

> It gets even worse because the way python handles assignment. To go
> back to my original program: why isn't the state variable that I
> defined local to that 'if' loop?

There's no such thing as an "if loop".

The only answer to your question is "that's the way it is"... or,
equivalently, "that's the way Guido made it."

Check out "Python Scopes and Name Spaces"
http://www.python.org/doc/2.2/tut/node11.html#SECTION0011200000000000000000

> while len(dq):
>
>    ...
>    if curstate.is_answer():
>        ...
>    else:
>        for state in ...
>
>
> The answer? Because you can't explicitly declare it. It therefore
> looks globally, finds the 'class state:' statement, and runs with it.
> I should be able to say:
>
>    for my state in curstate.next_states():
>
> to show explicitly what I'm doing.

You can, you just have to be careful not to "shadow" some other name
in your namespace(s). Again, python makes a trade off between
"babysitting" the programmer on the one hand vs. raw flexibility on
the other.

> Anyways, maybe I got off to a bad start, but I'm a bit leery of the
> language. In my estimation it's trying to be 'too clever by half', and
> this coming from a veteran bash/perl programmer. I mean, free form is
> one thing, but too much of a good thing can be harmful to your
> programming health. Maybe PyChecker or PyLint will help, I don't know.

I think if you let python seep into your thinking you'll eventually
come to love it.

It /IS/ very (too) clever, but the cleverness is (IMHO) spent on
getting out of your way, rather than trying to insure you're doing
things right.

Eric Raymond has a great article where he talks about learning python:
http://www.linuxjournal.com/article/3882

"My second [surprise] came a couple of hours into the project, when I
noticed (allowing for pauses needed to look up new features in
Programming Python) I was generating working code nearly as fast as I
could type. When I realized this, I was quite startled. An important
measure of effort in coding is the frequency with which you write
something that doesn't actually match your mental representation of
the problem, and have to backtrack on realizing that what you just
typed won't actually tell the language to do what you're thinking. An
important measure of good language design is how rapidly the
percentage of missteps of this kind falls as you gain experience with
the language."

I can vouch for this: I can routinely write 200~300 lines of python
code and have it run flawlessly the first time. This doesn't happen
every time, but it's the norm rather than the exception.


Give it a chance. It's (IMHO) /beautiful/.


Happy hacking,
~Simon


> Ed
>
> (
> ps - an aside, but what was the rationale behind only displaying one
> error at a time on trying to run a script? I typically like to run a
> compilation phase inside my editor (vim), get a list of errors, and
> then go to each one and fix them.

I dunno the rationale, but the mechanism is uncaught exceptions
propagate up and halt the interpreter. Since nothing keeps going
after an uncaught exception, there's nothing there to report the next
error.

> And how do you just check a script's syntax without running it
> anyways?

Just run it. ;]

FWIW, use the interactive interpreter (or IPython variant) to play
with the language until you learn the syntax well enough not to write
bad syntax. For me anyway, that was the best/fastest way to learn it.

Rob Williscroft

unread,
Oct 4, 2009, 4:02:13 PM10/4/09
to
Benjamin Kaplan wrote in news:mailman.838.1254682604.2807.python-
li...@python.org in comp.lang.python:

>> And how do you just check a script's syntax without running it
>> anyways?
>> )
>
> Because these aren't compile-time errors. Python has no compilation
> phase-

Sure it does, compilation happens for every script that is executed.

And for every import, if the pre-compiled byte code can't be found it
is compiled (and the byte code saved as a .pyc or .pyo file).

Its only when a the interpreter has the complete compiled byte code
for a script or imported module that it executes anything.

Python could, if it was wanted, detect multiple syntax and other
compilation errors, but AIUI the (CPython) developers choose not
to, as it significantly simplifies (and thus speeds up) the
compilation process, which can be significant for an interpreted
language.

For example I just ran a script with the one line:

print "hello world"

through IronPython (2.0 (2.0.0.0) on .NET 2.0.50727.3082)

I counted "1 and 2 and ... 12" before I seeing "hello world"

(Aside I think this is something that the current IronPython beta
(2.6) "fixes", but I havent tried it myself yet.)

> every statement (including def and class) is an executable

Yes but for example the execution of the statement:

def example() : pass

just assignes (binds) the compiled function to the name "example".

> statement and it gets turned into byte code at execution time. Just
> like any other language, when Python hits a runtime error, it stops.
>

Rob.
--
http://www.victim-prime.dsl.pipex.com/

Terry Reedy

unread,
Oct 4, 2009, 5:29:01 PM10/4/09
to pytho...@python.org
horos11 wrote:

> Anyways, maybe I got off to a bad start,

Blaming programming errors on non-existent bugs in the interpreter is
not a way to endear yourself.

And perhaps Python truly is not your style.

> Maybe PyChecker or PyLint will help, I don't know.

I do not use them, but others swear by them.

> ps - an aside, but what was the rationale behind only displaying one
> error at a time on trying to run a script? I typically like to run a
> compilation phase inside my editor (vim), get a list of errors, and
> then go to each one and fix them.

It would complicate the compiler. It is consistent with the rest of
Python's error reporting system (one runtime error only also). Error
reports after the first may be bogus. Python aware editors, like the one
with IDLE, put the cursor at the reported location of a syntax error.
And they only have one cursor ;-).

> And how do you just check a script's syntax without running it
> anyways?

The checker programs parse the code, so I would expect they report
syntex errors.

Or: put $, a syntax error, on a line at the bottom of your script to
abort execution. If the interpreter stops there, everything before is
syntacally OK. If using a Python-aware editor, you will pop back into
the edit window at the bottom of the file.

But of course, not running means not running the test code, so the
program is not necessarily OK at all.

Terry Jan Reedy


Rhodri James

unread,
Oct 6, 2009, 7:42:40 PM10/6/09
to pytho...@python.org
On Sun, 04 Oct 2009 19:44:48 +0100, horos11 <hor...@gmail.com> wrote:

[somehow managing to trim all other attributions: he's the innermost,
then me next]

>> > Thanks for the info, but a couple of points:
>>
>> > 1. it wasn't meant to be production code, simply a way to teach
>> > python.
>>
>> Speaking as someone who does teach Python, "Ew, no!" If you start by
>> teaching people bad habits, every educator who comes along afterwards
>> will curse your name. That includes teaching yourself.
>

> No offense, but I disagree. By programming without regards to pre-
> existing style or convention I learned far more than I otherwise would
> have if I had simply mimicked someone else.
>
> And I still think that unbridled assignment - especially assignment
> that can change the operational semantics of surrounding terms, at a
> distance no less - is a horrid thing.

[snip]

Thank you for providing a perfect example of my point. How are you
getting on unlearning that assumption?

Pretty much every assignment in every language changes the operational
semantics of surrounding terms. Most such changes are trivial, but for
an obvious example consider programs running finite state machines.
When you change the state variable, you change what the program will
do in the future, usually in fairly major ways that may not be visible
from wherever your assignment takes place.

I'm hardly an expert in the area, but that does seem to be the point
of a lot of object-oriented design.

0 new messages