Python2中types.MethodType第三个参数作用及2to3兼容问题
types.MethodType第三个参数的作用 Great question! Let's unpack exactly what that third parameter does in Python 2, and why you might encounter it even though the two-argument version works across both Python 2 and 3.
First, let's recap Python 2's method model—this is key to understanding the difference. Python 2 distinguishes between three related callables:
- Functions: Plain old
def-defined callables with no binding to a class or instance. - Bound methods: Functions bound to a specific instance; when called, the instance is automatically passed as the
selfargument. - Unbound methods: Functions associated with a class (but not an instance); they require an instance of that class (or a subclass) to be passed as the first argument when called.
What the third parameter does
The types.MethodType constructor in Python 2 has two primary use cases depending on whether you pass a second argument:
Two arguments (
types.MethodType(func, instance)): Creates a bound method tied toinstance. This is the version that works in both Python 2 and 3, and it's what you're using in yoursetattr(a, 'foo', types.MethodType(foo, a))example—this bindsfooto the instancea, so callinga.foo()automatically passesaasself.Three arguments (
types.MethodType(func, instance, class_)): This does one of two things:- If
instanceisNone: It creates an unbound method associated withclass_. This unbound method enforces that when called, the first argument must be an instance ofclass_(or a subclass). In Python 2, if you assign a plain function to a class attribute directly, Python automatically converts it to an unbound method—but using the three-argumentMethodTypelets you explicitly create this type. - If
instanceis an object (like in your example): It creates a bound method tied toinstance, but explicitly associates it withclass_instead of usingtype(instance). In most cases, this behaves identical to the two-argument version for everyday calls. The only tangible difference is in metadata: the bound method's__im_class__attribute will beclass_instead oftype(instance)(useful in rare reflection or metaprogramming scenarios).
- If
Example: Unbound methods with the third parameter
Let's see this in action in Python 2:
import types def greet(self): print(f"Hello from {self}") class Person(object): pass # Create an unbound method explicitly Person.greet = types.MethodType(greet, None, Person) # This works (passes a Person instance as self) Person.greet(Person()) # Output: Hello from <__main__.Person object at 0x...> # This throws an error (wrong type) Person.greet("not a person") # TypeError: unbound method greet() must be called with Person instance as first argument (got str instance instead) # If we just assign the function directly, Python 2 does the same auto-conversion: Person.greet = greet Person.greet(Person()) # Still works Person.greet("not a person") # Still throws the same error
Why the three-argument version might appear in legacy code
You might see someone use the three-argument form even when binding to an instance (like your example) for a few reasons:
- Habit or convention from older Python codebases where explicit class association was preferred.
- Rare metaprogramming scenarios where the method's
__im_class__metadata needs to be a specific class (not the instance's actual type, e.g., a parent class instead of a subclass).
But for almost all everyday use cases, the two-argument version is sufficient—and crucially, it's compatible with both Python 2 and 3.
Python 3 changes
Python 3 removed the concept of unbound methods entirely. When you assign a function to a class attribute, it stays a plain function (you have to manually pass self when calling it via the class). The types.MethodType constructor only accepts two arguments now, which creates a bound method for an instance—exactly the behavior you get from the two-argument form in Python 2.
内容的提问来源于stack exchange,提问作者pettus

