简体   繁体   中英

How to create new class instances dynamically at runtime in python?

I am trying to solve this problem:

Imagine a (literal) stack of plates. If the stack gets too high, it might topple. There- fore, in real life, we would likely start a new stack when the previous stack exceeds some threshold. Implement a data structure SetOfStacks that mimics this. SetOf- Stacks should be composed of several stacks, and should create a new stack once the previous one exceeds capacity. SetOfStacks.push() and SetOfStacks.pop() should behave identically to a single stack (that is, pop() should return the same values as it would if there were just a single stack). Bonus: Implement a function popAt(int index) which performs a pop operation on a specific sub-stack.

So I wrote the code:

#!/bin/env python

from types import *

class Stack:

    def __init__(self):
        self.items = []
        self.capacity = 3
        self.stackscount = 0

    def create(self):
        id = self.stackscount + 1
        id = str(id) + "_stack"
        # How to create a new instance of Stack class at runtime ?
        # the __init__ must be run too.

    def push(self, item):
        if self.size() <= self.capacity:
            self.items.append(item)
        else:
            self.create()

    def pop(self):
        return self.items.pop()

    def popAt(self):
        pass

    def peek(self):
        return self.items[len(self.items)-1]

    def size(self):
        return len(self.items)

s = Stack()
s.push(10)

How do I create a new s type object dynamically at runtime? I searched on the internet and found that using new.instance or new.classobj is the solution but when I did so my new object did not seem to have items from __init__ function. In python3, type() seems to be the answer but the docs doesn't have any examples.

You've confused yourself by referring to a "type object". In Python that means the class itself, not its instances.

To create new Stack objects, simply do what you're already doing: call the Stack class. You can append them to a list:

stacks = [Stack() for _ in range(5)]

However, as jon points out, that won't solve your problem since you haven't defined the SetOfStacks class.

The type() function is indeed what you are looking for. Documentation can be found here: https://docs.python.org/2/library/functions.html#type

You can call it like this:

# Bases is a tuple of parent classes to inherit
bases = Stack,

# Dict contains extra properties for the class, for example if you want to add a class variable or function
dict_ = {}

# Construct the class
YourClass = type('YourClass', bases, dict_)

# Create an instance of the class
your_instance = YourClass()

It looks like you are just looking at instance creation though:

class Stack(object):

    def create(self):
        id = self.stackscount + 1
        id = str(id) + "_stack"
        # How to create a new instance of Stack class at runtime ?
        # the __init__ must be run too.
        stack = Stack()

You could simply use a parent-child relation : when a Stack is full, it creates a child and delegate next pushes to it. It could lead to :

class Stack:

    def __init__(self, parent = None, id=None):
        self.stackscount = 0
        self.capacity = 3
        self.items = []
        self.parent = parent
        self.id = id
        self.child = None

    def create(self):
        id = self.stackscount + 1
        id = str(id) + "_stack"
        return Stack(self, id)

    def push(self, item):
        if self.size() <= self.capacity:
            self.items.append(item)
        else:
            if self.child is None:
                self.child = self.create()
            self.child.push(item)

    def pop(self):
        if self.child is not None:
            item = self.child.pop()
            if len(self.child.items) == 0:
                self.child = None
        else:
            item = self.items.pop()
        return item

    def popAt(self):
        pass

    def peek(self):
        if self.child is not None:
            item = self.child.peek()
        else:
            item = self.items[len(self.items)-1]
        return item

    def size(self):
        l = len(self.items)
        if self.child is not None:
            l += self.child.size()
        return l

s = Stack()
s.push(10)

popAt is still to be implemented, but I tested it and it correctly creates new stacks when pushing and empties and removes them when popping.

The implementation of popAt will require some evolutions to current pop implementation, to allow removing an intermediate stack :

def pop(self):
    if self.child is not None:
        item = self.child.pop()
        if len(self.child.items) == 0:
            self.child = self.child.child
            if self.child is not None:
                self.child.parent = self
    else:
        item = self.items.pop()
    return item

def popAt(self, stacknumber):
    s = self
    for i in range(stacknumber):
        s = s.child
        if s is None:
            return None
    if len(s.items) == 0:
        return None
    item = s.items.pop()
    if len(s.items) == 0 and s.parent is not None:
        s.parent.child = s.child
        if s.child is not None:
            s.child.parent = s.parent
    return item

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM