Undertanding OOP and static methods - python

I haven't coded in OOP ever before. I've some functions to handle and verify VAT numbers and I want to enclose them in a class (more later, with other classes for handle IBAN account numbers make a module or a package, I'm not sure yet what's the difference of both).
I take a VAT number (CIF in spanish terms) and, at first, I need to clean it from any other characters than digits and letters. Then validate the number.
Input:
h55/586-75 4
Desired Output:
H55586754
True
Real Output:
h55/586-75 4
False
My Code:
import re
class CheckingCIF:
_letras = "ABCDEFGHIJKLMNPQRSVW" # Not used yet.
def __init__(self, un_cif):
self.cif = un_cif
self._limpiarCIF()
def _limpiarCIF(self):
self.cif = re.sub('\W', "", self.cif.upper())
return self
def validarCodigoCIF(self):
if len(self.cif) != 9:
return False
numero = self.cif[1:10]
pares = int(numero[1]) + int(numero[3]) + int(numero[5])
impares = 0
for i in range(0, 8, 2):
j = int(numero[i]) * 2
if j < 10:
impares += j
else:
impares += j - 9
digito = str(pares+impares)[-1]
if int(digito) == 0:
checkCIF = 0
else:
checkCIF = 10 - int(digito)
if str(checkCIF) == self.cif[-1]:
return True
else:
return False
if __name__ == "__main__":
entradaCodigoCIF = input('Enter the VAT number: ')
mi_cif = CheckingCIF(entradaCodigoCIF)
print(mi_cif.cif)
print(CheckingCIF.validarCodigoCIF(mi_cif))
The problem isn't in the validarCodigoCIF(self) method, since I've test before and it works fine.
The issue probably is in the _limpiarCIF(self) method because my incomprehension of the Object Oriented Programming and the use of the self word and the static methods.

You don't have static methods, you have regular methods, but are not calling them on the instance:
entradaCodigoCIF = input('Enter the VAT number: ')
mi_cif = CheckingCIF(entradaCodigoCIF)
print(mi_cif.cif)
print(mi_cif.validarCodigoCIF())
Referencing the method on an instance gives you a bound method, an object that knows how to call the underlying function and pass in the instance as a first argument.

Related

function within f-string is returning the function outside the string, and returning None inside the string

I'm new to python and trying to do an f-string as follows:
next_patient = East_Room.get_highest_priority()
print(f"The next patient is {next_patient.display_symptoms()} please")
Where East_Room is an instance of a Class and get_highest_priority is a method within the class to display a patient with the highest integer for the 'severity' attribute as follows:
def get_highest_priority(self):
tmp_priority_patient = None
current_size = self.SLL_waiting_list.size()
counter = 1
while counter <= current_size:
tmp_node = self.SLL_waiting_list.get_node(counter)
tmp_patient = tmp_node.get_obj()
if tmp_priority_patient == None:
tmp_priority_patient = tmp_patient
else:
if tmp_patient.severity > tmp_priority_patient.severity:
tmp_priority_patient = tmp_patient
counter = counter + 1
return tmp_priority_patient
def display_symptoms(self):
print(f"{self.firstname} {self.lastname}:{self.symptoms}")
This is the output:
Conor : Naseau
The next patient is None please
I know that this method works as it works perfectly if I call it without the f-string. thanks for you help!
display_symptoms only prints information but doesn't return anything.
In Python, function that don't return anything return None, hence the output you got: "The next patient is None please"
If you also want the function to return this string, you have to explicitly return it:
def display_symptoms(self):
print(f"{self.firstname} {self.lastname}: {self.symptoms}")
return f"{self.firstname} {self.lastname}: {self.symptoms}"
An even better way to do it would be to make it a property:
#property
def display_symptoms(self):
return f"{self.firstname} {self.lastname}: {self.symptoms}"

How do I print all of the instances from a set of variables that are undefined from the beginning?

