Methods in Python are defined as functions in the class namespace. When call the method of the object, the function will be called with the object as the first argument. And furthermore, unbound methods can be called with passing self as the first argument. For example, str.upper('abc') returns 'ABC'. So class can be considered as a namespace for functions related to objects of the specified type. For methods defined in Python you can pass arbitrary object as self. But in methods defined in C it should be an instance of the class in which the method was defined. On one hand, it is very convenient -- you cab be sure that self is binary compatible with the specified class. On other hand, it restricts you. I propose to add the METH_GENERAL flag, which is applicable to methods as METH_CLASS and METH_STATIC (and is mutually incompatible with them). If it is set, the check for the type of self will be omitted, and you can pass an arbitrary object as the first argument of the unbound method. I have several use cases for this. 1. Bytes and bytearray methods. Bytes and bytearray has a lot of of sequence-like and string-like methods. They also implement the buffer protocol. There are other objects which implement the buffer protocol: memoryview, BytesIO, array.array, mmap.mmap, ctypes arrays, NumPy arrays, but they lack most of these methods. To use these methods (for example index()) you need to copy the content to a bytes or bytearray, that invalidates the purpose of the buffer protocol which was designed to avoid copying of binary data. With general methods we can make bytes.index() be applicable to any object which supports the buffer protocol. bytes.index() and bytearray.index() will be equivalent, but the difference between bytes.split() and bytearray.split() will be in the result type. 2. Set methods. Some set methods accept arbitrary number of arguments and accept not only sets, but any iterables. Sou you can get a union of two lists for example:
set().union([1, 2], [2, 3]) {1, 2, 3}
It does work because a union with an empty set is a no-op. This trick does not work with other methods. You have to convert the first iterable to set explicitly.
set([1, 2]).symmetric_difference([2, 3]) {1, 3}
With general methods we can make unbound set methods accepting arbitrary iterables and convert the first one to set implicitly (or avoid creating a set if it is possible). We could use set.symmetric_difference([1, 2], [2, 3]). Maybe there are other use cases. But I do not suggest making all methods of builtin types general: only if there is a more general protocol (as the buffer protocol or the iterator protocol) and there is a profit of using such protocol without creating an object of the corresponding type explicitly. For example, I think that str methods should not be general, despite the fact that any object can be converted to string. Implicit conversions to str does not have profit and may hide bugs. Other example -- float.as_integer_ratio() should not accept int, despite the fact that most function which accept float implicitly convert int to float. It is a lossy conversion for large integers, and the loss will affect the result. I used the term "general methods" to name this feature, but if there are better proposition I will use it.