Overriding member methods in __init__

C

c james

Given a condition at the time a class is instantiated, I want to change
how __call__ is used. From the example below, self.no is using self.yes
but self.__call__ is not. Can someone please explain why?

EXAMPLE:
class YesNo(object):
def __init__(self, which):
self.no = self.yes
self.__call__ = self.yes

def yes(self, val):
print 'Yes', val

def no(self, val):
print 'No', val

def __call__(self, val):
raise NotImplementedError()
Traceback ....
Not ImplementedError
 
B

Bruno Desthuilliers

c james a écrit :
Given a condition at the time a class is instantiated, I want to change
how __call__ is used. From the example below, self.no is using self.yes
but self.__call__ is not. Can someone please explain why?

IIRC, you can't override __magic__ methods on a per-instance basis.
EXAMPLE:
class YesNo(object):
def __init__(self, which):
self.no = self.yes
self.__call__ = self.yes

def yes(self, val):
print 'Yes', val

def no(self, val):
print 'No', val

def __call__(self, val):
raise NotImplementedError()


This should do the trick:

class YesNo(object):
def __init__(self, which):
self.which = which

def __call__(self, val):
return (self.no, self.yes)[self.which](val)

def yes(self, val):
print 'Yes', val

def no(self, val):
print 'No', val
 
C

c james

Bruno said:
c james a écrit :
Given a condition at the time a class is instantiated, I want to change
how __call__ is used. From the example below, self.no is using self.yes
but self.__call__ is not. Can someone please explain why?

IIRC, you can't override __magic__ methods on a per-instance basis.

This should do the trick:

class YesNo(object):
def __init__(self, which):
self.which = which

def __call__(self, val):
return (self.no, self.yes)[self.which](val)

def yes(self, val):
print 'Yes', val

def no(self, val):
print 'No', val

Thanks, I was trying to eliminate another level of indirection with a
test at each invocation of __call__
 
D

Duncan Booth

Thanks, I was trying to eliminate another level of indirection with a
test at each invocation of __call__
Try using different subclasses for each variant:

class YesNo(object):
def __new__(cls, which, *args, **kw):
if cls is YesNo:
if which:
return object.__new__(Yes)
else:
return object.__new__(No)

def __init__(self, which, *args, **kw):
print "New", self.__class__, which, args, kw

def __call__(self, val):
raise NotImplementedError()


class Yes(YesNo):
def __call__(self, val):
print 'Yes', val


class No(YesNo):
def __call__(self, val):
print 'No', val

 
H

Hrvoje Niksic

c james said:
class YesNo(object):
def __init__(self, which):
self.which = which

def __call__(self, val):
return (self.no, self.yes)[self.which](val)

def yes(self, val):
print 'Yes', val

def no(self, val):
print 'No', val

Thanks, I was trying to eliminate another level of indirection with a
test at each invocation of __call__

Allowing instance lookup of __call__ would slow down normal uses of
the internal __call__ mechanism. Since it used for all function and
method calls, it needs to remain extremely fast. If you're really
worried about performance, you can define YesNo.__new__ to return
either a Yes instance or a No instance, depending on the value:

class YesNo(object):
def __new__(cls, which):
if which:
return object.__new__(Yes)
else:
return object.__new__(No)

def yes(self, val):
print 'Yes', val

def no(self, val):
print 'No', val

class Yes(YesNo):
def __call__(self, val):
self.yes(val) # no check at every call

class No(YesNo):
def __call__(self, val):
self.no(val) # likewise
True
 
A

Arnaud Delobelle

Allowing instance lookup of __call__ would slow down normal uses of
the internal __call__ mechanism. Since it used for all function and
method calls, it needs to remain extremely fast. If you're really
worried about performance, you can define YesNo.__new__ to return
either a Yes instance or a No instance, depending on the value:

class YesNo(object):
def __new__(cls, which):
if which:
return object.__new__(Yes)
else:
return object.__new__(No)

def yes(self, val):
print 'Yes', val

def no(self, val):
print 'No', val

class Yes(YesNo):
def __call__(self, val):
self.yes(val) # no check at every call

class No(YesNo):
def __call__(self, val):
self.no(val) # likewise

Why not simply do:

class YesNo(object):
def __init__(self, which):
self.yesno = which and self.yes or self.no
def yes(self, val):
print 'Yes', val
def no(self, val):
print 'No', val
def __call__(self, val):
self.yesno(val)

I don't know which is fastest but I don't think there would be much
difference.
 
C

c james

Arnaud said:
Why not simply do:

class YesNo(object):
def __init__(self, which):
self.yesno = which and self.yes or self.no
def yes(self, val):
print 'Yes', val
def no(self, val):
print 'No', val
def __call__(self, val):
self.yesno(val)

I don't know which is fastest but I don't think there would be much
difference.

This is more in the spirit of what I was trying to accomplish.
Originally, I was unaware the __call__ could not be assigned a different
method.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top