How to generate a new instance of a class in recursion - python

Recently I was learning the sequence alignment algorithm. After I got the alignment matrix, I could find an optimal path, but I was in trouble when I was looking for multiple optimal paths (backtracking)!
My idea is to store the results of multiple paths with multiple instances, and finally loop through all instances of the base class to get the answer.
I know the following conditions:
What conditions to exit recursion
When do I need to create a new instance and when I don't create it?
But the problem is in the second condition. I don't know how many optimal results there are, and I don't know how many new instances will be created.
So I want to be able to dynamically generate an instance name with a variable.
I don't know how to do this:
# those equivalent to new_instance_name = ResultSeq()
a="new_instance_name"
create_new_instance(a,ResultSeq)
My result base class is ResultSeq:
class KeepRefs(object):
"""
reference:https://stackoverflow.com/questions/328851/printing-all-instances-of-a-class#comment167339_328851
"""
__refs__ = defaultdict(list)
def __init__(self):
self.__refs__[self.__class__].append(weakref.ref(self))
#classmethod
def get_instances(cls):
for inst_ref in cls.__refs__[cls]:
inst = inst_ref()
if inst is not None:
yield inst
class ResultSeq(KeepRefs):
"""
save two
"""
def __init__(self, seq1="", seq2=""):
super(ResultSeq, self).__init__()
self.seq1 = seq1
self.seq2 = seq2
Below is my recursive code:
def multi_backtracking(self, array, i, j, result_seq):
"""
:param array: V, E, F
:param i: row
:param j: col
:param result_seq: new instance of the class ResultSeq
:return: Multiple alignment results
"""
def create_new_obj(name, obj):
"""
I don't know how to do this.
"""
pass
if i == 0 and j == 0:
pass
else:
if array is self.array_V:
if sum(pass_judgement) == 1:
"""
An optimal path without creating a new instance.
"""
self.multi_backtracking(self.array_V, i, j, result_seq)
else:
"""
Multiple paths, need to create a new instance
"""
new_instance_name = "xxx"
create_new_obj(new_instance_name, ResultSeq)
...
if pass_judgement[0]:
result_seq.seq1 = self.origin_seq.seq1[i - 1] + result_seq.seq1
result_seq.seq2 = self.origin_seq.seq2[j - 1] + result_seq.seq2
self.multi_backtracking(self.array_V, i - 1, j - 1, new_instance_name)
if pass_judgement[1]:
self.multi_backtracking(self.array_E, i, j, new_instance_name)
if pass_judgement[2]:
self.multi_backtracking(self.array_F, i, j, new_instance_name)
This is just one of my solutions. If there are better suggestions, I will be happy to accept them, thank you!

You do not need names to store variables - you can use a simple list to store your instances:
class A:
def __init__(self,value):
self.value = value
def __repr__(self):
return f" _{self.value}_ "
def rec(i):
"""Recursive function, returns a list of instances of class A with decreasing
value i"""
if i < 0:
return []
return [A(i)] + rec(i-1)
k = rec(5)
print(k)
Output:
[ _5_ , _4_ , _3_ , _2_ , _1_ , _0_ ]
You can acccess your instances inside your list by indexing:
print(k[2]) # _3_
print(k[2].value + k[3].value) # 5
If you really need names, you can use a dictionary to store them - that is about the same as your existing baseclass KeepRefs does (*):
data = { "Instance1" : A(42), "Instance2" : A(3.141)}
print(data)
print( data["Instance1"].value + data["Instance2"].value )
Output:
{'Instance1': _42_ , 'Instance2': _3.141_ }
45.141
Most of the time when you need user generated "names" for variables you should very strongly reconsider your options.
(*) Your baseclass does not keep non-referenced instances around, a real dict will prevent garbage collecting:
k1 = ResultSeq("A","B")
k2 = ResultSeq("C","D")
k3 = ResultSeq("E","F")
for g in ResultSeq.get_instances():
print(g.seq1, g.seq2)
k2 = None # no instance of k2 anywhere
k3 = None # no instance of k3 anywhere
for g in ResultSeq.get_instances():
print(g.seq1, g.seq2)
A B
C D
E F
A B # 2.print loop after removing instances k2,k3
Documentation:
https://docs.python.org/3/library/weakref.html

Related

How can I modify my __repr__ to respresent correctly?

