Advancement of Python Object Oriented Programming (OOP)

Keywords: Python Programming IPython Attribute

isinstance and issubclass

1. isinstance()

Built-in functions in Python.

Syntax: isinstance (object, class info)

If the parameter object is an instance of classinfo or an instance of a subclass of the classinfo class, return True. If the object is not a given type of object, the result is always False.

class A(object):
    pass


class B(A):
    pass


obj1 = A()
obj2 = B()

a = isinstance(obj1, A)
b = isinstance(obj2, A)
print(a)
print(b)

Result:

True
True

Process finished with exit code 0

2. issubclass()

Built-in functions in Python.

Syntax: is subclass (sub, super)

Check whether the subclass is a derivative of the super class (subclass). If so, it returns True, not False.

class A(object):
    pass


class B(A):
    pass


obj1 = A()
obj2 = B()

print(issubclass(B, A))

Result:

True

Process finished with exit code 0

reflex

concept

In programming, we often encounter the requirement that we need to execute a method in the object or call a variable in the object, but for various reasons we can not determine whether this method or variable exists. This is an unknown method or variable that we need to access and operate with a special method or mechanism, which is called mechanism. Reflection.

Significance

The concept of reflection was first proposed by Smith in 1982. It mainly refers to the ability of a program to access, detect and modify its own state or behavior (introspection). The introduction of this concept soon led to the study of application reflexivity in computer science. It is first adopted in the field of programming language design, and has made achievements in Lisp and object-oriented.

Reflection in python object-oriented: Operating object-related properties in the form of strings. Everything in python is an object (you can use reflection).

Several important methods for recording reflection are described below.

hasattr

Determine whether there is this method or variable in the object:

class Person:
    def __init__(self, name):
        self.name = name

    def talk(self):
        print("%s Talking" % self.name)


p = Person('Zhang San')
p.talk()
print(hasattr(p, 'talk'))
print(hasattr(p, 'name'))
print(hasattr(p, 'python'))

Result:

Zhang San is talking
True
True
False

Process finished with exit code 0

getattr

Property values for returning objects:

class Person:
    def __init__(self, name):
        self.name = name

    def talk(self):
        print("%s Talking" % self.name)


p = Person('Zhang San')
p.talk()
g1 = getattr(p, 'name')
print(g1)  # Print parentheses
g2 = getattr(p, 'talk')
g2()  # Call the method in parentheses
g3 = getattr(p, 'python', 'No value found.')
print(g3)  # The third parameter is that the return value cannot be found

Result:

Zhang San is talking
Zhang San
Zhang San is talking
No value found.

Process finished with exit code 0

setattr

Add variables or methods to objects:

def func_one(self):
    print("%s Talking" % self.name)


class Person:
    def __init__(self, name):
        self.name = name


p = Person('Zhang San')
setattr(p, 'talk', func_one)  # Add func_one function to object p and name it talk
p.talk(p)  # Call the talk method

setattr(p, 'age', 30)  # Add an age variable with an assignment of 30
print(p.age)  # Print age:30

Result:

Zhang San is talking
30

Process finished with exit code 0

delattr

Delete variables in objects (methods cannot be deleted, but should be used cautiously in actual development)

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def talk(self):
        print("%s Talking" % self.name)


p = Person('Zhang San', 18)
delattr(p, 'age')
# print(p.age)  # 'Person' object has no attribute 'age'
# delattr(p, 'talk')  # Error reporting, cannot delete method

Result:


Process finished with exit code 0

In Python object-oriented, classes can also be objects:

class Foo:
    STATIC_WORD = 'Python'

    def __init__(self):
        self.name = 'Zhang San'

    def func(self):
        return 'func'

    @classmethod
    def bar(cls):
        return 'bar'


print(getattr(Foo, 'STATIC_WORD'))
print(getattr(Foo, 'func'))
print(getattr(Foo, 'bar'))

Result:

Python
<function Foo.func at 0x0000000000AA57B8>
<bound method Foo.bar of <class '__main__.Foo'>>

Process finished with exit code 0

Analysis: getattr represents the memory address of the method or variable in the object. When we use classes instead of instantiating objects, static attributes in invoking classes return their values, dynamic attributes return their memory addresses, and class methods in dynamic attributes return their class method locations.

_u str_ and u repr_u

Both u repr_ and u str_ methods are used for display, u str_ is user-oriented and u repr_ is programmer-oriented.

The following demonstrates the process of (u repr_) in ipython:

In [2]: class TestOne:
   ...:     def __init__(self):
   ...:         self.name = 'Jay Chou'
   ...:         self.age = 35
   ...:     def __repr__(self):
   ...:         return '%s %s %s' % (self.__class__.__name__,self.name,self.age)
   ...:

In [3]: str(TestOne())
Out[3]: 'TestOne Jay Chou 35'

In [4]: repr(TestOne())
Out[4]: 'TestOne Jay Chou 35'

The following demonstrates the process of (u str_) in ipython:

In [6]: class TestTwo:
   ...:     def __init__(self):
   ...:         self.name = 'Jay Chou'
   ...:         self.age = 35
   ...:     def __str__(self):
   ...:         return '%s %s %s' % (self.__class__.__name__,self.name,self.age)
   ...:

In [7]: str(TestTwo())
Out[7]: 'TestTwo Jay Chou 35'

In [8]: repr(TestTwo())
Out[8]: '<__main__.TestTwo object at 0x000001D2D7288B00>'

It can be seen that without u str_ the use of u repr_ in the str() method does appear, and vice versa. So the implementation of u str_ is actually optional. If you need an easy-to-understand function of printing object, you can achieve u str_.

_u getitem_u, u setitem_ and u delitem_u

Used for indexing operations, such as dictionaries. Represents the acquisition, setting, and deletion operations, respectively.

class Demo:
    def __init__(self):
        self.value = {}
        self.name = 'Jay Chou'

    def __getitem__(self, item):
        print('__getitem__ Obtain', item)
        return self.value[item]

    def __setitem__(self, key, value):
        print('__setitem__Set up', key, value)
        self.value[key] = value

    def __delitem__(self, key):
        print('__delitem__delete', key)
        del self.value[key]

    def __len__(self):
        return len(self.value)


print(Demo.__doc__)

demo = Demo()
demo['Jay Chou'] = 'Jay Chou'
demo['JJ'] = 'JJ Lin'
demo['Andy'] = 'Lau Andy'
demo['Jack Ma'] = 'Jack Ma'
print(demo['Jack Ma'])
del demo['Jay Chou']
print(len(demo))

Result:

None
Set item Set Jay Chou Jay Chou
Set item Set JJ Lin Junjie
Set item Set Andy Lau Dehua
_u setitem_u Set Jack Ma Yun
_u getitem_u Get Jack Ma
Jack Ma
_u delitem_u Delete Jay Chou
3

Process finished with exit code 0

__new__

The u new_ method accepts the same parameters as u init_, but u init_ is called after the class instance is created, and the u new_ method is the way to create this class instance.

class Demo:
    def __init__(self, name, age):
        print("__init__Method")
        self.name = name
        self.age = age

    def __new__(cls, *args, **kwargs):
        print("This is__new__Method")
        return super(Demo, cls).__new__(cls)

    def __str__(self):
        return 'Demo:%s-->%s' % (self.name, self.age)


if __name__ == '__main__':
    demo = Demo('Zhang San', 18)
    print(demo)

Result:

This is the u new_ method
_u init_ method
Demo: Zhang San - > 18

Process finished with exit code 0

We can see that u new_() is executed in front of u init_(), which opens up a space for functions.

__call__

Functions in Python are first-level objects. This means that references to functions in Python can be passed as input to other functions/methods, where they are executed. Instances (objects) of classes in Python can be treated as functions. That is, we can pass them as input to other functions / methods and call them, just as we call a normal function.

In view of its correlation with u init_ and u del_, we will study them together:

class Demo:
    lst = []

    def __init__(self, begin, end):
        print("__init__Method")
        for i in range(begin, end):
            self.lst.append(i)

    def __call__(self, index):  # The default is * args,** kwargs
        print("__call__Method")
        if index < len(self.lst):
            return self.lst[index]

    def __del__(self):
        print("__del__Method")  # Free memory
        new_index = int(input('Enter what you want to delete index: '))
        del self.lst[new_index]
        print(self.lst)
        print("Deleted and freed memory")


