Re: Another of those is issues.

2009-03-24 Thread J. Cliff Dyer
On Fri, 2009-03-20 at 11:20 -0700, Emanuele D'Arrigo wrote:
 Hi everybody,
 
 I was unit testing some code today and I eventually stumbled on one of
 those is issues quickly solved replacing the is with ==. Still,
 I don't quite see the sense of why these two cases are different:
 
  def aFunction():
 ... pass
 ...
  f = aFunction
  f is aFunction
 True   --- Ok, this seems reasonable. Nevertheless, I suspect I
 shouldn't quite rely on it.
 
  class MyClass(object):
 ... def myMethod(self):
 ... pass
 ...
  c = MyClass()
  m = c.myMethod
  m is c.myMethod
 False  --- What? Why is that?
 
 In my mind I was expecting that when the method is assigned to m all
 that it happens is that its address is assigned to the name m so
 that effectively the same address is now pointed to by two names, like
 in the function case. I googled around for some hint but I wouldn't
 exactly say I'm clear on the issue just yet...
 
 Can anybody shed some light? Or point to a resource to look at? Or
 what's the bit of python's source code that is responsible for dealing
 with those assignments?
 
 Manu
 

So here's a f'rinstance counterexample for you:

class TempAttributeClass(object):
  def __init__(self):
self.temp = True

  def foo(self, x):
return len(x) + 1

  def __getattribute__(self, attr):
attribute = object.__getattribute__(self,attr)
if hasattr(attribute, '__call__'):
  if object.__getattribute__(self, 'temp'):
self.temp = False
return len
  else:
return attribute
else:
  return attribute

The first time a method is accessed from an instance of this class, it
will return len instead.

 print TempAttributeClass.foo
unbound method TempAttributeClass.foo
 c = TempAttributeClass()
 l = [1,2,3]
 x = c.foo
 x(l) 
3
 c.foo
4
 x == c.foo
False
 print x
built-in function len
 print y
bound method TempAttributeClass.foo of __main__.TempAttributeClass
object at 0x7f672b35e290

c.foo is a bound attribute, but what has it been bound to?  Well, I
guess it technically, it's bound to the instance c, but what has it been
bound from?  That depends first on what it encounters when traversing
its base classes, and second on how it's accessing its attributes.  As
the example above shows, python is too dynamic to make any guarantees
about any of that.

Another way you could mess with that is by changing the __class__
attribute on c.

class A(object):
x = 4
def __init__(self):
self.y = 5

class B(object):
x = u'cow'
def __init__(self):
self.y = u'goat'

 c = A()
 c.x
4
 c.y
5
 c.__class__ = B
 # Note that neither c nor x were changed in the last step
... c.x # Class attribute found on B now
u'cow'
 c.y # Instance attribute: already initialized from A.__init__
5
 c.__init__() # Reinitialize c, now using B.__init__
 c.y # Re-initialized instance attribute
u'goat'


Cheers,
Cliff



--
http://mail.python.org/mailman/listinfo/python-list


Re: Another of those is issues.

2009-03-22 Thread Emanuele D'Arrigo
Thank you all for the replies!

Manu
--
http://mail.python.org/mailman/listinfo/python-list


Re: Another of those is issues.

2009-03-21 Thread Bruno Desthuilliers

Emanuele D'Arrigo a écrit :

Hi everybody,

I was unit testing some code today and I eventually stumbled on one of
those is issues quickly solved replacing the is with ==. Still,
I don't quite see the sense of why these two cases are different:


def aFunction():

... pass
...

f = aFunction
f is aFunction

True   --- Ok, this seems reasonable. Nevertheless, I suspect I
shouldn't quite rely on it.


And you're wrong.


class MyClass(object):

... def myMethod(self):
... pass
...

c = MyClass()
m = c.myMethod
m is c.myMethod

False  --- What? Why is that?


c.myMethod resolves to MyClass.__dict['myMethod'].__get__(c), which 
returns a new Method object.



In my mind I was expecting that when the method
is assigned to m all
that it happens is that its address  is assigned to the name m so
that effectively the same address is now pointed to by two names, like
in the function case.


The m = c.myMethod statement effectively binds name m to a Method 
instance. What you don't get is what really is a Method object.


You assume that the def statement behaves differently when used within 
a class statement - which is just not the case. The def statement 
_always_ create a function object. Just try this:


