A simple Python program to study classes - python-3.x

For the sake of studying the concept of classes in Python, I have written a program which is meant to calculate the average of a tuple of numbers. However, the program returns an error message which is quoted.
#!/usr/bin/python3
"""
Python program to calculate the average value of
a set of integers or float numbers.
Input format: a tuple, e.g. (1,2,3)
When run, the program generates an error message in line 27
"""
class Mean_value():
def __init__(self, operand):
self.operand = operand
def calculate_average(self, operand):
self.operand = operand
all_in_all = sum(operand)
nmbr = len(operand)
average = all_in_all/nmbr
self.average = average
return self.average
operand = input("Key in numbers as a tuple: ")
print(operand) #temp, the operand is taken in by the program
x = Mean_value.calculate_average(operand) #line 27
print(x)
The error message:
Traceback (most recent call last):
File "D:\Python\Exercise76a.py", line 27, in <module>
x = Mean_value.calculate_average(operand)
TypeError: calculate_average() missing 1 required positional argument: 'operand'
I would highly appreciate any hints from members more experienced than myself.

Any method in your class with self as the first parameter is an instance method, meaning it's supposed to be called on an instance of the class and not on the class itself.
In other words, the self parameter isn't just for show. When you do this:
x = Mean_value(operand)
x.calculate_average(operand)
the python interpreter actually takes x and passes it through to the function as the first parameter (i.e. self). Hence, when you try to call calculate_average() on the class Mean_value instead of on an object of that type, it only passes one of the two required parameters (there's no instance to pass automatically as self, so it just passes the one argument you've given it, leaving the second argument unspecified).
If you want to have a method be static (called on the class instead of on an instance of the class), you should use the #staticmethod decorator on the method in question, and omit the self parameter.

Another way to fix this error is to make your calculate_average method static. Like this:
#staticmethod
def calculate_average(operand):
# but be careful here as you can't access properties with self here.
all_in_all = sum(operand)
nmbr = len(operand)
average = all_in_all/nmbr
return average

The program contains comments
#!/usr/bin/python3
"""
The program computes the average value of a sequence of positive integers,
keyed in as a tuple.
After entering the tuple, the input function returns a string,
e.g.(1,2,3) (tuple) --> (1,2,3) (string).
On screen the two objects look the same.
The major code block deals with reversing the type of the input,
i.e. string --> tuple,
e.g. (1,2,3) (string) --> (1,2,3) (tuple).
The maths is dealt with by the class Average.
"""
class Average:
def __init__(self, tup):
self.tup = tup
def calculate(self):
return sum(self.tup)/len(self.tup)
"""Major code block begins ----------"""
#create containers
L_orig_lst = []
S_str = ""
print("The program computes the average value of")
print("a sequence of positive integers, input as a tuple.\n")
#in orig_str store the string-type of the tuple keyed in
orig_str = input("Key in the numbers as a tuple:\n")
lnth = len(orig_str)
#copy each character from orig_str into the list L_orig_lst (the original list)
for i in range(lnth):
if orig_str[i] in ['(', '.', ',' , ')', '1', '2', '3','4', '5', '6', '7', '8', '9', '0']:
#if one of the characters left parenthesis, period, comma, right parenthesis or a digit
#is found in orig_str, then S_str is extended with that character
S_str = S_str + orig_str[i]
L_orig_lst.append(S_str)
#set S_str to be empty
S_str = ""
elif orig_str[i] == " ":
pass
else:
print("Error in input")
break
#at this stage the following transformation has taken place,
#tuple (string) --> tuple (list)
#e.g. (1,2,3) (string) --> ['(' , '1' , ',' , '2' , ',' , '3' , ')'], L_orig_lst
#create new container
#and set S_str to be empty
L_rev_lst = []
S_str = ""
lnth = len(L_orig_lst)
#from the original list, L_orig_lst, copy those elements which are digits (type string)
#and append them to the revised list, L_rev_lst.
for i in range(lnth):
if L_orig_lst[i] in ['1', '2', '3','4', '5', '6', '7', '8', '9', '0']:
#if the element in the original list is a digit (type string),
#then extend S_str with this element
S_str = S_str + L_orig_lst[i]
elif L_orig_lst[i] == ',':
#if the element in the original list is a comma, then finalize the reading of the number,
#convert the current number (type string) into an integer
S_int = int(S_str)
#and append the integer to the revised list
L_rev_lst.append(S_int)
#set S_str to be empty
S_str = ""
else:
pass
#also convert the last number (type string) to an integer,
S_int = int(S_str)
#and also append the last integer to the revised list
L_rev_lst.append(S_int)
#now convert the revised list into a tuple
T_tpl = tuple(L_rev_lst)
"""Major code block ends --------"""
#calculate the average for the tuple T_tpl
#call the class
x = Average(T_tpl)
#instantiate the class
y = x.calculate()
print("Average value: ", y)

