[Python] Learning Notes - 7.4, Obtaining Object Information

Keywords: Attribute Python Lambda REST

When we get a reference to an object, how do we know what type of object it is and what methods it has?

Using type()

First, we judge the object type by using the type() function:

Basic types can be judged by type():

>>> type(123)
<class 'int'>
>>> type('str')
<class 'str'>
>>> type(None)
<type(None) 'NoneType'>

If a variable points to a function or class, it can also be judged by type():

>>> type(abs)
<class 'builtin_function_or_method'>
>>> type(a)
<class '__main__.Animal'>

But what type() function returns? It returns the corresponding Class type. If we want to judge in the if statement, we need to compare the type types of the two variables.

>>> type(123)==type(456)
True
>>> type(123)==int
True
>>> type('abc')==type('123')
True
>>> type('abc')==str
True
>>> type('abc')==type(123)
False

Judging the basic data type can write int, str, etc. directly, but what if you want to judge whether an object is a function? Constants defined in the types module can be used:

>>> import types
>>> def fn():
...     pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True

Using isinstance()

For class inheritance, using type() is inconvenient. To determine the type of class, we can use the isinstance() function.

Let's review the previous example, if the inheritance relationship is:

object -> Animal -> Dog -> Husky

Then, isinstance() tells us whether an object is of some type or not. First create three types of objects:

>>> a = Animal()
>>> d = Dog()
>>> h = Husky()

Then, judge:

>>> isinstance(h, Husky)
True

No problem, because the h variable points to the Husky object.

To judge again:

>>> isinstance(h, Dog)
True

Although h itself is Husky type, because Husky is inherited from Dog, h is also Dog type. In other words, isinstance() determines whether an object is the type itself or is located in the parent inheritance chain of that type.

So we can be sure that h is still an Animal type:

>>> isinstance(h, Animal)
True

Similarly, the actual type is the d of Dog and the Animal type:

>>> isinstance(d, Dog) and isinstance(d, Animal)
True

However, d is not Husky type:

>>> isinstance(d, Husky)
False

The basic types that can be judged by type() can also be judged by isinstance():

>>> isinstance('a', str)
True
>>> isinstance(123, int)
True
>>> isinstance(b'a', bytes)
True

And you can also determine whether a variable is one of some types, such as the following code to determine whether it is a list or tuple:?

>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True

Using dir()

If you want to get all attributes and methods of an object, you can use the dir() function, which returns a list containing strings, for example, to get all attributes and methods of an str object:

>>> dir('ABC')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

Attributes and methods like _xxx_ have special uses in Python, such as _len_ method return length. In Python, if you call the len() function to try to get the length of an object, in fact, inside the len() function, it automatically calls the _len_() method of the object, so the following code is equivalent:

>>> len('ABC')
3
>>> 'ABC'.__len__()
3

If we want to use len(myObj) as well, we write a _len_() method ourselves:

>>> class MyDog(object):
...     def __len__(self):
...         return 100
...
>>> dog = MyDog()
>>> len(dog)
100

The rest are common attributes or methods, such as lower() string returning lowercase:

>>> 'ABC'.lower()
'abc'

It is not enough to list attributes and methods. With getattr(), setattr(), and hasattr(), we can directly manipulate the state of an object:

>>> class MyObject(object):
...     def __init__(self):
...         self.x = 9
...     def power(self):
...         return self.x * self.x
...
>>> obj = MyObject()

Next, you can test the properties of the object:

>>> hasattr(obj, 'x') # Is there an attribute'x'?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # Is there an attribute'y'?
False
>>> setattr(obj, 'y', 19) # Set an attribute'y'
>>> hasattr(obj, 'y') # Is there an attribute'y'?
True
>>> getattr(obj, 'y') # Get the property'y'
19
>>> obj.y # Get the property'y'
19

If an attempt is made to obtain an attribute that does not exist, an AttributeError error is thrown:

>>> getattr(obj, 'z') # Get the property'z'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyObject' object has no attribute 'z'

You can pass in a default parameter and return the default value if the attribute does not exist:

>>> getattr(obj, 'z', 404) # Get the property'z', if it does not exist, return the default value 404
404

A method of obtaining an object can also be obtained:

>>> hasattr(obj, 'power') # Is there an attribute'power'?
True
>>> getattr(obj, 'power') # Get the property'power'
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn = getattr(obj, 'power') # Get the property'power'and assign it to the variable fn
>>> fn # fn points to obj.power
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn() # Calling fn() is the same as calling obj.power().
81

Summary

Through a series of built-in functions, we can analyze any Python object and get its internal data. It should be noted that only when we do not know the object information, we will get the object information. If you can write directly:

sum = obj.x + obj.y

Don't write:

sum = getattr(obj, 'x') + getattr(obj, 'y')

An example of the correct use is as follows:

def readImage(fp):
    if hasattr(fp, 'read'):
        return readData(fp)
    return None

Assuming that we want to read an image from a file stream fp, we first need to determine whether there is a read method for the FP object. If there is a read method, the object is a stream, and if not, it cannot be read. hasattr() comes in handy.

Note that in dynamic languages such as Python, there is a read() method according to the duck type, which does not mean that the fp object is a file stream. It may also be a network stream or a byte stream in memory. However, as long as the image data returned by the read() method is valid, the function of reading the image will not be affected.

Posted by marseille on Mon, 01 Apr 2019 10:27:29 -0700