11

I want to dynamically implement __str__ method on a object if the object doesn't already implement it.

I try using hasattr(obj, '__str__') it always returns me true as it picks it up from object class.

Is there a way to determine if an object actually implements __str__ ?

I know I can use inspect.getmembers(obj) but I am searching for a more pythonic way

EDIT

class Employee(object):
def __init__(self, name, age, emp_code):
    self.name = name
    self.age  = age
    self.emp_code = emp_code

Test

e = Employee("A", 23, "E1")
print hasattr(e, '__str__')
>> True

I want a check that returns False instead of picking up the method inherited from object.

user2357112
  • 260,549
  • 28
  • 431
  • 505
Bhushan
  • 2,256
  • 3
  • 22
  • 28
  • I already tried using hasattr for '__str__' however it always returns true. The other thing is, if I use hasattr for '__eq__' it works fine – Bhushan Oct 28 '13 at 06:40
  • 2
    Is it sufficient to check if `obj.__str__ != object.__str__`? – Gabe Oct 28 '13 at 06:40
  • 1
    Do you want this to work for any inherited `__str__` method? What if the method isn't from `object`, but some other class on the inheritance chain? – reem Oct 28 '13 at 06:41
  • I want to check only for the immediate class not the inherited ones – Bhushan Oct 28 '13 at 06:45
  • 1
    "dynamically implement `__str__`" smells highly suspicious. how/why are you doing this? – Eevee Oct 28 '13 at 06:48
  • 4
    I hope you're aware that you can't monkeypatch special methods onto existing objects; Python won't check the instance's dict for special method lookup. – user2357112 Oct 28 '13 at 06:50
  • Alas, monkey patching `__str__` doesn't work. – Bhushan Oct 28 '13 at 06:57
  • dynamic str would be used in a test case, i don't want the original objects to implement it, but when using test case want to print out some useful logging – Bhushan Oct 28 '13 at 06:58
  • why don't you just implement `__repr__` normally then? that's basically what it's for – Eevee Oct 28 '13 at 07:04
  • `__repr__` is supposed to provide unambiguous representation for the objects, also when one calls str(list) internally __repr__ is called. I don't want to accidentally start print some logs which are not desirable. – Bhushan Oct 28 '13 at 07:13
  • `__repr__` is only supposed to provide whatever's useful to a developer. and you can then just define `__str__` to raise a `TypeError`. – Eevee Oct 28 '13 at 07:17

5 Answers5

17

Since what you want to check is if it has a __str__ implementation that is not the default object.__str__. Therefore, you can do this:

Foo.__str__ is not object.__str__

To check with instantiated objects you need to check on the class:

type(f).__str__ is not object.__str__

This will also work even if Foo doesn't implement __str__ directly, but inherited it from another class than object, which seems to be what you want.

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
  • Good example use case of `is` instead of `==` also. EDIT: The OP wants something that doesn't look for inherited methods at all. – reem Oct 28 '13 at 06:45
  • 2
    need `type(f).__dict__['__str__']` to circumvent inheritance. mmm, dunders. – Eevee Oct 28 '13 at 06:48
  • Oddly, it even works when you do `f = Foo(); f.__str__ = lambda: 'sneaky'` because `str(f)` does not call `f.__str__()` (!). – torek Oct 28 '13 at 06:53
  • Though it still doesn't answer why `hasattr(obj, '__eq__')` works fine and `hasattr(obj, '__str__')` fails – Bhushan Oct 28 '13 at 06:54
  • @torek special methods are only ever checked on the class, yeah. – Eevee Oct 28 '13 at 06:55
  • @Bhushan because `object` implements `__str__` and not `__eq__` :) – Eevee Oct 28 '13 at 06:57
  • Apologies to Lennart, but how can I implement `__str__` dynamically ? When I do setattr(obj, lambda x:"new str") it keeps calling the object class toString() – Bhushan Oct 28 '13 at 07:03
  • 2
    you **cannot** implement special methods on objects. only on their classes. – Eevee Oct 28 '13 at 07:04
  • Ahh got it.. setattr(obj.__class__, '__str__', lambda x: "new String") – Bhushan Oct 28 '13 at 07:04
  • @Bhushan: 1. You don't need setattr. Just set the attribute. 2. Why not just implement the method on the class in the first place? – Lennart Regebro Oct 28 '13 at 07:05
  • @Eevee: Yet `object.__eq__` gets you a thing. It just gets you a 'method-wrapper ...' instead of a 'slot wrapper ...' (in Python2; in Python3 it gets you a slot-wrapper). In fact, in Python3, `hasattr(f, '__eq__')` is always true when `f` is an instance of a class derived from object. See also [Python method-wrapper type?](http://stackoverflow.com/q/10401935/1256452) – torek Oct 28 '13 at 07:06
  • @LennartRegebro I am doing it for a test utility which will print string representation if there isn't already one. Since the code is already in prod, I don't want people to implement str if it is not required for business logic – Bhushan Oct 28 '13 at 07:11
  • 1
    @Bhushan: It would probably be better not to do str() on objects in that case, but make your own method. – Lennart Regebro Oct 28 '13 at 07:12
  • Python 2's `object.__eq__` is not a method on the `object` _class_. it comes from `type`, of which `object` is an instance. Python 3 actually introduced an `__eq__` on the class. i assume this mess is due to the legacy of `__cmp__` and the general wacky default sorting in py2 – Eevee Oct 28 '13 at 07:13
  • @LennartRegebro Ohh yes, I can do it that way. Thanks for correcting – Bhushan Oct 28 '13 at 07:16
1

Any object inheriting from the object base will have a __str__ method, so testing if it exists is negligible.

You could store a flag attribute on the object, and test for that instead:

if not getattr(obj, 'has_str_override_flag'):
    override_str_here(obj)
    setattr(obj, 'has_str_override_flag', True)
invert
  • 2,016
  • 14
  • 20
0

Well in you object there is __dict__ that contains all the methods and variables that the object has. You can check if a given object has __str__() method implemented by

'__str__' in Employee.__dict__

or

'__str__' in vars(Employee)

There is no difference between vars() and __dict__, just vars() is more Pythonic.

P.Panayotov
  • 563
  • 5
  • 8
0

It turns out that built-in types rely on object.__str__ to do their (smart) formatting. I really only wanted to eliminate useless strings like <__main__.Foo object at 0x10299d390> and still have dict and other types printed properly. My solution:

objre = re.compile(r"<.* object at 0x[0-9a-f]+>")
if objre.fullmatch(str(obj)):
    # Do smarter formatting

This won't catch default formatting of modules, functions etc, for which source code could be shown instead via inspect.getsource(), but I am not displaying them in my variable inspector anyway.

Tronic
  • 1,248
  • 12
  • 16
0

Use type(e).__dict__.get(method_name) to avoid KeyError if method_name not exists in class when using type(e).__dict__[method_name]

e = Employee("A", 23, "E1")
if type(e).__dict__.get('__str__'):
    print('__str__ implemented')
else:
    print('__str__ not implemented')
Jonathan L
  • 9,552
  • 4
  • 49
  • 38