increase the size of array deque - python-3.x

I'm trying to be as efficient as possible with space while creating an array based deque. So, the array starts with size one, and I'll call a function called "grow" if the array is not large enough when I push new values to the deque (at either end). I then mod to preserve the front and back of the deque. Here is a sample of what I've done so far:
def __init__(self):
# capacity starts at 1; we will grow on demand.
self.__capacity = 1
self.__contents = [None] * self.__capacity
self.__front = 1
self.__back = 1
self.__size = 1
def __grow(self):
old_list = self.__contents
walk = self.__front
for k in range(self.__capacity):
self.__contents[k] = old_list[walk]
walk = (1 + walk) % len(old_list)
self.__front = 0
self.__capacity = self.__capacity * 2
def push_front(self, val):
if self.__size == len(self.__contents):
self.__grow(self.__capacity)
self.__front = (self.__front - 1) % len(self.__contents)
self.__contents[self.__front] = val
self.__size += 1
My question comes when I call the grow method. I keep getting the error that I am giving 'grow' two positional arguments, but I don't see where or how that's happening. If anyone has any ideas on how to improve this so that it only has one positional argument? Also, does my reasoning for a walk through to re-index in the grow method make sense as well as my reasoning for the push front method?

You need to add an argument to __grow if you are going to pass arguments to it, i.e.:
def __grow(self, size):
Currently, it only has a self argument, but you are also passing in self.__capacity when you call it. However, I think you really meant to call grow without arguments:
if self.__size == len(self.__contents):
self.__grow()

All instance methods in a class treat the calling instance as their first argument, unless you use the class to call the method in which case you must provide an instance as the first argument.
class A:
def __init__(self):
pass
def f(self, x):
print(self, x)
a = A()
a.f(1) # <A object at 0x7fa9a067da90> 1
A.f(a, 2) # <A object at 0x7fa9a067da90> 2
So when you call self.__grow(self.__capacity), that gets turned into Deque.__grow(self, self.__capacity). But your __grow method only takes self.

Related

How to decide whether to use return or plain variable manipulation inside functions?

I know that return is like throwing out a value at the end of an operation and that it actually stops the iteration or the function in which it's residing. I am having this very simple piece of code where classmethods & class variables are used.
class Person:
number_of_people = 0
def __init__(self, name):
#Person.number_of_people +=1
Person.add_person()
#classmethod
def get_person_count(cls):
return cls.number_of_people
#classmethod
def add_person(cls):
# return cls.number_of_people+1 <-- this does not work. Output is 0 and 0. Why?
cls.number_of_people += 1 #<-- this works
P1 = Person("Rups")
print(P1.get_person_count())
P2 = Person("RG")
print(P2.get_person_count())
As I have commented on the lines, why is my method giving output 0 both times and not the expected output(1 & 2), which is achieved using plan variable modification? Either way, I thought I should be able to use the value given out by add_person method in the init method, since there is no looping involved.
Returning a value does not mean it is modifying a variable. It just means that something can use what is returned. The difference is that cls.number_of_people += 1 changes number_of_people to it's value + 1 (due to the = sign), while return cls.number_of_people+1 takes number_of_people + 1 and "throws" it for something else to use.
What this means is that if add_person returns a value, anytime you call add_person(), there is a value that can be used.
# {...}
def add_person(cls):
return cls.number_of_people + 1
P1 = Person("Rups")
print(P1.add_person()) # prints 1 (number_of_people which is 0, then add 1)
print(P1.add_person()) # still prints 1

Variable declaration as a member of a function?

What type of declaration is the one indicated in this code
def call_counter(func):
def helper(x):
helper.calls1 += 1 # <== This
return func(x)
helper.calls1 = 0
return helper
#call_counter
def succ(x):
return x + 1
print(succ.calls1)
for i in range(10):
print(succ(i))
print(succ.calls1())
What's the name of this is the first time i see something like this
Functions are just objects in Python, so the same way you can add new attributes to instances of your own classes (and to the classes themselves) you can add them to your functions:
def foo():
pass
class Bar:
pass
bar = Bar()
foo.spam = 1
bar.spam = 2
print(foo.spam) # 1
print(bar.spam) # 2
Generally one wouldn't add new attributes to a function object though, since it can quickly get messy and hard to keep track of.

Access to the local environment of a function from another function called by the previous one

Let's take a look at this piece of code:
def a(): # N = 0
string = "pizza"
# stuff
res_b = b(string)
def b(string): # N = 1
# stuff
res_c = c(string)
return res_c
def c(string): # N = 2
# stuff
return thing
I have a long file which has basically the same shape than that. I would like to remove the parameter str from the definitions and to make b and c able to read it directly (I mean not using an external dictionary) from the N-1 function. So I wonder if a function could read the local environment of the one which called it.
Does anything look like what I am looking for ?

Count number of basic instruction and their type

