Feature request: String-inferred names

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Fri Dec 4 07:58:09 EST 2009


On Thu, 03 Dec 2009 23:12:39 -0600, Brad Harms wrote:

> On Tue, 2009-12-01 at 14:38 +0000, Steven D'Aprano wrote:
[...]
>> It's just special double-underscore methods like __init__ __add__ etc
>> that have to be in the class rather than the instance. (To be precise,
>> you can add such a method to the instance, but it won't be called
>> automatically.) Likewise staticmethods and classmethods won't work
>> correctly unless they are in the class. But ordinary methods work fine:
>> the only tricky bit is creating them in the first place.
>> 
>> >>> class K(object):
>> ...     pass
>> ...
>> >>> k = K()
>> >>> import types
>> >>> k.method = types.MethodType(lambda self: "I am %s" % self, k)
>> >>> k.method()
>> 'I am <__main__.K object at 0xb7cc7d4c>'
> 
> ...I'm not sure I follow your logic.
> 
> Yes, you can create an instancemethod out of a function and assign it to
> an instance after (or during) its instantiation, which is what Python's
> class/instance model provides automatically. However, to do so manually
> in this manner completely disregards the fundamentals of object-oriented
> programming, not to mention the basic guiding principles of nearly all
> Python code in existence. It totally breaks inheritance and
> polymorphism. Maybe I'm missing something, but I can't see how that line
> of thought helps anything.

I'm not recommending it as a standard technique instead of defining 
methods via the usual class statement. But it does work, and can be handy 
for the odd occasion where you want per-instance behaviour of some class. 
I'm not saying this is a common occurrence, but it does happen -- it's 
particularly handy if you have a standard behaviour which you want to 
override, e.g. monkey-patching specific instances. Instead of this:

class K:
    marker = None
    def method(self):
        if self.marker:
            return "special"
         return "normal"

k = K()
k.marker = 1

you can do this:

class K:
    def method(self):
         return "normal"

k = K()
k.method = type(k.method)(lambda self: "special", k)

So although unusual, it is useful.

As for breaking inheritance and polymorphism, not at all. Inheritance 
still works, and polymorphism is irrelevant: methods are, or aren't, 
polymorphic regardless of whether they are per instance or shared. 
Fundamentally, per-instance methods are nothing more than as per-instance 
attributes which happen to be callable.

It is "magic methods" like __len__ and friends that break the usual rules 
of inheritance. The normal lookup chain for instance.name, whether name 
is a callable method or a non-callable attribute, is:

instance
class
base class(es)

but for magic methods, the chain skips the instance step. That's done as 
an optimization, and given how rare it is to have per-instance methods, 
that's quite reasonable.



-- 
Steven



More information about the Python-list mailing list