Python __str__: Magic Console - python

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

Related

Python: Check if a method uses #staticmethod [duplicate]

assume following class definition:
class A:
def f(self):
return 'this is f'
#staticmethod
def g():
return 'this is g'
a = A()
So f is a normal method and g is a static method.
Now, how can I check if the funcion objects a.f and a.g are static or not? Is there a "isstatic" funcion in Python?
I have to know this because I have lists containing many different function (method) objects, and to call them I have to know if they are expecting "self" as a parameter or not.
Lets experiment a bit:
>>> import types
>>> class A:
... def f(self):
... return 'this is f'
... #staticmethod
... def g():
... return 'this is g'
...
>>> a = A()
>>> a.f
<bound method A.f of <__main__.A instance at 0x800f21320>>
>>> a.g
<function g at 0x800eb28c0>
>>> isinstance(a.g, types.FunctionType)
True
>>> isinstance(a.f, types.FunctionType)
False
So it looks like you can use types.FunctionType to distinguish static methods.
Your approach seems a bit flawed to me, but you can check class attributes:
(in Python 2.7):
>>> type(A.f)
<type 'instancemethod'>
>>> type(A.g)
<type 'function'>
or instance attributes in Python 3.x
>>> a = A()
>>> type(a.f)
<type 'method'>
>>> type(a.g)
<type 'function'>
To supplement the answers here, in Python 3 the best way is like so:
import inspect
class Test:
#staticmethod
def test(): pass
isstatic = isinstance(inspect.getattr_static(Test, "test"), staticmethod)
We use getattr_static rather than getattr, since getattr will retrieve the bound method or function, not the staticmethod class object. You can do a similar check for classmethod types and property's (e.g. attributes defined using the #property decorator)
Note that even though it is a staticmethod, don't assume it was defined inside the class. The method source may have originated from another class. To get the true source, you can look at the underlying function's qualified name and module. For example:
class A:
#staticmethod:
def test(): pass
class B: pass
B.test = inspect.getattr_static(A, "test")
print("true source: ", B.test.__qualname__)
Technically, any method can be used as "static" methods, so long as they are called on the class itself, so just keep that in mind. For example, this will work perfectly fine:
class Test:
def test():
print("works!")
Test.test()
That example will not work with instances of Test, since the method will be bound to the instance and called as Test.test(self) instead.
Instance and class methods can be used as static methods as well in some cases, so long as the first arg is handled properly.
class Test:
def test(self):
print("works!")
Test.test(None)
Perhaps another rare case is a staticmethod that is also bound to a class or instance. For example:
class Test:
#classmethod
def test(cls): pass
Test.static_test = staticmethod(Test.test)
Though technically it is a staticmethod, it is really behaving like a classmethod. So in your introspection, you may consider checking the __self__ (recursively on __func__) to see if the method is bound to a class or instance.
I happens to have a module to solve this. And it's Python2/3 compatible solution. And it allows to test with method inherit from parent class.
Plus, this module can also test:
regular attribute
property style method
regular method
staticmethod
classmethod
For example:
class Base(object):
attribute = "attribute"
#property
def property_method(self):
return "property_method"
def regular_method(self):
return "regular_method"
#staticmethod
def static_method():
return "static_method"
#classmethod
def class_method(cls):
return "class_method"
class MyClass(Base):
pass
Here's the solution for staticmethod only. But I recommend to use the module posted here.
import inspect
def is_static_method(klass, attr, value=None):
"""Test if a value of a class is static method.
example::
class MyClass(object):
#staticmethod
def method():
...
:param klass: the class
:param attr: attribute name
:param value: attribute value
"""
if value is None:
value = getattr(klass, attr)
assert getattr(klass, attr) == value
for cls in inspect.getmro(klass):
if inspect.isroutine(value):
if attr in cls.__dict__:
bound_value = cls.__dict__[attr]
if isinstance(bound_value, staticmethod):
return True
return False
Why bother? You can just call g like you call f:
a = A()
a.f()
a.g()

How do I change the representation of a Python function?

