Python - advanced functions

Posted by tyrol_gangster on Fri, 21 Jan 2022 19:31:16 +0100

Advanced function (2)

This is function advanced version 2.0,
What will be introduced are the three concepts of iteratable object, iterator and generator and their usage,
Only by understanding these three can we deepen our understanding of sequences.

Iteratable object

In the previous article, we talked about many iteratable objects,
For example, using zip, filter and map functions, we will get compression object, filter object and mapping object respectively, but these three are iterators,

Tip: just interested partners can see the content of my last article

Link directly below
Advanced function (1)

All this points to iterators in order to figure out what iterators are
We need to unlock the pre knowledge first. What is an iterative object?

What is an iteratable object

First textbook definition:

An iteratable object is a group of objects that have__ iter__ Class instance object of () method

The above is the definition of iteratable object, over.

Yes, the definition is so concise, but what the hell is a class instance?
Sure enough, to explain one problem will lead to another. It's really troublesome.
Then let me say:

Python is an object-oriented programming language,
The biggest feature of object-oriented language is class,
A large number of attributes and methods are encapsulated in the class, but they cannot be used directly,
You need to create an instantiated class object, which is called a class instance

OK, go back to the original topic, now that you know what you have__ iter__ The () method is an iteratable object,
So which class instances have this method?
As we all know, sequences are iteratable objects, but iteratable objects are far more than that. I will explain this later in simple terms,
But first we need to know how to see what this class has__ iter__ method

# We use__ dict__ You can check whether the class object has this method,
# If the class object itself has__ iter__ Method, the instantiated class instance also has
list.__dict__

{'__new__': <built-in method __new__ of type object at 0x00007FFA921F7610>, '__repr__': <slot wrapper '__repr__' of 'list' objects>, '__hash__': None, '__getattribute__': <slot wrapper '__getattribute__' of 'list' objects>, '__lt__': <slot wrapper '__lt__' of 'list' objects>, '__le__': <slot wrapper '__le__' of 'list' objects>, '__eq__': <slot wrapper '__eq__' of 'list' objects>, '__ne__': <slot wrapper '__ne__' of 'list' objects>
'__iter__': <slot wrapper '__iter__' of 'list' objects>.....(ellipsis N Multi attribute and method)

Meaning of iteratable objects

Before explaining the meaning, we must ask a question, that is, what is the principle of the for loop?
Let's abandon the for loop and use while to achieve the same effect as him;

list_1 = [1,3,5,7,9]
for element in list_1: 
	print(element)
# This will get 1, 3, 5, 7 and 9 in turn

count = 0						# Define a counter
length = len(list_1)
while count <= length:
	print(list_1[count])
	count += 1
# This will get 1, 3, 5, 7 and 9 in turn

We use the while loop to achieve the same function as the for loop,
But there are many more lines of code,
And the most important thing is that we access the elements in the list through the index,

(collection whispers: I'm an unordered sequence, and I don't deserve an index)

So what if we need to traverse the keys of the dictionary in turn?
It is easy to implement with a for loop, but it is very difficult to use a while loop.

Therefore, Python provides a unified method -- iteratable objects,

This provides great convenience, so that we are no longer limited by the index,
You can take values of iteratable objects at will.

Use of iteratable objects

Next, we will introduce the use of iteratable objects,

dict_1 = {'Jonasen': 'Jostar', 'Joseph': 'Jostar', 'Kujo': 'Jotaro'}
# This is an iteratable object. Next, we'll turn it into an iterator
iter_dict = dict_1.__iter__()

print(iter_dict)			
<dict_keyiterator object at 0x00000204EC58E840>

OK, this completes the conversion of the iterator,
Isn't it extremely simple, but if it's just like this, we only complete the iterator,

dict_1 = {'Jonasen': 'Jostar', 'Joseph': 'Jostar', 'Kujo': 'Jotaro'}
iter_dict = dict_1.__iter__()

# Update our code
print(iter_dict.__next__())				# This will take out the first key, Jonasen
print(iter_dict.__next__())				# Joseph
print(iter_dict.__next__())				# Kujo
print(iter_dict.__next__())				# Error, StopIteration

'First will have__iter__()Method is converted to an iterator and then used__next__()Continuous iteration'
'If the number of original elements is exceeded, an error will be reported StopIteration '

iterator

What is an iterator

The concept of iterator has been introduced above,

Iterators are used by iteratable objects__ iter__ () converted object,
And have__ next__ () enables us to iterate continuously

Advantages of iterators

1) Repeated value operations can be performed without using indexes;
2) Because the iterator adopts the principle of lazy calculation, it occupies very little memory;

