On Tue, Jul 07, 2015 at 06:50:25PM +0200, Peter Otten wrote:
[...]
Post by Peter OttenPost by Steven D'ApranoNot so. The point of del being a statement is that it should be
considered an operation on the *reference*, not the *value* of the
x = 23
delete(x) # if it existed, it would see the value 23
del x # operates on the reference "x", not 23
Read again. I said that
del x
in the global namespace can be emulated with
globals().pop("x")
and that there is no equivalent to
del x
if x is a local/nonlocal name.
Yes, I read all that. There *could* (at least in theory) be an
equivalent to `del x` using a function, which I called `delete("x")`,
that applied to locals/nonlocals as well as globals. It would still not
be *close* equivalent to del, because they operate in different spheres,
semantically.
Using pop() is not quite right, because it doesn't just remove the
key:value pair, it *returns the value*. So that's a another difference
between popping a key from the globals, and del:
del x:
- operates on the variable x, not the value of x
- unbinds that variable
- has no return result (is a statement, not an expression
globals().pop("x"):
- operates on a value, the string "x", not a variable
- conceptually, not an unbinding operation at all
- returns the value bound to the variable x
This makes a practical difference at the interactive interpreter:
popping as two side effects, only one of which is intended:
py> a, b = 1, 2
py> del a
py> globals().pop("b")
2
It's unlikely to change, since the current semantics of globals() is
documented as a language feature, but in principle at least a Python
implementation might optimize the language by making globals() more like
locals(), i.e. calling globals() returns a *copy* of the global
namespace, not the namespace itself.
As I said, this is unlikely to change without a period of deprecation,
but still, del is *intended* to unbind variables, pop is not. The fact
that globals().pop also unbinds them is an accident of the way manages
globals.
For all these reasons, if I saw
globals().pop("x")
in code I was reviewing, I would change it to `del x` without
hesitation. Not withstanding the fact that we *can* replace del with pop
as above, we shouldn't.
[...]
Post by Peter OttenI agree that if you think that explicitly unbinding a name is a useful
feature of the language a statement is the way to go. For me it's a feature
I hardly ever use and that I hardly ever find compelling in other people's
code.
I completely agree that del is rarely useful! But *rare* is not *never*.
There are two compelling cases for using del on names: explicitly
managing the names in a namespace (i.e. to avoid "namespace pollution")
and avoiding long-lived global references to objects which you no
longer need.
I agree that using del on a local variable is probably unnecessary
micro-management. I can't think of any scenario where you would want to
manually del a local variable. If you did, that's possibly a sign that
your function is too big.
When writing a script or application, name management is not a big deal.
But in a library, temporary variables are pollution. They make it harder
for the users of your library to tell what's part of the API and what
isn't, and they make "from module import *" less useful. So if I have a
temporary global variable, I may want to get rid of it once I'm finished
with it. Here's a snippet from a library module I have, designed to be
used with * imports:
tmp = set(C0.keys()) & set(C1.keys())
assert not tmp, 'duplicate control code acronyms: %s' % tmp
# Special check for SCG abbreviated acronym.
assert 'SGC' not in C0
assert 'SGC' not in C1
# Validate that the ^ and ESC codes are correct.
for C in (C0, C1):
for cc in C.values():
assert cc.code == _code(cc.ordinal), 'failed check: %s' % cc
del C, cc, tmp
Those three temporary variables, C, cc and tmp, would otherwise hang
around forever, polluting the namespace and confusing my module's users.
(My module's users, so far, is mostly me, but I'm easily confused.)
Post by Peter OttenI'd happily resort to
x = None
should the need arise to dereference a specific variable.
Ah, reading that makes me sad, because it looks like you are not getting
the difference between a *variable* (a name in a namespace) and the
*value* of that variable.
`x = None` does not remove the variable from the namespace, it just
binds it to None. So it is no substitute for the del statement.
Post by Peter OttenPost by Steven D'ApranoIt's a work-around for the fact that
Python doesn't have dedicated syntax to say "operate on the reference
foo" rather than the value of foo.
I think Danny's point was that you should not micromanage name bindings at
all. Then Alan added that del is useful for dicts etc. on which I replied
that a method would be sufficient for that.
Sure, Python *could* have used methods for deleting a key from a dict,
or a slice from a list:
mydict.delete(key) # like del mydict[key]
mylist.delete(1, 20, 3) # like del mylist[1:20:3]
But note that introduces a source of API confusion: people may use
mylist.remove(1) when they mean delete, or the other way around. Either
way, that error is harder to make with the del statement: there is no
reasonable way for a person to be confused about whether
del mylist[3]
removes the 3rd item, or an item with the value 3. With:
mylist = [3, 6, 9, 12]
mylist.delete(3)
it isn't clear whether you end up with [3, 6, 9] or [6, 9, 12].
And when it comes to attributes, we shouldn't use getattr, setattr or
delattr with constant arguments:
# Yes
y = x.spam
x.spam = 23
del x.spam
# No
y = getattr(x, "spam")
setattr(x, "spam", 23)
delattr(x, "spam")
I wouldn't hestitate to replace any of the second set with the version
from the first set.
--
Steve
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor