Using Configparser to create objects of a class? - python

I'm a little stumped on how to do this.
Let's say I have a employees.ini file that looks like this:
[amber]
sex=female
age=29
location=usa
income=60000
debt=300
[john]
sex=male
age=19
location=usa
income=19000
debt=nan
I have a for loop to access each piece of information and assign to a variable.
from configparser import ConfigParser
config=ConfigParser()
config.read('employees.ini')
for section in config.sections():
name=section
sex=config[section]['sex']
age=config[section]['age']
location=config[section]['location']
income=config[section]['income']
debt=config[section]['debt']
I also have a class where each section can be accepted as an object:
class Users:
def __init__(self, name, sex, age, location, debt):
self.__name=name
self.__sex=sex
self.__age=age
self.__location=location
self.__income=income
self.__debt=debt
def foo(self):
do a thing
def bar(self):
do a different thing ...
My hope was to now be able to access amber.foo and john.bar. However, I'm struggling on how to pass the variables out of the for loop into the class before they are overwritten by the next iteration of the loop. I feel like I might be overthinking this one.
My thought was this would make the code much more user friendly as a bulk of the code could be left untouched and only the .ini would need to be updated when a new user is needed.
Thanks for any help you could give.

I would add a class method to parse the configuration file data into a new object.
class User:
def __init__(self, name, sex, age, location, debt):
self.__name=name
self.__sex=sex
self.__age=age
self.__location=location
self.__income=income
self.__debt=debt
#classmethod
def from_config(cls, name, config):
return cls(name, config['sex'], config['age'], config['location'], config['debt']
def foo(self):
do a thing
def bar(self):
do a different thing ...
Now the details of how to actually create an instance of User are abstracted away in the class itself; the code that iterates through the configuration need only pass the relevant data to the class method.
from configparser import ConfigParser
config=ConfigParser()
config.read('employees.ini')
users = [User.from_config(section, config[section]) for section in config.sections()]
Since your class uses the key names of configuration file as parameter names, you could just unpack the dict and use __init__ directly instead of defining a class method.
from configparser import ConfigParser
config=ConfigParser()
config.read('employees.ini')
users = [User(section, **config[section]) for section in config.sections()]

Related

How to get&handle a list of objects in another class?

So I have a very simple "Customer" class which only stores the name and creates an id:
import secrets
class Customer:
def __init__(self, name):
self.name = name
def get_id(self):
id = secrets.token_hex(20)
return id
In another class my objective is to create a list where all the instances of Customer are stored and in all the functions in the class I need to handle either the name or the id of those customers.
The two methods I've found so far are import gc and do something like this
for i in gc.get_objects():
if isinstance(i, Customer):
customer_list.append(i)
which I really dont understand and don't know if it works.
The other way I've found is to use getmembers(), but again I still have no idea about the syntax in using this function and how the name and the id will be stored.
Thanks in advance for any help!
a) In the following example I demonstrate a way to store object instances in a class variable (list) and access them throught that list. b) I think that your method get_id returns different id every time is called, so considering that you want only one id per customer I suggest to create the id inside __init__ and store it in a property.
import secrets
class Customer:
objects = []
def __init__(self, name):
self.name = name
self.id = secrets.token_hex(20)
Customer.objects.append(self)
Customer('A test')
Customer('B test')
Customer('C test')
for c in Customer.objects:
print(c.name, c.id)

Call function of class using a variable function call

I'm trying to call a function from a Class thats name will change depending on what type of enemy is being instantiated. How can I accomplish this?
My attempt was this: AssignClass.[self.Class](self)
but obviously that sintax makes no sense
class Creature:
def __init__(self, Name, Class):
self.Name = Name
self.Class = Class
# Using a variable function call to remove
# the need for a ton of 'if' statements
AssignClass.[self.Class](self)
# Basically automate doing this:
if self.Class = "Orc":
AssignClass.Orc(self)
elif self.Class = "Wizard"
AssignClass.Wizard(self)
class AssignClass:
def Orc(Creature):
Creature.Class='Orc'
Creature.Health=100
Creature.Mana=0
def Wizard(Creature):
Creature.Class='Wizard'
Creature.Health=75
Creature.Mana=200
Evil_Wizard = Creature("Evil Wizard", "Wizard")
You can retrieve class methods using getattr() and then just pass your Creature instance, e.g.:
class Creature:
def __init__(self, Name, Class):
self.Name = Name
self.Class = Class
getattr(AssignClass, Class)(self)
Btw. this is everything but a recommended style for Python classes, the least of which is that you're shadowing the Creature class in your AssignClass (which shouldn't be a class in the first place). I'd recommend you to read the PEP 8 -- Style Guide for Python Code thoroughly.
Played around a little more and found that I can use eval for this. (Safe as no user input can be added here)
class Creature:
def __init__(self, Name, Class):
self.Name = Name
self.Class = Class
eval('AssignClass.'+Class)(self)

