0

Assume that class MyClass is sometimes, but not always, defined. I have a function foo(a=None) in which argument a can be None, a string, or an object of MyClass.

My question is: If MyClass is not defined in my Python session, how can I check the type of argument a in a fashion similar to isinstance without getting a NameError?

Note on duck-typing: I am deliberately limiting the function.

I'm using Python 2.6.x and Updating is not an option. A forward-compatible solution (especially for 2.7.x) is highly appreciated.

  • 2
    Simple, if it isn't defined, you get a `NameError`. There's no way around it – Vasili Syrakis Jan 17 '17 at 12:25
  • 1
    Why would your class be *defined* conditionally?! – deceze Jan 17 '17 at 12:31
  • 2
    Use `try-except`. If your class isn't defined then it's a given that no object would be an instance of it. – DeepSpace Jan 17 '17 at 12:31
  • 1
    `try-except` is probably the best suggestion. You can also check that `a` is not *not* `MyClass`: `isinstance(a, (str, type(None)))`. – wildwilhelm Jan 17 '17 at 12:36
  • @deceze The function will be used in both a stand-alone interpreter and an embedded one. The class can only be defined in the embedded interpreter. In fact, valid string and `MyClass` values both `__str()__` to the same string. – Mohammadreza Khoshbin Jan 17 '17 at 12:36
  • 2
    Mightn't it make more sense to define the class either way, but have it behave differently in different environments? That's kind of a fundamental idea of OOP. – deceze Jan 17 '17 at 12:38
  • @deceze I wasn't clear enough. `MyClass` is a propriety class belonging to the embedded Python that I'm using. – Mohammadreza Khoshbin Jan 17 '17 at 12:43
  • 1
    I'd still go with *conditionally defining* the class then; i.e. if the class doesn't exist natively, define your own replacement instead. Makes all code referring to this class simpler. That of course still leaves sort of the same question… – deceze Jan 17 '17 at 12:49

3 Answers3

2

I would suggest a different approach: polyfill the class so all code that wants to refer to it can simply do so:

try:
    from foo import Bar  # load the native class
except ImportError:
    class Bar:
        pass  # implement necessary parts here

You can put this into your own module and then from mymodule import Bar everywhere it's needed. That allows all your code to use Bar regardless of whether it's defined natively or not.

Even if redefining the class isn't your preferred way to handle this, handling the ImportError is still the way to handle this situation, since you will have to import the class either way and that's where the error will occur. Instead of defining the class, you may instead want to set a class_exists = False flag or something.

deceze
  • 510,633
  • 85
  • 743
  • 889
1

If MyClass isn't defined then you have no way to reference its type.

Therefore you can have no way to verify that type(a) has the correct value.

holdenweb
  • 33,305
  • 7
  • 57
  • 77
1

I workarounded the problem by overriding a method in MyClass and doing nothing in it (pass). After that I no longer needed to check its type.

Different workarounds may exist for different cases. Catching the NameError could be another one.

t = 'asdfas'
print(isinstance(t, str))
try:
    print(isinstance(t, MyClass))
except NameError:
    print(False)

Seems to me, that such a construct may appear in future python. Like typed python, which is quite new. And in typed python we have a possibility to use future types, in apos.

Jarekczek
  • 7,456
  • 3
  • 46
  • 66