print type(MyClass.__dict__[myMethod])
print type(MyClass.myMethod)
print type(c.myMethod)

What happens here is that the function type implements the descriptor 
protocol in such a way to return a Method object (a callable object 
wrapping the function and instance - IOW, a partial application of 
MyClass.__dict__[myMethod] and 'c') when resolved as a class 
attribute. So each time you evaluate c.myMethod, you get a new Method 
object.



I googled around for some hint but I wouldn't
exactly say I'm clear on the issue just yet...

Can anybody shed some light? Or point to a resource to look at?


I lost track of how many times I explained this on this newsgroup - but 
googling for +method +descriptor +lookup rules should yield some results.



Or
what's the bit of python's source code that is responsible for dealing
with those assignments?


It has nothing to do with assignement - it's about attributes lookup rules.

--
http://mail.python.org/mailman/listinfo/python-list


Re: Another of those is issues.

2009-03-21 Thread Martin v. Löwis
 m is c.myMethod
 False  --- What? Why is that?

I think nobody has said this plainly yet (although Terry
points it out also): You cannot rely that

  foo.bar is foo.bar

for any object foo and any attribute bar. In some cases,
that relation may hold, in other cases, it may not.
It depends on whether foo intercepts access to bar and
returns something different each time.

As others have explained: objects return something new
for every access to a method.

Regards,
Martin
--
http://mail.python.org/mailman/listinfo/python-list


Another of those is issues.

2009-03-20 Thread Emanuele D'Arrigo
Hi everybody,

I was unit testing some code today and I eventually stumbled on one of
those is issues quickly solved replacing the is with ==. Still,
I don't quite see the sense of why these two cases are different:

 def aFunction():
... pass
...
 f = aFunction
 f is aFunction
True   --- Ok, this seems reasonable. Nevertheless, I suspect I
shouldn't quite rely on it.

 class MyClass(object):
... def myMethod(self):
... pass
...
 c = MyClass()
 m = c.myMethod
 m is c.myMethod
False  --- What? Why is that?

In my mind I was expecting that when the method is assigned to m all
that it happens is that its address is assigned to the name m so
that effectively the same address is now pointed to by two names, like
in the function case. I googled around for some hint but I wouldn't
exactly say I'm clear on the issue just yet...

Can anybody shed some light? Or point to a resource to look at? Or
what's the bit of python's source code that is responsible for dealing
with those assignments?

Manu


--
http://mail.python.org/mailman/listinfo/python-list


Re: Another of those is issues.

2009-03-20 Thread Benjamin Peterson
Emanuele D'Arrigo manu3d at gmail.com writes:
 
  class MyClass(object):
 ... def myMethod(self):
 ... pass
 ...
  c = MyClass()
  m = c.myMethod
  m is c.myMethod
 False  --- What? Why is that?
 
 Can anybody shed some light? Or point to a resource to look at? Or
 what's the bit of python's source code that is responsible for dealing
 with those assignments?

Functions are descriptors (they have a __get__ method). Thus, every time a
method is resolved, a new bound method object is created with the object passed
to it. 




--
http://mail.python.org/mailman/listinfo/python-list


Re: Another of those is issues.

2009-03-20 Thread Scott David Daniels

Emanuele D'Arrigo wrote:

Hi everybody, ...

f = aFunction
f is aFunction

True   --- Ok, this seems reasonable. Nevertheless, I suspect I
shouldn't quite rely on it.

Actually, that's fine, you are simply comparing a pair of references


class MyClass(object):

... def myMethod(self):
... pass

c = MyClass()
m = c.myMethod
m is c.myMethod

False  --- What? Why is that?


Method access binds the instance in dynamically.

Comparing m is c.myMethod
is like comparing m is partial(MyClass.method, c)

--Scott David Daniels
scott.dani...@acm.org
--
http://mail.python.org/mailman/listinfo/python-list


Re: Another of those is issues.

2009-03-20 Thread Tim Wintle
On Fri, 2009-03-20 at 11:20 -0700, Emanuele D'Arrigo wrote:
  def aFunction():
 ... pass
 ...
  f = aFunction
  f is aFunction
 True   --- Ok, this seems reasonable. Nevertheless, I suspect I
 shouldn't quite rely on it.

