I am working on an application where variables get initialized to default values.
The user can change those values at any time. It should be possible for the user to reset some or all of the variables to default at any time.
How is the best way of going about this?
This would be a solution, but I have a feeling that it is suboptimal. Can you tell me if my feeling is correct and how I can do it better?
A_DEFAULT = "A_def"
B_DEFAULT = "B_def"
C_DEFAULT = "C_def"
class BusinessLogic_1(object):
def __init__(self):
self.setVariablesToDefault()
def setVariablesToDefault(self, variableNames=None):
# pass None to set all Variables to default
variableNames = variableNames or ["A","B","C"]
if "A" in variableNames:
self.A = A_DEFAULT
if "B" in variableNames:
self.B = B_DEFAULT
if "C" in variableNames:
self.C = C_DEFAULT
def printVariables(self):
print "A: %s, B: %s, C: %s" % (self.A, self.B, self.C)
if __name__ == "__main__":
print "0: Initialize"
businessLogic_1 = BusinessLogic_1()
businessLogic_1.printVariables()
print "Change A,B,C and then reset A,C"
businessLogic_1.A = "A_new"
businessLogic_1.B = "B_new"
businessLogic_1.C = "C_new"
businessLogic_1.printVariables()
This might be a solution.
It's a way to pass names of variables as strings and then to access them via these names.
Objects can have more than one name simultaneously, but names always point to a single object (at a given point of time).
class classWithVariablesThatHaveDefaultValues(object):
def __init__(self, some, example, variables, defaultValuesDict):
self.some = some
self.example = example
self.variables = variables
self.dictionaryWithDefaultValues = defaultValuesDict
def resetValues(self, *listOfVariables):
for variable in listOfVariables:
for key in self.dictionaryWithDefaultValues:
if key == variable:
vars(self)[key] = self.dictionaryWithDefaultValues[key]
if __name__ == "__main__":
defaultValuesDict = {"some":4, "example":5, "variables":6}
exampleObject = classWithVariablesThatHaveDefaultValues(1, 2, 3, defaultValuesDict)
exampleObject.some = 15
print exampleObject.some, exampleObject.example, exampleObject.variables
exampleObject.resetValues("example", "some")
print exampleObject.some, exampleObject.example, exampleObject.variables
The Output is:
15 2 3
4 5 3
You can achieve it in a manner very similar to how decimal.localcontext() works, but depending on your use case, this may not be suitable. This will allow you to manipulate and call any methods on the original object reflecting the updated values, and at the end of the with block, reset them to the values upon entry.
from contextlib import contextmanager
class A(object):
def __init__(self):
self.a = 3
self.b = 5
def display(self):
return self.a, self.b
a = A()
#contextmanager
def mycontext(obj):
old_a = obj.a
old_b = obj.b
yield obj
obj.a = old_a
obj.b = old_b
print 'before:', a.display()
with mycontext(a) as obj:
print 'entered:', a.display()
a.a = 3
a.b = 7
print 'changed:', a.display()
print 'hopefully original', a.display()
before: (3, 5)
entered: (3, 5)
changed: (3, 7)
hopefully original (3, 5)
Related
I tried this inheritance code and got an unexpected output. Kindly guide me where is my fault.
Child.py
from ParentClass import Parent
class ChildImp(Parent):
var2 = 200
def __init__(self):
Parent.__init__(self, 8, 3)
def getData(self):
self.var1 + self.Sub() + self.Add()
obj = ChildImp()
print(obj.getData())
ParentClass.py
class Parent:
var1 = 100
def __init__(self, a, b):
self.firstNUm = a
self.secondNUm = b
def Add(self):
return self.firstNUm + self.secondNUm
def Sub(self):
return self.firstNUm - self.secondNUm
obj1 = Parent(4, 6)
print(obj1.Add())
obj2 = Parent(9, 2)
print(obj2.Sub())
output:
10
7
None
Process finished with exit code 0
Where does this 10 and 7 come from?
Why there is a None in the output?
The output is from each of the following calls
10 # print(obj1.Add())
7 # print(obj2.Sub())
None # print(obj.getData())
note that Add and Sub will return the computed value, btu getData has no return so will implicitly return None hence the last output.
Note that the reason those Add and Sub lines are executing is because of the import statement. If you only want those to run when that script is directly invoked you would modify that block to
if __name__ == '__main__':
obj1 = Parent(4, 6)
print(obj1.Add())
obj2 = Parent(9, 2)
print(obj2.Sub())
Output is from the 3 print statements.
print(obj1.Add()) # prints 10
print(obj2.Sub()) # prints 7
print(obj.getData()) # prints None
Need a return on ChildImp getData() function otherwise returns None.
from ParentClass import Parent
class ChildImp(Parent):
var2 = 200
def __init__(self):
Parent.__init__(self, 8, 3)
def getData(self):
return self.var1 + self.Sub() + self.Add() # <== added return
obj = ChildImp()
print(obj.getData())
Also good practice to add if name == __main__ check in the parent class so only the main in the class called is executed.
# ParentClass.py
class Parent:
...
if __name__ == '__main__':
obj1 = Parent(4, 6)
print(obj1.Add())
obj2 = Parent(9, 2)
print(obj2.Sub())
10 and 7 are the return values of the Add and Sub methods
The None is there because getData does not return anything
For all three values there is a print call.
I am trying to create a class name RangePrime and it's instance attributes should print out the range of them and finally appear an issue. How to fix them?
class RangePrime:
def range_list(self,a,b):
self.a = a
self.b = b
x = []
if b < a:
x.extend(range(b, a))
x.append(a)
else:
x.extend(range(a, b))
x.append(b)
return x
after i ran this -> range_prime = RangePrime(1, 5) and it start to appear
TypeError: RangePrime() takes no arguments
I should get the following result:
>>> range_prime = RangePrime(1, 5)
>>> range_prime.range_list
[1, 2, 3, 4, 5]
It looks you have mixed using functions without a class definition and at the same time misdefining the functions within the class by lacking an __init__(). I have modified your code a bit to account for the class and its functions, so the intention of your code remains the same. Kindly try:
class RangePrime():
def __init__(self, a,b):
self.a = a
self.b = b
def range_list(self):
a = self.a
b = self.b
x = []
if b < a:
x.extend(range(b, a))
x.append(a)
else:
x.extend(range(a, b))
x.append(b)
return x
Which when running:
range_prime = RangePrime(1, 5)
range_prime.range_list()
Returns:
[1,2,3,4,5]
create object of the class first and then pass those parameter in your class method then it will work
ob=RangePrime()
print(ob.range_list(1,5))
I have a piece of code below:
// The only difference is grad
class TestOne(...):
def init(self):
self.input_one = tr.allocate( ..., grad = False)
self.input_two = tr.allocate( ..., grad = False)
class TestTwo(...):
def init(self):
self.input_one = tr.allocate( ..., grad = True)
self.input_two = tr.allocate( ..., grad = False)
class TestThree(...):
def init(self):
self.input_one = tr.allocate( ..., grad = False)
self.input_two = tr.allocate( ..., grad = True)
Test1 = TestOne()
Test2 = TestTwo()
Test3 = TestThree()
# definition of allocate. It is a wrapper of the PyTorch randn function
# https://pytorch.org/docs/stable/torch.html#torch.randn
def allocate(..., grad):
...
return torch.randn(..., require_grad=grad)
I want to reduce the duplicate code by implementing just one class but able to generate same objects as the code above.
class Test(...):
// how to make it return different values?
def auto_set(self):
return False
def init(self):
self.input_one = tr.allocate( ..., grad = self.auto_set())
self.input_two = tr.allocate( ..., grad = self.auto_set())
Test1 = Test()
# grad of input_one and input_two will be `False, False`
Test2 = Test()
# grad of input_one and input_two will be `True, False`
Test3 = Test()
# grad of input_one and input_two will be `False, True`
This is part of a big project, so I can't change the interface of the init function. There could be N number of inputs which would require N + 1 different classes. That is not a scalable implementation so want to find a solution to solve that.
PS: My previous question was causing too many confusions to others so I changed it hoping to clarify on what I really want to have.
Just posting my solution here:
class Test(object):
init_counter = 0
num_variable = 0
def increase_init_counter(self):
Test.init_counter += 1
Test.auto_set_counter = 0
def auto_set(self):
if Test.init_counter == 0:
Test.num_variable += 1
return False
else:
print ("init_counter: {}, auto_set_counter: {}".format(Test.init_counter, Test.auto_set_counter))
Test.auto_set_counter += 1
if Test.init_counter == Test.auto_set_counter:
return True
else:
return False
def init(self):
self.A = self.auto_set();
self.B = False;
self.C = self.auto_set();
print ("A: {}, B: {}, C: {}".format(self.A, self.B, self.C))
=== Test
TestA = Test()
TestA.init()
for _ in range(TestA.num_variable):
TestB = copy.deepcopy(TestA)
TestB.increase_init_counter()
TestB.init()
If you find yourself using numbered variable names (e.g. v1, v2, v3) you need to stop immediately and think "Should I use a list instead?" - and the answer is "yes" in almost all cases.
Other notes:
To pick random values, make a list of possible values (in this case, [True, False]) and use random.choice()
range() can make a list of N values, which we can use to make another list of random choices (see "list comprehension" when you don't understand the [x for x in iterable] syntax).
Classes have __init__ as the constructor, you don't need a manual init function.
Classes should use a capital letter at the start of their name.
Code:
from random import choice
class Test(object):
def __init__(self, num_values):
self.values = [choice([True, False]) for _ in range(num_values)]
def see(self):
print(self.values)
for _ in range(3):
test1 = Test(3)
test1.see()
prints something like:
[False, False, False]
[True, False, True]
[True, True, False]
Let's see IIUYC...:
What you can do is to add a global, or let's say better common variable to the class definition, which is incremented when instanciating new objects of that class (and perhaps also better decremented when they are deleted).
This would give you the opportunity to implement different behaviuors of __init__() depending on the number of objects already created before.
Imagine a test class like
class Test():
i = 0
def __init__(self):
Test.i += 1
def __del__(self):
Test.i -= 1
After creating a first object, the common counter is 1:
t1 = Test()
t1.i
1
After creating a second object, the common counter is 2:
t2 = Test()
t2.i
Out: 2
... in all existing objects, because it's a common counter:
t1.i
Out: 2
Some sample implementation of what I think you want to achieve:
class Test():
i = 0
def __init__(self):
self.A = bin(Test.i)[-1] == '1'
self.B = bin(Test.i)[-2] == '1'
Test.i += 1
def __del__(self):
Test.i -= 1
t1 = Test()
print(t1.i, t1.A, t1.B)
# 1 False False
t2 = Test()
print(t2.i, t2.A, t2.B)
# 2 True False
t3 = Test()
print(t3.i, t3.A, t3.B)
# 3 False True
First of all, I suspect that what you need is a list of instance attributes (the variables in each object of the type).
class test(object):
def __init__(self):
self.v = []
# how to make it return different values?
def auto_set(self):
return False
def init(self):
self.v.append(self.auto_set())
def see(self):
print (self.v)
for _ in range(3):
test1 = test()
test1.init()
test1.see()
This will allow you to add to the attribute list. Is that enough to get you moving? We can't suggest a more thorough solution until you explain your system better.
Using Python 2.7.10, I have this script:
#!/usr/bin/python
#Do `sudo pip install boto3` first
import boto3
import json
def generate(key, value):
"""
Creates a nicely formatted Key(Value) item for output
"""
return '{}={}'.format(key, value)
def main():
ec2 = boto3.resource('ec2', region_name="us-west-2")
volumes = ec2.volumes.all()
for vol in volumes:
#print(vol.__str__())
#print(vol.__dict__)
print vol
# vol object has many attributes, which can be another class object.
# For ex:
#vol.volume_id),
#vol.availability_zone),
#vol.volume_type),
# only process when there are tags to process
# HERE: tags is another object which can contain a dict/list
#if vol.tags:
# for _ in vol.tags:
# # Get all of the tags
# output_parts.extend([
# generate(_.get('Key'), _.get('Value')),
# ])
# output everything at once.
print ','.join(output_parts)
if __name__ == '__main__':
main()
Is there a single function which can recursively print all the object's attributes using a single call? How can I print the values of val.xxxxx and val.tags.xxxx in one call.
I tried printing the object using .__dict__ or .__str__() but it didn't help.
Here's a function that you can drop into the str for your object. You can also call it directly, passing in the object you wish to print. The function returns a string that represents a nicely formatted walk of your object's contents.
Credit goes to #ruud from forum.pythonistacafe.com for coming up with this solution.
def obj_to_string(obj, extra=' '):
return str(obj.__class__) + '\n' + '\n'.join(
(extra + (str(item) + ' = ' +
(obj_to_string(obj.__dict__[item], extra + ' ') if hasattr(obj.__dict__[item], '__dict__') else str(
obj.__dict__[item])))
for item in sorted(obj.__dict__)))
class A():
def __init__(self):
self.attr1 = 1
self.attr2 = 2
self.attr3 = 'three'
class B():
def __init__(self):
self.a = A()
self.attr10 = 10
self.attrx = 'x'
class C():
def __init__(self):
self.b = B()
class X():
def __init__(self):
self.abc = 'abc'
self.attr12 = 12
self.c = C()
def __str__(self):
return obj_to_string(self)
x = X()
print(x)
Output:
<class '__main__.X'>
abc = abc
attr12 = 12
c = <class '__main__.C'>
b = <class '__main__.B'>
a = <class '__main__.A'>
attr1 = 1
attr2 = 2
attr3 = three
attr10 = 10
attrx = x
I have a class Population that contains several method.
According to an input I want the run the method on an instance of the class Population in a given order.
To be a bit more accurate in what I am trying to achieve is quite the same than using is something like that:
stuff = input(" enter stuff ")
dico = {'stuff1':functionA, 'stuff2':functionC, 'stuff3':functionB, 'stuff4':functionD}
dico[stuff]()
Except that the functionA, functionB etc... are methods and not functions:
order_type = 'a'
class Population (object):
def __init__(self,a):
self.a = a
def method1 (self):
self.a = self.a*2
return self
def method2 (self):
self.a += 2
return self
def method3 (self,b):
self.a = self.a + b
return self
if order_type=='a':
order = {1:method1, 2:method2, 3:method3}
elif order_type=='b':
order = {1:method2, 2:method1, 3:method3}
else :
order = {1:method3, 2:method2, 3:method1}
my_pop = Population(3)
while iteration < 100:
iteration +=1
for i in range(len(order)):
method_to_use = order[i]
my_pop.method_to_use() # But obviously it doesn't work!
Hope I've made my question clear enough!
Note that one of my method need two arguments
Pass the instance explicitly as first argument:
method_to_use = order[i]
method_to_use(my_pop)
Full working code:
order_type = 'a'
class Population (object):
def __init__(self,a):
self.a = a
def method1 (self):
self.a = self.a*2
return self
def method2 (self):
self.a += 2
return self
def method3 (self):
self.a = 0
return self
if order_type=='a':
order = [Population.method1, Population.method2, Population.method3]
elif order_type=='b':
order = [Population.method2, Population.method1, Population.method3]
else :
order = [Population.method3, Population.method2, Population.method1]
my_pop = Population(3)
while iteration < 100:
iteration +=1
for method_to_use in order:
method_to_use(my_pop)
If you want to pass more than one argument, simply use the *args syntax:
if order_type=='a':
order = [Population.method1, Population.method2, Population.method3]
arguments = [(), (), (the_argument,)]
elif order_type=='b':
order = [Population.method2, Population.method1, Population.method3]
arguments = [(), (), (the_argument,)]
else :
order = [Population.method3, Population.method2, Population.method1]
arguments = [(the_argument, ), (), ()]
my_pop = Population(3)
while iteration < 100:
iteration +=1
for method_to_use, args in zip(order, arguments):
method_to_use(my_pop, *args)
The () is an empty tuple, hence *args will expand to no additional arguments, while (the_argument,) is a 1-element tuple that will pass the argument to the method.
Use getattr:
order = {1:'method1', 2:'method2', 3:'method3'} #values are strings
...
method_to_use = order[i]
getattr(mypop, method_to_use)()
You can use operator.methodcaller:
from operator import methodcaller
method_to_use = methodcaller('method' + str(i))
method_to_use(my_pop)