Python - Abstract class subclassing

I'm trying to find the best for users of my python library to implement an abstract class I wrote.
Namely, my abstract class define an API to access specific values stored in a database, but I would like to let the user choose how to store it (simple text file, json, sqlite, etc.)
My problem is, how should I retrieve the class the user create and use it in my library ?
This is the solution I came up with, but I don't find it very graceful and wonder if there is a more pythonic way.
In my library:
from abc import ABC, abstractmethod
class Database(ABC):
#abstractmethod
def get(self, index):
pass
#abstractmethod
def insert(self, data):
pass
def get_database():
"""call this anywhere I need a concrete database class"""
return Database.__subclasses__()[-1]
In the user code
class SqliteDatabase(Database):
def get(self, index):
# sqlite SELECT and such
return data
def insert(self, data):
# sqlite INSERT INTO
# return data with index provided
return data
Of course, I will return a better error than IndexError if there is no subclass defined, but you get the idea.
Thank you in advance !
I finally settled for something else, as Blorgbeard suggested
_databases = {}
def register(dbname="default"):
def wrapper(klass):
_databases[dbname] = klass
return klass
return wrapper
def get_db(name="default"):
return _databases[name]
And the user only needs to declare
#register()
class SqliteDatabase:
def __get__(self, index):
# retrieve data
if data is None:
raise KeyError(index)
return data
This way, anybody can declare as many as databases as they want.
If you have improvements over this version, I'll gladly take them.

Python pass instance of itself as an argument to another function

I have a UserModel class that will essentially do everything like login and update things.
I'm trying to pass the instance of itself (the full class) as an argument to another function of another class.
For example: (obviously not the code, but you get the idea)
from Car import CarFactory
class UserModel:
def __init__(self,username):
self.username = username
def settings(self,colour,age,height):
return {'colour':colour,'age':age,'height':height}
def updateCar(self,car_id):
c = CarFactory(car_id, <<this UserModel instance>>)
So, as you can see from the very last line above I would like to pass an instance of UserModel to the CarData class, so when within the CarData class I can access the UserModel.settings(), however, I am unsure of the syntax. I could of course just do:
c = CarFactory(car_id,self.settings)
Any help would be grateful appreciated.
Thanks
c = CarFactory(car_id, self)
doesnt work?
on a side note it would be self.settings() not self.settings ... unless you define settings to be a property

Polymorphism or Inheritance or any other suggestion?

I trying my hands on python. I am trying to implement a crypto class which does enc/dec . In my crypto class i require user to pass 3 args to do the enc dec operations. Till now i was reading key from file and doing the operations. Now i want to provide a generate key function also. But problem is that to call generate keys i dont want user to provide any arguments while initiating the class.
So what essentially i am trying to achieve is that when the crypto class is instantiated without giving any arguments, i just want to expose generate_key function. and when all the 3 args are provided while instantiating class, I want to expose all other enc/dec functions but not key gen function.
I am not able to understand is it a polymorphism situation, or inheritance or should i just use 2 different classes one having generate keys and other for enc dec functions..
Please give me some suggestion about how can i handle this situation efficiently?
Example:
class crypto:
def __init__(self,id, val1):
self._id = id
self._val1 = val1
def encrypt(self):
""" encryption here """
def save(self):
""" save to file """
def load(self):
""" load from file"""
def decrypt(self):
""" decryption here"""
def gen_keys(self):
""" gen key here"""
So Now, when this crypto class is instantiate with no arguments, i just want to expose gen keys function. and if it is instantiated with the id and val1, then i want to expose all functions but not gen keys.
I hope this will provide some clarification about my question. Please suggest me how can i achieve this.
Thanks,
Jon
You want a factory with either inherited or duck-typed objects. For example:
class CryptoBasic(object):
def __init__(self, *args):
"""Do what you need to do."""
def basic_method(self, *args):
"""Do some basic method."""
class CryptoExtended(CryptoBasic):
def __init__(self, *args):
"""Do what you need to do."""
def extended_method(self, *args):
"""Do more."""
# This is the factory method
def create_crypto(req_arg, opt_arg=None):
if opt_arg:
return CryptoExtended(req_arg, opt_arg)
else:
return CryptoBasic(req_arg)

Categories

Resources