My __repr__ method works fine using objects created in it's class, but with objects that were created with the help of importing a library and using methods from it, it only represented the memory address...
from roster import student_roster #I only got the list if students from here
import itertools as it
class ClassroomOrganizer:
def __init__(self):
self.sorted_names = self._sort_alphabetically(student_roster)
def __repr__(self):
return f'{self.get_combinations(2)}'
def __iter__(self):
self.c = 0
return self
def __next__(self):
if self.c < len(self.sorted_names):
x = self.sorted_names[self.c]
self.c += 1
return x
else:
raise StopIteration
def _sort_alphabetically(self,students):
names = []
for student_info in students:
name = student_info['name']
names.append(name)
return sorted(`your text`names)
def get_students_with_subject(self, subject):
selected_students = []
for student in student_roster:
if student['favorite_subject'] == subject:
selected_students.append((student['name'], subject))
return selected_students
def get_combinations(self, r):
return it.combinations(self.sorted_names, r)
a = ClassroomOrganizer()
# for i in a:
# print(i)
print(repr(a))
I tried displaying objects that don't rely on anther library, and they dispayed properly.
The issue I was facing was linked to me not understanding the nature of the object. itertools.combinations is an iterable, and in order to represent the values stored I needed to either:
unpack it inside a variable like:
def get_combinations(self, r):
*res, = it.combinations(self.sorted_names, r)
return res
Iter through it inside a loop and leave the original code intact like
for i in a.get_combinations(2):
print(i)
I prefer the second solution

How to recursively create a python dictionary from unknown depth & width but also add values?

This is a follow up question to this post:
How to recursively create a nested dictionary of unknown size in python?
I need to somehow incorporate a value for each element as well.
Starting with the previous solution:
def unpack(obj):
return {str(o): unpack(o) for o in obj.get_items()}
Every item also has a value associated with it besides the name.
I tried the following, but it wouldn't work:
def unpack(obj):
return {{str(o): unpack(o), 'value':o.value} for o in obj.get_items()}
I get a "unhashable type: 'dict'" error.
The resulting dictionary should look something like the following:
example_dict = {'level_1': {'level_2':{},'value':'b'},'value' : 'a'}
Where each nested level would have a value associated with the name of the level.
Ok, so if I understood you correctly you want to put an object tree into a hierarchical dictionary. My first go at this would be
import random
names = ['foo_%s'%i for i in range(10)]
# Make hierarchical test case
class Test:
def __init__(self, depth):
self.name = random.choice(names)
if depth > 1:
self.child = Test(depth-1)
else:
self.child = None
def __str__(self):
return self.name
test = Test(3)
# The meat
def unpack(x):
ret = dict()
for k, v in x.__dict__.items():
try:
ret[k] = unpack(v)
except AttributeError:
ret[k] = v
return ret
print(unpack(test))
‚unpack‘ tries to recursively find all variables of an object and writes them into a dict. If that fails it returns the variable. Note that ‚x.str‘ has to be implemented.

access list of instantiated objects form within the object

