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,
"(e-mail address removed)", ...]:
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 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