By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,383 Members | 2,063 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,383 IT Pros & Developers. It's quick & easy.

too dynamic - how to avoid?

P: n/a
mic
I've spent last hour trying to debug my code, when I found out that instead
of executing object's method I accidentaly overridden it with variable (see
below example). My stupid! But as the system becomes more complex, I begun
to wonder how to avoid such situations in the future. Does anybody have some
experiences about that?

Simple example:

class test:
def a(self, value):
print value
t = test()
t.a('my test') <= returns obviously 'my test'
t.a = 'my test' <= creates object's attribute a, so I'm loosing my method

Regards,

Michal
Jul 18 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
mic wrote:
I've spent last hour trying to debug my code, when I found out that
instead of executing object's method I accidentaly overridden it with
variable (see below example). My stupid! But as the system becomes more
complex, I begun to wonder how to avoid such situations in the future.
Does anybody have some experiences about that?
Yes, and the experience is: it's not a problem in practice. Still,
if you disagree, Python gives you the tools to protect yourself -- read
on.

Simple example:

class test:
def a(self, value):
print value
t = test()
t.a('my test') <= returns obviously 'my test'
t.a = 'my test' <= creates object's attribute a, so I'm loosing my method


First of all, be sure to make your classes newstyle, e.g.
class test(object):
otherwise, by default, you get oldstyle classes, where compatibility
constraints mean most important new features just can't work right.

Now, limiting discussion to newstyle classes only:

in a class's dictionary there are two kinds of descriptors --
somewhat arbitrarily names 'data' and 'non-data' kinds of descriptors.

The 'non-data' kind, used for example for methods, are SPECIFICALLY
designed to be overridable per-instance. The 'data' kind aren't.

(Names are rather artificial; the real distinction is whether a
__set__ method is present in the descriptor -- if yes, it's data,
otherwise it's non-data -- calling it "setting-intercept" might
be clearer than calling it 'data'...!). Check it out...:

class c(object):
def a(self): pass
b = property(a)

descriptor 'a' is non-data, so it can be overridden in instances;
descriptor 'b' is data, so it cannot. E.g.:
x=c()
x.a=23
x.b=23 Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: can't set attribute


The 'property' type of descriptors isn't quite suitable for what
you want, of course, because even just ACCESSING x.b makes a CALL
to x.a. Rather, you want a new and different "nonrebindablemethod"
type of descriptor whose __get__ is just like the function, while
its __set__ raises the exception. So, make such a type:

class norebind(object):
def __init__(self, func): self.func = func
def __get__(self, *args): return self.func.__get__(*args)
def __set__(self, *args): raise TypeError

class c(object):
def a(self): pass
b = norebind(a)

There -- now, after x=c(), attempts to rebind x.b will raise a
TypeError, as you apparently wish. Note that you can code the
class as:

class c(object):
def a(self): pass
a = norebind(a)

so that there's no x.b -- just a non-rebindable x.a.
You won't need it in practice, but it's still a cool hack:-).

Alex

Jul 18 '05 #2

P: n/a
"mic" <al*****@onet.pl> writes:
I've spent last hour trying to debug my code, when I found out that instead
of executing object's method I accidentaly overridden it with variable (see
below example). My stupid! But as the system becomes more complex, I begun
to wonder how to avoid such situations in the future. Does anybody have some
experiences about that?


- use of decent naming schemes presumably helps (and if your class gets so big
that you can't remember what are attributes and what are methods refactoring
would probably be a good idea)

- if that's not enough you can always do something like override __setattr__,
to check that you don't overwrite instance methods, e.g. (UNTESTED):

import types
class bar:
...
def __setattr__(self, attr, value):
if isinstance(getattr(self, attr, None), types.MethodType):
raise RuntimeError("Trying to overwrite method %s" % attr)
else setattr(self, attr, value)
- if you need this often, you could write a function or metaclass to avoid
duplicating the above in all classes where you feel you need it.
'as
Jul 18 '05 #3

P: n/a
"mic" <al*****@onet.pl> wrote:
I've spent last hour trying to debug my code, when I found out that instead
of executing object's method I accidentaly overridden it with variable (see
below example). My stupid! But as the system becomes more complex, I begun
to wonder how to avoid such situations in the future. Does anybody have some
experiences about that?

Simple example:

class test:
def a(self, value):
print value
t = test()
t.a('my test') <= returns obviously 'my test'
t.a = 'my test' <= creates object's attribute a, so I'm loosing my method


From this I can't discern whether you're asking a simple question or
want some sophisticated, nifty programming advice. I'm assuming you
just want some help using the interpreter and the overall programming
environment.

If something -whatever- is not quite as expected it's very important
to read the traceback (if there is one) from the interpreter output,
for example in this case trying to call t.a('my test') after t.a has
been bound to a string will result in some complaint from the
interpreter that type 'str' has no call method. It's also very a good
idea to include the traceback in usenet posts since that makes it
possible to receive more specific comments.

Another thing is that it's very handy to use the interactive
interpreter to test pieces of code that behave in unexpected ways.
Just try it out and check the output of your functions. It's not like
indexing an array out of bounds will make your complete system crash
or make it instable, Python is reasonably well defended against simple
mistakes.

The dir command is handy too, for example dir(t.a) will give some info
about what the interpreter thinks t.a is. Next, sprinkling your code
with print statements -turning it into a poor mans debugger system-
works very well for most of the mistakes of this calibre.

Please note that given the dynamic nature of Python the above code
snippet might be exactly what you want and there's no way for the
interpreter yet to do what you intend rather than what you code ;-)

Then there's the debugger inside Idle, but the strategies above are
sufficient in most cases, so that -at least in my case- it's almost
never necessary to use it. I mostly use Scite as an editor and have
pychecker* a single keypress away, but I only use it to doublecheck my
code after it runs as expected.

HTH,

Anton

* http://pychecker.sourceforge.net/

Jul 18 '05 #4

P: n/a
On Thu, 02 Oct 2003 11:56:49 +0200, mic wrote:
My stupid! But as the system becomes more complex, I begun
to wonder how to avoid such situations in the future. Does anybody have some
experiences about that?


1) Don't do it.
2) You can use a naming convention
a) Methods have verbs, variables don't: set_temperature, temperature
b) Prefix members with warts: x.temperature() x._temperature or
x.its_temperature
c) Your choice here
3) See #1, above

Pychecker doesn't seem to pick this up. I don't know about pylint.
I guess it might be something possible if you are talking methods
and attributes.

Tim
Jul 18 '05 #5

P: n/a
"mic" <al*****@onet.pl> writes:
I've spent last hour trying to debug my code, when I found out that instead
of executing object's method I accidentaly overridden it with variable (see
below example). My stupid! But as the system becomes more complex, I begun
to wonder how to avoid such situations in the future. Does anybody have some
experiences about that?


I don't understand how that could cause a problem. Why didn't you
immediately get a traceback with a message something like 'a is not
callable'?
John
Jul 18 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.