Reputation: 51
According to the following snippet:
import time
def custom_time():
return time.time()
class TimeWrapper:
builtin_time = time.time
def print_builtin(self):
print(self.builtin_time())
custom_time = custom_time
def print_custom(self):
print(self.custom_time())
wrapper = TimeWrapper()
wrapper.print_builtin()
# 1660163626.7973292
wrapper.print_custom()
# TypeError: custom_time() takes 0 positional arguments but 1 was given
time.time(wrapper)
# TypeError: time.time() takes no arguments (1 given)
custom_time(wrapper)
# TypeError: custom_time() takes 0 positional arguments but 1 was given
I do not understand why wrapper.print_builtin()
is working.
Is it not supposed to be the equivalent of time.time(wrapper)
?
Is there a connection with the unused
argument from C implementation ?
If it is not the case, I'm still interested in this unused variable.
Upvotes: 2
Views: 78
Reputation: 114518
This is an interesting side-effect of how methods really work. A method is just a function in a class dictionary. For example:
class A:
def b(self):
print("b")
def c(self):
print("c")
A.c = c
a = A()
The reason that both b
and c
are equally methods of A
is that they are descriptors. When you access a descriptor from an instance of a class using dot notation, as in a.b
or a.c
, python will perform the following binding: type(a).b.__get__(a)
. The bound method is a callable that automatically passes self
to the underlying function. Whether you define a method in the class or outside a class and add it to the class dictionary by other means, it will behave the same.
The behavior of c
in the example above is exactly the same as custom_time
in your example. By setting custom_time = custom_time
in the class body, you are creating a method just as if you had placed def custom_time():
in the class body. When you call the subsequently bound method as self.custom_time()
, the bound method passes instance self
as the first argument, even though the function accepts no arguments. Hence your error.
Upvotes: 2
Reputation: 532208
time.time
has type builtin_function_or_method
, not function
. Such objects do not implement the descriptor protocol:
>>> time.time.__get__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'builtin_function_or_method' object has no attribute '__get__'
so self.builtin_time
simply returns time.time
, not a method
object that implicitly passes self
as the first argument to time.time
.
That is, self.builtin_time()
is exactly the same as time.time()
, not time.time(self)
.
Upvotes: 2