Is there a way to identify an inherited method in Python? - python

I want to tell inherited methods apart from overloaded or newly defined methods. Is that possible with Python?
Example:
class A(object):
def spam(self):
print 'A spam'
def ham(self):
print 'A ham'
class B(A):
def spam(self):
print 'Overloaded spam'
def eggs(self):
print 'Newly defined eggs'
Desired functionality:
>>> magicmethod(B.spam)
'overloaded'
>>> magicmethod(B.ham)
'inherited'
>>> magicmethod(B.eggs)
'newly defined'
Is there a "magic method" like in the example, or some way to tell those types of method implementations apart?

I'm not sure it's a good idea, but you can probably do it by using hasattr and __dict__.
def magicmethod(clazz, method):
if method not in clazz.__dict__: # Not defined in clazz : inherited
return 'inherited'
elif hasattr(super(clazz), method): # Present in parent : overloaded
return 'overloaded'
else: # Not present in parent : newly defined
return 'newly defined'

If you know the ancestor, you can simply test:
>>> B.spam == A.spam
False
>>> B.ham == A.ham
True
And to find list of all base classes, look here: List all base classes in a hierarchy of given class?
I shall also point that if you need this, your class design is probably wrong. You should not care about such things in OOP (unless you're creating an object inspector or something like that).

A general way will be (python 2.*):
def _getclass(method):
try:
return method.im_class
except AttributeError:
return method.__class__
def magicmethod(method):
method_cls = _getclass(method)
if method.__name__ not in method_cls.__dict__:
return 'inherited'
for cls in method_cls.__mro__[1:]:
if method.__name__ in cls.__dict__:
return 'overloaded'
return 'newly defined'
__test__ = {"example": """
>>> class A(object):
... def spam(self):
... print 'A spam'
... def ham(self):
... print 'A ham'
>>> class B(A):
... def spam(self):
... print 'Overloaded spam'
... def eggs(self):
... print 'Newly defined eggs'
>>> magicmethod(B.spam)
'overloaded'
>>> magicmethod(B.ham)
'inherited'
>>> magicmethod(B.eggs)
'newly defined'
>>> magicmethod(B.__init__)
'inherited'
"""}

For new-style classes, you have a method mro(), returning the method resulution order list. [0] is the class itself.
So you could do
>>> any(hasattr(i, 'ham') for i in B.mro()[1:])
True
>>> any(hasattr(i, 'spam') for i in B.mro()[1:])
True
>>> any(hasattr(i, 'eggs') for i in B.mro()[1:])
False
So eggs is newly defined.
>>> any(getattr(B, 'ham') == getattr(i, 'ham', None) for i in B.mro()[1:])
True
>>> any(getattr(B, 'spam') == getattr(i, 'spam', None) for i in B.mro()[1:])
False
So ham is inherited.
With these, you can craft your own heuristics.

Expanding on hamstergene's answer; a class stores its base classes in the class variable __bases__.
So:
>>> B.spam == B.__bases__[0].spam
False
>>> B.ham == B.__bases__[0].ham
True
>>> B.eggs == B.__bases__[0].eggs
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'A' has no attribute 'eggs'
>>> hasattr(B,"eggs")
True
>>> hasattr(B.__bases__[0],"eggs")
False

Related

How do we get an optional class attribute in Python?

For dictionary we can use .get method. What about a class's attribute and provide a default value?
You can use hasattr and getattr.
For example:
hasattr(foo, 'bar')
would return True if foo has an attribute named bar, otherwise False and
getattr(foo, 'bar', 'quux')
would return foo.bar if it exists, otherwise defaults to quux.
It's dead simple: use a keyword argument.
>>> class Foo(object):
... def __init__(self, my_foo=None):
... self.my_foo = my_foo
...
>>> f = Foo()
>>> f.my_foo
>>> repr(f.my_foo)
'None'
>>> f2 = Foo(2)
>>> f2.my_foo
2
If you are looking for an object which does not have an attribute until you set it, Jason's idea is pretty good unless you directly refer to the attribute. You'll have to work around the AttributeError you'll get. Personally, I'm not a fan of creating objects which must be constantly surrounded by try/except blocks just for the sake of not setting an instance attribute.
Python isn't much for getters and setters. However, you can use property() to work around this problem:
>>> class Foo(object):
... def __init__(self):
... pass
... def get_my_foo(self):
... return getattr(self, "_my_foo", "there's no my_foo")
... def set_my_foo(self, foo):
... self._my_foo = foo
... my_foo = property(get_my_foo, set_my_foo)
...
>>> f = Foo()
>>> f.my_foo
"there's no my_foo"
>>> f.my_foo = "foo!"
>>> f.my_foo
'foo!'
It works just as well to call get_my_foo and set_my_foo, if you like. An added benefit is that you can omit the setter to make a read-only attribute, provided someone using your object doesn't change the underlying _my_foo.

Ways to set per instance __call__?

What I want to do is something like:
class Foo(object):
def __init__(self):
pass
def f(self):
print "f"
def g(self):
print "g"
# programatically set the "default" operation
fer=Foo()
fer.__call__=fer.f
# a different instance does something else as its
# default operation
ger=Foo()
ger.__call__=ger.g
fer() # invoke different functions on different
ger() # objects depending on how they were set up.
But as of 2.7 (which I'm currently using) I can't do this, the attempts at fer()
raise an exception.
Is there a way to, in effect, set a per instance __call__ method?
The normal stuff with types.MethodType unfortunately doesn't work here since __call__ is a special method.
From the data model:
Class instances are callable only when the class has a __call__() method; x(arguments) is a shorthand for x.__call__(arguments).
This is slightly ambiguous as to what is actually called, but it's clear that your class needs to have a __call__ method.
You'll need to create some sort of hack:
class Foo(object):
def __init__(self):
pass
def f(self):
print "f"
def g(self):
print "g"
def __call__(self):
return self.__call__()
f = Foo()
f.__call__ = f.f
f()
g = Foo()
g.__call__ = g.g
g()
Careful with this though, it'll result in an infinite recursion if you don't set a __call__ on an instance before you try to call it.
Note that I don't actually recommend calling the magic attribute that you rebind __call__. The point here is to demonstrate that python translates: f() into f.__class__.__call__(f) and so there's nothing you can do to change it on a per-instance basis. the class's __call__ will be called no matter what you do -- You just need to do something to change the behavior of the class's __call__ per-instance which is easily achieved.
You could use a setter type thing to actually create methods on your class (rather than simple functions) -- and of course that could be turned into a property:
import types
class Foo(object):
def __init__(self):
pass
def f(self):
print "f"
def g(self):
print "g"
def set_func(self,f):
self.func = types.MethodType(f,self)
def __call__(self,*args,**kwargs):
self.func(*args,**kwargs)
f = Foo()
f.set_func(Foo.f)
f()
def another_func(self,*args):
print args
f.set_func(another_func)
f(1,2,3,"bar")
You might be trying to solve the wrong problem.
Since python allows procedural creation of classes you could write code like that:
>>> def create_class(cb):
... class Foo(object):
... __call__ = cb
... return Foo
...
>>> Foo1 = create_class(lambda self: 42)
>>> foo1 = Foo1()
>>> foo1()
>>> Foo2 = create_class(lambda self: self.__class__.__name__)
>>> foo2 = Foo2()
>>> foo2()
Please note thought that Foo1 and Foo2 do not have a common base class in this case. So isinstance and issubclass will not work. If you need them to have a common base class I would go for the following code:
>>> class Foo(object):
... #classmethod
... def create_subclass(cls, cb):
... class SubFoo(cls):
... __call__ = cb
... return SubFoo
...
>>> Foo1 = Foo.create_subclass(lambda self: 42)
>>> foo1 = Foo1()
>>> foo1()
>>> Foo2 = Foo.create_subclass(lambda self: self.__class__.__name__)
>>> foo1 = Foo2()
>>> foo2()
'Foo'
>>> issubclass(Foo1, Foo)
True
>>> issubclass(Foo2, Foo)
True
I really like the second way as it provides a clean class hierarchy and looks quite clean to me.
Possible solution:
class Foo(object):
def __init__(self):
self._callable = lambda s: None
def f(self):
print "f"
def set_callable(self, func):
self._callable = func
def g(self):
print "g"
def __call__(self):
return self._callable()
d = Foo()
d.set_callable(d.g)

How to check if a function exist (but not inherited) in python?

Kind of related to this question:
https://stackoverflow.com/questions/8708525/how-to-check-if-mako-function-exist
I want to check if a function exists for a given class, but not inherited, so that the parent can called the child's function, since otherwise it would result in an infinite recursion..
edit:
it actually gives a maximum stack level error, which is the same.
the equivalent code would be:
class A(object):
def f(x):
b = B()
b.f()
class B(A):
pass
a = A()
a.f()
i understand this is not clean or preferred, but it is what the template translates to, and I dunno how to check for it otherwise.
I want to check if a function exists for a given class, but not inherited
Yes, you can check the class dictionary directly. Either use the __dict__ attribute or the built-in vars() function::
>>> class A(object):
def f(x):
pass
>>> class B(A):
def g(x):
pass
>>> 'f' in vars(B)
False
>>> 'g' in vars(B)
True
If what you need is to check whether the method is defined directly in instance's class and not in one of its ancestors then you can try this:
import inspect
def has_method(obj, name):
v = vars(obj.__class__)
# check if name is defined in obj's class and that name is a method
return name in v and inspect.isroutine(v[name])
class A:
def foo(self):
print 'foo'
class B(A):
pass
b = B()
a = A()
print has_method(a, 'foo') # => True
print has_method(b, 'foo') # => False

Python __str__: Magic Console

Suppose one decided (yes, this is horrible) to create handle input in the following manner: A user types in a command on the python console after importing your class, the command is actually a class name, the class name's __str__ function is actually a function with side effects (e.g. the command is "north" and the function changes some global variables and then returns text describing your current location). Obviously this is a stupid thing to do, but how would you do it (if possible)?
Note that the basic question is how to define the __str__ method for a class without creating an instance of the class, otherwise it would be simple (but still just as crazy:
class ff:
def __str__(self):
#do fun side effects
return "fun text string"
ginst = ff()
>>ginst
What you are looking for is the metaclass
class Magic(type):
def __str__(self):
return 'Something crazy'
def __repr__(self):
return 'Another craziness'
class Foo(object):
__metaclass__ = Magic
>>> print Foo
Something crazy
>>> Foo
Another craziness
in console you're getting representation of your object, which __repr__ is responsible for. __str__ used for printing:
>>> class A:
def __str__(self):
return 'spam'
>>> A()
<__main__.A object at 0x0107E3D0>
>>> print(A())
spam
>>> class B:
def __repr__(self):
return 'ham'
>>> B()
ham
>>> print(B())
ham
>>> class C:
def __str__(self):
return 'spam'
def __repr__(self):
return 'ham'
>>> C()
ham
>>> print(C())
spam
You could use instances of a class rather than classes themselves. Something like
class MagicConsole(object):
def __init__(self, f):
self.__f = f
def __repr__(self):
return self.__f()
north = MagicConsole(some_function_for_north)
south = MagicConsole(some_function_for_south)
# etc

Getting the class name of an instance

How do I find out the name of the class used to create an instance of an object in Python?
I'm not sure if I should use the inspect module or parse the __class__ attribute.
Have you tried the __name__ attribute of the class? ie type(x).__name__ will give you the name of the class, which I think is what you want.
>>> import itertools
>>> x = itertools.count(0)
>>> type(x).__name__
'count'
If you're still using Python 2, note that the above method works with new-style classes only (in Python 3+ all classes are "new-style" classes). Your code might use some old-style classes. The following works for both:
x.__class__.__name__
Do you want the name of the class as a string?
instance.__class__.__name__
type() ?
>>> class A:
... def whoami(self):
... print(type(self).__name__)
...
>>>
>>> class B(A):
... pass
...
>>>
>>>
>>> o = B()
>>> o.whoami()
'B'
>>>
class A:
pass
a = A()
str(a.__class__)
The sample code above (when input in the interactive interpreter) will produce '__main__.A' as opposed to 'A' which is produced if the __name__ attribute is invoked. By simply passing the result of A.__class__ to the str constructor the parsing is handled for you. However, you could also use the following code if you want something more explicit.
"{0}.{1}".format(a.__class__.__module__,a.__class__.__name__)
This behavior can be preferable if you have classes with the same name defined in separate modules.
The sample code provided above was tested in Python 2.7.5.
In Python 2,
type(instance).__name__ != instance.__class__.__name__
# if class A is defined like
class A():
...
type(instance) == instance.__class__
# if class A is defined like
class A(object):
...
Example:
>>> class aclass(object):
... pass
...
>>> a = aclass()
>>> type(a)
<class '__main__.aclass'>
>>> a.__class__
<class '__main__.aclass'>
>>>
>>> type(a).__name__
'aclass'
>>>
>>> a.__class__.__name__
'aclass'
>>>
>>> class bclass():
... pass
...
>>> b = bclass()
>>>
>>> type(b)
<type 'instance'>
>>> b.__class__
<class __main__.bclass at 0xb765047c>
>>> type(b).__name__
'instance'
>>>
>>> b.__class__.__name__
'bclass'
>>>
Alternatively you can use the classmethod decorator:
class A:
#classmethod
def get_classname(cls):
return cls.__name__
def use_classname(self):
return self.get_classname()
Usage:
>>> A.get_classname()
'A'
>>> a = A()
>>> a.get_classname()
'A'
>>> a.use_classname()
'A'
Good question.
Here's a simple example based on GHZ's which might help someone:
>>> class person(object):
def init(self,name):
self.name=name
def info(self)
print "My name is {0}, I am a {1}".format(self.name,self.__class__.__name__)
>>> bob = person(name='Robert')
>>> bob.info()
My name is Robert, I am a person
Apart from grabbing the special __name__ attribute, you might find yourself in need of the qualified name for a given class/function. This is done by grabbing the types __qualname__.
In most cases, these will be exactly the same, but, when dealing with nested classes/methods these differ in the output you get. For example:
class Spam:
def meth(self):
pass
class Bar:
pass
>>> s = Spam()
>>> type(s).__name__
'Spam'
>>> type(s).__qualname__
'Spam'
>>> type(s).Bar.__name__ # type not needed here
'Bar'
>>> type(s).Bar.__qualname__ # type not needed here
'Spam.Bar'
>>> type(s).meth.__name__
'meth'
>>> type(s).meth.__qualname__
'Spam.meth'
Since introspection is what you're after, this is always you might want to consider.
You can simply use __qualname__ which stands for qualified name of a function or class
Example:
>>> class C:
... class D:
... def meth(self):
... pass
...
>>> C.__qualname__
'C'
>>> C.D.__qualname__
'C.D'
>>> C.D.meth.__qualname__
'C.D.meth'
documentation link qualname
To get instance classname:
type(instance).__name__
or
instance.__class__.__name__
both are the same
You can first use type and then str to extract class name from it.
class foo:pass;
bar:foo=foo();
print(str(type(bar))[8:-2][len(str(type(bar).__module__))+1:]);
Result
foo
If you're looking to solve this for a list (or iterable collection) of objects, here's how I would solve:
from operator import attrgetter
# Will use a few data types to show a point
my_list = [1, "2", 3.0, [4], object(), type, None]
# I specifically want to create a generator
my_class_names = list(map(attrgetter("__name__"), map(type, my_list))))
# Result:
['int', 'str', 'float', 'list', 'object', 'type', 'NoneType']
# Alternatively, use a lambda
my_class_names = list(map(lambda x: type(x).__name__, my_list))

Categories