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.
Related
I have a class for a Dialogue system as follows
class DIALOGUE(object):
def __init__(self, place, who, sTime, eTime, isActive, mood, menuText, func, repeatable, num):
self.place = place
self.who = who
self.sTime = sTime
self.eTime = eTime
self.isActive = isActive
self.mood = mood
self.menuText = menuText
self.func = func
self.repeatable = repeatable
self.num = num
#property
def ACheck(self):
global Date
if self.sTime == "none":
return True
else:
tHour,tMin = self.sTime.split(":")
if tHour >= Date.Hour and tMin <= Date.Minute:
tHour,tMin = self.eTime.split(":")
if tHour < Date.Hour and tMin < Date.Minute:
return True
return False
#property
def BCheck(self):
global Act
if self.who == Act:
return True
else:
return False
#property
def CCheck(self):
global Location
if self.place == Location:
return True
if self.place == "none":
return True
return False
#property
def DCheck(self):
if self.repeatable:
return True
else:
if self.num > 0:
return False
else:
return True
#property
def CanChat(self):
if self.isActive and self.ACheck and self.BCheck and self.CCheck and self.DCheck:
return True
else:
return False
def SetActive(self):
self.isActive = True
def Do(self):
self.num += 1
renpy.call(self.func)
Most of this should be self explanatory but I parse an XML file into a list of Instances of this class.
The user is presented with a list of available dialogues based on what Location they are in, what time of day it is and what NPC they have selected. If the dialogue is not repeatable The DCheck method looks at whether or not the dialogue has been completed before i.e if the dialogue is not repeatable and self.num > 0 the method will return False
Essentially it loops through all the dialogues and carries out i.CanChat and if this value returns True, the Dialogue is added to the menu
The issue I'm having is that the Check methods aren't returning the correct value. Specifically DCheck is returning True all the time, regardless of whether the Dialogue is repeatable or not, and ignoring the value of self.num
The class is created in an init python: block and then the xml file is parsed in a separate python block which is called from inside the start label
It's probably something really simple but I can't figure it out.
The list of instances is parsed as follows
Dialogues = []
for j in Dialo:
JPlace = j.find('Place').text
JWho = j.find('Who').text
JsTime = j.find('Start').text
JeTime = j.find('End').text
JMood = int(j.find('Mood').text)
JText = j.find('Text').text
JFunc = j.find('Func').text
JRep = j.find('Rep').text
if JRep == "True":
Jrep = True
else:
Jrep = False
Dialogues.append(DIALOGUE(JPlace, JWho, JsTime, JeTime, False, JMood, JText, JFunc, JRep, 0))
The method for creating the menu is as follows
def TalkCheck():
talks = []
talks.append(("Nevermind.", "none"))
for i, q in enumerate(Dialogues):
if q.CanChat:
talks.append((q.menuText,i))
renpy.say(None, "", interact=False)
talkchoice = renpy.display_menu(talks)
if talkchoice <> "none":
talkchoice = int(talkchoice)
Dialogues[talkchoice].Do()
Your question is incomplete - you didn't post a MCVE, we don't know the effective values for "repeatble" and "num" that leads to this behaviour, and we don't even know if it's using Python 2.x or Python 3.x - so we can just try and guess. Now since you mention that you "parse an XML file into a list of instances", I stronly suspect you are running Python 2.x and passing those values as strings instead of (resp.) boolean and int. In Python 2, "-1" (string) compares greater than 0 (int) - it raises a TypeError in Python 3.x -, and in both cases a non-empty string evals to True in a boolean context (bool('False') == True). Since there's no obvious logical error in your method implementation, that's the only explanation I can think of.
BTW, expressions have a boolean values and return exits the function, so you can simplify your code:
#property
def DCheck(self):
if self.repeatable:
return True
return self.num > 0
I have the following example in which the next method of a class is supposed to return the values from two generators:
class Test():
def __next__(self):
g1, g2 = self._gen1(), self._gen2()
return next(g1), next(g2)
def _gen1(self):
i = 0
while True:
yield i
i += 2
def _gen2(self):
i = 1
while True:
yield i
i += 2
However, when I call next for this class, the values are not incremented.
>>> t = Test()
>>> next(t)
>>> (0, 1)
>>> next(t)
>>> (0, 1)
What is wrong? Is there a more eloquent way to write this class?
Although I have no idea what you are trying to accomplish, here is a cleaned up version which (I think) does what you want.
class Test():
def __init__(self):
self.g1 = self._gen2()
self.g2 = self._gen1()
def __next__(self):
return next(self.g1), next(self.g2)
def _gen1(self):
i = 0
while True:
yield i
i += 2
def _gen2(self):
i = 1
while True:
yield i
i += 2
t = Test()
print(next(t))
print(next(t))
print(next(t))
Your code doesn't work because it recreates the generator functions every time __next__() is called, which effectively resets them back to their initial state before their next next() values are returned:
def __next__(self):
g1, g2 = self._gen1(), self._gen2() # Don't do this here.
return next(g1), next(g2)
You can fix that by adding an __init__() method and initializing them in it:
class Test:
def __init__(self):
self.g1, self.g2 = self._gen1(), self._gen2() # Initialize here.
def __next__(self):
return next(self.g1), next(self.g2)
...
A more eloquent and slightly more concise way to do it which likewise will avoid the problem would be to use the builtin zip() function to create an "iterator of generators" that will return pairs of next values from each generator every time it's called. Another advantage is it's very easy to extend to handle even more generators simply just changing the __init__() method.
Here's what I mean:
class Test:
def __init__(self):
self.generators = zip(self._gen1(), self._gen2())
def __next__(self):
return next(self.generators)
def _gen1(self):
i = 0
while True:
yield i
i += 2
def _gen2(self):
i = 1
while True:
yield i
i += 2
t = Test()
for _ in range(3):
print(next(t))
Output:
(0, 1)
(2, 3)
(4, 5)
I am trying to make some binary singal system by boolean variables I named with LIGHTx.
LIGHT1 = True
LIGHT2 = True
LIGHT3 = False
LIGHT4 = False
Next, I nest these variables into a list for future calculation,
signal = [LIGHT1, LIGHT2, LIGHT3, LIGHT4]
Currently I am using the idea from Python: Boolean List to Binary String and Convert base-2 binary number string to int to convert the list to int number which is my signal. Here, [1,1,0,0] means 12.
In [97]: boolList2BinString(signal)
Out[97]: 12
My questions are:
How can I automatically updating the elements of "signal" by updating the value of the LIGHTs, rather than running signal = [LIGHT1, LIGHT2, LIGHT3, LIGHT4] again and again? Whitch means, in the rest of my codes, I only need to run LIGHTx = xxxx and boolList2BinString(signal). (Maybe some way like pointer of C++ ?)
If it is impossible with question 1, is there any way that I can fix the order of the LIGHTs in the list?
[Update]
Please exclude the way that building the 'signal' list inside the 'boolList2BinString' function.
Original:
def boolList2BinString(lst):
return int('0b' + ''.join(['1' if x else '0' for x in lst]), 2)
Building inside:
def boolList2BinString():
osignal = [LIGHT1 , LIGHT2 , LIGHT3 , LIGHT4 ]
return int('0b' + ''.join(['1' if x else '0' for x in signal ]), 2)
Thanks in advance!
you can create a class to hold the boolean, then it would act like a pointer
>>> class Light:
... def __init__(self, value):
... self.value = value
... def get(self):
... return(self.value)
... def set(self, value):
... self.value = value
then use light.get() to get the value, or light.set() to set the value
>>> Light1 = light(True)
>>> Light2 = light(False)
>>> lights = [light1, light2]
>>> for l in lights:
... print(l.get())
...
True
False
example showing set:
>>> for l in lights:
... print(l.get())
...
True
False
>>> light2.set(True)
>>> for l in lights:
... print(l.get())
...
True
True
>>>
Perhaps you just need some sort of wrapper.
class Light(object):
def __init__(self, state):
self.state = state
def false(self):
self.state = False
def true(self):
self.state = True
LIGHT1 = Light(True)
LIGHT2 = Light(True)
LIGHT3 = Light(False)
LIGHT4 = Light(False)
signal = [LIGHT1, LIGHT2, LIGHT3, LIGHT4]
And then you simply can change states of each lights as LIGHT1.true() or LIGHT1.false() and value in signal list will be changed automatically.
LIGHT1.false()
LIGHT1.state # False
LIGHT1.true()
LIGHT1.state # True
The methods naming could be changed, of course.
You could use a special property class to set bits in an integer.
Here is an example:
class Light(property):
def __init__(self, rank):
self.rank= rank
super(Light, self).__init__(self._get, self._set)
def _get(self, signal):
return (signal.value & (1 << self.rank)) != 0
def _set(self, signal, value):
if value:
signal.value |= 1 << self.rank
else:
signal.value &= ~(1 << self.rank)
class Signal(object):
def __init__(self, value=0):
self.value = value
l1 = Light(3)
l2 = Light(2)
You can then use that simply:
>>> s = Signal()
>>> s.value
0
>>> s.l1
False
>>> s.l1 = True
>>> s.l1
True
>>> s.value
8
(Tested on both Python 2.7 and Python 3.5)
When I try to enter the code below, I get [None, None] printed on the console rather than the expected [3, 3] and was wondering what would help to fix this.
class Blah(object):
def track(self,dot):
self.dot = dot
class Second(Blah):
def __init__(self,arg):
self.blocky = []
x = 0
while x < 2:
self.blocky.append(Blah.track(self,arg))
x += 1
bleh = Second(3)
print bleh.blocky
Among other more minor issues, your track method doesn't return anything, so you're passing the returned value of a function that returns nothing (None in other words) into that list.
The following worked for me:
class Blah(object):
def track(self, dot):
self.dot = dot
return self.dot
class Second(Blah):
def __init__(self, arg):
self.blocky = []
x = 0
while x < 2:
self.blocky.append(self.track(arg))
x += 1
Blah.track doesn't have a return statement, so it returns None.
You could fix this by doing:
class Blah(object):
def track(self, dot):
self.dot = dot
return dot
Also, you're calling Blah.track(self, dot) when you could just be calling self.track(dot), since self is a Second, which is a subclass of Blah.
That might look like this:
class Second(Blah):
def __init__(self,arg):
self.blocky = []
x = 0
while x < 2:
self.blocky.append(self.track(arg))
x += 1
The track method isn't returning anything. Perhaps you meant this?
def track(self, dot):
self.dot = dot
return dot
Also, since Second inherits from Blah you can replace
Blah.track(self, arg)
with
self.track(arg)
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)