Lazy evaluation
The iterator itself is a data stream, and only one value will be saved at the same time. Because of this storage method, even the original
The list has hundreds of elements. After being converted into an iterator object, it will only save one value, and
Use__ next__ () will discard the original and use the next (iteration).

Disadvantages of iterators

1) Because lazy calculation can only save one value at a time, iterators can only take values in turn, and can not be used at the same time
Backtracking to the previous value;
2) We can't measure the length of the iterator. We can't know the length unless we traverse all the elements (because iterators don't support len())

How to use iterators

Next, we will continue to introduce the use of iterators,
what?
You think it's over?
Oh, I can only say that in the future, you must always underline 8 more than others when using iterators and iteratable objects.

The old rule, let Miss Python tell us herself__ iter__ What is the principle of.

help(list.__iter__)

# You will get the following information
'''
__iter__(self, /)
    Implement iter(self).     ===>  English: use for yourself iter()function
'''

The so-called__ iter__ () is just using the function iter() on yourself
It means that whenever we use list__ iter__ () has the same effect as iter(list)!

(if you are interested, you can also use help(iter) and let Python tell you the iter function)

So what's next__ next__ () in fact, it is the same,
There is a function called next()

generator

OK, then there's something new - the generator.

What is a generator

Generator:
Iterators defined by ourselves

Yes, it's so simple,
The generator actually has our own defined iterator,

In the previous article, we introduced the use of iter() or__ iter__ () convert iteratable objects into iterators,
Now we're going to write an iterator ourselves (we call it a generator)

How to use the generator

Using the generator as a function

def new_range(start:int,end:int,step=3):
	while end >= start:
		yield end
		end -= step
	yield 'End of operation'
generator = new_range(1,9)				# Initialize generator
print(next(generator))					# 9
print(next(generator))					# 6
print(next(generator))					# 3
print(next(generator))					# End of operation

This effect is achieved when the function is used in combination with yield,
The following points should be noted about yiled:

1) A function that uses yield must be initialized, even if it does not require any parameters;
2) The effect of yield in the function is similar to that of return. When it is executed, a return value will be given, but the subsequent code will be suspended temporarily (return directly terminates the execution of the subsequent code);
3) yield can be used to receive external input;

Next, let's introduce how the yield receives external input,

def power(num):
    while True:
        x = yield
        print(x**num)

power_2 = power(2)
power_2.send(None)					# Initialize the function, which is equivalent to next(power_2), and let it execute to yiled to wait for receiving parameters
power_2.send(2)						# Assign 2 to x, which is equivalent to x = 2
power_2.send(3)						# After printout, execute to yield again and receive parameter 3

The above realizes how to receive external input,
However, in order to complete this, we must pay attention to the following points:

1) A loop must be used, otherwise an error will be reported after receiving a parameter
2) return cannot be used in a loop, otherwise the entire loop will be terminated

Let me demonstrate it with the code,

def power(num):
    x = yield
    print(x ** num)

pow_2 = power(2)
next(pow_2)
pow_2.send(3)

'''
9
StopIteration
'''

First, a 9 is output, and then the StopIteration error is given,
Because POW is used_ 2. After using the send() method, the function will automatically find the next yiel d,
If the loop is not used, an error message will be given to stop the iteration.

def power(num):
    while True:
        x = yield
        return x**num

pow_2 = power(2)
next(pow_2)
pow_2.send(3)

'''
StopIteration: 9
'''

With the return value, the whole while loop will be destroyed,
When using pow_ 2. An error of stopping the loop is given when return is executed after send().

Generator Expressions

Generator expressions are actually list parsing,
Interested friends can directly poke the link below and jump to my previous articles for more information.
Python - list parsing

generator = ( i for i in range(5))
print(generator)
# <generator object <genexpr> at 0x0000026D4FD75E70>

generator = [i for i in range(5)]
print(generator)
# [0, 1, 2, 3, 4]

When using list parsing, you should pay special attention to whether to use parentheses or square brackets,
Because the two are very different.

Introduction to the principle of for loop

After completing the introduction of iteratable objects, iterators and generators,
It is very necessary to introduce the principle of the for loop,
Because the for loop is actually a combination of iter(), next(), while and try... except

dict_1 = {'Jonasen': 'Jostar', 'Joseph': 'Jostar', 'Kujo': 'Jotaro'}

iter_dict = iter(dict_1)
while True:
	try:
		print(next(iter_dict))
	except StopIteration:
		break

Take apart the steps

1) Converts an iteratable object to an iterator
2) Put it into the while loop for loop printing, and call next() continuously
3) Using exception capture, stop the entire loop when StopIteration is detected

That's all the content of this article,
The last advanced function will introduce the following important programming method, recursion.

Topics: Python Back-end