How to determine if a variable is an instance in Python 3? I consider something to be an instance if it has __dict__ attribute.
Example:
is_instance_of_any_class(5) # should return False
is_instance_of_any_class([2, 3]) # should return False
class A:
pass
a = A()
is_instance_of_any_class(a) # should return True
I have seen messages about using isinstance(x, type) or inspect.isclass(x) but this would give True for the class (A), not the instance.
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__').
Related
This question already has answers here:
What are the differences between type() and isinstance()?
(8 answers)
Closed 2 years ago.
From what I read googling, it seems that isinstanceof() is always better than type().
What are some situations when using type() is better than isinstanceof() in python?
I am using python 3.7.
They do two different things, you can't really compare them directly. What you've probably read is that you should prefer isinstance when checking the type of an object at runtime. But that isn't the only use-case for type (that is the use-case for isinstance, as its name implies).
What may not be obvious is that type is a class. You can think of "type" and "class" as synonymous. Indeed, it is the class of class objects, a metaclass. But it is a class just like int, float, list, dict etc. Or just like a use-defined class, class Foo: pass.
In its single argument form, it returns the class of whatever object you pass in. This is the form that can be used for type-checking. It is essentially equivalent to some_object.__class__.
>>> "a string".__class__
<class 'str'>
>>> type("a string")
<class 'str'>
Note:
>>> type(type) is type
True
You might also find this form useful if you ever wanted access to the type of an object itself for other reasons.
In its three-argument form, type(name, bases, namespace) it returns a new type object, a new class. Just like any other type constructor, just like list() returns a new list.
So instead of:
class Foo:
bar = 42
def __init__(self, val):
self.val = val
You could write:
def _foo_init(self, val):
self.val = val
Foo = type('Foo', (object,), {'bar':42, '__init__': _foo_init})
isinstance is a function which checks if... an object is an instance of some type. It is a function used for introspection.
When you want to introspect on the type of an object, usually you will probably use isintance(some_object, SomeType), but you might also use type(some_object) is SomeType. The key difference is that isinstance will return True if some_object.__class__ is precisely SomeType or any of the other types SomeType inherits from (i.e. in the method resolution order of SomeType, SomeType.mro()).
So, isinstance(some_object, SomeType) is essentially equivalent to some_object.__class__ is SomeType or some_object.__class__ in SomeType.mro()
Whereas if you use type(some_object) is SomeType, you are only asking some_object.__class__ is SomeType.
Here's a practical example of when you might want to use type instead of isinstance, suppose you wanted to distinguish between int and bool objects. In Python, bool inherits from int, so:
>>> issubclass(bool, int)
True
So that means:
>>> some_boolean = True
>>> isinstance(some_boolean, int)
True
but
>>> type(some_boolean) is int
False
type says the type of variable:
a = 10
type(a)
It will give its type as 'int'
isinstance() says if variable is related to specified type
class b:
def __init__(self):
print('Hi')
c = b()
m = isinstance(c, b)
It will return True because object c is of class type a otherwise it will return False.
Look at the following code:
a = 3
type(a) == object
False
isinstance(a, object)
True
How is this to be explained?
Everything is an object in Python, which includes ints, strings, functions and classes. Therefore, isinstance(a, object) will return you True . But 3 is actually an integer, which is a sub_class create from object. Therefore type(a) can equal to int only.
I can give you an example.
Suppose we have two classes, Sub is a sub_class of Base.
class Base:
def __init__(self):
self.kappa='kappa'
class Sub(Base):
def __init__(self):
super().__init__()
obj=Base()
int_rino=Sub()
print(isinstance(obj, Base))
print(isinstance(obj, Sub))
print(isinstance(int_rino, Base))
print(isinstance(int_rino, Sub))
print(type(int_rino) == Base)
The result will be:
True
False
True
True
False
This is a common construct in most object-oriented languages that support inheritance. When a child class (in your case int) inherits from a parent (in your case object), it is said to have an "is-a" relationship. That is, an int is a (or an) object.
This "is-a" relationship is what isinstance is checking. From the docs:
Return true if the object argument is an instance of the classinfo argument, or of a (direct, indirect or virtual) subclass thereof.
There is a similar issubclass function to check the same relationship for a class instead of an instance of that class. In fact, in most cases, isinstance(x, y) == issubclass(type(x), y).
type returns the exact class that an object was constructed from. That means that checking type(3) == object is exactly equivalent to checking int == object. Hopefully you can see that that's unambiguously false.
On a related tangent, classes should always be the same reference within a given run of the interpreter, so you can use is instead of == for comparison. So type(3) is int will be true. That's how == is implemented for all the types you're ever likely to come across anyway.
So:
class A(object): pass
class B(A): pass
def class_factory(letter):
"""rtype : type[A]""" # is this correct ?
if letter == 'A': return A # note no parenthesis ! returns the type, not an instance
elif letter == 'B': return B
raise NotImplementedError
Can't seem to find any docs and searching is rather tricky.
Bonus: How would this be achieved in the python 3.5 implementation of type hints ?
The correct usage would be """rtype: type""". You are specifying the type of the object that is returned, and no matter whether you are returning A or B, the actual object you return is an instance of type. You can see this if you run the following:
class A(object): pass
class B(A): pass
print(type(A))
print(type(A()))
print(type(B))
print(type(B()))
Because you are returning a type in every case, the return type should be type. There is no way of specifying that the class object you return has specific properties, since those properties aren't dependent on the type of the object you return, but on the specific instance of the type you return.
Type hinting in doc strings is not standardised. So there a number of answers.
That being said I would say your return type is a function that returns instances of A. That is, a class is a callable that return instances of itself. Which would be something like:
(Foo, Bar) -> A
Where the Foo and Bar are the types of the arguments to the function.
not sure what exactly are you trying to achieve here but something like this can help ..
>>> class A(object):
pass
>>> class B(A):
pass
>>> def test(letter):
if isinstance(letter,A):
Do something if letter is of object A
elif isinstance(letter,B):
Do something if letter is of object B
I have a dictionary, named
descendDict
And it contains 4 keys which are class objects, which have values that are both letters and other class objects.
Now what I'm trying to do is sort through the dictionary, and call out different actions if the value brought up in the dictionary is a class object, or if it is a letter:
for x in descendDict:
print x, descendDict[x]
for y in descendDict[x][0]:
if y != (classObject?):
#Action
for x in descendDict:
for z in descendDict[x][0]:
if z != (classObject?):
if y == z:
dist = 0
else:
dist = float(nodeDict[y]) + float(nodeDict[z])
In the if statements:
if... != (classObject?):
I am trying to determine whether the variable in the dictionary is, or is not a class object, but i just dont know how to do this.
Here is one the entries:
<__main__.Node instance at 0xb6738> ([<__main__.Node instance at 0xb6710>, 'A', <__main__.Node instance at 0xb6760>], '0.1')
I am sorting through it's first keys list, but i am trying to figure out if the values in the list are a class object, or a letter.
Not sure what you mean by "class object" since everything in Python is a first-class object. If you're trying to figure out if it's an instance of a specific class you can just use isinstance
if isinstance(y, someClass):
# do stuff
its better to define a method in your class then say
if hasattr(d[x],myClassMethodName):#then do this
else:#not a member
this method of checking allows much greater flexibility
for #RussellBorogove
try:
d[x].myMethod(*args,**kwargs)
except:
print "This is not an instance of my class and maybe a letter"
You probably want isinstance(x,type):
x = str
isinstance(x, type)
#=> True
class x(object):pass
isinstance(x, type)
#=> True
class x:pass
isinstance(x, type)
#=> False
x = "foo"
isinstance(x, type)
#=> False
Obviously, you'll have to stick to new-style classes, but you should be anyway.
However, it sounds like you're somehow trying to create your own object dispatch system. I strongly recommend that you move to some kind of common base class for all of your objects, and use method dispatch combined with higher-order methods to achieve whatever you're trying to do.
In Python it's common to use the "easier to ask forgiveness than permission" (EAFP) model, which looks like:
for y in collection:
try:
# treat it like it's a Node
y.actionMethod()
except AttributeError:
# that method doesn't exist, so it's not a Node
# do something else with it
print y
This is preferred over using isinstance(), because it allows you to define several otherwise unrelated classes each with their own actionMethod() without having to change this dispatch code.
In python. when I write x = 5, x becomes an instance of int automatically. But suppose I have defined a new class say number and I want x to become an instance of number instead of int when I assign it the value 5. Is this possible?
ie, Instead of this -->
>>> x = 5
>>> type(x)
<type 'int'>
Is this possible:
>>> x = 5
>>> type(x)
<type 'number'>
No. You would have to write a monkey patch to achieve this, that is incredibly unpythonic, can you simply not write
x = number(5)
:)
Note that you really should never do something like this. Jakob has the right answer, i.e. use x = number(5).
However, that said, I wanted to try how it could be done in theory, and here's one solution in the form of a decorator:
import types
class number(object):
def __init__(self, value):
self.value = value
def replace_int(x):
if isinstance(x, int):
return number(x)
else:
return x
def custom_numbers(f):
code = f.func_code
consts = tuple(map(replace_int, code.co_consts))
new_code = types.CodeType(code.co_argcount, code.co_nlocals,
code.co_stacksize, code.co_flags,
code.co_code, consts, code.co_names,
code.co_varnames, code.co_filename,
code.co_name, code.co_firstlineno,
code.co_lnotab)
return types.FunctionType(new_code, f.func_globals, f.func_name)
Any function you decorate, will end up using your custom number class:
#custom_numbers
def test():
x = 5
print type(x)
>>> test()
<class '__main__.number'>
The decorator works by replacing integer constants from the function's code-object with instances of the custom class. However, since function.co_code and code.co_consts are both read-only attributes, we have to create new code and function objects with the altered values.
One caveat is, that the values are assumed to be constants, so new instances are not created for each invocation of the function. If you mutate the value, that new value will be reflected in each subsequent call of the function.
You would have to take advantage of Python's language services to compile the statement and then walk the AST replacing the objects as appropriate.
In fact, 5 is an instance of int, x is just pointing to it. All variables in Python are references to objects. Thus, when you write type(x) you get the type of the object which x holds a reference to, in this case it is int.
If you assign another value to x, say x = "string", x will hold a reference to that string object, and type(x) will return <type 'str'>.