Context:
I developed a python script to be run on a remote linux server. Running using Python 3.6.1. The script worked but was very messy, and procedurally written as opposed to OO. So, I re-wrote this script into 2 different classes. One main class and a blueprint class for objects.
My script is a lot more complicated, i just simplified it for this question.
Desired Function:
Read values from CSV file. Create Objects from these values, 1 object per line. Do some calculations on the values on init'ing the object (in the objects class). Have these objects be accessible from the main class (Base class).
Problems:
I need some clarification on:
The main method is not running. Tried variants on the method call, like Base.main(), including the "if name" statement inside the Base class, and it complains about self not being defined
The "self" reference. Are my usages of this correct? For example: Adding the attribute "age" into the Person objects so you can access it with person.age for example. My method call "self.input_file_handling(Base.inputFilePath)" etc.
Script:
import csv
class Person:
def calculate_age(self):
self.age = 2017 - self.birthYear
def __init__(self, name, birthYear):
self.name = self.strip_characters(self, name)
self.birthYear = int(birthYear)
self.calculate_age()
class Base:
inputFilePath = "input.csv"
people = []
def main():
self.input_file_handling(Base.inputFilePath)
#More methods here
#staticmethod
def input_file_handling(input_file_path):
input_file_path = str(input_file_path)
with open(input_file_path, 'r') as csv_file:
csv_reader = csv.DictReader(csv_file)
for line in csv_reader:
name = line['Name']
age = line['age']
person = Person(name, age)
people.append(person)
if __name__ == '__main__':
main()
First the main method of Base class is not static because it use the self variable, so is necessary receive that.
If you want call the main method and use the self variable you need make something like that:
class Base:
def main(self):
pass
if __name__ == '__main__':
instance_of_base = Base()
instance_of_base.main()
You can call the input_file_handling method without using self, because it's static
Base.input_file_handling(Base.inputFilePath)
I think you need learn more about how python resolve static things and the class and object variables.
Python is not C. There is no main function that automagically executes.
The main method that you defined is inside Base class, but it doesn't accept an argument for the instance.
Either modify it so it accept it (ie self by the convention) or make it a static method.
Then in if __name__ == '__main__': either use Base().main() or Base.main(), depending on what approach you decided to take.
But you don't seem to need any of this, and only doing it for the sake of forcing Python to look/work as other languages (looking at you C++/Java). Python doesn't require you to have a class or a 'main' function/method to execute code.
Your code written in a Pythonic way would be: (Python3)
import csv
from time import time, gmtime
INPUT_FILE_PATH = "input.csv"
class Person:
def __init__(self, name, birth_year):
self.name = name.strip()
self.birth_year = birth_year
#property
def birth_year(self):
return self._birth_year
#setter.birth_year
def birth_year(self, value):
self._birth_year = value
self._age = gmtime(time()).tm_year - value
#property
def age(self):
return self._age
#setter.age
def age(self, value):
self._birth_year = gmtime(time()).tm_year - value
self._age = value
def input_file_handling(input_file_path):
people = []
with open(input_file_path, 'r') as csv_file:
csv_reader = csv.DictReader(csv_file)
for line in csv_reader:
people.append(Person(line['Name'], int(line['age'])))
return people
if __name__ == '__main__':
people = input_file_handling(INPUT_FILE_PATH)
You seem to come from a OOP-only language (C# maybe?).
Some tips:
Avoid globals when able for variables, use them for function definition, class definition and constants.
Do not use a new class to store functions that do not require it
Use lower case and '' for variable and function names, Use CamelCase for class names, use caps and '' for constants.
Use duck typing: do not check that a argument is of a given type, try to use it as if it was and handle throw exceptions if it isn't.
Properties ar your friends if you want to force a specific bahaviour at getting or setting a class attributes
If you do not understand somehting ask in the comments.
Related
I'm building a task manager and I want to use a complete-func that's going to do something with the instantiated and then call del and delete the instantiated class object. Is it possible? I'm trying hard to find a solution.
Tried to use a function from the class, and tried to find articles about this subject, but no success.
from datetime import date
class reg_task:
def __init__(self, what_to_do, date=date.today(), hour=None, tag=None, project="day to day task", priority=None, remind_time=None):
self.what_to_do = what_to_do
self.date = date
self.hour = hour
self.tag = tag
self.project = project
self.priority = priority
self.remind_time = remind_time
def __str__(self):
return f'task {self.what_to_do}, to-do-date - {self.date}'
def tasks_complete(self):
with open(r"C:\Users\Avi Fenesh\Desktop\python\tasks_project\archive\archive", "a") as archive:
archive.write(f"{str(self)} \n")
del self
The problem is with tasks_complete(). When I call the function it doesn't delete the instantiated class object.
That's because objects can't be garbage collected as long as someone holds a reference to them. Simply doing del self is not enough.
See: del self vs self.__del__() - and what is the proper way to cleanup in python?
Framework: Robot, Language: Python-3.7.1 Proficiency: Novice
I have a variable args=[] defined at class level. The values of the variables are being assigned from command prompt using module 'sys'
import sys
class Runner():
args = []
def argument_reader(self):
self.args = list(sys.argv)
def login(self):
return self.args[1], self.args[2]
I could print all the values of args as long as execution stays within the module. If I wanted to call the same values from other module, it does not return anything as the values are being cleared out from the memory. Since class variables are static by default in python, why system is not RETAINING the values?
cmd line>>py Runner.py testing test#123
For Example:
Calling method from same class:-
run = Runner()
run.argument_reader()
print(run.login())
Output>>> testing, testing#123
Calling the same method from another class:-
runn = Runner.Runner()
print(runn.login())
output>> IndexError: list index out of range
If you want a singleton-type value, change your code to look like this.
class Runner():
args = []
def argument_reader(self):
Runner.args = list(sys.argv)
def login(self):
return Runner.args[1], Runner.args[2]
Otherwise, you'll have to call argument_reader() on each instance.
I would like some advice on how to best design a class and it's instance variables. I initialize the class with self.name. However, the main purpose of this class it to retrieve data from an API passing self.name as a parameter, and then parsing the data accordingly. I have a class method called fetch_data(self.name) that makes the API request and returns ALL data. I want to store this data into a class instance variable, and then call other methods on that variable. For example, get_emotions(json), get_personality_traits(json), and get_handle(json), all take the same dictionary as a parameter, assign it to their own local variables, and then manipulate it accordingly.
I know I can make fetch_data(self.name) return data, and then call fetch_data(self.name) within the other methods, assign the return value to a local variable, and manipulate that. The problem is then I will need to call the API 5 times rather than 1, which I can't do for time and money reasons.
So, how do I make the result of fetch_data(self.name) global so that all methods within the class have access to the main data object? I know this is traditionally done in an instance variable, but in this scenario I can't initiliaze the data since I don't have it until after I call fetch_data().
Thank you in advance!
It seems like you just need to do something like this:
class Foo(object):
def __init__(self, name):
self.name = name
self.data = None
def fetch_data(self):
if self.data is None:
# Only call the API once
self.data = self.really_fetch_data()
return self.data
def get_emotions(self):
emotions = self.fetch_data().get("emotions")
...
Why don't you just try to solve this as you described?
For example, you can take this as a starting point:
import json
class APIBundle(object):
def __init__(self, name):
self.name = name
self.data = None
self.update()
def update():
response = json.loads(API_request(self.name))
# Do some parsing on response
self.data = response
def get_emotions():
# Work through current data state
# and filter as desired
result = []
for message in self.data['messages']:
if message.find(':)') != -1:
result.append((message, 'positive'))
if message.find(':(') != -1:
result.append((message, 'negative'))
return result
if __name__ == '__main__':
ab = APIBundle('my-secret-name')
print(self.get_emotions())
Try to do it with self.data=None , or make an instance variable and call whenever you need. writing algorithm will make this thing more complex try to solve issue with inbuilt functions or with algorithm program vulnerability will affect alot.
I have an issue with inheritance.
This is my main program:
def main(argv):
rfp = reqboxfileparserng() # Inherits from reqboxfileparser()
rfp.importsdir = './data/'
if rfp.parsingasutf8_win():
rfp.parsefile("./data/LRCv12.txt")
Here are the classes:
class reqboxfileparser():
def __init__(self):
... removed code ...
# Init mmap
self.file = None
self.f = None
def parsefile(self, filename):
# Public
self.filename = filename
# Init mmap
self.file = codecs.open(filename, encoding='utf-8', mode='r') # open(filename, 'r')
self.f = mmap.mmap(self.file.fileno(), 0, access=mmap.ACCESS_READ)
self.f.seek(0) # rewind
# Parsing stuff
self.getfunlist()
self.vlog(VERB_MED, "len(fun) = %d" % (len(self.funlist)))
self.getfundict()
self.vlog(VERB_MED, "fundict = %s" % (self.fundict))
... rest of reqboxfileparser() class code removed ...
class reqboxfileparserng(reqboxfileparser, object):
def __init__(self):
# Public
reqboxfileparser.__init__(self)
self.fundict = {}
self.importsdir = ''
def getfunlist(self):
"""
Overrided method to load from a CSV file
"""
self.funlist = []
fh = open(self.importsdir + 'in-uc-objects.csv', 'rb')
f = csv.reader(fh, delimiter=',')
... rest of the code removed, it works fine ...
def getfundict(self):
"""
Fills the fundict property with a dict where each element is indexed
by the fun name and each value is an object from the model
"""
self.__fundict = {}
beginloc = self.bodystartloc()
# PROBLEM!
finalloc = super(reqboxfileparser, self).f.size() - 1
... rest of the code removed ...
As you can see I have two classes, the first is reqboxfileparser() and the second one is reqboxfileparserng() which inherits from the first one.
On the main program I call the method: parsefile("./data/LRCv12.txt") [not overrided] which later calls getfundict() [overrided] on the second class, but when I try to access f.size() it always fails with TypeError: must be type, not classobj.
It's been a while since I don't develop classes with inheritance but if I'm not wrong the concepts are right. I'm newbie to Python.
Any help please?
Thanks a lot.
There are two issues at hand here:
Super and old-style classes:
class reqboxfileparser(): does not inherit from object, as a consequence, super(reqboxfileparser, self) will always yield the error:
TypeError: must be type, not classobj.
Improper super call in inheriting classes:
You're doing super(reqboxfileparser, self), but you're passing the inherited class (reqboxfileparser) as first argument, not the inheriting class.
As a consequence, Python would try to find a class that reqboxfileparser inherits from which implements what you're looking for you're looking for: f.
But that's not want you want: what you want an ancestor of reqboxfileparserng that implements f; that would be reqboxfileparser.
Please have a look at the documentation for the most common super call syntax.
Your solution
You probably guessed by now that you should be using super(reqboxfileparserng, self) instead.
Plus, you should always be using new-style classes (But that alone wouldn't solve your issue, you would get a different error complaining thatAttributeError: 'super' object has no attribute 'f', which would be True, as object does not provide f).
One last thing...
But here, you have one last issue!
You're trying to refer to f which is an attribute of the instance of the child class. This attribute is not present when you use the super call as it's not present in the class definition of the parent, which is the one the super call will use. (It's in the __init__ method)
I won't go into much more detail as to why this matters for super, but the idea is to basically use super only for stuff defined at class-level. Usually, methods are, so they're great candidates for super calls.
Here's an example describing what I mean:
class reqboxfileparser():
g = 'THIS IS G'
def __init__(self):
self.f = 'THIS IS F'
self.g = 'THIS IS NEW G'
def get_g(self):
return self.g
class reqboxfileparserng(reqboxfileparser, object):
def __init__(self):
reqboxfileparser.__init__(self)
def getfundict(self):
print super(reqboxfileparserng, self).g # Prints "THIS IS G"
print super(reqboxfileparserng, self).get_g() # Prints "THIS IS NEW G"
print super(reqboxfileparserng, self).f # This raises an AttributeError
if __name__ == '__main__':
o = reqboxfileparserng()
o.getfundict()
Overall, a super call is pretty similar to using ParentClass.stuff, only it deals with multiple inheritance better, and should be used for this reason.
You can see that here, reqboxfileparser.f would raise an AttributeError.
Footnote: a classobj is an old-style class, a type is a new-style class.
The point you're missing is that f is an attribute of the current class. It's inherited: when you call super(...).__init__(), the code sets f on self. So to access it from the subclass, you just do self.f, just like any other attribute.
The same is true of any attribute or method. You only need to use super when your subclass has actually overridden something, and you need to call the superclass's version. So there's no need to call super to get access to parsefile, for example: self.parsefile() would do fine.
I was trying to include my own functions in mainpage class, but when calling them it's not working at all, so what i did is to create a class for it and included that function in it. and in get () of mainpage class i created an instance for that class and called the function like object_name.function name() but it ain't working
class encipher:
def time_stomp():
t1=time.time()
dt = datetime.now()
dt.now()
stri=""
stri+=(str(dt.minute*dt.microsecond)[0:4])
stri+=(str(dt.second*dt.microsecond)[0:2])
stri+=(str(dt.microsecond)[0:3])
stri+=(str(dt.microsecond)[2:3])
stri+=(str(dt.microsecond)[1:2])
stri+=(str(dt.microsecond)[0:1])
return stri
#-------------------------------------------------------------
def keygen():
key_stri=""
ko=0
datalist_str1=self.time_stomp()
for i in range(6):
key_stri+=((hex(operator.xor(int(datalist_str1[ko:ko+2]),128)).replace("0x","")).zfill(2))
ko+=2
#print "Key:",key_stri
#print "Key:",key_stri
#print "Key:",key_stri
return key_stri
class MainPage(webapp.RequestHandler):
def get(self):
ddes=encipher()
global final_data_hex
global username
global filename
username = self.request.get("name")
filename=self.request.get("filename")
addr=self.request.get("mac")
path="d:/xampp/htdocs/encrypt/"+username+'/'+filename
f1 = open(path, 'r')
#f1=open(path,"r")
string=f1.read()
i=0
addr=addr.replace(":",'')
#self.response.out.write(ddes.keygen())
A python instance method needs to accept at least one parameter, self. "It's not working" is a horrible explanation of a problem; if you'd read your tracebacks you'd see an error about .keygen() accepting 0 arguments with 1 provided.
But yes, there's no reason to encapsulate methods in a class if what you really want is a function.
I figured it out. We can simply include functions out of the class and it will work perfectly.