demo = Demo(0, 10)
print(demo(2))
print(demo(5))
print(demo(8))

Result:

_u init_ method
_u call_ method
2
_u call_ method
5
_u call_ method
8
_u del_ method
Enter the index to delete:5
[0, 1, 2, 3, 4, 6, 7, 8, 9]
Deleted and freed memory

Process finished with exit code 0

__len__

If a class behaves like a list, the len() function is used to get how many elements it has. To make the len() function work properly, the class must provide a special method len(), which returns the number of elements.

class Demo:
    def __init__(self, *args):
        self.names = args

    def __len__(self):
        return len(self.names)


demo = Demo(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)
print(len(demo))

Result:

10

Process finished with exit code 0

You may think it's useless, so I'll show you an algorithmic problem.

Examples: Fibonacci sequence is composed of 0, 1, 1, 2, 3, 5, 8. Write a Fib class. Fib(10) represents the top 10 elements of a sequence. Print (Fib(10)) can print out the top 10 elements of a sequence. len(Fib(10)) can correctly return the number of columns 10.

Reference code:

class Fib:
    def __init__(self, num):
        a, b, L = 0, 1, []
        for n in range(num):
            L.append(a)
            a, b = b, a + b
            self.numbers = L

    def __str__(self):
        return str(self.numbers)

    def __len__(self):
        return len(self.numbers)


f = Fib(10)
print(f)
print(len(f))

Result:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
10

Process finished with exit code 0

_u hash_ and u eq_u

python has two hash libraries, hashlib in cryptography, adler32() in zlib and crc32().

For simple numbers, these two libraries are not needed. Just use hash functions, which are often used to locate elements in set s, dict s, etc.

Each object in python has an id, which is essentially its memory address. The is comparison is based on id, and its value can be viewed by id(x). The u hash_ method of base class object is to return its id/16 as integer.

Note that only immutable numerical types can use hash methods, list s and dict s do not. So, if we create a mutable object, let the hash function return None.

The u eq_() method is used for=== comparison and is based on hash values.   

For immutable object, hash returns an id-based variable, EQ can be compared with id. And mutable object writes eq, hash returns None.

class DemoPar:
    insure = False

    def __init__(self, rank, suit, hard, soft):
        self.rank = rank
        self.suit = suit
        self.hard = hard
        self.soft = soft

    def __repr__(self):
        return "{__class__.__name__}(suit={suit!r}, rank={rank!r})". \
            format(__class__=self.__class__, **self.__dict__)

    def __str__(self):
        return "{rank}{suit}".format(**self.__dict__)

    def __eq__(self, other):
        return self.suit == other.suit and self.rank == other.rank

    def __hash__(self):
        return hash(self.suit) ^ hash(self.rank)


class DemoSub(DemoPar):
    insure = True

    def __init__(self, rank, suit):
        super().__init__('A', suit, 1, 11)


demoSubOne = DemoSub(1, '?')
demoSubTwo = DemoSub(1, '?')

print(id(demoSubOne), id(demoSubTwo))
print(id(demoSubOne) / 16, id(demoSubTwo) / 16)
print(hash(demoSubOne), hash(demoSubTwo))
print(demoSubOne == demoSubTwo)
print(demoSubOne is demoSubTwo)

Result:

1638200644552 1638200644608
102387540284.5 102387540288.0
-6769852609266822034 -6769852609266822034
True
False

Process finished with exit code 0

 

Reference resources

  1. https://blog.csdn.net/qianguozheng/article/details/50396776
  2. http://www.cnblogs.com/Eva-J/articles/7351812.html#_label7
  3. http://python.jobbole.com/86506/
  4. https://blog.csdn.net/yaokai_assultmaster/article/details/70256621
  5. https://blog.csdn.net/lis_12/article/details/54631368
  6. https://www.cnblogs.com/superxuezhazha/p/5792199.html
  7. https://www.cnblogs.com/pengsixiong/p/5381850.html

 

Posted by daiwa on Tue, 25 Dec 2018 10:27:06 -0800