On Tue, Jul 07, 2015 at 06:50:25PM +0200, Peter Otten wrote: [...] > > Not so. The point of del being a statement is that it should be > > considered an operation on the *reference*, not the *value* of the > > reference. So: > > > > 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. [...] > I 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.) > I'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. > > It'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 - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor