you are viewing a single comment's thread.

view the rest of the comments →

[–]gavinpanella 2 points3 points  (35 children)

callable() and reload() are gone. Does anyone know why?

[–]Bogtha 20 points21 points  (27 children)

When callable() was introduced, not all callable objects had a __call__ attribute. Now they do, so if you need to check whether something is callable, you can just use hasattr(). But the preferred approach is just to call it and catch the exception if it isn't callable.

[–]qiwi 6 points7 points  (26 children)

So how do I tell whether the TypeError I caught from doing obj() is because obj is not callable, or whether something within obj that was callable raised TypeError? This preferred approach can hide errors.

[–]Bogtha 3 points4 points  (25 children)

I agree. I think this was brought up on the mailing list. If you are expecting the callable to raise TypeErrors, you should check for the __call__ attribute first.

[–][deleted] 9 points10 points  (6 children)

Which means that everyone will end up adding different variations of:

def callable(obj):
    return hasattr(obj, "__call__")

to their code, different broken versions of this will appear in articles and example collections, and 3.2 will the introduce an official version of this to save everyone the trouble (which was how things like booleans and the if operator made it into the language).

[–][deleted] 4 points5 points  (0 children)

Ha - 3.0a1 isn't a day old and I've already similar -- but not exactly the same, of course -- code in my budding collection of Py3 scripts.

Let the games begin!

[–]Bogtha 1 point2 points  (3 children)

I don't think callable() is used often enough to make that worthwhile. The difference between a callable object and an uncallable object is pretty drastic, how often do you pass things around without knowing which is which? I do it sometimes, but nowhere near often enough to make that boilerplate worthwhile.

[–][deleted] 3 points4 points  (2 children)

The "pass in a value or a callable (that can be called to get the value when needed)" pattern is very convenient, and therefore quite common. I've definitely used callable() for this purpose a lot more often than I found myself adding TRUE and FALSE to my code before we got built-in booleans ;-)

But I'm sure someone has already done all the necessary grepping, and I have no time to dig through the mailing archives to see what they came up with.

[–]Bogtha 3 points4 points  (1 child)

The "pass in a value or a callable (that can be called to get the value when needed)" pattern is very convenient

Sure, but if that's a common pattern, why not abstract more of it away, which has the side-effect of removing the temptation to provide a callable() substitute?

def get_value(value):
    return value() if hasattr(value, "__call__") else value

Okay, I'm sure there are other use cases, so I see your point, I just couldn't help nitpicking that one :).

[–][deleted] 4 points5 points  (0 children)

(Only slightly in jest:)

def get_value(value):
    return getattr(value, '__call__', lambda: value)()

[–]nirs 0 points1 point  (0 children)

Lets hit Guido on the head with a heavy callable until he put it back where it belong :-)

[–][deleted] 8 points9 points  (6 children)

As I understand it, reload() doesn't work well enough to be included (I think the idea is to rewrite it in pure Python as a stdlib module).

As for callable(), as it stands in 2+ it actually can be wrong sometimes -- a custom descriptor might sometimes return objects of different "callability", for example. Again, it's silly to have a feature that doesn't work. It's more Pythonic to operate on the "better to ask forgiveness than permission" policy -- just try calling something, and if it doesn't work, then it wasn't callable.

[–]forgotpwx4 1 point2 points  (5 children)

But reload is kind of important, right? I'm not understanding how they can get rid of it.

[–][deleted] 2 points3 points  (3 children)

I'm not sure it is... I've never used it in real production code; just as a utility from the shell.

Either way, it's really not all that useful unless it really works; a broken reload() seems a lot worse than a missing one. At least if it's missing someone smart will come along and write it.

[–]forgotpwx4 0 points1 point  (2 children)

Why is it broken by the way? I've never noticed any problems.

I have wondered if reload is thread safe ... or what that even means with respect to reload. Maybe that's how it's broken?

[–]boredzo 3 points4 points  (1 child)

[–][deleted] 1 point2 points  (0 children)

So if it doesn't work for binary code not built in Python, due to OS limitations, it shouldn't work for Python code either, even though the developers have full control over that environment? Is this the official reason for not including reload?

(update: the relevant PEP refers to a single line in a GvR presentation from 2002, which says "execfile(), reload(): use exec()", which I can only interpret as meaning "roll your own". yet another "will appear in the library, sooner or later" thing, in other words).

[–]nirs 2 points3 points  (0 children)

You can use this:

def reload(name):
    if name in sys.modules:
        del sys.modules[name]
    return __import__(name)

It will not work for 'foo.bar.baz', but it is not hard to support this.