How to Check If a Variable Is an Instance of a Class

How to check whether a variable is a class or not?

Even better: use the inspect.isclass function.

>>> import inspect
>>> class X(object):
... pass
...
>>> inspect.isclass(X)
True

>>> x = X()
>>> isinstance(x, X)
True
>>> inspect.isclass(x)
False

Determine if a variable is an instance of any class

I think your understanding of what an instance is wrong here, since everything is an object in python, so 5 is an object of class int and [2,3] is an object of class list and so on.

isinstance(x, y) is the way to go if you just want to check if x is an object of y, but if you want to check if x is an object of builtin class or your own custom defined class then you should be checking the existence of __dict__ using hasattr(x, '__dict__').

How do I check if a variable is an instance of a class?

It's almost exactly the same. You can use Object's instance_of? method:

"a".instance_of? String # => true
"a".instance_of? Object # => false

Ruby also has the is_a? and kind_of? methods (these 2 are aliases, and work exactly the same), which returns true is one of the superclasses matches:

"a".is_a? String # => true
"a".is_a? Object # => true

How can I check if a object is an instance of a specific class?

You can check if an object is an instance of a class with instanceof, e.g.

if($role instanceof SimpleXMLElement) {
//do stuff
}

How to check a variable is class object or not

In 2.x, a class object can be be a type (new-style classes) or a classobj (classic classes). The type type is a builtin, but the classobj type is not. So, how do you get it? That's what the types module is for.

isinstance(MyClass, (types.TypeType, types.ClassType))

In 3.x, you don't need to worry about classic classes, so:

isinstance(MyClass, type)

Even if you want to compare the types directly, you should never compare any objects by their str. Compare:

>>> class MyClassicClass:
... pass
>>> str(type(MyClassicClass)) == "<type 'classobj'>"
True
>>> str("<type 'classobj'>") == "<type 'classobj'>"
True

You can almost always just compare objects directly:

>>> type(MyClassicClass) == types.ClassType
True
>>> "<type 'classobj'>" == types.ClassType
False

(And in the incredibly rare cases where you really do need to compare the string representation for some reason, you want the repr, not the str.)

How to check if variable is a specific class in python?

Use isinstance, this will return true even if it is an instance of the subclass:

if isinstance(x, my.object.kind)

Or:

type(x) == my.object.kind #3.x

If you want to test all in the list:

if any(isinstance(x, my.object.kind) for x in alist)

What's the best way to check if class instance variable is set in Python?

You've forgotten the EAFP principle:

try:
value = self.__var
except AttributeError:
# do something else

If you're determined to use a sentinel, you can combine it with a class variable:

class EC():
__var = object():
...
if self.__var is not EC.__var:
...

Check to see if derived class defines a specific instance variable, throw error from metaclass if not

"Normal" instance variables, such as the ones taught since Python 2 early days can't be checked at class creation time - all instance variables are dynamically created when the __init__ (or other) method is executed.

However, since Python 3.6 it is possible to "annotate" variables in the class body - these usually serve only as a hint for static type checking tools, which, in turn, do nothing when the program is actually run.

However, when annotating an attribute in the class body, without providing an initial value (which would then create it as a "class attribute"), it will show in the namespace inside the __annotations__ key (and not as a key themselves).

In short: you can design a metaclass requiring an attribute to be annotated in the class body, although you can't ensure it is actually filled-in with a value inside __init__ before it is actually run. (But it can be checked after it is called the first time - check the second part of this answer).

All in all - you'd need something like this:

class BaseMeta(type):
def __new__(cls, name, bases, namespace):
print(cls, name, bases, namespace)
if name != 'Base' and (
'__annotations__' not in namespace or
'bar' not in namespace['__annotations__']
):
raise TypeError("bar not annotated in derived class body")
return super().__new__(cls, name, bases, namespace)

class Base(metaclass=BaseMeta):
def foo(self):
return self.bar

class Derived(Base):
bar: int
def __init__(self):
self.path = '/path/to/locality'
self.bar = 0