Related

How to unpack input in Leetcode

I'm a newbie to programming and have solved a few questions in codechef and hackerrank. In those platforms,generally lists or elements in a list/array are given as a string of integers with spaces in them
eg: '5 4 6 7'
I can unpack them using an input().split() method in python
But in leetcode, I'm given an input of type
'[1,2,3,4], target=7'
I'm finding it hard to unpack these values from a string into a meaningful datatype. Could someone help me out here? [Context: Two sum problem in leetcode https://leetcode.com/problems/two-sum/]
I tried appending the odd indices of the string into a list
Input: nums = [2,7,11,15], target = 9
a=input()
l=[]
for i in range(len(a)):
if i%2!=0:
l.append(a[i])
print(l)
But I got the following output and the following error
Stdout ['2', '7', '1', ',', '5']
Runtime error
TypeError: 'int' object is not iterable
Line 19 in _deserialize (./python3/__deserializer__.py)
param_1 = des._deserialize(line, 'integer[]')
Line 25 in _driver (Solution.py)
_driver()
Line 43 in <module> (Solution.py)
I think what you're looking for is .split's sep keyword argument, which allows you to split from any character. This is usually defaulted to " " which is why you don't need to put it in every time.
Also as some others mentioned, you don't need to take any inputs, as the function is already taking inputs.
nums = nums[1:-1].split(sep=",")
If you did have to process an input like nums = [2,7,11,15], target = 9 my approach would be:
inp = input() # get input
inp = inp.replace("nums = ", "").replace("target = ", "") # remove the value names
nums, target = inp.split(sep=", ") # unpack items from list: [nums, target]
nums = nums[1:-1].split(sep=", ")
or just condense it down to:
nums, target = input().replace("nums = ", "").replace("target = ", "").split(sep=", ")
nums = nums[1:-1].split(sep=",")

Difference between lists direct assignment and slice assignment

I have:
def reverseString(self, s: List[str]) -> None:
s[:] = s[::-1] # Works
... and
def reverseString(self, s: List[str]) -> None:
s = s[::-1] # Doesn't work
Where s is a list of characters lets say s = ["k","a","k","a","s","h","i"]
While doing a question on leetcode it rejected when I used s = ... but accepted when I used s[:] = ... and also it was written that DO NOT RETURN ANYTHING but return s.reverse also worked.
This is actually a bit complex and requires two explanations.
First, a python function argument act as label on the passed object. For example, in the following code, arg is the local label (/name) attached to the initial list. When the label arg is re-used, for example by attaching it to a new object (17), the original list is not reachable anymore within function f.
On the other hand, outside of f, the list labeled L is still here, untouched:
def f(arg):
arg = 17
print(arg) # 17
L = ['a', 'list']
f(L)
print(L) # ['a', 'list']
That explains why the following function doesn't reverse your list in place:
def reverse_list(arg):
arg = arg[::-1]
print(arg) # ['list', 'a']
L = ['a', 'list']
reverse_list(L)
print(L) # ['a', 'list']
This function simply attach the label arg to a new list (that is indeed equal to the reversed list).
Secondly, the difference between arg[:] = ... and arg = ... is that the first will modify the content of the list (instead of attaching the label arg to a new object). This is the reason why the following works as expected:
def alt_reverse_list(arg):
arg[:] = arg[::-1]
L = ['a', 'list']
alt_reverse_list(L)
print(L) # ['list', 'a']
In this second example we say that the list has been mutated (modified in place). Here is a detailed explanation on slice assignments
For the same reason, calling arg.reverse() would have worked.
Identifying objects
Using the id() function can help figure out what is going on with the argument in the first example (where we don't mutate the list but affect a new value):
def reverse_list(arg):
print("List ID before: ", id(arg))
arg = arg[::-1]
print("List ID after: ", id(arg))
L = ['a', 'list']
print("Original list ID: ", id(L))
reverse_list(L)
print("Final list ID: ", id(L))
Which will print something like:
Original list ID: 140395368281088
List ID before: 140395368281088
List ID after: 140395368280447 <--- intruder spotted
Final list ID: 140395368281088
Here we can clearly see that after calling arg = arg[::-1] the object we are manipulating under the name arg is not the same. This shows why the function doesn't have any (side) effect.

How can I make an Enum that allows reused keys? [duplicate]

I'm trying to get the name of a enum given one of its multiple values:
class DType(Enum):
float32 = ["f", 8]
double64 = ["d", 9]
when I try to get one value giving the name it works:
print DType["float32"].value[1] # prints 8
print DType["float32"].value[0] # prints f
but when I try to get the name out of a given value only errors will come:
print DataType(8).name
print DataType("f").name
raise ValueError("%s is not a valid %s" % (value, cls.name))
ValueError: 8 is not a valid DataType
ValueError: f is not a valid DataType
Is there a way to make this? Or am I using the wrong data structure?
The easiest way is to use the aenum library1, which would look like this:
from aenum import MultiValueEnum
class DType(MultiValueEnum):
float32 = "f", 8
double64 = "d", 9
and in use:
>>> DType("f")
<DType.float32: 'f'>
>>> DType(9)
<DType.double64: 'd'>
As you can see, the first value listed is the canonical value, and shows up in the repr().
If you want all the possible values to show up, or need to use the stdlib Enum (Python 3.4+), then the answer found here is the basis of what you want (and will also work with aenum):
class DType(Enum):
float32 = "f", 8
double64 = "d", 9
def __new__(cls, *values):
obj = object.__new__(cls)
# first value is canonical value
obj._value_ = values[0]
for other_value in values[1:]:
cls._value2member_map_[other_value] = obj
obj._all_values = values
return obj
def __repr__(self):
return '<%s.%s: %s>' % (
self.__class__.__name__,
self._name_,
', '.join([repr(v) for v in self._all_values]),
)
and in use:
>>> DType("f")
<DType.float32: 'f', 8>
>>> Dtype(9)
<DType.float32: 'd', 9>
1 Disclosure: I am the author of the Python stdlib Enum, the enum34 backport, and the Advanced Enumeration (aenum) library.

Alien Dictionary Python

Alien Dictionary
Link to the online judge -> LINK
Given a sorted dictionary of an alien language having N words and k starting alphabets of standard dictionary. Find the order of characters in the alien language.
Note: Many orders may be possible for a particular test case, thus you may return any valid order and output will be 1 if the order of string returned by the function is correct else 0 denoting incorrect string returned.
Example 1:
Input:
N = 5, K = 4
dict = {"baa","abcd","abca","cab","cad"}
Output:
1
Explanation:
Here order of characters is
'b', 'd', 'a', 'c' Note that words are sorted
and in the given language "baa" comes before
"abcd", therefore 'b' is before 'a' in output.
Similarly we can find other orders.
My working code:
from collections import defaultdict
class Solution:
def __init__(self):
self.vertList = defaultdict(list)
def addEdge(self,u,v):
self.vertList[u].append(v)
def topologicalSortDFS(self,givenV,visited,stack):
visited.add(givenV)
for nbr in self.vertList[givenV]:
if nbr not in visited:
self.topologicalSortDFS(nbr,visited,stack)
stack.append(givenV)
def findOrder(self,dict, N, K):
list1 = dict
for i in range(len(list1)-1):
word1 = list1[i]
word2 = list1[i+1]
rangej = min(len(word1),len(word2))
for j in range(rangej):
if word1[j] != word2[j]:
u = word1[j]
v = word2[j]
self.addEdge(u,v)
break
stack = []
visited = set()
vlist = [v for v in self.vertList]
for v in vlist:
if v not in visited:
self.topologicalSortDFS(v,visited,stack)
result = " ".join(stack[::-1])
return result
#{
# Driver Code Starts
#Initial Template for Python 3
class sort_by_order:
def __init__(self,s):
self.priority = {}
for i in range(len(s)):
self.priority[s[i]] = i
def transform(self,word):
new_word = ''
for c in word:
new_word += chr( ord('a') + self.priority[c] )
return new_word
def sort_this_list(self,lst):
lst.sort(key = self.transform)
if __name__ == '__main__':
t=int(input())
for _ in range(t):
line=input().strip().split()
n=int(line[0])
k=int(line[1])
alien_dict = [x for x in input().strip().split()]
duplicate_dict = alien_dict.copy()
ob=Solution()
order = ob.findOrder(alien_dict,n,k)
x = sort_by_order(order)
x.sort_this_list(duplicate_dict)
if duplicate_dict == alien_dict:
print(1)
else:
print(0)
My problem:
The code runs fine for the test cases that are given in the example but fails for ["baa", "abcd", "abca", "cab", "cad"]
It throws the following error for this input:
Runtime Error:
Runtime ErrorTraceback (most recent call last):
File "/home/e2beefe97937f518a410813879a35789.py", line 73, in <module>
x.sort_this_list(duplicate_dict)
File "/home/e2beefe97937f518a410813879a35789.py", line 58, in sort_this_list
lst.sort(key = self.transform)
File "/home/e2beefe97937f518a410813879a35789.py", line 54, in transform
new_word += chr( ord('a') + self.priority[c] )
KeyError: 'f'
Running in some other IDE:
If I explicitly give this input using some other IDE then the output I'm getting is b d a c
Interesting problem. Your idea is correct, it is a partially ordered set you can build a directed acyclcic graph and find an ordered list of vertices using topological sort.
The reason for your program to fail is because not all the letters that possibly some letters will not be added to your vertList.
Spoiler: adding the following line somewhere in your code solves the issue
vlist = [chr(ord('a') + v) for v in range(K)]
A simple failing example
Consider the input
2 4
baa abd
This will determine the following vertList
{"b": ["a"]}
The only constraint is that b must come before a in this alphabet. Your code returns the alphabet b a, since the letter d is not present you the driver code will produce an error when trying to check your solution. In my opinion it should simply output 0 in this situation.

Why every value I am putting into List using Insert keyword has a data type String

"""
Why every value I am putting into List using Insert keyword has a data type String. Also inserted vale index -1 but the list is not arranged like that.
Please go through the Image Description
"""
enter image description here
lis = []
def takeinput():
x = int(input("Enter how many element you want to put into list"))
while x != 0:
lis.insert(-1,input())
x = x-1
return lis
takeinput()
type(lis[0])
insert doesn't change the datatype of what it inserts into the list. Integer remains integer, strings remain strings:
>>> lis = [1,2,3,4]
>>> lis.insert(-1, 5)
>>> lis
[1, 2, 3, 5, 4]
As you see above, your new value is at the second last index of the list.
I think that is unwanted.
Normally you would use append instead of insert to fill an array.
lis = []
new_var = 'foo'
if new_var not in lis:
lis.append(new_var)
# ['foo']
You store strings into the list because with
lis.insert(-1,input())
you insert the string of input() at the last element of your list.
input() ever gives a string.
If you want to have another datatype stored, you need to cast your input into this datatype before storing into your list.
lis = []
def takeinput():
x = int(input("Enter how many element you want to put into list"))
while x != 0:
new_item = input() # store input string
new_item = int(new_item) # cast it to int for example
lis.append(new_item) # append it to the list
x = x-1
return lis
takeinput()
type(lis[0])
In python you can store everything into lists.

Resources