You can rely on this in the above - you've just assigned the name f to
the same object as aFunction

 
  class MyClass(object):
 ... def myMethod(self):
 ... pass
 ...
  c = MyClass()
  m = c.myMethod
  m is c.myMethod
 False  --- What? Why is that?

I believe that c.myMethod is actually a new object that's similar to
lambda self,*args,**kwargs: MyClass.myMethod(self,*args,**kwargs).

ie:

The MyClass *instance* has checked if there is an object
self.__dict__[myMethod], and when it hasn't found it it creates a new
function which wraps the call to the base class up correctly. It's more
complicated than this though because you see the same behaviour when
checking the method on the class definition.

Seem to remember Raymond Hettinger pointing to the code that does this
as part of his descriptor tutorial talk at europython - but I can't
find the slides to reference.

hope that helps,

Tim Wintle

--
http://mail.python.org/mailman/listinfo/python-list


Re: Another of those is issues.

2009-03-20 Thread Steve Holden
Emanuele D'Arrigo wrote:
 Hi everybody,
 
 I was unit testing some code today and I eventually stumbled on one of
 those is issues quickly solved replacing the is with ==. Still,
 I don't quite see the sense of why these two cases are different:
 
 def aFunction():
 ... pass
 ...
 f = aFunction
 f is aFunction

In fact, for any defined unqualified name x the assignment n = x
guarantees that n is x is True.

 True   --- Ok, this seems reasonable. Nevertheless, I suspect I
 shouldn't quite rely on it.
 
You can take that to the bank on any working Python implementation. It's
hardwired into the language's semantics.

 class MyClass(object):
 ... def myMethod(self):
 ... pass
 ...
 c = MyClass()
 m = c.myMethod
 m is c.myMethod
 False  --- What? Why is that?
 
 In my mind I was expecting that when the method is assigned to m all
 that it happens is that its address is assigned to the name m so
 that effectively the same address is now pointed to by two names, like
 in the function case. I googled around for some hint but I wouldn't
 exactly say I'm clear on the issue just yet...
 
 Can anybody shed some light? Or point to a resource to look at? Or
 what's the bit of python's source code that is responsible for dealing
 with those assignments?
 
Instance-relative references to class methods are a very special case.
They become what are called bound methods - the interpreter creates a
new bound method for each reference.

This allows the bound method to provide the instance as a first argument
when it is called.

 class C(object):
...   def MyMethod(self):
... pass
...
 c = C()
 a = c.MyMethod
 b = c.MyMethod
 a, b
(bound method C.MyMethod of __main__.C object at 0x7ff33fcc, bound
method C.MyMethod of __main__.C object at 0x7ff33fcc)


regards
 Steve
-- 
Steve Holden   +1 571 484 6266   +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/
Want to know? Come to PyCon - soon! http://us.pycon.org/

--
http://mail.python.org/mailman/listinfo/python-list


Re: Another of those is issues.

2009-03-20 Thread Terry Reedy

Emanuele D'Arrigo wrote:

Hi everybody,

I was unit testing some code today and I eventually stumbled on one of
those is issues quickly solved replacing the is with ==. Still,
I don't quite see the sense of why these two cases are different:


def aFunction():

... pass
...

f = aFunction
f is aFunction

True   --- Ok, this seems reasonable. Nevertheless, I suspect I
shouldn't quite rely on it.


class MyClass(object):

... def myMethod(self):
... pass
...

c = MyClass()
m = c.myMethod
m is c.myMethod

False  --- What? Why is that?


Compare that to MyClass.myMethod is MyClass.myMethod, which is True at 
least in 3.0.  Repeated attribute accesses may or may not return the 
same object.  Remember that class (and instance) attributes can be 
computed properties, or produced by whatever means in __getattr__.


Also, x.a = b; x.a==b may or may not return True as the setting might be 
intercepted by __setattr__.


tjr

--
http://mail.python.org/mailman/listinfo/python-list


Re: Another of those is issues.

2009-03-20 Thread Christian Heimes
Terry Reedy wrote:

 Compare that to MyClass.myMethod is MyClass.myMethod, which is True at
 least in 3.0.  

It's true because Python 3.0 has no unbound methods. MyClass.myMethod
returns the function object. It's possible to get the same behavior in 2.x:

  MyClass.myMethod.im_func is MyClass.myMethod.im_func

Christian

--
http://mail.python.org/mailman/listinfo/python-list