multiple functions in Python - python

We have some variable, or other instance: a='?'.
We have such input:
f = a(3112).bas(443).ssad(34)
When we type
print(f)
Output should be:
3112a-443bas-34ssad
I've tried some ways to solve this and have found information about chaining, but I still have the problem. I can't return class name to the brginning of the string.
This, what I have:
class A():
def __getattribute__(self, item):
print (str(item))
return super(A, self).__getattribute__(item)
def __init__(self, x):
self.x = x
print (str(x))
def b(self, item):
print (str(item))
return self
def c(self, item):
print (str(item))
return self
def d(self, item):
print (str(item))
return self
A(100).b(200).c(300).d(400)
My output:
100
b
200
c
300
d
400
But I couldn't concatenate it in one string.

Dynamic way
class A(object):
def __init__(self, integer):
self._strings = ['{}a'.format(integer)]
def __getattr__(self, attrname, *args):
def wrapper(*args, **kwargs):
self._strings.append('{}{}'.format(args[0], attrname))
return self
return wrapper
def __str__(self):
return '-'.join(self._strings)
print(A(100).bas(200).ssad(300))
Output
100a-200bas-300ssad
But also
print(A(100).egg(200).bacon(300).SPAM(1000))
Output
100a-200egg-300bacon-1000SPAM
Static way
class A(object):
def __init__(self, integer):
self._strings = ['{}a'.format(integer)]
def bas(self, integer):
self._strings.append('{}bas'.format(integer))
return self
def ssad(self, integer):
self._strings.append('{}ssad'.format(integer))
return self
def __str__(self):
return '-'.join(self._strings)
print(A(100).b(200).c(300))
Output
100a-200bas-300ssad
More about __str__

You can override the __str__ method to define your specific output:
class A():
def __init__(self, a, b="", c="", d=""):
self._a = a
self._b = b
self._c = c
self._d = d
def __str__(self):
return '{}a-{}b-{}c-{}d'.format( self.a, self.b, self.c, self.d )
def b(self, item):
self._b = item
return self
def c(self, item):
self._c = item
return self
def d(self, item):
self._d = item
return self
f = A(100).b(200).c(300).d(400)
print(f) # 100a-200b-300c-400d

