I have simple task: we have class TestingClass and we wanna simply test his methods. And we have class TestHelper for testing purpose.
class TestingClass():
def testing_method_1(self):
return False
def testing_method_2(self):
return True
class TestHelper():
def __init__(self, class_name):
pass
def add(self, func_name, func_result):
pass
def run(self):
pass
helper = TestHelper(TestingClass)
helper.add(“testing_method_1”, False)
helper.add(“testing_method_2”, True)
result = helper.run()
my target implement methods for class TestHelper . I solved it for myself but I think its bad realization. I initialize empty dictionary and test class. Next I add every method and test method result to dictionary. In run method I compare results.
class TestHelper():
def __init__(self, class_name):
self.test_class = class_name()
self.func_list = {}
def add(self, func_name, func_result):
temp = 'self.test_class.' + func_name
self.func_list[temp] = func_result
def run(self):
for f in self.func_list.keys():
if eval(f)() == self.func_list[f]:
print('yes')
else:
print('no')
Can I resolve it in best way? Thanks!
Using eval for this purpose is overkill.
You could instead use the getattr() function to retrieve the function and call it.
Read more: Python Docs
class TestHelper():
def __init__(self, class_name):
self.test_class = class_name()
self.func_list = {}
def add(self, func_name, func_result):
# { <function>:<desired result> }
self.func_list[func_name] = func_result
def run(self):
for func, desired_result in self.func_list.items():
if getattr(self.test_class, func)() is desired_result:
print('yes')
else:
print('no')
This code produces results:
...
>>> helper = TestHelper(TestingClass)
>>> helper.add("testing_method_1", False)
>>> helper.add("testing_method_2", True)
>>> result = helper.run()
yes
yes
Of course you should also test if the class even has an attribute with the given function name. You can use hasattr() for this.
Related
target code:
test_box = TestBox(Checkers.begin_with("op") and Checkers.end_with("or"))
test_box.run("operator") # True
test_box.run("option") # False
What I think(may be in the wrong way): TestBox may be a class or a method, and begin_with and end_with are classmethod of class Checkers, but how to make Checkers.begin_with("op") and Checkers.end_with("or") evaluated until test_box.run() was called?
I have found a solution which use lambda, post here:
class TestBox:
def __init__(self, func):
self._func = func
def run(self, string):
Checkers.string = string
return self._func()
class Checkers:
string = None
#classmethod
def begin_with(cls, val):
return cls.string.startswith(val)
#classmethod
def end_with(cls, val):
return cls.string.endswith(val)
if __name__ == '__main__':
test_box = TestBox(lambda: Checkers.begin_with("op") or Checkers.end_with("or"))
print(test_box.run("operator")) # True
print(test_box.run("xxtion")) # False
print(test_box.run("xxtionor")) # True
I need to access the value of an attribute defined at the parent class inside an inner class, here's the code:
class main(object):
def __init__(self):
self.session_id = None
self.devices = self.Devices(self.session_id)
class Devices(object):
def __init__(self, session_id):
self.session_id = session_id
And here's how I would like to use it:
>>> m = main()
>>> m.session_id = 1
>>> m.session_id
1
>>> m.devices.session_id
>>>
My expectation is that m.devices.session_id will always have the exact same value as m.session_id. I understand that at this point when I instantiate the inner class the session_id value is passed down as None because that's how it was initiated but I'm not sure how I can keep both values the same without doing something very ugly like:
m.devices.session_id = m.session_id
outside the class code.
How can I accomplish that inside the class itself ?
The other answer works, but I think this is a better design: lose the nested class, and add a getter on the device object to lookup a backref:
class Main(object):
def __init__(self):
self.session_id = None
self.devices = Devices(main_obj=self)
class Devices(object):
def __init__(self, main_obj):
self.main_obj = main_obj
...
#property
def session_id(self):
return self.main_obj.session_id
The difference here is that you're not storing the same data twice, so they can not get out of sync - there is only one "source of truth" for the session_id (on main object).
In the earlier answer, the data is actually stored in two different namespaces and will get out of sync as easily as m.devices.session_id = 123.
You can do it like this:
class main(object):
def __init__(self):
self._session_id = None
self.devices = self.Devices(self._session_id)
#property
def session_id(self):
return self._session_id
#session_id.setter
def session_id(self, value):
self._session_id = self.devices.session_id = value
class Devices(object):
def __init__(self, session_id):
self.session_id = session_id
I suppose I'm missing something obvious, but I can't get the name of methods when I'm using decorators. When I run this code, I get the error:
AttributeError: 'str' object has no attribute "__name__"
Could somebody tell me how I can get the name of these decorated method?
Thanks
def Print(*arg, **kwarg):
func, *arguments = arg
print(func.__name__ + "(): {}".format(func=arguments[0]))
class Bob(object):
def __init__(self):
pass
#property
def stuff(self):
return "value from stuff property"
#stuff.setter
def stuff(self, noise):
return noise
class Tester:
def __init__(self):
self.dylan = Bob()
def randomTest(self):
Print(self.dylan.stuff, 1)
if __name__ == "__main__":
whatever = Tester()
whatever.randomTest()
stuff isn't a function or a method; it's a property. The syntax
#property
def stuff(...):
...
creates an instance of the property class using stuff as the argument to property, equivalent to
def stuff(...):
....
stuff = property(stuff)
and instances of property don't have a __name__ attribute, as you've seen.
(It's a little trickier with the setter, since the function and the property have to have the same name. But defining stuff a "second" time doesn't override the existing property named stuff.)
The individual methods are accessed via attributes of the property.
>>> Bob.stuff.fget.__name__
'stuff'
>>> Bob.stuff.fset.__name__
'stuff'
Note another, longer, way to create the same property:
class Bob:
def stuff_getter(self):
...
def stuff_setter(self, noise):
...
stuff = property(stuff_getter, stuff_setter)
del stuff_getter, stuff_setter # Clean up the namespace
def Print(*arg, **kwarg):
func, *arguments = arg
print(func.__name__ + "(): {}".format(func=arguments[0]))
class Bob():
def __init__(self, s):
self.stuff = s
#property
def myStuff(self):
return self.stuff
#myStuff.setter
def setStuff(self, noise):
self.stuff = noise
class Tester:
def __init__(self):
self.dylan = Bob(1)
def randomTest(self):
print(self.dylan.stuff)
if __name__ == "__main__":
whatever = Tester()
whatever.randomTest()
This should work :)
I want to do this:
a = TestClass1() <br>
a.test.fun() #==> this i want to call TestClass2 method fun() <br>
a.test(a=10).fun() #===> this i want to call TestClass3 method fun() <br>
Does anyone know how to separate this?
I have three classes:
class TestClass1:
aa = ""
def __init__(self):
self.aa = "ccc"
def __getattr__(self, item):
print("test 1 get attr = ",item)
return TestClass2() or TestClass3() #==> I don't how to seperate test and test(a =10)
def __getitem__(self, item):
print("__getitem__",item)
class TestClass2:
def __call__(self, *args, **kwargs):
print("TestClass2 __call__ ")
return self
def fun(self):
print("this TestClass2 fun()")
class TestClass3:
def __call__(self, *args, **kwargs):
print("TestClass3 33333 call 3 ")
return self
def fun(self):
print("this TestClass3 fun()")
in both examples given __getattr__ is called with argument "test".
you need to do something like this:
class TestClass1:
def __getattr__(self, item):
if item == 'test2':
return TestClass2()
elif item == 'test3':
return TestClass3()
a = TestClass1()
a.test2.fun()
a.test3.fun()
EDIT: Let me explain further. Well, in python there is no difference between a function and an attribute, everything in python is an object, all objects are treated the same, be it an integer or a function.
When you do a.test it is lowered to a.__getattr__('test').
And when you do a.test(a=10) it is lowered to a.__getattr__('test')(a=10).
The returned object from a.__getattr__('test') is the same.
In the second case you are fetching the attribute test then calling it with an argument a=10.
EDIT2: What you are trying to do could be achieved this way:
class TestClass1:
test = TestClass2()
class TestClass2:
def __call__(self, a):
if a == 10:
return TestClass3()
def fun():
print("this TestClass2 fun()")
a = TestClass1()
a.test # this is TestClass2
a.test.fun # this is TestClass2.fun
a.test(a=10) # this is TestClass3
a.test(a=10).fun # this is TestClass3.fun
EDIT3: A simpler approach would be making test a function:
class TestClass1:
def test(a=None):
if a is None:
return TestClass2()
if a == 10:
return TestClass3()
a = TestClass1()
a.test().fun # TestClass2.fun
a.test(a=10).fun # TestClass3.fun
I've got a class which contains a number of lists where whenever something is added to one of the lists, I need to trigger a change to the instance's state. I've created a simple demonstration class below to try to demonstrate what I'm trying to do.
Suppose I have a class like this:
class MyClass:
added = False
def _decorator(self, f):
def func(item):
added = true
return f(item)
return func
def __init__(self):
self.list = [1, 2, 3]
self.list.append = self._decorator(self.list.append)
Since a list is built in, I cannot change it's .append method
cls = MyClass() #gives me an AttributeError since '.append' is readonly
Ideally, I could do the following:
cls = MyClass()
cls.list.append(4)
cls.added #would be true
How should I go about this? Would subclassing list allow me to change it's behavior in this way? If so, how would I pass in the class's state without changing the methods signature?
Thanks!
You cannot monkey-patch builtins, so subclassing is the only way (and actually better and cleaner IMHO). I'd go for something like this:
class CustomList(list):
def __init__(self, parent_instance, *args, **kwargs):
super(CustomList, self).__init__(*args, **kwargs)
self.parent_instance = parent_instance
def append(self, item):
self.parent_instance.added = True
super(CustomList, self).append(item)
class MyClass(object):
added = False
def __init__(self):
self.list = CustomList(self, [1,2,3])
c = MyClass()
print c.added # False
c.list.append(4)
print c.added # True
Would this suit your needs?
class MyClass(object):
added = False
def __init__(self):
self.list = [1,2,3]
def append(self, obj):
self.added = True
self.list.append(obj)
cls = MyClass()
cls.append(4)
cls.added #true
It might be helpful to know what exactly you're trying to achieve.