I want to call a nested function directly, like this:
Template('/path/to/file').expect('key').to_be_in('second_key')
Template('/path/to/file').expect('key').to_be('value')
I tried this:
class Template(object):
def __init__(self, path):
self.content = json.load(open(path, 'r'))
def expect(self, a):
def to_be_in(b):
b = self.content[b]
return a in b
def to_be(b):
a = self.content[b]
return a == b
But I get the following error:
Template('~/template.json').expect('template_name').to_be_in('domains')
AttributeError: 'NoneType' object has no attribute 'to_be_in'
How to achieve that in Python ?
You have to return an object which provides a to_be_in member that is a function, to wit (example only):
class Template_Expect(object):
def __init__(self, template, a):
self.template = template
self.a = a
def to_be_in(self, b):
b = self.template.content[b]
return self.a in b
def to_be(self, b):
a = self.template.content[b]
return a == b
class Template(object):
def __init__(self, path):
self.content = json.load(open(path, 'r'))
def expect(self, a):
return Template_Expect(self, a)
Related
I have a Common (or could call Base) class.
from enum import Enum
class Common:
def a(self, condition):
if condition == True:
return self.Keys.F.value
else:
return self.Keys.G.value
def b(self):
return Common.a(self, True) * 10
and multiple other classes, all of them use the Common class.
class KlassOne:
class Keys(Enum):
E = 0
F = 1
G = 2
def func(self, attribute):
w = Common.a(self, condition=bool(attribute))
x = Common.b(self)
return w, x
class KlassTwo:
class Keys(Enum):
E = 0
G = 1
F = 2
def func(self, attribute):
y = Common.a(self, condition=bool(attribute))
z = Common.b(self)
return y, z
how do I avoid the Common.a(self, ...) way of implementing this.
Is there an alternative to it?
You can instantiate your class :
class KlassOne:
def func(self, attribute):
common = Common()
w = common.a(condition=bool(attribute))
x = common.b()
return w, x
Your recent update to the question means that Common looks more like a mixin. (I would refactor b like this)
class Common:
def a(self, condition):
if condition == True:
return self.Keys.F.value
else:
return self.Keys.G.value
def b(self):
return self.a(True) * 10
The above Common does not need to import from enum.
Now your other classes can inherit from the above, just as a mixin:
from enum import Enum
class KlassOne(Common):
class Keys(Enum):
E = 0
F = 1
G = 2
def func(self, attribute):
w = self.a(condition=bool(attribute))
x = self.b()
return w, x
First, the Common.a(... is not necessary inside Common:
class Common:
def a(self, condition):
if condition == True:
return 1
else:
return 2
def b(self):
return self.a(True) * 10
Second, if you want to pass self of KlassOne to a method of class Common, then KlassOne actually should be an instance of class Common:
class KlassOne:
def func(self, attribute):
w = Common.a(self, condition=bool(attribute)) # <- here self is instance of KlassOne
x = Common.b(self)
return w, x
This is an argument strongly in favour of inheritance:
class KlassOne(Common):
def func(self, attribute):
w = self.a(condition=bool(attribute))
x = self.b()
return w, x
If you want to use composition, you would need to instantiate Common, e.g. like
class KlassOne:
def __init__(self):
self.common = Common()
def func(self, attribute):
w = self.common.a(condition=bool(attribute))
x = self.common.b()
return w, x
How do I implement the Subclass B for the function getdata() to return the details in the constructor? I could achieve that if the constructor in B takes a single object, but having difficulty if the objects were two or more and passed as a list.
This example shows what I intended. Code lacks the full implementation.
class A(object):
def __init__(self, a):
self.a = a
def geta(self):
return str(self.a)
class B(A):
def __init__(self, b,c, [objA1, objA2]):
self.b = b
self.c = c
super().__init__()
# ...
def geta(self):
return str(self.a)
def getb(self):
return str(self.b)
def getdata(self):
return str(self.geta()) + str(self.getb()) + ...
obja1 = A('John')
obja2 = A('Doe')
obj = B('123', '456', [obja1, obja2])
# Test1 obj.getdata() == "John Doe 123 456"
You could do like this and pass as normal arguments and then convert into list
class B(A):
def __init__(self,b,objA1,objA2):
self.b = b
self.list = [objA1, objA2]
super().__init__()
obj = B("hello", "JOHN","DOE")
like this works aswell, basicaly u say that objs will be a list
class B(A):
def __init__(self,b, objs: list):
self.b = b
self.list = objs
super().__init__()
obj = B("hello", ["JOHN","DOE"])
So you don't need inheritance here. Composition will be enough.
This code produces output according to your requirements:
class A:
def __init__(self, a):
self.a = a
def __repr__(self):
return str(self.a)
class B:
def __init__(self, b, c, others):
self.b = b
self.c = c
self.others = others
def getdata(self):
items = self.others + [self.b, self.c]
return ' '.join([str(item) for item in items])
obja1 = A('John')
obja2 = A('Doe')
obj = B('123', '456', [obja1, obja2])
print(obj.getdata())
Output:
John Doe 123 456
I'm trying to create a class A which is basically a list of objects B.
I would like to be able to call a method in A which automatically
returns a list of the corresponding method in B:
A.method(x) = [B.method(x) for B in A]
The issue is that I need a dynamical behavior, so any method in B is
automatically "inherited" by A without having to hard code it.
I have tried using lambda functions and exec("""def ..."""),
but nothing seems to work. Here is an attempt:
class A(object):
def __init__(self,Bs):
self.listOfBs = Bs[:]
if self.listOfBs:
for method_name in dir(self.listOfBs[0]):
if not callable(getattr(self.listOfBs[0],method_name)):
continue
f = lambda x: [getattr(B,method_name)(x) for B in self.listOfBs]
setattr(self,method_name,f)
class B(object):
def __init__(self,name):
self.name = name
def getName(self,x):
return self.name+x
#So if I define:
a = A([B('x'),B('y'),B('z')])
#I would like to have: a.getName('W') = ['xW','yW','zW']
#However I get the error: TypeError: 'str' object is not callable
I think there should be an easy/elegant way of implementing the above behavior in python, but I couldn't find anything that works.
You may use __getattr__ to make method lookup dynamic
class A:
def __init__(self, bs):
self.bs = bs
def __getattr__(self, method_name):
def call(*args, **kw):
return [getattr(b, method_name)(*args, **kw) for b in bs]
return call
Thanks a lot. I had tried getattr before, but was missing some steps.
Just for the record, following Glazner's suggestion here is a working solution, which works both with attributes and methods:
class A(object):
def __init__(self,Bs):
self.listOfBs = Bs[:]
def __getattr__(self, attr):
if not all(hasattr(b,attr) for b in self.listOfBs):
raise AttributeError("Attribute %s not found." %attr)
val = getattr(self.listOfBs[0],attr)
if not callable(val):
return np.array([getattr(b,attr) for b in self.listOfBs])
def call(*args, **kw):
return [getattr(b, attr)(*args, **kw) for b in self.listOfBs]
return call
class B(object):
def __init__(self,name):
self.name = name
def getName(self,x):
return self.name+x
a = A([B('x'),B('y'),B('z')])
a.name #Returns ['x','y','z']
a.getName('W') #Returns ['xW','yW','zW']
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'
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()