I want to access a list of instantiated objects with a method inside the objects' class in Python 3.
I assume I can't give the the whole list to the object, as it would contain itself.
Concretely: how do I access cells[] from within the class cell? Or is this the wrong way to think about it? the end goal is to easily program cell behavior like cell.moveUp() -- all cells are connected to 8 neighbors.
I am missing something, probably since I don't have much experience in python/programming.
#!/usr/bin/env python3
import random
class cell:
""" cell for celluar automata """
def __init__(self, n=0, nghbrs=[], a=0.00, b=0.00, c=0.00):
self.n = n #id
self.nghbrs = nghbrs #list of connected neighbors
self.a = a #a value of the cell
self.b = b
self.c = c
def growUp(self):
if self.a > .7: # if cell is "bright"
cells[self.nghbrs[7]].a = self.a # update cell above (nghbrs[7] = cell above )
def main():
iterations = 4
links = initLinks() # 150 random links [link0, link2, ... , link7]*150
val1 = initval() # 150 random values
cells = [cell(nghbrs[0], nghbrs[1], val1[nghbrs[0]])for nghbrs in enumerate(
links)] # create cell objects, store them in cells and init. neigbours , a
for i in range(iterations): # celluar automata loop
for c in cells:
c.growUp()
def initLinks(): #for stackoverflow; in real use the cells are arranged in a grid
nghbrs = []
for i in range(150):
links = []
for j in range(8):
links.append(random.randrange(0, 150))
nghbrs.append(links)
return nghbrs
def initval():
vals = []
for i in range(150):
vals.append(random.random())
return vals
if __name__ == "__main__":
main()
run as is cells cannot be accessed in the method growUp():
NameError: name 'cells' is not defined
You could make a CellsList class (subclass of list) that has a method which you call to get a new cell.
class CellsList(list):
def add_cell(self, *args, **kwargs):
"""
make a cell, append it to the list, and also return it
"""
cell = Cell(cells_list=self, *args, **kwargs)
self.append(cell)
return cell
then in the cell itself (I've renamed the class Cell and above I am using cell as in instance variable in accordance with usual capitalisation convention) you have an attribute cells_list where you store a back-reference to the cells list. (I'm also fixing the initialisation of nghbrs to avoid a mutable object in the defaults.)
class Cell:
""" cell for celluar automata """
def __init__(self, n=0, nghbrs=None, a=0.00, b=0.00, c=0.00, cells_list=None):
self.n = n #id
self.nghbrs = (nghbrs if nghbrs is not None else []) #list of connected neighbors
self.a = a #a value of the cell
self.b = b
self.c = c
self.cells_list = cells_list
def growUp(self):
if self.a > .7: # if cell is "bright"
self.cells_list[self.nghbrs[7]].a = self.a # update cell above (nghbrs[7] = cell above )
And then inside main, you can change your current code that instantiates Cell (or what you call cell) directly (your line with cells = ...) to instead use cells.add_cell
cells = CellsList()
for nghbrs in enumerate(links):
cells.add_cell(nghbrs[0], nghbrs[1], val1[nghbrs[0]])
Here we're not actually using the value returned by add_cell, but we return it anyway.
Note: this approach allows you to maintain multiple independent lists of cells if you wish, because it does not rely on any class variables to hold the list -- everything is held in instance variables. So for example, your main program could model multiple regions, each containing a different cells list, by instantiating CellsList more than once, and calling the add_cell method of the relevant CellsList instance to create a new cell.
You can track instances of cell() by making the cells list a static variable of your class, which can be easily accessed from within all instances of the class.
import random
class cell:
""" cell for celluar automata """
cells = []
def __init__(self, n=0, nghbrs=[], a=0.00, b=0.00, c=0.00):
self.n = n #id
self.nghbrs = nghbrs #list of connected neighbors
self.a = a #a value of the cell
self.b = b
self.c = c
def growUp(self):
if self.a > .7: # if cell is "bright"
self.cells[self.nghbrs[7]].a = self.a # update cell above (nghbrs[7] = cell above )
def main():
iterations = 4
links = initLinks() # 150 random links [link0, link2, ... , link7]*150
val1 = initval() # 150 random values
cell.cells = [cell(nghbrs[0], nghbrs[1], val1[nghbrs[0]])for nghbrs in enumerate(
links)] # create cell objects, store them in cells and init. neigbours , a
for i in range(iterations): # celluar automata loop
for c in cell.cells:
c.growUp()
def initLinks(): #for stackoverflow; in real use the cells are arranged in a grid
nghbrs = []
for i in range(150):
links = []
for j in range(8):
links.append(random.randrange(0, 150))
nghbrs.append(links)
return nghbrs
def initval():
vals = []
for i in range(150):
vals.append(random.random())
return vals
if __name__ == "__main__":
main()

How to access (and modify) arbitrary items in a hierarchy of classes in python

I have a class built in a way as follows for building a tree structure.
class Node(object):
def __init__(self, data):
self.data = data
self.children = []
def add_child(self, obj):
self.children.append(obj)
n00 = Node('n00')
n00.add_child(Node('n000'))
n00.add_child(Node('n001'))
n0 = Node('n0')
n0.add_child(n00)
n0.add_child(Node('n01'))
n0.add_child(Node('n02'))
n1 = Node('n1')
n1.add_child(Node('n10'))
n1.add_child(Node('n11'))
n20 = Node('n20')
n20.add_child(Node('n200'))
n20.add_child(Node('n201'))
n2 = Node('n2')
n2.add_child(n20)
n2.add_child(Node('n21'))
h = Node('head')
h.add_child(n00)
h.add_child(n01)
h.add_child(n02)
Now that when I want to only access an item, it can be done by with a simple function such as:
def access(tree, *id):
item = tree
for i in id:
item = item.children[i]
return item.data
print(access(h,0,1))
The problem is when I want to make changes to any node, I cannot use this method and always need to manually type in the lengthy members such as:
h.children[1].children[0].data = 'new value'
or
h.children[0].children[0].children[1].add_child(Node('n0010'))
Now whenever the depth of the tree gets deeper, it becomes quite painful to repeatedly type all this.
Is there a 'Python' way to make changes to items in a tree similar to the access method?
Just go ahead and modify the node: Use the same "walking" technique as in your access method, only then don't return item.data but assign a new value to it:
def modify(new_data, tree, *id):
item = tree
for i in id:
item = item.children[i]
item.data = new_data
Example:
print(access(h, 0, 1))
modify("n001new", h, 0, 1)
print(access(h, 0, 1))
Which prints:
n001
n001new
Same thing for adding children:
def insert_child(new_child, tree, *id):
item = tree
for i in id:
item = item.children[i]
item.add_child(new_child)
Call it like:
insert_child(Node('n0010'), h, 0, 1)
If you know the "path" in the tree of the node you wish to edit, you could create a method to your Node class to return that node using recursion. Something like this:
def getnode(self, path):
if len(path) > 1:
return self.children[path[0]].getnode(path[1:])
else:
return self.children[path[0]]
Here path is a tuple or a list. For example h.getnode((1, 0)).data is equivalent to h.children[1].children[0].data
You can improve this simple method with some try except block to prevent errors in case a tuple is too long or with wrong index, if needed.
EDIT
using the * operator maybe is simple:
def getnode(self, *path):
if len(path) > 1:
return self.children[path[0]].getnode(*path[1:])
else:
return self.children[path[0]]
this way you just write h.getnode(1, 0).data (no double parentheses)

