Πώς να χρησιμοποιήσετε τους τελεστές αποσυσκευασίας (*, **) στην Python;

Η Python είναι η πιο χρησιμοποιούμενη γλώσσα προγραμματισμού. Σήμερα θα μάθετε να χρησιμοποιείτε ένα από τα βασικά χαρακτηριστικά του —αλλά συχνά αγνοούνται—, την αποσυσκευασία στην Python.

Πιθανότατα έχετε δει * και ** στον κώδικα άλλων ή ακόμα και να τα έχετε χρησιμοποιήσει χωρίς να γνωρίζετε πραγματικά ποιος είναι ο σκοπός τους. Θα εξετάσουμε την έννοια της αποσυσκευασίας και πώς να τη χρησιμοποιήσετε για να γράψετε περισσότερο κώδικα Pythonic.

Ακολουθεί μια λίστα με έννοιες που θα σας φανούν χρήσιμες κατά την ανάγνωση αυτού του σεμιναρίου:

  • Iterable: Οποιαδήποτε ακολουθία που μπορεί να επαναληφθεί με έναν βρόχο for, όπως σύνολα, λίστες, πλειάδες και λεξικά
  • Callable: Ένα αντικείμενο Python που μπορεί να κληθεί χρησιμοποιώντας διπλή παρένθεση (), για παράδειγμα, myfunction()
  • Shell: Διαδραστικό περιβάλλον χρόνου εκτέλεσης που μας επιτρέπει να εκτελούμε κώδικα Python. Μπορούμε να το ονομάσουμε εκτελώντας “python” σε ένα τερματικό
  • Μεταβλητή: Συμβολικό όνομα που αποθηκεύει ένα αντικείμενο και έχει μια δεσμευμένη θέση μνήμης.

Ας ξεκινήσουμε με την πιο συχνή σύγχυση: Οι αστερισμοί στην Python είναι επίσης αριθμητικοί τελεστές. Ένας αστερίσκος

χρησιμοποιείται για πολλαπλασιασμό, ενώ δύο από αυτά (**) αναφέρονται σε εκθετικότητα.

>>> 3*3
9
>>> 3**3
27

Μπορούμε να το αποδείξουμε ανοίγοντας ένα κέλυφος Python και πληκτρολογώντας:

Σημείωση: Πρέπει να έχετε εγκαταστήσει την Python 3 για να ακολουθήσετε αυτό το σεμινάριο. Εάν δεν το έχετε εγκαταστήσει, ανατρέξτε στον οδηγό εγκατάστασης Python.

Όπως μπορείτε να δείτε, χρησιμοποιούμε τον αστερίσκο μετά τον πρώτο αριθμό και πριν από τον δεύτερο. Όταν το βλέπετε αυτό, σημαίνει ότι χρησιμοποιούμε τους αριθμητικούς τελεστές.

>>> *range(1, 6),
(1, 2, 3, 4, 5)
>>> {**{'vanilla':3, 'chocolate':2}, 'strawberry':2}
{'vanilla': 3, 'chocolate': 2, 'strawberry': 2}

Από την άλλη πλευρά, χρησιμοποιούμε τους αστερίσκους (*, **) πριν από έναν επαναληπτικό για να τον αποσυσκευάσουμε — για παράδειγμα:

Πίνακας περιεχομένων

Μην ανησυχείτε αν δεν το καταλάβετε, αυτό είναι απλώς ένας προοίμιος για την αποσυσκευασία στην Python. Προχωρήστε λοιπόν και διαβάστε ολόκληρο το σεμινάριο!

Τι είναι η αποσυσκευασία;

Η αποσυσκευασία είναι η διαδικασία λήψης αντικειμένων — επαναληπτικών όπως λίστες, πλειάδες και λεξικά. Σκεφτείτε το σαν να ανοίγετε ένα κουτί και να βγάζετε διάφορα αντικείμενα όπως καλώδια, ακουστικά ή USB.

  Πώς να διορθώσετε το Kernel_task High CPU σε Mac

Η αποσυσκευασία στην Python είναι παρόμοια με την αποσυσκευασία ενός κουτιού στην πραγματική ζωή.

>>> mybox = ['cables', 'headphones', 'USB']
>>> item1, item2, item3 = mybox

Ας μεταφράσουμε αυτό το ίδιο παράδειγμα σε κώδικα για καλύτερη κατανόηση:

Όπως μπορείτε να δείτε, εκχωρούμε τα τρία στοιχεία μέσα στη λίστα mybox σε τρεις μεταβλητές item1, item2, item2. Αυτό το είδος ανάθεσης μεταβλητών είναι η θεμελιώδης έννοια της αποσυσκευασίας στην Python.

>>> item1
'cables'
>>> item2
'headphones'
>>> item3
'USB'

Εάν προσπαθήσετε να λάβετε την αξία κάθε στοιχείου, θα παρατηρήσετε ότι το στοιχείο1 αναφέρεται σε “καλώδια”, στο στοιχείο 2, αναφέρεται σε “ακουστικά” και ούτω καθεξής.

>>> newbox = ['cables', 'headphones', 'USB', 'mouse']
>>> item1, item2, item3 = newbox
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)

Μέχρι εδώ, όλα φαίνεται να είναι εντάξει με αυτόν τον κωδικό, αλλά τι θα γινόταν αν θέλαμε να αποσυσκευάσουμε μια λίστα με περισσότερα στοιχεία σε αυτήν — διατηρώντας τον ίδιο αριθμό μεταβλητών που έχουν εκχωρηθεί;

Μάλλον περίμενες τέτοιου είδους σφάλμα. Ουσιαστικά εκχωρούμε 4 στοιχεία λίστας σε τρεις μεταβλητές, πώς καταφέρνει η Python να εκχωρήσει τις σωστές τιμές; Δεν το κάνει, αυτό συμβαίνει επειδή παίρνουμε ένα ValueError

με το μήνυμα “πάρα πολλές τιμές για αποσυσκευασία”. Αυτό συμβαίνει επειδή ορίζουμε τρεις μεταβλητές στα αριστερά και τέσσερις τιμές (που αντιστοιχούν στη λίστα newbox) στα δεξιά.

>>> lastbox = ['cables', 'headphones']
>>> item1, item2, item3 = lastbox
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)

Εάν προσπαθήσετε να κάνετε μια παρόμοια διαδικασία, αλλά με περισσότερες μεταβλητές από τιμές για αποσυσκευασία, θα λάβετε ένα άλλο ValueError εκτός από αυτό με ένα ελαφρώς διαφορετικό μήνυμα:

Σημείωση: Εργαζόμαστε με λίστες, αλλά μπορείτε να χρησιμοποιήσετε αυτήν τη μορφή αποσυσκευασίας με οποιοδήποτε επαναληπτικό (λίστες, σύνολα, πλειάδες, λεξικά)

Πώς λοιπόν θα ξεπεράσουμε αυτή την κατάσταση; Υπάρχει κάποιος τρόπος να αποσυσκευάσετε όλα τα στοιχεία ενός iterable σε μερικές μεταβλητές χωρίς να λάβετε σφάλματα;

Σίγουρα υπάρχει, και ονομάζεται τελεστής αποσυσκευασίας ή τελεστής αστερίσκου (*, **). Ας δούμε πώς να το χρησιμοποιήσετε στην Python.

Πώς να αποσυσκευάσετε λίστες με τον τελεστή *

Ο τελεστής αστερίσκου

>>> first, *unused, last = [1, 2, 3, 5, 7]
>>> first
1
>>> last
7
>>> unused
[2, 3, 5]

χρησιμοποιείται για την αποσυσκευασία όλων των τιμών ενός iterable που δεν έχουν εκχωρηθεί ακόμη.

>>> first, *_, last = [1, 2, 3, 5, 7]
>>> _
[2, 3, 5]

Ας υποθέσουμε ότι θέλετε να λάβετε το πρώτο και το τελευταίο στοιχείο μιας λίστας χωρίς τη χρήση ευρετηρίων, θα μπορούσαμε να το κάνουμε με τον τελεστή αστερίσκου:

>>> first, *_, last = [1, 2]
>>> first
1
>>> last
2
>>> _
[]

Όπως καταλαβαίνετε, λαμβάνουμε όλες τις αχρησιμοποίητες τιμές με τον τελεστή αστερίσκου. Ο προτιμώμενος τρόπος απόρριψης τιμών είναι να χρησιμοποιήσετε μια μεταβλητή υπογράμμισης (_), η οποία μερικές φορές χρησιμοποιείται ως “εικονική μεταβλητή”.

Μπορούμε να χρησιμοποιήσουμε αυτό το τέχνασμα ακόμα κι αν η λίστα έχει μόνο δύο στοιχεία:

Σε αυτήν την περίπτωση, η μεταβλητή υπογράμμισης (εικονική μεταβλητή) αποθηκεύει μια κενή λίστα, ώστε οι άλλες δύο μεταβλητές γύρω τους να έχουν πρόσβαση στις διαθέσιμες τιμές της λίστας.

>>> *string = 'PythonIsTheBest'

Συνήθης αντιμετώπιση προβλημάτων

>>> *string = 'PythonIsTheBest'
  File "<stdin>", line 1
SyntaxError: starred assignment target must be in a list or tuple

Μπορούμε να αποσυσκευάσουμε ένα μοναδικό στοιχείο ενός επαναληπτικού. Για παράδειγμα, θα καταλήξετε σε κάτι σαν αυτό: Ωστόσο, ο παραπάνω κώδικας θα επιστρέψει ένα SyntaxError:Αυτό γιατί σύμφωνα με το

  Μια εισαγωγή στο Terraform για αρχάριους – Εκμάθηση Terraform

Προδιαγραφή PEP

:

>>> *string, = 'PythonIsTheBest'
>>> string
['P', 'y', 't', 'h', 'o', 'n', 'I', 's', 'T', 'h', 'e', 'B', 'e', 's', 't']

Μια πλειάδα (ή λίστα) στην αριστερή πλευρά μιας απλής εργασίας

>>> *numbers, = range(5)
>>> numbers
[0, 1, 2, 3, 4]

Αν θέλουμε να αποσυσκευάσουμε όλες τις τιμές ενός iterable σε μια μεμονωμένη μεταβλητή, πρέπει να δημιουργήσουμε μια πλειάδα, επομένως η προσθήκη ενός απλού κόμματος θα είναι αρκετή:

Ένα άλλο παράδειγμα θα ήταν η χρήση της συνάρτησης εμβέλειας, η οποία επιστρέφει μια ακολουθία αριθμών.

Τώρα που ξέρετε πώς να αποσυσκευάζετε λίστες και πλειάδες με έναν αστερίσκο, ήρθε η ώρα να μπείτε σε λεξικά αποσυσκευασίας.

Πώς να αποσυσκευάσετε λεξικά με τον τελεστή **

>>> **greetings, = {'hello': 'HELLO', 'bye':'BYE'} 
...
SyntaxError: invalid syntax

Ενώ ένας μεμονωμένος αστερίσκος χρησιμοποιείται για την αποσυσκευασία λιστών και πλειάδων, ο διπλός αστερίσκος (**) χρησιμοποιείται για την αποσυσκευασία λεξικών.

>>> food = {'fish':3, 'meat':5, 'pasta':9} 
>>> colors = {'red': 'intensity', 'yellow':'happiness'}
>>> merged_dict = {**food, **colors}
>>> merged_dict
{'fish': 3, 'meat': 5, 'pasta': 9, 'red': 'intensity', 'yellow': 'happiness'}

Δυστυχώς, δεν μπορούμε να αποσυσκευάσουμε ένα λεξικό σε μια μεμονωμένη μεταβλητή όπως κάναμε με πλειάδες και λίστες. Αυτό σημαίνει ότι τα ακόλουθα θα δημιουργήσουν ένα σφάλμα:

Ωστόσο, μπορούμε να χρησιμοποιήσουμε τον τελεστή ** μέσα σε καλούμενα και άλλα λεξικά. Για παράδειγμα, αν θέλουμε να δημιουργήσουμε ένα συγχωνευμένο λεξικό, φτιαγμένο από άλλα λεξικά, θα μπορούσαμε να χρησιμοποιήσουμε τον παρακάτω κώδικα:

Αυτός είναι ένας αρκετά σύντομος τρόπος για να δημιουργήσετε σύνθετα λεξικά, ωστόσο, αυτή δεν είναι η κύρια προσέγγιση της αποσυσκευασίας στην Python.

Ας δούμε πώς μπορούμε να χρησιμοποιήσουμε την αποσυσκευασία με καλούμενα

Συσκευασία σε Λειτουργίες: args και kwargs

Πιθανότατα έχετε δει args και kwargs πριν είτε εφαρμοστούν σε κλάσεις ή συναρτήσεις. Ας δούμε γιατί πρέπει να τα χρησιμοποιούμε μαζί με καλέσιμα.

>>> def product(n1, n2):
...     return n1 * n2
... 
>>> numbers = [12, 1]
>>> product(*numbers)
12

Συσκευασία με τον χειριστή * (args)

>>> product(12, 1)
12

Ας υποθέσουμε ότι έχουμε μια συνάρτηση που υπολογίζει το γινόμενο δύο αριθμών.

>>> numbers = [12, 1, 3, 4]
>>> product(*numbers)
...
TypeError: product() takes 2 positional arguments but 4 were given

Όπως μπορείτε να δείτε, αποσυσκευάζουμε τους αριθμούς της λίστας στη συνάρτηση, επομένως στην πραγματικότητα εκτελούμε τα εξής:

>>> def product(*args):
...     result = 1
...     for i in args:
...             result *= i
...     return result
...
>>> product(*numbers)
144

Μέχρι εδώ, όλα λειτουργούν μια χαρά, αλλά τι γίνεται αν θέλαμε να περάσουμε μια μεγαλύτερη λίστα; Σίγουρα θα δημιουργήσει ένα σφάλμα επειδή η συνάρτηση λαμβάνει περισσότερα ορίσματα από όσα μπορεί να διαχειριστεί.

  Κάντε πιο εύκολες τις φτηνές διεθνείς κλήσεις με αυτές τις 10 εφαρμογές/εργαλεία

Μπορούμε να τα λύσουμε όλα αυτά απλώς συσκευάζοντας τη λίστα απευθείας στη συνάρτηση, η οποία δημιουργεί ένα επαναληπτικό στο εσωτερικό της και μας επιτρέπει να περάσουμε οποιονδήποτε αριθμό ορισμάτων στη συνάρτηση.

Εδώ αντιμετωπίζουμε την παράμετρο args ως επαναληπτική, περπατώντας στα στοιχεία της και επιστρέφοντας το γινόμενο όλων των αριθμών. Σημειώστε πώς ο αρχικός αριθμός του αποτελέσματος πρέπει να είναι ένα γιατί αν ξεκινήσουμε με μηδέν, η συνάρτηση θα επιστρέφει πάντα μηδέν. Σημείωση: Το args είναι απλώς μια σύμβαση, μπορείτε να χρησιμοποιήσετε οποιοδήποτε άλλο όνομα παραμέτρουΘα μπορούσαμε επίσης να περάσουμε αυθαίρετους αριθμούς στη συνάρτηση χωρίς τη χρήση λίστας, όπως και με την ενσωματωμένη

>>> product(5, 5, 5)
125
>>> print(5, 5, 5)
5 5 5

λειτουργία εκτύπωσης

>>> def test_type(*args):
...     print(type(args))
...     print(args)
... 
>>> test_type(1, 2, 4, 'a string')
<class 'tuple'>
(1, 2, 4, 'a string')