I have a program that I want to be able to print all of the instances of each variable using my method that I created. Problem is I can't figure out a way to print them since each are listed under a different variable that aren't configured from hardcoding them in and I need a way to automatically recall them in my code.
class fit:
def __init__(self,day,did,workout='Not Recorded',time='An unknown amount of',calories='An unknown amount of'):
self.day = day
self.did = did
if did.lower()=='no':
self.workout = 'Not Recorded'
self.time = "An unknown amount of Minutes"
self.calories = "An unknown amount of Calories"
else:
self.workout = workout
self.time = "{} Minutes".format(time)
self.calories = "{} Calories".format(calories)
def formate(self):
self.formate = "{}:\n\nDid you work out: {}\nWorkout focus: {}\nYou worked out for: {}\nYou burned: {}\n\n----------------------------------------------------------".format(self.day,self.did,self.workout,self.time,self.calories)
return self.formate
def reader(day,index):
file = open('readme.txt')
file = file.read()
stripped = file.rsplit("\n")
for i in range(len(stripped)):
stripped[i] = stripped[i].rsplit(" ")
del stripped[-1]
if int(index) >= len(stripped[day-1]):
return "none"
else:
return stripped[day-1][index]
x = 0
def create_new_instance(class_name,instance_name):
globals()[instance_name] = class_name(reader(x,0),reader(x,1),reader(x,2),reader(x,3),reader(x,4))
print('Class instance {} created'.format(instance_name))
while True:
try:
x+=1
ins = 'day_' + str(x)
create_new_instance(fit,ins)
except:
break
break
def printer(instance):
print(.formate())
while True:
x+=1
inst = 'day_' + str(x)
printer(inst)
An example of this might be that I have 8 lines of data from a text document and I have a system that creates instances of day_1, day_2, day_3 ect until day_8 and then I want to print each of those instances out, but again I don't have those instances directly hardcoded into my code so I don't know how I'd do it. I've tried looking into maybe a while loop and increasing a variable by 1 and concatenating it with day and trying to make a variable out of that but the my limited experience with python isn't helping.
A very unpythonic and ugly way would be to use exec, for example:
day_3=5
x = 'day_'+'3'
exec("print("+x+")")
I would recommend another way to store your variables though.

Python variable's value doesn't get changed outside the function

I'm working on a school project. I made a test version of my program, because I'm new to Python and I only have experience with C#, so I'm still learning te basics. My problem is the following:
Before the function "Fill_Array()" I declared a variable (" max_element_var") that is supposed to store the max number of elements that can be stored in the array ("content_array"). Later in the function I change it's value to the input of the console, which happens, and the function runs as it should, the only problem being is that outside the function the value of " max_element_var" stays "None". What should I do in order to fix this?
#__Test__#
def Test():
class Que:
def __init__(self, content, max_element ,actual_elements):
self.content = content
self.max_element = max_element
self.actual_elements = actual_elements
max_element_var = None
content_array = []
def Fill_array():
print("What should be the max number of elements that can be stored in the array? (Type in an integer!)")
max_element_var = int(input())
if(max_element_var>0):
import random
random_var = random.randrange(0,max_element_var)
for x in range(max_element_var-random_var):
content_array.append(x)
else:
print("It has to be more than 0!")
Fill_array()
Fill_array()
actual_elements_var = len(content_array)
que = Que (content_array, max_element_var, actual_elements_var)
print("Content: ", que.content)
print("Max number of elements: ", que.max_element)
print("Actual number of elements: ", que.actual_elements)
#__Test__#
#__Full__#
def Full():
pass
#__Full__#
#__Version_selector__#
def Version_selector():
print("Which version should be used? (Type in the number!)")
print("1 - Test")
print("2 - Full")
answer = int(input())
if(answer == 1):
Test()
Version_selector()
elif(answer == 2):
Full()
Version_selector()
#__Version_selector__#
Version_selector()
In python variables are automatically created as local, in the scope of the function which used them alone.
To solve your problem you may either
(1) return the variable, passing it from one function the other explicitly.
(2) declare it as global so all functions have access to it.
More about scopes here and here.
Consider the following code. In the code below you persumably change the value of x but in fact there is a big difference between the x inside the function and outside. The x inside the function is a local variable and will "disappear" once the function ends. If you want to save the value of x you must use return x and save the outcome to a variable. For example, See the function a_saving_example(x)
you may also use a global variable though some say it is bad practice and it is better to use return in your function.
def times_two(x):
x = x * 2
x = 5
print(x)
times_two(x)
print(x)
output:
5
5
saving example:
def a_saving_example(x):
x = x * 2
return x
x = 5
print(x)
x = a_saving_example(x)
print(x)
output:
5
10
Modified code to correct some issues.
Import normally done at top of module (not within functions)
Remove nested class definition inside function (obfuscates things in simple code)
Changed recursive calls to a while loop (a better way to repeat execution of a function from beginning in Python since no tail recursion).
Code Refactoring
import random
class Que:
def __init__(self, content, max_element ,actual_elements):
self.content = content
self.max_element = max_element
self.actual_elements = actual_elements
def Fill_array():
" Returns requested size and array "
while True:
prompt = """"What should be the max number of elements that can be stored in the array? Type in an integer!: """
max_element_var = int(input(prompt))
if max_element_var > 0:
random_var = random.randrange(0,max_element_var)
return max_element_var, [x for x in range(max_element_var-random_var)]
else:
print("It has to be more than 0!")
def Test():
max_element_var, content_array = Fill_array()
actual_elements_var = len(content_array)
que = Que (content_array, max_element_var, actual_elements_var)
print("Content: ", que.content)
print("Max number of elements: ", que.max_element)
print("Actual number of elements: ", que.actual_elements)
#__Test__#
#__Full__#
def Full():
pass
#__Full__#
#__Version_selector__#
def Version_selector():
while True:
prompt = """Which version should be used? (Type in the number!)
1 - Test
2 - Full
3 - Quit\n\t"""
answer = int(input(prompt))
if answer == 1:
Test()
elif answer == 2:
Full()
else:
break
#__Version_selector__#
Version_selector()

