basically I've got a booking class with fields each declared manually. I am curious if theres a more neat solution for the given task.
class Booking:
def __init__(self, json_data):
self.referenceNumber = json_data["referenceNumber"]
self.fromDate = json_data["fromDate"]
self.preferredDate1 = json_data["preferredDate1"]
self.preferredTimeFrom = json_data["preferredTimeFrom"]
self.time = json_data["time"]
self.partySize = json_data["partySize"]
self.budgetAmountTotal = json_data["budgetAmountTotal"]
self.budgetAmountPerPerson = json_data["budgetAmountPerPerson"]
self.budgetCurrencySign = json_data["budgetCurrencySign"]
self.venueName = json_data["venueName"]
self.venueId = json_data["venueId"]
self.cityName = json_data["cityName"]
self.clientName = json_data["clientName"]
self.clientContactName = json_data["clientContactName"]
self.status = json_data["status"]
self.statusText = json_data["statusText"]
self.assigneeId = json_data["assigneeId"]
self.assignee = json_data["assignee"]
self.lastAction = json_data["lastAction"]
self.inquiryChannel = json_data["inquiryChannel"]
self.venueDateFormat = json_data["venueDateFormat"]
self.bookingId = json_data["bookingId"]
self.inquiryHold = json_data["inquiryHold"]
self.isSpaceSelectedForHolds = json_data["isSpaceSelectedForHolds"]
self.id = json_data["id"]
bonus if i am not given an unresolved reference warning when I am calling for the attribute.
A simple self.__dict__.update(json_data) might do the trick.
Given the code in the question, access to attributes would be, for example, in the style of:
Booking().fromDate
However, if you don't mind accessing the value by its key name then you can greatly simplify the code as follows:
class Booking:
def __init__(self, json_data):
self._json = json.data
def __getitem__(self, key):
return self._json.get(key)
Then (for example)...
pd = {'fromDate': '2022/10/18'}
print(Booking(pd)['fromDate'])
How about this?
def set_attr_from_json(obj, json_data):
for key, value in json_data.items():
setattr(obj, key, value)
class Booking:
def __init__(self, json_data):
set_attr_from_json(self, json_data)
Since you want to control how your class attributes should be built, I think you should use metaclass like this
import json
from types import SimpleNamespace
class BookingMeta(type):
def __call__(self, json_data):
obj = super().__call__(json_data)
obj = json.loads(json.dumps(json_data), object_hook=lambda d: SimpleNamespace(**d))
return obj
class Booking(metaclass=BookingMeta):
def __init__(self, json_data):
pass
b = Booking({"name": {"first_name": "hello", "last_name": "world"}, "age": 23, "sub": ["maths", "Science"]})
print(b.name.first_name)
print(b.age)
#hello
#23
First thing first - upon suggestions, please do your best to be understandable for newbies as if it is too complex, it may not be much useful as I need to furtherly continue after the current ask. Thank you in advance for that :)
I'm trying to define an object with multiple variables that I may use.
So far I was able to create the basic class for myself (with just ID of the object), but I am now struggling to add the rest of the variables needed for the object.
The data that I have to store with the multiple instance of the object is as follows:
id of the user - this is the value thru which I need to be searching thru the objects as I will have multiple entries of the below example data for different time intervals that I need to count. It does not need to be changed within the objects variables.
Name - The name of the person for whom I will be counting the hours spent. It is static (does not need to be changed within the objects variables).
Started timestamp and Ended timestamp - The time within which the person has executed things. As I will have multiple instances of data coming towards the object, I need to check for overlapping of shifts and if so, such hours to be avoided, but if extra hours beside the overlapped - to be added. E.g. if overlapping is not a perfect match, then the additional time spent to be added to the "total spent hours". The data received for both timestamps are in format that I convert into datatime with "datetime.strptime(start, '%Y-%m-%dT%H:%M:%S+02:00')
Schedule ID - it is the ID of the entry for the started and ended timestamps. It may be saved as an array as it will not be used except for reporting purposes - e.g. the person has processed things during it's first shift (start_timestamp thru end_timestamp).
Array of contacts that I need to separate to two different values - one for e-mail, other for phone number (including country code). The array returns as [email, country_code, phone_number]
Quote of example data that I have:
PersonID: ID1234
Name: Anton Todorov
Started at: 2022-12-26T00:00:00+02:00
Ended at: 2022-12-26T02:00:00+02:00
Schedule ID: SCHEDID1
Contacts: ['a.todorov#e-mail.email', 359, '000000000']
---===Separator===---
PersonID: ID5678
Name: Morgan Freeman
Started at: 2022-12-26T02:00:00+02:00
Ended at: 2022-12-26T14:00:00+02:00
Schedule ID: SCHEDID2
Contacts: ['slogan#draftkings.com', 1, '0000000000']
---===Separator===---
PersonID: ID1234
Name: Anton Todorov
Started at: 2022-12-26T14:00:00+02:00
Ended at: 2022-12-27T02:00:00+02:00
Schedule ID: SCHEDID3
Contacts: ['a.todorov#e-mail.email', 359, '000000000']
So with that on, I have to calculate the total hours that each person has spend from within these sections of data that I have.
The object that I have so far is as follows:
class DataItem(object):
def __init__(self, person_id):
self._person_id = person_id
self._updatable_id = ""
#property
def person_id(self):
return self._person_id
#property
def updatable_id(self):
return self._updatable_id
#updatable_id.setter
def updatable_id(self, value):
self._updatable_id = value
#updatable_id.deleter
def updatable_id(self):
del self._updatable_id
class Persons(object):
def __init__(self):
self._ids = []
def find_person_by_id(self, person_id):
# search by id
existing = [i for i in self._ids if i.person_id == person_id]
if not existing:
# create and append
existing_person = DataItem(id)
self._ids.append(existing_person)
else:
# assign to existing
existing_person = existing[0]
# return the object to be acted upon
return existing_person
So.. Would someone be able to assist me with furtherly developing the object so that I may be storing the data properly inside of each of its instances, please?
I would gladly appreciate all detailed suggestions (especially as soon as I am also able to understand them).
Thank you all in advance!
I finally developed what I was looking for.
A bit messy, but that does exactly what I need.
Thanks to #Robert Lee for the attempt, despite it was not what I chose to continue with.
class PersonData(object):
def __init__(self, email, country_code, phone_number, user_id, names):
self._email = email
self._country_code = country_code
self._phone_number = phone_number
self._user_id = user_id
self._names = names
self._started = []
self._ended = []
self._schedule_id = []
#property
def email(self):
return self._email
#property
def country_code(self):
return self._country_code
#property
def phone_number(self):
return self._phone_number
#property
def user_id(self):
return self._user_id
#property
def names(self):
return self._names
#property
def started(self):
return self._started
#started.setter
def started(self, started):
self._started.append(started)
#started.deleter
def started(self):
del self._started
#property
def ended(self):
return self._ended
#ended.setter
def ended(self, ended):
self._ended.append(ended)
#ended.deleter
def ended(self):
del self._ended
#property
def schedule_id(self):
return self._schedule_id
#schedule_id.setter
def schedule_id(self, schedule_id):
self._schedule_id.append(schedule_id)
#schedule_id.deleter
def schedule_id(self):
del self._schedule_id
class PeopleBuffer(object):
def __init__(self):
self._people = []
def find_by_id(self, email, country_code, phone_number, user_id, names):
# search by id
existing = [i for i in self._people if i.user_id == user_id]
if not existing:
# create and append if not found
existing_person = PersonData(email, country_code, phone_number, user_id, names)
self._people.append(existing_person)
else:
# assign to existing
existing_person = existing[0]
# return an object to be acted upon
return existing_person
def return_all(self):
for each_person in self._people:
print("each_person: ")
print("Email: %s" % each_person.email)
print("Country Code: %s" % each_person.country_code)
print("Phone Number: %s" % each_person.phone_number)
print("User Id: %s" % each_person.user_id)
print("Names: %s" % each_person.names)
print("Started: %s" % each_person.started)
print("Ended: %s" % each_person.ended)
print("ScheduleId: %s" % each_person.schedule_id)
class MainApplication(object):
def __init__(self):
self._buffer = PeopleBuffer()
def _populate_person(self, email, country_code, phone_number, user_id, names, started, ended, schedule_id):
person = self._buffer.find_by_id(email, country_code, phone_number, user_id, names)
person.started.append(started)
person.ended.append(ended)
person.schedule_id.append(schedule_id)
def _print_people(self):
self._buffer.return_all()
def main(self):
while input("Continue? ") != "No":
user_id = input("Enter UserId: ")
names = input("Enter Name: ")
started = input("Enter Started: ")
ended = input("Enter Ended: ")
schedule_id = input("Enter ScheduleId: ")
email = input("Enter Email: ")
country_code = input("Enter CountryCode: ")
phone_number = input("Enter PhoneNumber: ")
self._populate_person(email, country_code, phone_number, user_id, names, started, ended, schedule_id)
self._print_people()
def main():
app = MainApplication()
app.main()
if __name__ == '__main__':
main()
Based on what you are doing I would consider doing json data format and do something like this. Please excuse my quick and dirty code but I think fundamentally you are looking for a way to create a data format that might work for your scenario.
Looking over it one more time, I feel like this might be the format you are looking for
[
{
"person_id": "ID1234",
"name": "Anton Todorov",
"schedule": [
{
"schedule_id": "SCHEDID1",
"started_at": "2022-12-26T00:00:00+02:00",
"ended_at": "2022-12-26T02:00:00+02:00"
},
{
"schedule_id": "SCHEDID3",
"started_at": "2022-12-26T14:00:00+02:00",
"ended_at": "2022-12-27T02:00:00+02:00"
}
],
"contact_info": {
"email": "a.todorov#e-mail.email",
"country_code": 359,
"phone_number": "000000000"
}
},
{
"person_id": "ID5678",
"name": "Morgan Freeman",
"schedule": [
{
"schedule_id": "SCHEDID2",
"started_at": "2022-12-26T02:00:00+02:00",
"ended_at": "2022-12-26T14:00:00+02:00"
}
],
"contact_info": {
"email": "slogan#draftkings.com",
"country_code": 1,
"phone_number": "000000000"
}
}
]
Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
def main():
people = list()
person = dict()
person['person_id'] = 'ID1234'
person['name'] = 'Anton Todorov'
person['schedule'] = list()
schedule = dict()
schedule['schedule_id'] = 'SCHEDID1'
schedule['started_at'] = '2022-12-26T00:00:00+02:00'
schedule['ended_at'] = '2022-12-26T02:00:00+02:00'
person['schedule'].append(schedule)
schedule = dict()
schedule['schedule_id'] = 'SCHEDID3'
schedule['started_at'] = '2022-12-26T14:00:00+02:00'
schedule['ended_at'] = '2022-12-27T02:00:00+02:00'
person['schedule'].append(schedule)
contact_info = dict()
contact_info['email'] = 'a.todorov#e-mail.email'
contact_info['country_code'] = 359
contact_info['phone_number'] = '000000000'
person['contact_info'] = contact_info
people.append(person)
person = dict()
person['person_id'] = 'ID5678'
person['name'] = 'Morgan Freeman'
person['schedule'] = list()
schedule = dict()
schedule['schedule_id'] = 'SCHEDID2'
schedule['started_at'] = '2022-12-26T02:00:00+02:00'
schedule['ended_at'] = '2022-12-26T14:00:00+02:00'
person['schedule'].append(schedule)
contact_info = dict()
contact_info['email'] = 'slogan#draftkings.com'
contact_info['country_code'] = 1
contact_info['phone_number'] = '000000000'
person['contact_info'] = contact_info
people.append(person)
print(json.dumps(people, indent=4))
if __name__ == '__main__':
main()
First things first; Your example feels more like a Java example written in Python. Instance variables are in practice properties, so all of your #property methods is redundant code.
dataclasses module is implemented for cases like yours. For example,
Schedule data class:
# schedule.py
from dataclasses import dataclass, field
from datetime import datetime
from typing import Union
#dataclass(unsafe_hash=True)
class Schedule:
schedule_id: str
start: Union[str, datetime]
end: Union[str, datetime]
def __post_init__(self):
self.start = self._datetime_converter(self.start)
self.end = self._datetime_converter(self.end)
def _datetime_converter(self, dt: str):
return datetime.strptime(dt, '%Y-%m-%dT%H:%M:%S+02:00')
def overlaps_with(self, other: Schedule):
return not ((self.start >= other.end) ^ (other.start >= self.end))
#property
def deltatime(self):
return self.end - self.start
Worker data class:
# worker.py
from functools import reduce
from dataclasses import dataclass, field
from .schedule import Schedule
#dataclass
class Worker:
person_id: str
name: str
contacts: str = field(repr=False)
schedules: set[Schedule] = field(init=False, default_factory=set)
email: str = field(init=False, default='')
country: int = field(init=False, default=-1)
phone: str = field(init=False, default='')
def __post_init__(self):
self.email, self.country, self.phone = self.contacts
#classmethod
def add_from_json(cls, worker_id: str, file: str):
NotImplemented
def overlapping_schedules(self, schedule: Schedule):
return filter(lambda s: s.overlaps_with(schedule), self.schedules)
def schedule_overlaps(self, schedule: Schedule):
return any(self.overlapping_schedules(schedule))
def add_schedule(self, schedule: Schedule):
if not self.schedule_overlaps(schedule):
self.schedules.update({schedule})
else:
NotImplemented
def add_schedules_from_json(self, file: str):
NotImplemented
def remove_schedule(self, schedule: Schedule):
self.schedules -= {schedule}
#property
def total_time_scheduled(self):
deltas = map(lambda s: s.deltatime, self.schedules)
return reduce(lambda x, y: x + y, deltas)
def __hash__(self):
return hash(id(self.person_id))
def __eq__(self, other):
return self.person_id == other.person_id
In theory you don't really need to create a Workers class. The methods __hash__ and __eq__ take care of that and you just need to create a set[Worker]. However, if you still want to create a Workers class, just loop over the existing methods.
I am starting to learn about object-oriented programming and I'm having a rough time with it.
I have some questions about it:
class Record:
"""Represent a record."""
def __init__(self, category, name, value):
self._category = category
self._name = name
self._value = value
# 1. Define the formal parameters so that a Record can be instantiated
# by calling Record('meal', 'breakfast', -50).
# 2. Initialize the attributes from the parameters. The attribute
# names should start with an underscore (e.g. self._amount)
#property
def amount (self):
return self._value
# Define getter methods for each attribute with #property decorator.
# Example usage:
# >>> record = Record('meal', 'breakfast', -50)
# >>> record.amount
# -50
class Records:
"""Maintain a list of all the 'Record's and the initial amount of money."""
def __init__(self):
# 1. Read from 'records.txt' or prompt for initial amount of money.
# 2. Initialize the attributes (self._records and self._initial_money)
# from the file or user input.
self._records =[]
self._money = 0
fh = open(file='records.txt', mode='r')
if ',' not in i:
self._money = int(i.strip())
else:
raw_line = i.strip()
category, activity, value = raw_line.split(',')
x = Record(category, activity, value)
self._records.append(x)
print("Welcome back!")
fh.close()
#property
def view(self):
for i in self._records:
print(Record._category)
#1. Print all the records and report the balance.
x = Records()
Records.view()
I wanted to print out value from my newly acquired list but I don't know how to pass my data from class Records to class Record for processing. How should I approach this?
I've searched for couple days now but couldn't find anything so maybe it's not possible.
As in topic, is there a way for a dict to "inherit" from a class so all the methods and properties are visible via "intelisens" ?
Example
class Word(object):
def __init__(self, word):
self.word = word
self.base_word = ''
self.derived_words = set()
self.sub_words = set()
self.frequency = 0
def method_1(self):
do something here
def method_2(self):
do something else here
myDict['computer'] = Word('computer')
myDict['notebook'] = Word('notebook')
and then i can obviously do this and it will work
mydict['computer'].method_2()
mydict['notebook'].frequency = 12
but i'd like to know if there is a way to make myDict object know that this methods and properties of the object are available and they would show up in "intelisense".
Picture Example
I'm using PyCharm.
Best regards
Bartek
PyCharm does support type hinting. I'm assuming you are using Python 2.7 since you are inheriting object. I have 3 ways you could do this in Python 2.7.
1
myDict['computer'] = Word('computer')
computer1 = myDict['computer'] # type: Word
2
computer2 = myDict['computer']
""":type : Word """
Now when you use computer1 or computer2 you should get the drop down that you like.
3
If your dictionary always returns a Word object you could create a dict object which inherits from dict, and make a function which returns Word type using rtype in the method docstring.
class Word(object):
def __init__(self, word):
self.word = word
def foo(self):
return self.word
class FooDict(dict):
def __init__(self, *arg, **kw):
super(FooDict, self).__init__(*arg, **kw)
def get_item(self, item):
"""
My docstring.
:return: a class of the type I want.
:rtype: Word
"""
return self[item]
a = Word("foo")
d = FooDict()
d['computer'] = a
computer3 = d.get_item('computer')
Now computer3 should behave how you like.
Reposting user2235698 answer from comment to my first post, for future googlers
Just add type hint to d definition.
It will be like d = {} # type: typing.Dict[str, Word] or d: typing.Dict[str, Word] = {} (since Python 3.6) – user2235698 21 hours ago
so now code looks like this:
import typing
class Word():
def __init__(self, word):
self.word = word
self.base_word = ''
self.derived_words = set()
self.sub_words = set()
self.meaning = ''
self.reading = ''
self.frequency = ''
self.sub_chars = set()
def analyze_sub_words(self):
print('working')
myComputer = Word('computer')
d: typing.Dict[str, Word] = {}
d['computer'] = myComputer
# now hints are being displayed
d['computer'].base_word
I am working on a small module.
I have a class called pricelist. It contains the attributes prefix and price.
class pricelist:
def setPrefix(self,prefix):
self.prefix = prefix
def setPrice(self,price):
self.price = price
def getPrefix(self):
return self.prefix
def getPrice(self):
return self.price
def getPrefixLength(self):
return len(self.prefix)
I have created a list of pricelist objects.
now i want to perform the operation, where when i give a phone number as input, i want to find prefix of the number and the corresponding price related to the prefix.
Example:
prefix price
46 2.0
44 3.0
.
.
.
.
when i give the input say "46 7223232323", it should return the price corresponding to it.
I am new to python and python classess, so can you please help me out with the logic of this
Keep the prefixes and prices in a dict:
self.data = {"46": 2.0,"44":3.0}
inp = "46 7223232323"
get_pre = inp.split()[0]
print (self.data.get(get_pre))
2.0
class Pricelist:
def __init__(self):
self.data = {"46": 2.0,"44":3.0}
p = Price_list()
inp = "46 7223232323"
get_pre = inp.split()[0]
print (p.data.get(get_pre,"Sorry that is an invalid prefix")) # if the prefix does not exist, it will output "Sorry that is an invalid prefix"
You can access attributes directly without getters and setters:
class Price_list:
def __init__(self,prefix,price):
self.prefix = prefix
self.price = price
self.pre_len = len(self.prefix)
p = Price_list("46", "4.99")
print (p.prefix, p.price, p.pre_len)
You can use data as a class attribute and add all instance attributes to it:
class Price_list:
data = {}
def __init__(self, prefix, price):
self.prefix = prefix
self.price = price
self.pre_len = len(self.prefix)
p = Price_list("46", "4.99")
p.data[p.prefix] = [p.price]
p1 = Price_list("44", "3.99")
p1.data[p1.prefix] = [p1.price]