Most object oriented way of solving this in python?

I've been told to write a simple program that generates coupon codes, which should offer more than two algorithms (any two) and that the algorithm and the number of codes generated should be read from a config file. Also I've been told that the solution would involve using a known design pattern and that I should look for what pattern is.
I've come up with two solutions for this, but I don't think I've found a proper OOP design pattern that fits for the problem, since objects are data with methods that operate over that data, and in this problem there is little data to operate over, it's more a function (functional?) problem to my naive eyes. Here are the two, one is basically executing the proper static method for the algorithm in the config file and the other returns a reference to a function. Both generate the numbers and print them to the screen.
First method:
class CouponGenerator:
SEQUENTIAL_NUMBERS = "sequentialNumbers"
FIBONACCI_NUMBERS = "fibonacciNumbers"
ALPHANUMERIC_SEQUENCE = "alphanumericSequence"
quantity = 0
algorithm = ""
def __init__(self, quantity, algorithm):
self.quantity = quantity
self.algorithm = algorithm
def generateCouponList(self):
numbers = list()
if self.algorithm == self.SEQUENTIAL_NUMBERS:
numbers = CouponGenerator.generateSequentialNumbers(self.quantity)
elif self.algorithm == self.FIBONACCI_NUMBERS:
numbers = CouponGenerator.generateFibonacciSequence(self.quantity)
for number in numbers:
print number
#staticmethod
def getCouponGenerator(configFile):
cfile = open(configFile)
config = cfile.read()
jsonconfig = json.loads(config)
cg = CouponGenerator(jsonconfig['quantity'], jsonconfig['algorithm'])
return cg
#staticmethod
def generateSequentialNumbers(quantity):
numbers = list()
for n in range(1, quantity+1):
zeroes = 6-len(str(n))
numbers.append(zeroes*"0"+str(n))
return numbers
#staticmethod
def generateFibonacciSequence(quantity):
def fib(n):
a, b = 0, 1
for _ in xrange(n):
a, b = b, a + b
return a
numbers = list()
for n in range(1, quantity+1):
number = fib(n)
zeros = 6-len(str(number))
numbers.append(zeros*"0"+str(number))
return numbers
if __name__ == "__main__":
generator = CouponGenerator.getCouponGenerator("config")
generator.generateCouponList()
Second solution:
class CouponGenerator:
#staticmethod
def getCouponGenerator(algorithm):
def generateSequentialNumbers(quantity):
numbers = list()
for n in range(1, quantity+1):
zeroes = 6-len(str(n))
numbers.append(zeroes*"0"+str(n))
return numbers
def generateFibonacciSequence(quantity):
def fib(n):
a, b = 0, 1
for _ in xrange(n):
a, b = b, a + b
return a
numbers = list()
for n in range(1, quantity+1):
number = fib(n)
zeros = 6-len(str(number))
numbers.append(zeros*"0"+str(number))
return numbers
generators = {"sequentialNumbers": generateSequentialNumbers,
"fibonacciNumbers": generateFibonacciSequence}
return generators[algorithm]
class CouponGeneratorApp:
configFile = "config"
def __init__(self):
cfile = open(self.configFile)
config = cfile.read()
self.jsonconfig = json.loads(config)
self.generateCouponCodes()
def generateCouponCodes(self):
generator = CouponGenerator.getCouponGenerator(self.jsonconfig["algorithm"])
numbers = generator(self.jsonconfig["quantity"])
for n in numbers:
print n
if __name__ == "__main__":
app = CouponGeneratorApp()
If you want to make it a little more object oriented I suggest you use some kind of strategy pattern, that means, use a class per generation algorithm (which should have a common interface) and specify that CouponGenrator use an object which implements this interface to do whatever it has to do. This is theory and making interface and everything in your case might be a little to much.
http://en.wikipedia.org/wiki/Strategy_pattern
you could try something like :
class SequentialGenerator(Object):
def implementation():
...
class FibonacciGenerator(Object):
def implementation():
...
class CouponGenerator(Object):
def set_generator(generator):
# set self.generator to either an instance
# of FibonacciGenerator or SequentialGenerator
def generate_coupon_code():
# at some point calls self.generator.implementation()

Categories

Resources