Python Prefix / Infix / Postfix expression evaluation

Little brief about the code:
I have to do a class that will evaluate prefix, postfix or infix expression. It has to determine whether it is pre/post/infix and convert them to postfix, for example prefixTOpostfix() (others are deleted as not needed now) method in the code which converts from '/x7' to 'x7/', the expression is edited in method edit() from 'x7/' to 'x 7 /'. Both methods work fine, tested on multiple examples (not posting here the whole code as it is and assignment, but also they are not needed. The question being asked is just an error I am getting, don't worry I am not asking for solution to my assignment). There is also assign method, because there can be variables, for example 'a = 3', and it can be somewhere in the expression.
Problem: When i run print(v.evaluate('x 7/')) (what is already in postfix), where x = 14, it returns 2 as it should. However when I run print(v.evaluate('/x 7')) (what is in prefix) it returns None. Both expressions look exactly the same after they ran through their methods 'x 7 /' (I had testing prints in the code), Both stacks are the same. First there is '14', then '14 7', and lastly '2'. When I change return(s.pop()) to return(s.top()), both expressions are evaluated fine as '2'. So why return(s.pop()) doesn't work with the second one ? If there are more questions about the code or something isn't clear enough, tell me I will try to explain it differently.
class MyClass:
class Stack:
...
def __init__(self):
self.table = {}
def __repr__(self):
...
def assign(self, variable, exp):
if '+-*/%' in exp: # temporary solution
exp = self.evaluate(exp)
self.table[variable] = exp
def evaluate(self, exp):
if exp[0] in '+-*/%': # Prefix
new_exp = self.prefixTOpostfix(exp)
self.evaluate(new_exp)
elif exp[len(exp)-1] in '+-*/%': # Postfix
s = self.Stack()
exp = self.edit(exp) # from 'x7/' to 'x 7 /'
for item in exp.split():
if item == '+':
s.push(s.pop() + s.pop())
... # other operations
elif prvok == '/':
temp = s.pop()
if temp == 0:
return None
s.push(s.pop() // temp) # it has to be // !
else: # if it is number / variable
if item in self.table:
s.push(int(self.table[item]))
else:
s.push(int(item))
s.printOUT()
return(s.pop())
else: # Infix
...
def prefixTOpostfix(self, exp):
...
def edit(self, exp):
...
if exp[0] in '+-*/%': # Prefix
new_exp = self.prefixTOpostfix(exp)
self.evaluate(new_exp)
You need to return the result of your recursive call.
if exp[0] in '+-*/%': # Prefix
new_exp = self.prefixTOpostfix(exp)
return self.evaluate(new_exp)

How to deal with large csv file in python?

I have CSV file that contains a data of 40k rows.
My each function open csv file and works with it and then close it.
Is there a way that I can open the file once and then close it and I can work with it whenever I want? I tried to put each field in a separate list and work whit it whenever I call it or in dictionary but both methods works good up to 1k row if more then it takes long time to processes it, I found a way to speed up by filtering them, but not sure how to apply it.
sample of my codes.
files=open("myfile.csv","r")
def spec_total():
total = 0.0
files.readline() # skip first row
for line in files:
field=line.strip().split(",") #make Into fields
tall=float(field[0])
if tall >= 9.956:
total +=tall
print("The sum is: %0.5f" % (total))
spec_total()
files.close()
other function
files=open("3124749c.csv","r")
def code():
match= 0
files.readline() # skip first row
for row in files:
field=row.strip().split(",") #make Into fields
code=(field[4])
import re
if re.search(r'\[[A-Za-z][0-9]+\][0-9]+[A-Za-z]{2}[0-9]+#[0-9]+', code) is None:
match += 1
print("The answer that do not match code is :",match)
code()
files.close()
and there is plenty more functions that opens each time the csv file and split them into field in order to recognise which field I am referring to.
If I understand correctly try:
import csv
total = 0.0
for row in csv.reader(open("myfile.csv")):
tall = float(row[0])
if tall >= 9.956:
total += tall
print("The sum is: %0.5f" % total)
More complex version - create calculation classes for processing each row.
class Calc(object):
def process(self,row):
pass
def value(self):
pass
class SumColumn(Calc):
def __init__(self, column=0,tall=9.956):
self.column = column
self.total = 0
def process(self, row):
tall = float(row[0])
if tall >= self.tall:
self.total += tall
def value(self):
return self.total
class ColumnAdder(Calc):
def __init__(self, col1, col2):
self.total = 0
self.col1 = col1
self.col2 = col2
def process(self, row):
self.total += (row[self.col1] + row[self.col2])
def value(self):
return self.total
class ColumnMatcher(Calc):
def __init__(self, col=4):
self.matches = 0
def process(self, row):
code = row[4]
import re
if re.search(r'\[[A-Za-z][0-9]+\][0-9]+[A-Za-z]{2}[0-9]+#[0-9]+', code) is None:
self.match += 1
def value(self):
return self.matches
import csv
col0_sum = SumColumn()
col3_sum = SumColumn(3, 2.45)
col5_6_add = ColumnAdder(5,6)
col4_matches = ColumnMatcher()
for row in csv.reader(open("myfile.csv")):
col0_sum.process(row)
col3_sum.process(row)
col5_6_add.process(row)
col4_matches.process(row)
print col0_sum.value()
print col3_sum.value()
print col5_6_add.value()
print col4_matches.value()
This code was typed into SO, which was a tedious affair - so bare with on syntax etc.
For illustration purposes only - not to be taken too literally.
All is object in Python: that means functions too.
So there is no need to define special classes to craft functions as instances of these classes as sotapme does, since every function we define is already an object in the sense of 'instance of a class'.
Now, if someone needs to create several functions of the same type, for example each of them adds all the values of a precise CSV file's column, that's right that it's interesting to create these many functions by a repeating process.
At this point, raises the question: using function factory or class ?
Personnaly, I prefer the function factory way because it is less verbose.
I also discovered in the Theran's answer HERE that it's also faster.
In the following code, I use a trick with globals() to give a particular name to each function created by means of a function factory. Some will say it's bad, but I don't know why. If there's another way to do the same , I will be happy to learn it.
In the code, 3 functions are build by a function factory, and I let one defined by plain normal definition (op3).
Python is fantastic!
import csv
import re
# To create a CSV file
with open('Data.csv','wb') as csvhandle:
hw = csv.writer(csvhandle)
hw.writerows( ((2,10,'%%',3000,'-statusOK-'),
(5,3,'##',500,'-modo OOOOKKK-'),
(1,60,'**',700,'-- anarada-')) )
del hw
# To visualize the content of the CSV file
with open(r'Data.csv','rb') as f:
print "The CSV file at start :\n "+\
'\n '.join(map(repr,csv.reader(f)))
def run_funcs_on_CSVfile(FUNCS,CSV):
with open(CSV,'rb') as csvhandle:
for f in FUNCS:
# this is necessary for functions not created via
# via a function factory but via plain definition
# that defines only the attribute col of the function
if 'field' not in f.__dict__:
f.field = f.col - 1
# columns are numbered 1,2,3,4,...
# fields are numbered 0,1,2,3,...
for row in csv.reader(csvhandle):
for f in FUNCS:
f(row[f.field])
def SumColumn(name,col,start=0):
def g(s):
g.kept += int(s)
g.kept = start
g.field = col -1
g.func_name = name
globals()[name] = g
def MultColumn(name,col,start=1):
def g(s):
g.kept *= int(s)
g.kept = start
g.field = col - 1
g.func_name = name
globals()[name] = g
def ColumnMatcher(name,col,pat,start = 0):
RE = re.compile(pat)
def g(s,regx = RE):
if regx.search(s):
g.kept += 1
g.kept = start
g.field = col - 1
g.func_name = name
globals()[name] = g
SumColumn('op1',1)
MultColumn('op2',2)
ColumnMatcher('op4',5,'O+K')
def op3(s):
s = int(s)
if s%2:
op3.kept += (2*s)
else:
op3.kept += s
op3.kept = 0
op3.col = 4
print '\nbefore:\n ' +\
'\n '.join('%s.kept == %d'
% (f.func_name, f.kept)
for f in (op1,op2,op3,op4) )
# The treatment is done here
run_funcs_on_CSVfile((op2,op3,op4,op1),r'Data.csv')
# note that the order of the functions in the tuple
# passed as argument can be any either one or another
print '\nafter:\n ' +\
'\n '.join('%s(column %d) in %s.kept == %d'
% (f.func_name, f.field+1, f.func_name, f.kept)
for f in (op1,op2,op3,op4) )
.
result
.
The CSV file at start :
['2', '10', '%%', '3000', '-statusOK-']
['5', '3', '##', '500', '-modo OOOOKKK-']
['1', '60', '**', '700', '-- anarada-']
before:
op1.kept == 0
op2.kept == 1
op3.kept == 0
op4.kept == 0
after:
op1(column 1) in op1.kept == 8
op2(column 2) in op2.kept == 1800
op3(column 4) in op3.kept == 4200
op4(column 5) in op4.kept == 2

Categories

Resources