>>> def hehe():
... return "spam"
...
>>> repr(hehe)
'<function hehe at 0x7fe5624e29b0>'
I want to have:
>>> repr(hehe)
'hehe function created by awesome programmer'
How do I do that? Putting __repr__ inside hehe function does not work.
EDIT:
In case you guys are wondering why I want to do this:
>>> defaultdict(hehe)
defaultdict(<function hehe at 0x7f0e0e252280>, {})
I just don't like the way it shows here.
No, you cannot change the representation of a function object; if you wanted to add documentation, you'd add a docstring:
def foo():
"""Frob the bar baz"""
and access that with help(foo) or print foo.__doc__.
You can create a callable object with a custom __repr__, which acts just like a function:
class MyCallable(object):
def __call__(self):
return "spam"
def __repr__(self):
return 'hehe function created by awesome programmer'
Demo:
>>> class MyCallable(object):
... def __call__(self):
... return "spam"
... def __repr__(self):
... return 'hehe function created by awesome programmer'
...
>>> hehe = MyCallable()
>>> hehe
hehe function created by awesome programmer
>>> hehe()
'spam'
Usually, when you want to change something about the function, say function signature, function behavior or function attributes, you should consider using a decorator. So here is how you might implement what you want:
class change_repr(object):
def __init__(self, functor):
self.functor = functor
# lets copy some key attributes from the original function
self.__name__ = functor.__name__
self.__doc__ = functor.__doc__
def __call__(self, *args, **kwargs):
return self.functor(*args, **kwargs)
def __repr__(self):
return '<function %s created by ...>' % self.functor.__name__
#change_repr
def f():
return 'spam'
print f() # spam
print repr(f) # <function hehe created by ...>
Note, that you can only use class based decorator, since you need to override __repr__ method, which you can't do with a function object.
Not directly the answer to your question, but perhaps you really want a docstring?
>>> def hehe():
... '''hehe function created by awesome programmer'''
... return 'spam'
...
>>> help(hehe)
Help on function hehe in module __main__:
hehe()
hehe function created by awesome programmer
Here's a slightly more flexible version of what's in Alexander Zhukov's answer:
def representation(repr_text):
class Decorator(object):
def __init__(self, functor):
self.functor = functor
def __call__(self, *args, **kwargs):
return self.functor(*args, **kwargs)
def __repr__(self):
return (repr_text % self.functor.__name__ if '%' in repr_text
else repr_text)
return Decorator
from collections import defaultdict
#representation('<function %s created by awesome programmer>')
def f():
return list
dd = defaultdict(f)
print repr(dd)
Output:
defaultdict(<function f created by awesome programmer>, {})
Sincerepresentation()returns a decorator, if you wanted the same boilerplate on several functions you could do something like this:
myrepr = representation('<function %s created by awesome programmer>')
#myrepr
def f():
...
#myrepr
def g():
...
etc

Python properties and string formatting

I was under the impression python string formatting using .format() would correctly use properties, instead I get the default behaviour of an object being string-formatted:
>>> def get(): return "Blah"
>>> a = property(get)
>>> "{a}!".format(a=a)
'<property object at 0x221df18>!'
Is this the intended behaviour, and if so what's a good way to implement a special behaviour for properties (eg, the above test would return "Blah!" instead)?
property objects are descriptors. As such, they don't have any special abilities unless accessed through a class.
something like:
class Foo(object):
#property
def blah(self):
return "Cheddar Cheese!"
a = Foo()
print('{a.blah}'.format(a=a))
should work. (You'll see Cheddar Cheese! printed)
Yes, this is basically the same as if you just did:
>>> def get(): return "Blah"
>>> a = property(get)
>>> print a
If you want "Blah" just call the function:
>>> def get(): return "Blah"
>>> a = property(get)
>>> "{a}!".format(a=a.fget())
Python properties do interop well with .format(). Consider the following example:
>>> class Example(object):
... def __init__(self):
... self._x = 'Blah'
... def getx(self): return self._x
... def setx(self, value): self._x = value
... def delx(self): del self._x
... x = property(getx,setx,delx, "I'm the 'x' property.")
...
>>>
>>> ex = Example()
>>> ex.x
'Blah'
>>> print(ex.x)
'Blah'
>>> "{x.x}!".format(x=ex)
'Blah!'
I believe your problem stems from your property not being part of a class. How are you actually using properties that they aren't working with .format()?

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

Categories