Re: Type of an object: ‘obj.__class__’ versus ‘type(obj)’

2013-12-16 Thread Steven D'Aprano
On Tue, 17 Dec 2013 08:14:09 +0100, dieter wrote:

> Steven D'Aprano  writes:
> 
>> On Mon, 16 Dec 2013 12:51:21 +1100, Ben Finney wrote: ... "type(obj)"
>> versus "obj.__class__" That is an excellent question, I only wish I had
>> an excellent answer to give you. Obviously great minds think alike
>> because I was going to ask the same question, prompted by this comment
>> from Nick Coghlan on the python-dev list:
>>
>> "...type(obj).__name__ (working with the concrete type, ignoring any
>> proxying) or obj.__class__.__name__ (which takes proxying into
>> account)..."
>>
>> So there is a difference between them, but I'm not entirely sure what
>> it is.
> 
> I understand the difference: sometimes you work with proxies (e.g.
> "weakref" proxies). A proxie should work mostly like the proxied object
> - but in rare cases, you want to detect that what you have is actually a
> proxie rather than the real object. You can use "type(obj)" to check the
> real type ob "obj" (in some sense, it is more direct - more reliable;
> giving you the real type of "obj"). "obj.__class__" on the other hand
> uses standard attribute access - and proxying may have customized
> attribute access to access the proxied object's attributes rather than
> its own: then "obj.__class__" would give you not the type of "obj" (the
> proxie) but that of the proxied object.


I think I need to see an actual working demonstration, because as far as 
I can see, type(obj) returns obj.__class__.

I'm not suggesting you are wrong, only that code speaks more loudly than 
words :-)


-- 
Steven
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Type of an object: ‘obj.__class__’ versus ‘type(obj)’

2013-12-16 Thread dieter
Steven D'Aprano  writes:

> On Mon, 16 Dec 2013 12:51:21 +1100, Ben Finney wrote:
> ... "type(obj)" versus "obj.__class__"
> That is an excellent question, I only wish I had an excellent answer to 
> give you. Obviously great minds think alike because I was going to ask 
> the same question, prompted by this comment from Nick Coghlan on the 
> python-dev list:
>
> "...type(obj).__name__ (working with the concrete type, ignoring any
> proxying) or obj.__class__.__name__ (which takes proxying into 
> account)..."
>
> So there is a difference between them, but I'm not entirely sure what it 
> is.

I understand the difference: sometimes you work with proxies
(e.g. "weakref" proxies). A proxie should work mostly like the proxied
object - but in rare cases, you want to detect that what you have
is actually a proxie rather than the real object.
You can use "type(obj)" to check the real type ob "obj" (in some
sense, it is more direct - more reliable; giving you the real
type of "obj"). "obj.__class__" on the other hand uses standard
attribute access - and proxying may have customized attribute access
to access the proxied object's attributes rather than its own: then
"obj.__class__" would give you not the type of "obj" (the proxie)
but that of the proxied object.

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


Re: Type of an object: ‘obj.__class__’ versus ‘type(obj)’

2013-12-16 Thread Steven D'Aprano
On Mon, 16 Dec 2013 12:51:21 +1100, Ben Finney wrote:

> Howdy all,
> 
> What is the Pythonic way to determine the type of an object? Are there
> multiple valid ways, and when should each be used?

That is an excellent question, I only wish I had an excellent answer to 
give you. Obviously great minds think alike because I was going to ask 
the same question, prompted by this comment from Nick Coghlan on the 
python-dev list:

"...type(obj).__name__ (working with the concrete type, ignoring any
proxying) or obj.__class__.__name__ (which takes proxying into 
account)..."

So there is a difference between them, but I'm not entirely sure what it 
is.


> We have ‘obj.__class__’, an attribute bound to the object's class. Or is
> it? When is that true, and when should we not rely on it?

I think you can rely on it. I don't believe you can delete the __class__ 
attribute from an instance:

py> class X(object):
... pass
...
py> x = X()
py> x.__class__

py> del x.__class__
Traceback (most recent call last):
  File "", line 1, in 
TypeError: can't delete __class__ attribute


I think it is fair to consider __class__ to be part of the "object API" 
shared by all objects. I suppose it's possible to create a metaclass 
which does not expose a __class__ attribute, but I would consider that 
broken by design.

Furthermore, you can dynamically set the __class__ of an instance in 
order to dynamically change its type and therefore behaviour (although 
there are restrictions on what you can change it to, and from). Using the 
same x instance as above:

py> class Y(object):
... pass
...
py> x.__class__ = Y
py> type(x)



This is by design, and it allows a very useful form of dynamic behaviour:

http://code.activestate.com/recipes/68429-ring-buffer/


 
> We have ‘type(obj)’, calling the constructor for the ‘type’ type in
> order to get a reference to the type of ‘obj’. Or is it? When is that
> true, and when should we not rely on it?

Are there circumstances where type(obj) and obj.__class__ return 
something different? Based on Nick's comment above, I would have to guess 
the answer must be yes, but I don't know what those circumstances are.


Aside: I'm not sure that it is useful to think of type as the constructor 
in the one-argument form. If you recall, prior to Python 2.2 `type` was a 
regular function which took one argument and returned the argument's type:

[steve@ando ~]$ python1.5
Python 1.5.2 (#1, Aug 27 2012, 09:09:18)  [GCC 4.1.2 20080704 (Red Hat 
4.1.2-52)] on linux2
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> type



The types returned were very different from the types we know and love 
since the class/type unification of version 2.2:

>>> type(42)

>>> int

>>> type(42)('2')
Traceback (innermost last):
  File "", line 1, in ?
TypeError: call of non-function (type type)


So while it is *technically* correct that type(...) calls the type 
constructor, the one-argument form type(obj) is intended to behave as a 
function, while the three-argument form type(name, bases, namespace) is 
intended to behave as a constructor of types. But I digress.


> Are there other ways to get at the type of a Python object? What reasons
> are there to choose or avoid them?


I am not aware of any other ways.



-- 
Steven
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Type of an object: ‘obj.__class__’ versus ‘type(obj)’

2013-12-15 Thread Ben Finney
Chris Angelico  writes:

> On Mon, Dec 16, 2013 at 3:50 PM, Ben Finney  
> wrote:
> > Should we expect (ignoring pathological cases) the assertion
> > ‘type(obj) is obj.__class__’ to hold true? If not, under what
> > circumstances would it be sensible for those to differ?
>
> By "pathological cases", do you mean arbitrarily changing
> obj.__class__

By “pathological cases” I mean to acknowledge that, in Python, of course
any attribute or function can be changed merely to thwart some rule
about how those attributes and functions will generally behave — and to
exclude such cases from the question where there is no purpose to the
case other than the thwarting of the general rule.

-- 
 \ “I still have my Christmas Tree. I looked at it today. Sure |
  `\   enough, I couldn't see any forests.” —Steven Wright |
_o__)  |
Ben Finney

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


Re: Type of an object: ‘obj.__class__’ versus ‘type(obj)’

2013-12-15 Thread Devin Jeanpierre
On Sun, Dec 15, 2013 at 8:50 PM, Ben Finney  wrote:
> Should we expect (ignoring pathological cases) the assertion
> ‘type(obj) is obj.__class__’ to hold true? If not, under what
> circumstances would it be sensible for those to differ?

They differ on old-style classes (in 2.x): the type will be either
classobj or instance; and the __class__ doesn't exist (for class
objects) or is what you'd expect (for instances).

This isn't particularly pathological, so I disagree with the
suggestion that one should always definitely use type() for style
reasons.

-- Devin
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Type of an object: ‘obj.__class__’ versus ‘type(obj)’

2013-12-15 Thread Chris Angelico
On Mon, Dec 16, 2013 at 3:50 PM, Ben Finney  wrote:
> Should we expect (ignoring pathological cases) the assertion
> ‘type(obj) is obj.__class__’ to hold true? If not, under what
> circumstances would it be sensible for those to differ?

By "pathological cases", do you mean arbitrarily changing
obj.__class__, or is there some other way for them to differ?

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Type of an object: ‘obj.__class__’ versus ‘type(obj)’

2013-12-15 Thread Ben Finney
Ned Batchelder  writes:

> Generally, my answer would be, "You probably don't need the type as
> much as you think you do."  
> […]
> Also, don't overlook isinstance().

Agreed.

> But when you do need it, type(x) is better than x.__class__, simply
> because we should always favor builtin functions over direct access of
> dunder-names where possible.

Thanks.

Should we expect (ignoring pathological cases) the assertion
‘type(obj) is obj.__class__’ to hold true? If not, under what
circumstances would it be sensible for those to differ?

-- 
 \   “For fast acting relief, try slowing down.” —Jane Wagner, via |
  `\   Lily Tomlin |
_o__)  |
Ben Finney

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


Re: Type of an object: ‘obj.__class__’ versus ‘type(obj)’

2013-12-15 Thread Ned Batchelder

On 12/15/13 8:51 PM, Ben Finney wrote:

Howdy all,

What is the Pythonic way to determine the type of an object? Are there
multiple valid ways, and when should each be used?

We have ‘obj.__class__’, an attribute bound to the object's class. Or is
it? When is that true, and when should we not rely on it?

We have ‘type(obj)’, calling the constructor for the ‘type’ type in
order to get a reference to the type of ‘obj’. Or is it? When is that
true, and when should we not rely on it?

Are there other ways to get at the type of a Python object? What reasons
are there to choose or avoid them?



Generally, my answer would be, "You probably don't need the type as much 
as you think you do."   But when you do need it, type(x) is better than 
x.__class__, simply because we should always favor builtin functions 
over direct access of dunder-names where possible.


Also, don't overlook isinstance().

--
Ned Batchelder, http://nedbatchelder.com

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


Type of an object: ‘obj.__class__’ versus ‘type(obj)’

2013-12-15 Thread Ben Finney
Howdy all,

What is the Pythonic way to determine the type of an object? Are there
multiple valid ways, and when should each be used?

We have ‘obj.__class__’, an attribute bound to the object's class. Or is
it? When is that true, and when should we not rely on it?

We have ‘type(obj)’, calling the constructor for the ‘type’ type in
order to get a reference to the type of ‘obj’. Or is it? When is that
true, and when should we not rely on it?

Are there other ways to get at the type of a Python object? What reasons
are there to choose or avoid them?

-- 
 \ “Pinky, are you pondering what I'm pondering?” “I think so, |
  `\Brain, but Zero Mostel times anything will still give you Zero |
_o__)  Mostel.” —_Pinky and The Brain_ |
Ben Finney

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