Python How to Initialize Reader Object in Class Definition - python

I want to make a singleton class that gathers data from a csv file, and in order to do that, it needs to have a data member of type DictReader; but I am not sure how I would initialize this member in the class definition, as it can only be initialized like so:
with open('sourceFile.csv') as source:
reader = csv.DictReader(source)
Because Python will not allow you to declare variables without initialization, I need to know how I can initialize the reader object in the class Singleton.

Are you looking for something like:
class MySingleton(object):
def __init__(self, source):
self.my_reader = DictReader(source)
if __name__ == '__main__':
singleton = MySingleton(sourcefile)
for row in singleton.my_reader:
# do stuff

Related

Setting previously not pickleable attributes of a class during unpickling

I have classes that contain unpickleable attributes, e.g. COM interfaces. When I pickle the classes I can remove those attributes to make the whole instance of this class pickleable.
But when I unpickle the dumped data again, of course I want to re-establish those previously removed attributes. The easiest for me would be to provide the new values, e.g. the COM interfaces, as additional parameters to __setstate__() but of course this is not possible.
Is there another nice solution to this without setting all those attributes one by another from externally? Maybe something using __getnewargs__(), which I have not really understood yet?
Here is a minimal example:
import win32com.client as COM
import pickle
class Test:
def __init__(self, app):
self.app = app
def __getstate__(self):
attr = self.__dict__.copy()
# Remove the unpicklable entries.
attr['app'] = None
return attr
def __setstate__(self, attr):
self.__dict__.update(attr)
# FIXME: Re-establish COM interfaces here! Would be nice to provide
# app as parameter an do self.app = app here.
# This must be done outside the class since it is only that easy in this
# minimal example.
app = COM.Dispatch('designer.Application')
test = Test(app)
with open('Test.pickle', 'wb') as fid:
pickle.dump(test, fid)
with open('Test.pickle', 'rb') as fid:
test_new = pickle.load(fid)
# Of course now I could do
# test_new.app = app
# But this is cumbersome with a lot of such attributes to be set...
print(test.app, test_new.app)

How can you pass a user configurable dict into a class instance

I have a class that makes objects allowing me to access properties of an experimental camera system. I have some configuration properties saved in a dict for where certain cameras should be initially located. As these initial settings may vary I cannot hard code them into the class but need them separate in a text file that I access using the json library.
Is there a way to pass the dict into a class so its key value pairs can be used?
Simplified code
import any_dict_01
import json
data = any_dict_01
class dummy(data):
def __init__(self):
self.data = data
def getDict(self):
print(self.data)
a = dummy()
a.getDict()
Working Code
based on hints and advice from karl in the comments under the question I figured out how to do it (I hope karl puts his comments as an answer so I can accept it).
import json
data = 'my_rig.txt'
class dummy:
def __init__(self, data):
self.data = data
def getDict(self):
with open(data) as json_file:
data = json.load(json_file)
print(data)
a =dummy()
theDict = a.getDict(data)
By request:
data = any_dict_01 does not make data be any particular dict defined by the any_dict_01 module. It makes data be another name for that same module.
Anyway, this question isn't really about classes. The way you get information into the __init__ method is the same way that you get information into any ordinary function: by giving it a parameter, and passing the information in as an argument.
Your code would work by fixing the last part like this:
def __init__(self, data):
self.data = data
def getDict(self):
return self.data
a = dummy(data)
theDict=a.getDict()
You can make the dict accessible with dot notation, as if it were a class instance, like this.
class dummy:
def __init__(self, my_dict):
self.my_dict = my_dict

Python, main method not running (multiple classes in same file)

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.

How do I best store API data into a Python class instance variable?

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.

Field inheritance access in python

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.

Categories

Resources