class A(object):
def fun(self):
pass
ins_a = A.fun
ins_b = A().fun
I came across this piece of code and I am unable to understand the difference between the 2 objects.
Just try the above code in the interactive interpreter:
>>> class A(object):
... def fun(self):
... pass
...
>>> ins_a = A.fun
>>> ins_b = A().fun
>>> ins_a
<unbound method A.fun>
>>> ins_b
<bound method A.fun of <__main__.A object at 0x7f694866a6d0>>
As you can see, it is a matter of bound/unbound methods. A bound method is a method "tied" to an object. You can have a more thorough explanation in this SO answer.
The biggest difference is if you try to call the methods:
If we add a print "hello world", it will make it more obvious.
class A(object):
def fun(self):
print ("hello world")
ins_a = A.fun
ins_b = A().fun
Now try calling both:
In [10]: ins_a()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-52906495cc43> in <module>()
----> 1 ins_a()
TypeError: unbound method fun() must be called with A instance as first argument (got nothing instead)
In [11]: ins_b()
hello world
In python 3 they are different types as the unbound method type is gone:
In [2]: type(ins_a)
Out[2]: builtins.function
In [3]: type(ins_b)
Out[3]: builtins.method
Related
Let's say a function looks at an object and checks if it has a function a_method:
def func(obj):
if hasattr(obj, 'a_method'):
...
else:
...
I have an object whose class defines a_method, but I want to hide it from hasattr. I don't want to change the implementation of func to achieve this hiding, so what hack can I do to solve this problem?
If the method is defined on the class you appear to be able to remove it from the __dict__ for the class. This prevents lookups (hasattr will return false). You can still use the function if you keep a reference to it when you remove it (like the example) - just remember that you have to pass in an instance of the class for self, it's not being called with the implied self.
>>> class A:
... def meth(self):
... print "In method."
...
>>>
>>> a = A()
>>> a.meth
<bound method A.meth of <__main__.A instance at 0x0218AB48>>
>>> fn = A.__dict__.pop('meth')
>>> hasattr(a, 'meth')
False
>>> a.meth
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'meth'
>>> fn()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: meth() takes exactly 1 argument (0 given)
>>> fn(a)
In method.
You could redefine the hasattr function. Below is an example.
saved_hasattr = hasattr
def hasattr(obj, method):
if method == 'MY_METHOD':
return False
else:
return saved_hasattr(obj, method)
Note that you probably want to implement more detailed checks than just checking the method name. For example checking the object type might be beneficial.
Try this:
class Test(object):
def __hideme(self):
print 'hidden'
t = Test()
print hasattr(t,"__hideme") #prints False....
I believe this works b/c of the double underscore magic of hiding members (owning to name mangling) of a class to outside world...Unless someone has a strong argument against this, I'd think this is way better than popping stuff off from __dict__? Thoughts?
Consider the following case:
class Meta(type):
def shadowed(cls):
print "Meta.shadowed()"
def unshadowed(cls):
print "Meta.unshadowed()"
class Foo(object):
__metaclass__ = Meta
def shadowed(self):
print "Foo.shadowed()"
I can call get the bound method unshadowed on Foo and it works fine:
>>> Foo.unshadowed
<bound method Meta.unshadowed of <class '__main__.Foo'>>
>>> Foo.unshadowed()
Meta.unshadowed()
However, I can't seem to get the bound method shadowed on Foo - it directs me rather to the unbound method which must be called with instances of Foo:
>>> Foo.shadowed
<unbound method Foo.shadowed>
>>> Foo.shadowed()
Traceback (most recent call last):
File "<pyshell#45>", line 1, in <module>
Foo.shadowed()
TypeError: unbound method shadowed() must be called with Foo instance as first argument (got nothing instead)
Is there any way to get <bound method Meta.shadowed of <class '__main__.Foo'>>?
It seems one potential answer (maybe not the best) is found in this answer on how to bind unbound methods. So we can do this:
>>> Meta.shadowed.__get__(Foo, Meta)()
Meta.shadowed()
Better demonstration:
class Meta(type):
def shadowed(cls):
print "Meta.shadowed() on %s" % (cls.__name__,)
def unshadowed(cls):
print "Meta.unshadowed() on %s" % (cls.__name__,)
class Foo(object):
__metaclass__ = Meta
def shadowed(self):
print "Foo.shadowed()"
class Bar(object):
__metaclass__ = Meta
Bar.unshadowed() #Meta.unshadowed() on Bar
Bar.shadowed() #Meta.shadowed() on Bar
Foo.unshadowed() #Meta.unshadowed() on Foo
#Foo.shadowed() #TypeError
Meta.shadowed.__get__(Foo, Meta)() #Meta.shadowed() on Foo
Here is an example I just played through on my machine:
$ python
Python 2.7.4 (default, Apr 19 2013, 18:28:01)
[GCC 4.7.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
# just a test class
>>> class A(object):
... def hi(self):
... print("hi")
...
>>> a = A()
>>> a.hi()
hi
>>> def hello(self):
... print("hello")
...
>>>
>>> hello(None)
hello
>>>
>>>
>>>
>>> a.hi = hello
# now I would expect for hi to work the same way as before
# and it just prints hello instead of hi.
>>> a.hi()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: hello() takes exactly 1 argument (0 given)
>>>
>>> def hello():
... print("hello")
...
# but instead this one works, which doesn't contain any
# reference to self
>>> a.hi = hello
>>> a.hi()
hello
>>>
>>>
>>>
>>>
>>> a.hello = hello
>>> a.hello()
hello
What is happening here? Why doesn't the function get the parameter self, when it is used as a method? What would I need to do, to get a reference to self inside it?
A method in a class referenced via an instance is bound to that instance, in your case:
In [3]: a.hi
Out[3]: <bound method A.hi of <__main__.A object at 0x218ab10>>
Compare to:
In [4]: A.hi
Out[4]: <unbound method A.hi>
So, to achieve the effect you probably want, do
In [5]: def hello(self):
...: print "hello"
...:
In [6]: A.hi = hello
In [7]: a.hi()
hello
Beware - this will apply to all instances of A. But if you want to override a method on one instance only, do you really need to pass self?
It is the way functions are accessed when they are class attributes.
A function added as a class attribute gets accessed as a descriptor. You see that if you do
class A(object):
pass
def f(*a): pass
A.f = f
print f
print A.f
print A().f
Here, you get the output
<function f at 0x00F03D70>
<unbound method A.f>
<bound method A.f of <__main__.A object at 0x00F089D0>>
The same output you'd get with
print f
print f.__get__(None, A)
print f.__get__(A(), A)
because that's the way how descriptors work.
All this - the transformation from a function to a method via the descriptor protocol - does not happen on instance attributes.
If you do
a = A()
a.f = f
then a.f is as well read back as a function, not as a method. Thus, you should consider this at the time you do the assignment and rather do
a.f = lambda: f(a)
in order to pass a to the function.
I'm new to python and trying to get a list of the classes an object's class inherits from. I'm trying to do this using the bases attribute but I'm not having any success. Can someone please help me out?
def foo(C):
print(list(C.__bases__))
class Thing(object):
def f(self):
print("Yo")
class Shape(Thing):
def l(self):
print("ain't no thang")
class Circle(Shape):
def n(self):
print("ain't no shape")
test = Circle()
foo(test)
Only classes have __bases__; class instances do not. You can get the class object through an instance's __class__: use foo(test.__class__) or foo(Circle).
Use inspect, from documentation
Return a tuple of class cls’s base classes, including cls, in method
resolution order. No class appears more than once in this tuple. Note
that the method resolution order depends on cls’s type. Unless a very
peculiar user-defined metatype is in use, cls will be the first
element of the tuple.
>>> import inspect
>>> inspect.getmro(test.__class__)
(<class '__main__.Circle'>, <class '__main__.Shape'>, <class '__main__.Thing'>, <type 'object'>)
>>>
This traverses up the inheritance hierarchy & prints all classes, including object. Pretty Cool eh ?
print '\n'.join(base.__name__ for base in test.__class__.__bases__)
Or, using the inspect module:
from inspect import getmro
print '\n'.join(base.__name__ for base in getmro(test))
Your implementation of foo works. But you need to pass a class to foo, not an instance.
In [1]: def foo(C):
...: print(list(C.__bases__))
...:
In [2]: class Thing(object):
...: def f(self):
...: print("Yo")
...:
In [3]: class Shape(Thing):
...: def l(self):
...: print("ain't no thang")
...:
In [4]: class Circle(Shape):
...: def n(self):
...: print("ain't no shape")
...:
In [5]: test = Circle()
In [6]: foo(test)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-6-7b85deb1beaa> in <module>()
----> 1 foo(test)
<ipython-input-1-acd1789d43a9> in foo(C)
1 def foo(C):
----> 2 print(list(C.__bases__))
3
AttributeError: 'Circle' object has no attribute '__bases__'
In [7]: foo(Thing)
[<type 'object'>]
In [8]: foo(Circle)
[<class '__main__.Shape'>]
In [9]: foo(Shape)
[<class '__main__.Thing'>]
If I make a simple class like this:
class Foo:
i = 1
j = 2
Can I instantiate a new object by simply using Foo on the right-hand side ( as opposed to saying Foo() )? I would guess not, but I just tried the following and it worked:
finst = Foo
print finst.i
It works, because i is not a property of the object (or instance) but of the class. You are not creating a new instance.
Try:
class Foo:
def bar(self):
print 42
finst = Foo
finst.bar()
Traceback (most recent call last):
File "", line 1, in
TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)
You did not instantiate an object. You just defined a variable in class scope, and accessed it.
Foo by itself is the class object for class Foo:
>>> type(Foo)
<type 'classobj'>
>>> type(Foo())
<type 'instance'>
Your code:
finst = Foo
print finst.i
decodes as:
bind the name finst to the Foo class object.
print the value of the class' attribute i
That's because finst is merely an alias for the class Foo, and i and j are class variables, not instance variables. If you had declared them as instance variables:
class Foo:
def __init__(self):
self.i = 1
self.j = 2
Then your code would cause an error.
To answer your question, no, you must call a constructor to create an instance.