I have some code (few hundreds of lines) and i would like to reproduce the code on some "real" controller.
I would like to predict how long the code would take to run by counting how many instructions (basic arithmetic, type of operation (floating point, binary, etc..)
And i wonder if it is possible to do on python (if yes how so ? haven't found anything yet)
I know there is a time feature to measure how long it takes to run the code but the calculation power of my PC and the controller i plan to use are not the same.
Also i tried counting it myself but it is quite a pain and subject to errors
Ideal result would be like:
X number of basic arithmetic operation using INT
Y number of basic arithmetic operation using FLOAT
Z binary operation
etc ...
Thank you
Your question got me thinking. I wrote a little framework for how you might implement something like this. Basically you create your own number class and a collection to hold them all. Then you over-ride the default operators and increment a variable every time you enter those functions. Note that this is NOT robust.. There's no error checking and it assumes that all operations are done with the custom class objects.
from collections import defaultdict # Acts like a dictionary, but every time you add a key, the value defaults to a specified value
class Collection(object): # Use this to hold your custom types
def __init__(self):
self.items = []
return
def add_item(self, item):
self.items.append(item)
class myFloat(object): # Your custom float class
def __init__(self, val, collection):
""" val is the value, collection is the Collections object where we will place your object """
self.val = float(val)
self.op_counts = defaultdict(int) # a dictionary where values default to an integer, 0.
collection.add_item(self) # Add this object to the collection
def __add__(self, other): # Called when you use + on two myFloat
self.op_counts["+"] += 1 # Adds 1 to the number of "+" used
return self.val + other.val # returns the result.
def __sub__(self, other): # Called when you use - on two myFloat
self.op_counts["-"] += 1
return self.val - other.val
def __mul__(self, other): # Called when you use * on two myFloat
self.op_counts["*"] += 1
return self.val * other.val
def __truediv__(self, other): # Called when you use / on two myFloat
self.op_counts["/"] += 1
return self.val / other.val
### EXAMPLE
import random
ops = ["+", "-", "*", "/"]
# We should create a separate Collection object for each custom type we have.
# Since we only have myFloat, we make one Collection object to hold the myFloats.
float_collection = Collection()
# This instantiates a myFloat object with val=7.12 and uses your float_collection
y = myFloat(7.12, float_collection)
for x in range(1, 1000):
op = random.choice(ops) # Pick a random operation
xx = myFloat(x, float_collection) # Instantiate another myFloat
# Now perform the operation on xx and y. eval evaluates the string but
# opens the door for security holes if you are worried about hackers. CAREFUL.
eval(f"y{op}xx") # Remove this line and use the one below if your python < 3.6
# eval("y{}xx".format(op))
print("### RESULTS ###")
result_op_counts = defaultdict(int) # We use this to count up our results
# Sorry for the confusing syntax. The items parameter of the Collection object
# is NOT the same as the items() method for dictionaries.
# float_collection.items is a list of your myFloats.
# the items() method for dictionary returns a dict_items object that you can iterate through.
# This loop tallies up all the results
for myFloatObj in float_collection.items:
for op, ct in myFloatObj.op_counts.items():
result_op_counts[op] += ct
# And this loop prints them.
for k,v in result_op_counts.items():
print(f"{k}: {v} operations") # Remove this line and use the one below if your python < 3.6
# print("{}: {} operations".format(k, v))
This outputs
### RESULTS ###
*: 227 operations
/: 247 operations
+: 275 operations
-: 250 operations

OOP - Call function containing instance of class within the same class

I am new to programming and have done some research on instance, class, and static variables. Lately, I have tried to simplify my code on my projects to help me learn more in Python. In this particular instance, no pun intended, I'd like to be able to call the somefoo() function that will assign arguments to the init instance variables one and two, depending on conditions. From my understanding, in order to call the somefoo() function, the Foo() class must be instantiated; however, the parameters the class requires are within the somefoo() function within that class. Thank you in advance!
import random
class Foo():
def __init__(self, one, two):
self.foobar = random.random()
self.one = one
self.two = two
def somefoo(self):
if self.foobar > 0.5:
one = ':)'
two = 1
Foo(one, two)
if self.foobar < 0.5:
one = ':('
two = 0
Foo(one, two)
somefoo()
To begin with, I don't even know if you have checked your code before posting it here for help because there is something really wrong with it. There are lot of syntax mistakes. This is how it's supposed to be...
import random
class Foo:
def __init__(self, one, two):
self.foobar = random.random()
self.one = one
self.two = two
def somefoo(self):
if self.foobar > 0.5:
one = ':)'
two = 1
Foo(one, two)
if self.foobar < 0.5:
one = ':('
two = 0
Foo(one, two)
somefoo()
There were parenthesis before the class name which were not required in python along with useless indents. Python is sensitive when it comes to indents so make sure your indents are meaningful, and use them logically. Now coming to your question; here is how it can be done:
import random
class Foo:
def __init__(self, one, two):
self.foobar = random.random()
self.one = one
self.two = two
self.somefoo()
def somefoo(self):
if self.foobar > 0.5:
self.one = ':)'
self.two = 1
if self.foobar < 0.5:
self.one = ':('
self.two = 0
def __str__(self):
return str(self.one)+" "+str(self.two)
print(Foo(10,20))
Basically the part where you are trying to call somefoo is not wrong and yes python does execute the class down to the bottom when it makes a object of it in memory, but in your code the method is of bound type (i.e. it needs and object for execution). So what you can do is use some sort of object factory pattern, or go with the one I have pasted above, in which as soon as object is generated, it calls the bound method which swipes the data of instance in question and displays the output. In python3 unbound methods are introduced which can be used without the self object reference. Make sure you look into them too and how they work, as they may help you to come with more flexible solution to your problems.

Resources