On Tue, 6 Sep 2011 11:10 am Chris Torek wrote: >>> black_knight = K() >>> black_knight.spam() >>> black_knight.eggs() >>> >>> the first parameters ... are magic, and invisible. >>> >>> Thus, Python is using the "explicit is better than implicit" rule >>> in the definition, but not at the call site. ... > > In article <m2wrdnf53u....@cochabamba.vanoostrum.org> > Piet van Oostrum <p...@vanoostrum.org> wrote: >>It *is* explicit also at the call site. It only is written at the left >>of the dot rather than at the right of the parenthesis. > > It cannot possibly be explicit. The first parameter to one of the > method functions is black_knight, but the first parameter to the > other method is black_knight.__class__.
I think you are expecting more explicitness than actually required. There are degrees of explicitness: - The current President of the United States is a black man. - On 6th September 2011, the duly constituted President of the United States of America is a black man. - On 6th September 2011, the duly constituted government official with the title of President of the nation known as the United States of America is an individual member of the species Homo sapiens with XY chromosomes and of recent African ancestry. As opposed to implicit: - He is a black guy. There is no requirement for every last gory detail to be overtly specified in full. I quote from WordNet: explicit adj 1: precisely and clearly expressed or readily observable; leaving nothing to implication; "explicit instructions"; "she made her wishes explicit"; "explicit sexual scenes" [syn: expressed] [ant: implicit] 2: in accordance with fact or the primary meaning of a term [syn: denotative] Note the second definition in particular: in accordance with the primary meaning of a term: the primary meaning of "class method" is that it receives the class rather than the instance as first argument. The "explicit is better than implicit" Zen should, in my opinion, be best understood as a recommendation that code should, in general, avoid getting input from context. In general, functions should avoid trying to decide which behaviour is wanted according to context or the environment: def func(x): if running_in_a_terminal(): print "The answer is", (x+1)/2 else: printer = find_a_printer() if printer is not None: printer.send((x+1)/2, header="func(%r)"%x, footer="Page 1") else: # Try sending email to the current user, the default user, # postmaster or root in that order. msg = make_email("The answer is", (x+1)/2) for user in [get_current_user(), DEFAULT_USER, "root@localhost.localdomain", ...]: result = send_mail(msg, to=user) if result == 0: break else: # Fall back on beeping the speakers in Morse code ... (what if I want to beep the speakers from the terminal?), but not as a prohibition against code like this: def factorial(x): # Return the factorial of the integer part of x. n = int(x) if n <= 1: return 1 return n*factorial(n-1) There's no need to require the user to explicitly call int(x) before calling factorial just to satisfy the Zen. A function is free to process arguments as required, even to throw out information (e.g. float -> int, instance -> class). What it shouldn't do is *add* information implied by context (or at least, it should be very cautious in doing so, and document it carefully, and preferably allow the caller to easily override such implied data). > Which one is which? Is spam() the instance method and eggs() the > class method, or is spam() the class method and eggs the instance > method? (One does not, and should not, have to *care*, which is > kind of the point here. :-) ) You can't tell just from the syntax used to call them: function(arg) bound_method(arg) builtin_function_or_method(arg) callable_instance(arg) type(arg) all use the same syntax. There is no requirement that you should be able to tell *everything* about a line of code just from the syntax used. If you want to know whether black_knight.spam is an instance method or a class method, or something else, use introspection to find out. > By "that" I assume you mean the name "black_knight" here. But the > name is not required to make the call; see the last line of the > following code fragment: > > funclist = [] > ... > black_knight = K() > funclist.append(black_knight.spam) > funclist.append(black_knight.eggs) > ... > # At this point, let's say len(funclist) > 2, > # and some number of funclist[i] entries are ordinary > # functions that have no special first parameter. > random.choice(funclist)() Irrelevant. The instance used for the bound method is explicitly specified when you create it. But there's no requirement that you need to explicitly specify the instance every single time you *use* the bound method. The instance is part of the bound method, it isn't implied by context or history or guessed from the environment. Contrast what Python actually does with a hypothetical language where bound methods' instances are implicitly assigned according to the most recent instance created: black_knight = Knight() funclist.append(spam) # refers to black_knight.spam white_knight = Knight() funclist.append(spam) # refers to white_knight.spam baldrick = Knave() funclist.append(eggs) # oops, Knaves don't have an eggs attribute -- Steven -- http://mail.python.org/mailman/listinfo/python-list