Книга: Practical Programming, Fourth Edition
Назад: Slicing Lists
Дальше: List Methods

Aliasing: What’s in a Name?

When two variables refer to the same object, they are called aliases

An alias is an alternative name for an object. In Python, two variables are considered aliases when they have the same identity. For example, the following code creates two variables that both refer to the same list:

Aliasting

When you modify the list using one of the variables, references through the other variable also show the change:

 >>>​​ ​​celegans_phenotypes​​ ​​=​​ ​​[​​'Emb'​​,​​ ​​'Him'​​,​​ ​​'Unc'​​,​​ ​​'Lon'​​,​​ ​​'Dpy'​​,​​ ​​'Sma'​​]
 >>>​​ ​​celegans_alias​​ ​​=​​ ​​celegans_phenotypes
 >>>​​ ​​id(celegans_phenotypes)
 140293381748160
 >>>​​ ​​id(celegans_alias)
 140293381748160
 >>>​​ ​​id(celegans_phenotypes)​​ ​​==​​ ​​id(celegans_alias)
 True
 >>>​​ ​​celegans_phenotypes[5]​​ ​​=​​ ​​'Lvl'
 >>>​​ ​​celegans_phenotypes
 ['Emb', 'Him', 'Unc', 'Lon', 'Dpy', 'Lvl']
 >>>​​ ​​celegans_alias
 ['Emb', 'Him', 'Unc', 'Lon', 'Dpy', 'Lvl']

Aliasing is one of the reasons why the notion of mutability is essential. For example, if x and y refer to the same list, then any changes you make to the list through x will be “seen” by y, and vice versa. Aliasing can lead to all sorts of hard-to-find errors in which a list’s value changes as if by magic, even though your program doesn’t appear to assign anything to it. Immutable values, such as strings, are immune to aliasing. Since a string can’t be changed after it has been created, it’s safe to have aliases for it.

Mutable Parameters

Aliasing occurs when you use list parameters, as parameters are variables. Here is a function that takes a list, removes its last item, and returns the list:

 >>>​​ ​​def​​ ​​remove_last_item(L:​​ ​​list)​​ ​​->​​ ​​list:
 ...​​ ​​"""Return list L with the last item removed.
 ...
 ... Precondition: len(L) >= 0
 ...
 ... >>> remove_last_item([1, 3, 2, 4])
 ... [1, 3, 2]
 ... """
 ...​​ ​​del​​ ​​L[-1]
 ...​​ ​​return​​ ​​L
 ...
 >>>

In the code that follows, a list is created and stored in a variable; then that variable is passed as an argument to the remove_last_item function:

 >>>​​ ​​celegans_markers​​ ​​=​​ ​​[​​'Emb'​​,​​ ​​'Him'​​,​​ ​​'Unc'​​,​​ ​​'Lon'​​,​​ ​​'Dpy'​​,​​ ​​'Lvl'​​]
 >>>​​ ​​remove_last_item(celegans_markers)
 ['Emb', 'Him', 'Unc', 'Lon', 'Dpy']
 >>>​​ ​​celegans_markers
 ['Emb', 'Him', 'Unc', 'Lon', 'Dpy']

When the call on function remove_last_item is executed, parameter L is assigned the memory address that celegans_markers contains. That makes celegans_markers and L aliases. When the last item of the list that L refers to is removed, that change is “seen” by celegan_markers as well.

Since remove_last_item modifies the list parameter, the modified list doesn’t need to be returned. You can remove the return statement:

 >>>​​ ​​def​​ ​​remove_last_item(L:​​ ​​list)​​ ​​->​​ ​​None:
 ...​​ ​​"""Remove the last item from L.
 ...
 ... Precondition: len(L) >= 0
 ...
 ... >>> remove_last_item([1, 3, 2, 4])
 ... """
 ...​​ ​​del​​ ​​L[-1]
 ...
 >>>​​ ​​celegans_markers​​ ​​=​​ ​​[​​'Emb'​​,​​ ​​'Him'​​,​​ ​​'Unc'​​,​​ ​​'Lon'​​,​​ ​​'Dpy'​​,​​ ​​'Lvl'​​]
 >>>​​ ​​remove_last_item(celegans_markers)
 >>>​​ ​​celegans_markers
 ['Emb', 'Him', 'Unc', 'Lon', 'Dpy']

As you’ll see in , several list methods modify a list and return None, like the second version of remove_last_item.

Назад: Slicing Lists
Дальше: List Methods