If bar: int is not present in the derived class body, the metaclass will raise. However, if self.bar = 0 is not present inside __init__, the metaclass has no way to "know" it - not without running the code.

Close things present in the language

There has been for sometime in Python "abstractclasses" - they
do almost exactly what your first example proposes: one can mandate
that derived classes implement methods with a certain name. However,
this check is made when the class is first instantiated, not when
it is created. (Thus allowing more than one level of abstract classes inheriting one from another, and that works as far as none of those
is instantiated):


In [68]: from abc import ABC, abstractmethod

In [69]: class Base(ABC):
...: def foo(self):
...: ...
...: @abstractmethod
...: def bar(self): pass
...:

In [70]: class D1(Base): pass

In [71]: D1()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-71-1689c9d98c94> in <module>
----> 1 D1()

TypeError: Can't instantiate abstract class D1 with abstract methods bar

In [72]: class D2(Base):
...: def bar(self):
...: ...
...:

In [73]: D2()
Out[73]: <__main__.D2 at 0x7ff64270a850>

And then, along with "abstractmethods", the ABC bases (which are implemented with a metaclass not unlike the one in your example, although they do have some support in the language core), it is possible to declare "abstractproperties" - these are declared as class attributes, and will raise an error on class instantiation (just like above), if the derived class do not override the attribute. The main difference to the "annotations" approach above is that this actually requires a value to be set on the attribute on the class body, where as the bar: int declaration do not create an actual class attribute:

In [75]: import abc                                                                                           

In [76]: class Base(ABC):
...: def foo(self):
...: ...
...: bar = abc.abstractproperty()
...:
...:
...:

In [77]: class D1(Base): pass

In [78]: D1()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-78-1689c9d98c94> in <module>
----> 1 D1()

TypeError: Can't instantiate abstract class D1 with abstract methods bar

In [79]: class D2(Base):
...: bar = 0
...:

In [80]: D2()

I undestand this may not be desirable - but I called the attention to the natural "instantiation time" error-raising, in these cases, because it is possible to do a..

#... Check instance attribute after __init__ run for the first time.

In this approach, the check is only performed when the class is instantiated, not when it is declared - and consists in wrapping __init__ in a decorator that will check for the required attributes after it is run for the first time:

from functools import wraps

class BaseMeta(type):
def __init__(cls, name, bases, namespace):
# Overides __init__ instead of __new__:
# we process "cls" after it was created.
wrapped = cls.__init__
sentinel = object()
@wraps(wrapped)
def _init_wrapper(self, *args, **kw):
wrapped(self, *args, **kw)
errored = []
for attr in cls._required:
if getattr(self, attr, sentinel) is sentinel:
errored.append(attr)
if errored:
raise TypeError(f"Class {cls.__name__} did not set attribute{'s' if len(errored) > 1 else ''} {errored} when instantiated")
# optionally "unwraps" __init__ after the first instance is created:
cls.__init__ = wrapped
if cls.__name__ != "Base":
cls.__init__ = _init_wrapper
super().__init__(name, bases, namespace)

And checking that in the interactive mode:

In [84]: class Base(metaclass=BaseMeta): 
...: _required = ["bar"]
...: def __init__(self):
...: pass
...:

In [85]: class Derived(Base):
...: def __init__(self):
...: pass
...:

In [86]: Derived()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-87-8da841e1a3d5> in <module>
----> 1 Derived()

<ipython-input-83-8bf317642bf5> in _init_wrapper(self, *args, **kw)
13 errored.append(attr)
14 if errored:
---> 15 raise TypeError(f"Class {cls.__name__} did not set attribute{'s' if len(errored) > 1 else ''} {errored} when instantiated")
16 # optionally "unwraps" __init__ after the first instance is created:
17 cls.__init__ = wrapped

TypeError: Class Derived did not set attribute ['bar'] when instantiated

In [87]: class D2(Base):
...: def __init__(self):
...: self.bar = 0
...:

In [88]: D2()
Out[88]: <__main__.D2 at 0x7ff6418e9a10>



Related Topics



Leave a reply



Submit