.

Τέλος, ας πάρουμε τον τύπο αντικειμένου των args μιας συνάρτησης.

Όπως σημειώνεται στον παραπάνω κώδικα, ο τύπος των args θα είναι πάντα πλειάδα και το περιεχόμενό τους θα είναι όλα τα ορίσματα χωρίς λέξεις-κλειδιά που θα μεταβιβάζονται στη συνάρτηση.

Συσκευασία με τον χειριστή ** (kwargs)

>>> def make_person(name, **kwargs):
...     result = name + ': '
...     for key, value in kwargs.items():
...             result += f'{key} = {value}, '
...     return result
... 
>>> make_person('Melissa', id=12112, location='london', net_worth=12000)
'Melissa: id = 12112, location = london, net_worth = 12000, '

Όπως είδαμε προηγουμένως, ο τελεστής ** χρησιμοποιείται αποκλειστικά για λεξικά. Αυτό σημαίνει ότι με αυτόν τον τελεστή μπορούμε να μεταβιβάσουμε ζεύγη κλειδιού-τιμής στη συνάρτηση ως παράμετρο.

Ας δημιουργήσουμε μια συνάρτηση make_person, η οποία λαμβάνει ένα όρισμα θέσης «όνομα» και έναν απροσδιόριστο αριθμό ορισμάτων με λέξεις-κλειδιά.

Όπως μπορείτε να δείτε, η πρόταση **kwargs μετατρέπει όλα τα ορίσματα με λέξεις-κλειδιά σε ένα λεξικό, το οποίο μπορούμε να επαναλάβουμε μέσα στη συνάρτηση.

>>> def test_kwargs(**kwargs):
...     print(type(kwargs))
...     print(kwargs)
... 
>>> test_kwargs(random=12, parameters=21)
<class 'dict'>
{'random': 12, 'parameters': 21}

Σημείωση: Το kwargs είναι απλώς μια σύμβαση που μπορείτε να ονομάσετε αυτήν την παράμετρο με ό,τι θέλετε

Μπορούμε να ελέγξουμε τον τύπο των kwargs με τον ίδιο τρόπο που κάναμε με τα args:

>>> def my_final_function(*args, **kwargs):
...     print('Type args: ', type(args))
...     print('args: ', args)
...     print('Type kwargs: ', type(kwargs))
...     print('kwargs: ', kwargs)
... 
>>> my_final_function('Python', 'The', 'Best', language="Python", users="A lot")
Type args:  <class 'tuple'>
args:  ('Python', 'The', 'Best')
Type kwargs:  <class 'dict'>
kwargs:  {'language': 'Python', 'users': 'A lot'}

Η εσωτερική μεταβλητή kwargs μετατρέπεται πάντα σε λεξικό, το οποίο αποθηκεύει τα ζεύγη κλειδιών-τιμών που μεταβιβάζονται στη συνάρτηση.

Τέλος, ας χρησιμοποιήσουμε args και kwargs στην ίδια συνάρτηση:

συμπέρασμα

  • Οι τελεστές αποσυσκευασίας είναι πραγματικά χρήσιμοι σε καθημερινές εργασίες, τώρα ξέρετε πώς να τους χρησιμοποιείτε τόσο σε μεμονωμένες δηλώσεις όσο και σε παραμέτρους συναρτήσεων.
  • Σε αυτό το σεμινάριο μάθατε:
  • Χρησιμοποιείτε * για πλειάδες και λίστες και ** για λεξικά
  • Μπορείτε να χρησιμοποιήσετε τελεστές αποσυσκευασίας σε κατασκευαστές συναρτήσεων και κλάσεων

Τα args χρησιμοποιούνται για τη μετάδοση παραμέτρων χωρίς λέξεις-κλειδιά σε συναρτήσειςΤα kwargs χρησιμοποιούνται για τη μεταβίβαση παραμέτρων με λέξεις-κλειδιά στις συναρτήσεις.