Here I tried it in another way , ie, If you want to take the function name instead of manually giving it you can use inspect in python. Try this code :
import inspect
class A():
l = []
def __init__(self, x):
self.x = x
print (str(x))
self.l.append(str(x) + "a")
def b(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
def c(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
def d(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
print("-".join(A(100).b(200).c(300).d(400).l))
The o/p is like :
'100a-200b-300c-400d'

Related

Function decorator that will return self?

I have to following class that will make an object with chainable methods that derive from class variables. Since this code is quite repetitive, my challenge is to make a decorator that can apply over method a, b and c. The problem I am facing is that I cannot seem to find a way to construct a wrapper that will return the instance (self). Is there a better way to construct this?
class Test:
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
self.call_chain = []
def a(self, truth):
def func():
return self._a == truth
self.call_chain.append(func)
return self
def b(self, truth):
def func():
return self._b == truth
self.call_chain.append(func)
return self
def c(self, val):
def func():
return self._c == val
self.call_chain.append(func)
return self
def evaluate(self):
try:
for f in self.call_chain:
if f() == False:
raise ValueError('False encountered')
except ValueError:
self.call_chain.clear()
return False
self.call_chain.clear()
return True
It works chained like this:
c = Test(True, False, 13)
c.a(True).b(False).c(13).evaluate()
The trick is to store the arguments to the function as part of the call chain. The easiest way is to use functools.partial objects.
from functools import wraps, partial
def chain(func):
#wraps(func)
def wrapper(self, *args, **kwargs):
suspended = partial(func, self, *args, **kwargs)
self.call_chain.append(suspended)
return self
return wrapper
class Test:
def __init__(self, a, b, c):
self.call_chain = []
self._a = a
self._b = b
self._c = c
#chain
def a(self, val):
return self._a == val
#chain
def b(self, val):
return self._b == val
#chain
def c(self, val):
return self._c == val
def evaluate(self):
try:
for f in self.call_chain:
if f() == False:
raise ValueError('False encountered')
except ValueError:
self.call_chain.clear()
return False
self.call_chain.clear()
return True
c = Test(True, False, 13)
c.a(True).b(False).c(13).evaluate() # True
c.a(True).b(False).c(11).evaluate() # False

Chaining instance methods in python

I would like create a class in python with method and sub-method.
Example what I want to do :
foo = Foo()
foo.playlist('my playlist').add('i_add_a_track_in_"my playlist".ogg')
foo.playlist('my playlist').delete('i_remove_this_track.ogg')
I have this code for now :
class Foo(object):
def playlist(self, name):
pass #my function...
def add(self, track):
pass #adding track
def delete(self, track):
pass #delete track
Please help me, I don't know how i can do it.
Thank you
IIUC, you want to chain method calls one after another? All you'd have to do is return self at the end of each function.
class Foo(object):
...
def playlist(self, name):
...
return self
... # and so on
MVCE:
In [229]: class Foo:
...: def __init__(self, data):
...: self.data = data
...:
...: def add(self, val):
...: self.data += val
...: return self
...:
...: def sub(self, val):
...: self.data -= val
...: return self
...:
In [231]: x = Foo(0)
In [232]: x = x.add(10).sub(5) # or just x.add(10).sub(5)
In [233]: x.data
Out[233]: 5
If I understand correctly, foo.playlist('someplaylist').do_something() should actually be a shortcut for
playlist = foo('someplaylist')
playlist.do_something()
where playlist is NOT a foo object (ie: foo.do_something() is not supposed to make any sense and should just raise an error) but an instance of a distinct class.
If that's indeed the case, you actually want two classes: Foo with method playlist(...) that returns a Playlist object, and Playlist with add() and delete() methods:
class Playlist(object):
def __init__(self, name):
self.name = name
def add(self, what):
print("adding {} to playlist {}".format(what, self.name))
def delete(self, what):
print("deleting {} from playlist {}".format(what, self.name))
class Foo(object):
def playlist(self, name):
return Playlist(name)

Automatically create (and keep) an object when accessed

I would like to do something like this:
class A:
def hello(): print "Hello"
# I do not want to explicitly setup a:
a = A()
# a = A() -> I want this to happen automatically when I access a
# My first try is this:
def a():
return A()
# Also, I do not want to call a as a function a(): it must be an object
# And it must stay alive and initialized
a.hello() # a is created, as object of class A
a.hello() # I do not want a second instantiation
How can I implement this? properties? cached-properties? They are only for classes: a is a module-level object.
Maybe something like this:
class A(object):
def hello(self):
print "Hello"
class LazyA(object):
def __init__(self):
self.instance = None
def __getattr__(self, k):
if self.instance is None:
self.instance = A()
return getattr(self.instance, k)
a = LazyA()
def lazyinit(cls):
class p(object):
def __init__(self, *args, **kws):
self._init = lambda: cls(*args, **kws)
self._obj = None
def __getattr__(self, k):
if not self._obj:
self._obj = self._init()
return getattr(self._obj, k)
return p
Example:
#lazyinit
class A(object):
def __init__(self, a, b):
print("initializing...")
self.x = a + b + 2
def foo(self):
return self.x
x = A(39, 1)
print x
print x.foo()
print x.foo()
Generalization of the answer by Pavel:
class LazyClass(object):
def __init__(self, myclass, *args, **kwargs):
self.instance = None
self.myclass = myclass
self.args = args
self.kwargs = kwargs
def __getattr__(self, k):
if self.instance is None:
self.instance = self.myclass(*self.args, **self.kwargs)
return getattr(self.instance, k)
class A(object):
def __init__ (self, name):
self.name = name
print "Created"
def hello(self):
print "Hello " + self.name
import unittest
class TestLazyClass(unittest.TestCase):
def setUp(self):
self.a = LazyClass(A, 'Daniel')
def test_it(self):
self.a.hello()
self.a.hello()

Decorate a class in Python by defining the decorator as a class

What is a simple example of decorating a class by defining the decorator as a class?
I'm trying to achieve what has been implemented in Python 2.6 using PEP 3129 except using classes not functions as Bruce Eckel explains here.
The following works:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
def wrappedClass(*args):
return cls(*args)
return type("TestClass", (cls,), dict(newMethod=self.newMethod, classattr=self.arg))
def newMethod(self, value):
return value * 2
#Decorator("decorated class")
class TestClass(object):
def __init__(self):
self.name = "TestClass"
print "init %s"%self.name
def TestMethodInTestClass(self):
print "test method in test class"
def newMethod(self, value):
return value * 3
Except, in the above, wrappedClass is not a class, but a function manipulated to return a class type. I would like to write the same callable as follows:
def __call__(self, cls):
class wrappedClass(cls):
def __init__(self):
... some code here ...
return wrappedClass
How would this be done?
I'm not entirely sure what goes into """... some code here ..."""
If you want to overwrite new_method(), just do it:
class Decorator(object):
def __init__(self, arg):
self.arg = arg
def __call__(self, cls):
class Wrapped(cls):
classattr = self.arg
def new_method(self, value):
return value * 2
return Wrapped
#Decorator("decorated class")
class TestClass(object):
def new_method(self, value):
return value * 3
If you don't want to alter __init__(), you don't need to overwrite it.
After this, the class NormalClass becomes a ClassWrapper instance:
def decorator(decor_arg):
class ClassWrapper:
def __init__(self, cls):
self.other_class = cls
def __call__(self,*cls_ars):
other = self.other_class(*cls_ars)
other.field += decor_arg
return other
return ClassWrapper
#decorator(" is now decorated.")
class NormalClass:
def __init__(self, name):
self.field = name
def __repr__(self):
return str(self.field)
Test:
if __name__ == "__main__":
A = NormalClass('A');
B = NormalClass('B');
print A
print B
print NormalClass.__class__
Output:
A is now decorated. <br>
B is now decorated. <br>
\__main__.classWrapper

How to intercept instance method calls?

I am looking for a way to intercept instance method calls in class MyWrapper below:
class SomeClass1:
def a1(self):
self.internal_z()
return "a1"
def a2(self):
return "a2"
def internal_z(self):
return "z"
class SomeClass2(SomeClass1):
pass
class MyWrapper(SomeClass2):
# def INTERCEPT_ALL_FUNCTION_CALLS():
# result = Call_Original_Function()
# self.str += result
# return result
def __init__(self):
self.str = ''
def getFinalResult(self):
return self.str
x = MyWrapper()
x.a1()
x.a2()
I want to intercept all function calls make through my wrapper class. In my wrapper class I want to keep track of all the result strings.
result = x.getFinalResult()
print result == 'a1a2'
Some quick and dirty code:
class Wrapper:
def __init__(self, obj):
self.obj = obj
self.callable_results = []
def __getattr__(self, attr):
print("Getting {0}.{1}".format(type(self.obj).__name__, attr))
ret = getattr(self.obj, attr)
if hasattr(ret, "__call__"):
return self.FunctionWrapper(self, ret)
return ret
class FunctionWrapper:
def __init__(self, parent, callable):
self.parent = parent
self.callable = callable
def __call__(self, *args, **kwargs):
print("Calling {0}.{1}".format(
type(self.parent.obj).__name__, self.callable.__name__))
ret = self.callable(*args, **kwargs)
self.parent.callable_results.append(ret)
return ret
class A:
def __init__(self, val): self.val = val
def getval(self): return self.val
w = Wrapper(A(10))
print(w.val)
w.getval()
print(w.callable_results)
Might not be thorough, but could be a decent starting point, I guess.
You could wrap your methods with decorators a instanciation time:
#!/usr/bin/env python
import inspect
def log(func):
def _logged(*args, **kw):
print "[LD] func", func.__name__, "called with:", args, kw
result = func(*args, **kw)
print "[LD] func", func.__name__, "returned:", result
return result
return _logged
class A(object):
def __init__(self):
for x in inspect.getmembers(self, (inspect.ismethod)):
if not x[0].startswith('__'):
setattr(self, x[0], log(getattr(self, x[0])))
def hello(self):
print "Hello"
def bye(self):
print "Bye"
return 0
Now if you call hello or bye, the call goes through log first:
a = A()
a.hello()
a.bye()
# [LD] func hello called with: () {}
# Hello
# [LD] func hello returned: None
# [LD] func bye called with: () {}
# Bye
# [LD] func bye returned: 0
What you want to do is quite similar to this question.
You should take your example code in the reverse order, i mean creating a class to record return values of method calls, and make the classes you want to watch inherit from it.
Which would give something like this
class RetValWatcher(object):
def __init__(self):
self.retvals = []
def __getattribute__(self, name):
attr = super(RetValWatcher, self).__getattribute__(name)
if callable(attr):
def wrapped(*args, **kwargs):
retval = attr(*args, **kwargs)
self.retvals.append(retval)
return retval
return wrapped
else:
return attr
def getFinalResult(self):
return ''.join(self.retvals)
class MyClass(RetValWatcher):
def a(self):
self.internal_z()
return 'a1'
def b(self):
return 'b1'
def internal_z(self):
return 'z'
x = MyClass()
x.a()
x.b()
print x.getFinalResult()
#'za1b1'
With some minor changes, this method would also allow you to record return values across all RetValWatcher instances.
Edit: added changes suggested by singularity's comment
Edit2: forgot to handle the case where attr is not a method (thx singularity again)
Edit3: fixed typo

Categories