Let's say I have a module named foo with a class Bar. Bar has a classwide counter attribute that allows me to track the order which instances were created. foo looks like this:
from itertools import count
class Bar:
class_count = count(0)
def __init__(self):
self.id = self.class_count.next()
Now I have a test file where I am testing the various functionalities of Bar. I am unsure of how to test this id attribute, because the other unittests are creating instances of Bar and so I don't know what the given id of a Bar instance should be. Furthermore, this behavior of my class means that my unittests are independent of each other, which is undesirable. How should I structure my unittests so the tests are independent of each other?
You could use setUp to safe the current count and then temporarily reset the count. Then with tearDown you restore the original state again:
from itertools import count
import unittest
class Bar:
class_count = count(0)
def __init__(self):
self.id = next(self.class_count)
class TestBar(unittest.TestCase):
def setUp(self):
self.nxtcount = next(Bar.class_count) # safe current state
Bar.class_count = count(0) # reset to 0
def tearDown(self):
Bar.class_count = count(self.nxtcount) # reset to old state
def teststh1(self):
x = Bar()
self.assertEqual(x.id, 0)
def teststh2(self):
x1 = Bar()
x2 = Bar()
x3 = Bar()
self.assertEqual(x1.id, 0)
self.assertEqual(x2.id, 1)
self.assertEqual(x3.id, 2)
This makes sure every test method will start with a Bar.class_count of 0.
I would stub out Bar to bypass the constructor.
class BarStub(Bar):
def __init__(self):
self.class_count = None
self.id = None
Now you can test like this:
class TestBar(...):
def setUp(...)
...
self.bar = BarStub()
def test_foo_should_blah_when_blah(self):
with mock.patch.object(self.bar, 'count_class', side_effect=[...]) as mock_count:
actual = self.bar.unit_under_test(...)
mock_count.assert_called_with([...])
Related
I have a question which is more regarding OOP in general rather than python specific.
Is ist possible to store instances of ClassA in instance of ClassB without a specific method, i.e. by some kind of inheritance.
Example: let's say I have one Model class and one Variable class
class Model():
def __init__(self):
self.vars = []
def _update_vars(self,Variable):
self.vars.append(Variable)
class Variable(Model):
def __init__(self,**kwargs):
self.__dict__.update(kwargs)
Is it now possible to call _update_vars whenever an instance of variable is being created.
So if I do something like this:
mdl = Model()
varA = Variable(...)
varB = Variable(...)
that mdl.vars would now include varA and varB.
I know that I could easily do this by passing the variables as an argument to a "public" method of Model. So I am not looking for
mdl.update_vars(varA)
So my two questions are:
is this possible?
if yes: would this very non-standard OOP programming?
Thanks for your help!
That's not how class inheritance is supposed to work. You only want to inherit something if the child class is going to make use of a good amount of the attributes/methods within the parent class. If the child class has a markedly different structure it should be a class of its own.
In either case, as mentioned by #jasonharper, at some point you would need to give direction as to which Variable instance belongs in which Model instance, so you're likely to end up with something like these:
varA = Variable(mdl, ...)
# or this
mdl.varA = Variable(...)
With the first way, you would maintain the method on your Variable class:
class Foo:
def __init__(self):
self.vars = []
class Bar:
def __init__(self, foo_instance, **kwargs):
foo_instance.vars.append(self)
f = Foo()
b = Bar(f, hello='hey')
f.vars
# [<__main__.Bar object at 0x03F6B4B0>]
With the second way, you can append the Variable instances into a list each time it's added:
class Foo:
def __init__(self):
self.vars = []
def __setattr__(self, name, val):
self.__dict__.update({name: val})
if not name == 'vars': # to prevent a recursive loop
self.vars.append(val)
f = Foo()
f.vars
# []
f.a = 'bar'
f.vars
# ['bar']
Of course, an easier way would be to just look directly into the __dict__ each time you want vars:
class Bar:
#property
def vars(self):
# Or you can return .items() if you want both the name and the value
return list(self.__dict__.values())
b = Bar()
b.a = 'hello'
b.vars
# ['hello']
Both of these will work the same even if you assigned the attributes with your own class instances.
You can use super() for this and pass the instance to the parent
class Model():
vars = []
def __init__(self, other=None):
if other:
self.vars.append(other)
class Variable(Model):
def __init__(self, a):
self.a = a
super().__init__(self)
mdl = Model()
varA = Variable(3)
varB = Variable(4)
print(mdl.vars)
I have created two class objects that retrieve information from a database and store them in pandas in order for me to use the data science libraries. They both return values that I display in a Django template. I want to create a third value that is just the calculated difference of the first two and also display that in the Django template.
First class object:
class IntDailyNumbers (object):
def __init__(self, begin_date, end_date, store=None):
self.begin_date = begin_date
self.end_date = end_date
self.store = store
self.int_daily_numbers = pd.DataFrame(list(gapayment.objects.values('Trans_Store', 'Fee_Pd', 'Trans_date')))
self.int_daily_numbers['Fee_Pd'] = pd.to_numeric(self.int_daily_numbers['Fee_Pd'])
self.int_daily_numbers['Trans_date'] = pd.to_datetime(self.int_daily_numbers['Trans_date'])
self.sum_int_daily_numbers = np.sum(self.int_daily_numbers[(self.int_daily_numbers['Trans_date'] >=self.begin_date) &
(self.int_daily_numbers['Trans_date'] <= self.end_date) &
(self.int_daily_numbers['Trans_Store'] == self.store.store_number)])
def get_sum_int_daily_numbers(self):
sum_intdailynumbers = self.sum_int_daily_numbers['Fee_Pd']
sum_intdailynumbers = round(sum_intdailynumbers.astype(float), 3)
return sum_intdailynumbers
def __str__(self):
return self.get_sum_int_daily_numbers()
Second Class Object:
class IntDailyGoals (object):
def __init__(self, begin_date, end_date, store=None):
self.begin_date = begin_date
self.end_date = end_date
self.store = store
#print(self.begin_date, self.end_date, self.store.store_number)
self.int_mnth_goal = pd.DataFrame(list(StoreGoalsInput.objects.values('store_number',
'interest',
'date')))
self.int_mnth_goal['interest'] = pd.to_numeric(self.int_mnth_goal['interest'])
self.int_mnth_goal['date'] = pd.to_datetime(self.int_mnth_goal['date'])
self.mnth_goal_int =self.int_mnth_goal[(self.int_mnth_goal['date'] >= self.begin_date) &
(self.int_mnth_goal['date'] <= self.end_date) &
(self.int_mnth_goal['store_number'] == self.store.store_number)]
self.mnth_goal_int= self.mnth_goal_int['interest']
self.tot_workingdays = np.busday_count(np.datetime64(self.begin_date),
np.datetime64(self.end_date),
weekmask='Mon Tue Wed Thu Fri Sat')
self.div_intmnthgoal_workingdays = round(np.divide(self.mnth_goal_int, self.tot_workingdays),2)
def get_div_goalsint_wdays(self):
div_goalsint_wdays = self.div_intmnthgoal_workingdays.tolist()[0]
return div_goalsint_wdays
def __str__(self):
return self.get_div_goalsint_wdays()
I believe I need to make a third class for the difference calculation but I cannot figure out how to pass the returns of the first two.
How I understand your question, it has nothing to do with django, but with passing objects from one class to another. Here are two simple solutions, given by class C and class D.
First lets define a minimal example of your two classes. Both have a method, that does something and returns something.
class A:
def foo(self):
print('foo')
return 'foo'
class B:
def bar(self):
print('bar')
return 'bar'
Solution 1: We create a third class, that has an instance of type A and an instance of type B as member variable.
# Contains a class instance of A and B and baz() accesses their methods.
class C:
def __init__(self, a, b):
self.a = a
self.b = b
def baz(self):
self.a.foo()
self.b.bar()
You can use this class with:
# main
a = A()
b = B()
c = C(a,b)
c.baz()
Solution 2: We simply pass the two return values to the function qux(). This function can also be part of a class, if you want it to be.
class D:
def qux(self, res_a, res_b):
print(res_a, res_b)
Here we can use qux() in the following way
# main
a = A()
b = B()
d = D()
d.qux(a.foo(),b.bar())
Since there was some confusion about inheritance. You can also inherit the methods. Don't confuse this with Solution 1. And I don't advise to use inheritance here. The idea of inheritance is, that a child class object is-a parent-class object, like a square is-a rectangle. And that is not what you want.
class E(A,B):
def foobar(self):
self.foo()
self.bar()
Usage from main:
e = E()
e.foobar()
I am looking for a way to apply a function to all instances of a class. An example:
class my_class:
def __init__(self, number):
self.my_value = number
self.double = number * 2
#staticmethod
def crunch_all():
# pseudocode starts here
for instances in my_class:
instance.new_value = instance.my_value + 1
So the command my_class.crunch_all() should add a new attribute new_value to all existing instances. I am guessing I will have to use #staticmethod to make it a "global" function.
I know I could keep track of the instances that are being defined by adding something like my_class.instances.append(number) in __init__ and then loop through my_class.instances, but I had no luck so far with that either. Also I am wondering if something more generic exists. Is this even possible?
Register objects with the class at initialisation (i.e. __init__) and define a class method (i.e. #classmethod) for the class:
class Foo(object):
objs = [] # registrar
def __init__(self, num):
# register the new object with the class
Foo.objs.append(self)
self.my_value = num
#classmethod
def crunch_all(cls):
for obj in cls.objs:
obj.new_value = obj.my_value + 1
example:
>>> a, b = Foo(5), Foo(7)
>>> Foo.crunch_all()
>>> a.new_value
6
>>> b.new_value
8
I did a complex class and now I have to track it and register it in a bigger class for management.
The problem, is that the complex class may create a new instance of itself. Therefore, I have to detect this new creation in my manager.
The other problem is that there is not only one manager. They're used like a session manager. Each has a initial complex object in it. If the complex object instantiates a new instance of itself, only the good manager must be warned.
Here is an example of code to present my problem:
class Foo:
def create_another(self):
# Do something
return Foo()
class Manager:
def __init__(self):
init_object = SomeDecorator(Foo()) # I guess there will be a decorator
self.objects = [init_objects]
m1 = Manager()
assert len(m1.objects) == 1
m1.objects[0].create_another()
assert len(m1.objects) == 2
m2 = Manager()
assert len(m1.objects) == 2
assert len(m2.objects) == 1
m1.objects[0].create_another()
assert len(m1.objects) == 3
assert len(m2.objects) == 1
m2.objects[0].create_another()
assert len(m1.objects) == 3
assert len(m2.objects) == 2
Just sketching out an idea (incomplete / untested):
provide the manager as parameter: Foo.__init__(self, manager) and store it as attribute
You'll have to call init_object = Foo(self) in Manager.__init__()
then, you can use the info about the manager in your create_another() method to
instantiate the new instance correctly
modify the Manager.objects-list (I would recommend a method instead of modifying it direclty)
If your Foo objects can only be tracked by one manager at a time, this can simply be accomplished by notifying it when calling create_another.
Example code:
class Foo:
def __init__(self, manager=None):
self.manager = manager
def create_another(self):
# do something
foo = Foo(self.manager)
if self.manager is not None:
self.manager.notify_object_created(foo)
return foo
class Manager:
def __init__(self):
init_object = SomeDecorator(Foo(self))
self.objects = [init_object]
def notify_object_created(self, foo):
self.objects.append(foo)
Edited after reading the comments:
If you don't want to change the Foo class, the other solution is to dynamically decorate Foo's constructor, by tracking it, adding the above feature to it.
Example code:
class Foo:
def create_another(self):
# do something
return Foo()
class Manager:
def __init__(self):
self.objects = []
self.track(Foo())
def track(self, foo):
def decorated_create_another():
new_foo = foo._create_another()
self.track(new_foo)
return new_foo
foo._create_another = foo.create_another
foo.create_another = decorated_create_another
self.objects.append(foo)
Of course, this doesn't check for overriding an existing _create_another method, tracking the same Foo object several times, etc...
That's what __new__ is for, isn't it?
https://stackoverflow.com/a/13054570/705086
class foo():
def __init__(self)
self.var1 = 1
class bar():
def __init__(self):
print "foo var1"
f = foo()
b = bar()
In foo, I am doing something that produces "var1" being set to 1
In bar, I would like to access the contents of var1
How can I access var1 in the class instance f of foo from within the instance b of bar
Basically these classes are different wxframes. So for example in one window the user may be putting in input data, in the second window, it uses that input data to produce an output. In C++, I would have a pointer to the caller but I dont know how to access the caller in python.
As a general way for different pages in wxPython to access and edit the same information consider creating an instance of info class in your MainFrame (or whatever you've called it) class and then passing that instance onto any other pages it creates. For example:
class info():
def __init__(self):
self.info1 = 1
self.info2 = 'time'
print 'initialised'
class MainFrame():
def __init__(self):
a=info()
print a.info1
b=page1(a)
c=page2(a)
print a.info1
class page1():
def __init__(self, information):
self.info=information
self.info.info1=3
class page2():
def __init__(self, information):
self.info=information
print self.info.info1
t=MainFrame()
Output is:
initialised
1
3
3
info is only initialised once proving there is only one instance but page1 has changed the info1 varible to 3 and page2 has registered that change.
No one has provided a code example showing a way to do this without changing the init arguments. You could simply use a variable in the outer scope that defines the two classes. This won't work if one class is defined in a separate source file from the other however.
var1 = None
class foo():
def __init__(self)
self.var1 = var1 = 1
class bar():
def __init__(self):
print var1
f = foo()
b = bar()
Same as in any language.
class Foo(object):
def __init__(self):
self.x = 42
class Bar(object):
def __init__(self, foo):
print foo.x
a = Foo()
b = Bar(a)
Alternatively you could have a common base class from which both derived classes inherit the class variable var1. This way all instances of derived classes can have access to the variable.
Something like:
class foo():
def __init__(self)
self.var1 = 1
class bar():
def __init__(self, foo):
print foo.var1
f = foo()
b = bar(foo)
You should be able to pass around objects in Python just like you pass around pointers in c++.
Perhaps this was added to the language since this question was asked...
The global keyword will help.
x = 5
class Foo():
def foo_func(self):
global x # try commenting this out. that would mean foo_func()
# is creating its own x variable and assigning it a
# value of 3 instead of changing the value of global x
x = 3
class Bar():
def bar_func(self):
print(x)
def run():
bar = Bar() # create instance of Bar and call its
bar.bar_func() # function that will print the current value of x
foo = Foo() # init Foo class and call its function
foo.foo_func() # which will add 3 to the global x variable
bar.bar_func() # call Bar's function again confirming the global
# x variable was changed
if __name__ == '__main__':
run()