Cross-classes manipulations of objects in Python - python

I am trying to make a simple library OOP program in Python.Here is the structure:
class Books(object) with attributes
class Books(object):
book_id=""
book_title=""
Books=[book_id,book_title]
def __init__(self,book_id,book_title):
self.book_id = book_id
self.book_title = book_title
#Books=[book_id,book_title]
book2= Books('1504231','Murders')
print(book1.__str__())
class BookList(Books) with objects of created by class Books
class BookList(Books):
def __init__(self):
self.listbook = []
book_list= BookList()
book_list.add_book_object(book2)
book_list.show_books()
(Operations in this scope works for me good)
class Users(object) with attributes (Similar def and init as for Books)
user1= Users ('adfelko','Adam')
print(user1.__str__())
class UserList(Users) with objects of created by class Users (Similar def and init as for BookList)
user_list= UserList()
user_list.add_user_object(user1)
user_list.show_users()
(Operations in this scope works for me good)
Now, I am trying to create actual Lease class, which will hold dictionary of objects(each object=each lease, each leases = [users object, books object])
This is my try:
#Definition of class Leases
class Leases(Users,Books):
#Set constructor
def __init__(self,user,book):
self.leases = [user,book]
#Create a lease
def borrow_book_to_user(self,u_name,t_book):
user=u_name
book=t_book
lease = [user,book]
self.leases.append(lease)
#Show lease
def __str__(self):
print(self)
Maybe I have a bad concept of using it, not sure, but I should probably not go through lists- BookList and UserList ?
Or how I should I get it connected and be able to call functions of the previous classes?
The thing for now works:
lease= Leases(user1,book2)
lease.__str__()
But the output looks something like this:
[<__main__.Users object at 0x0000010E69BFE280>, <__main__.Books object at 0x0000010E69BFE1F0>]
I would like to get direct out put like:
[ ['adfelko','Adam'],['1504231','Murders'] ]
With possibility to get access and change the attributes of this Users or Books object from Leases class, is someone able to help here please ?
Thanks
Best Regards
UPDATE:
#guimoute Thank you for your comment! It did not help to resolve, but helped me to understand more in depth.
I had to rethink my usage of Leases class(other stuff stay same):
#Definition of class leases
class Leases():
#Set constructor
def __init__(self):
self.leases = []
#Create lease object
def add_lease_object(self,user,book):
lease = { user : book}
self.leases.append(lease)
#Create lease object
def del_lease_object(self,user,book):
lease = { user : book}
self.leases.remove(lease)
#Show lease
def __str__(self):
return(self.leases)
#Show leases
def show_leases(self):
for l in self.leases:
#print(vars(l))
#json.dump(l,str)
print(l.__str__())
And I am executing:
lease= Leases()
lease.add_lease_object(user1,book2)
#print(lease.__str__())
print("*************************")
lease.show_leases()
print("*************************")
lease.add_lease_object(user2,book3)
print("*************************")
lease.show_leases()
print("*************************")
lease.del_lease_object(user2,book3)
print("*************************")
lease.show_leases()
Which seems to be working right, but again it is not showing output of nested objects as a string values:
{<main.Users object at 0x000001F9BD98E250>: <main.Books object at 0x000001F9BD8F2EB0>}
{<main.Users object at 0x000001F9BD98E250>: <main.Books object at 0x000001F9BD8F2EB0>} {<main.Users object at 0x000001F9BD98ED90>: <main.Books object at 0x000001F9BD98E1F0>}
{<main.Users object at 0x000001F9BD98E250>: <main.Books object at 0x000001F9BD8F2EB0>}
As you can see above I have tried even:
#print(vars(l))
#json.dump(l,str)
But similar result when trying to access nested object of different class. Do you have any better idea please ? Thank you

The ouptut you see:
{<main.Users object at 0x000001F9BD98E250>: <main.Books object at 0x000001F9BD8F2EB0>} {<main.Users object at 0x000001F9BD98ED90>: <main.Books object at 0x000001F9BD98E1F0>}
Is the default text representation of your instances of Users and Books. If you want it to display differently, you just have to override the __str__ method in both of these classes:
class Books(object):
[...]
def __str__(self) -> str:
return "{}, {}".format(self.book_id, self.book_title)
Now, when you directly (like with str(book1)) or indirectly call for a textual reprensentation of your Book and similarly User objects, your __str__ methods will be used instead of the default one.

Related

Is there a way to turn a class object name into the string associated with it?

So in my program, a certain function (good_function()) needs to use the string name (attribute_name) of an object when referencing an attribute(object_name.attribute) of an object(object_name). This attribute is also another object from a different class. However, when I pull out this attribute to be used, it brings up the class object name (<main.Class2 object at abcde12345>) instead of the name of the attribute (attribute_name). The current output and setup is as follows.
class Class():
def __init__(self, attribute):
pass
class Class2():
pass
attribute_name = Class2()
object_name = Class(attribute_name)
object_name.attribute = attribute_name
def good_function(thing):
#doesn't really matter
pass
good_function(object_name.attribute)
print(object_name.attribute)
>>> <__main__.Class2 object at abcde12345>
It reads "object_name.attribute"(attribute_name) "as the attribute_name"'s object ID name thingamajiggy (<main.Class2 object at abcde12345>) instead of just "attribute_name". So my question is: Is there a way to translate the callsign (<main.Class2 object at abcde12345>) into the "attribute name" to which it corresponds? (see desired output below) Thanks in advance, I hope this wasn't too confusing, and I'll be as active as I can in responses. The desired output and setup is below.
cclass Class():
def __init__(self, attribute):
pass
object_name.attribute = 'attribute_name'
def magic_function(object):
#solve for here
return object
def good_function(thing):
#doesn't really matter
pass
variable = magic_function(object_name.attribute)
good_function(variable)
print(variable)
>>> attribute_name
If I'm understanding correctly, then I don't think what you want is possible, assuming the actual reference attribute is just a native type.
However, if you made the attribute an instance of your own custom class then any instance could implement the __str__ method to display whatever you wanted:
class MyClass():
def __str__(self):
return 'MyClass str'

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)

Python3 OOP: Select all objects of a particular class w/o variables

I have simple class:
class ChannelMessages:
def __init__(self, channel, date, message):
self.channel = channel
self.date = date
self.message = message
... somecode here ...
for message in messages:
ChannelMessages(name, message.to_dict()['date'], message.to_dict()['message'])
... name, date, message - is a variables ...
I want now to select all ChannelMessages class objects and put it in a variable. Im dont need to saving it anywhere, i need to render this Classes once on my app.
Im trying to use something like Django ORM:
ChannelMessages.objects.all()
but i cant select them this way. So is there a way to select all created objects w\o vars? Or i always shold specify variables for every created class object?
There's no built-in way to refer to all created instances of a particular class. APIs which enable you to do this have to implement this behaviour. Luckily you can very simply reproduce this behaviour with a class variable:
class ChannelMessages:
all_messages = []
def __init__(self, channel, date, message):
self.channel = channel
self.date = date
self.message = message
all_messages.append(self)
The all_messages list now hold a reference to all instantiated objects of its class, which, like all class variables, you can access either through the class itself (ChannelMessage.all_messages) or through any particular instance of the class (self.all_messages).
A more elegant solution would be using metaclasses and implementing __iter__ for the class itself, so you could write for message in ChannelMessages, but from a practical standpoint this works just as fine.
Why not store the items in a list?
allMessages = []
for message in messages:
allMessages.append(ChannelMessages(name, message.to_dict()['date'], message.to_dict()['message'])
Which can also be done in a single line using a list comprehension:
allMessages = [ChannelMessages(name, message.to_dict()['date'], message.to_dict()['message']) for message in messages]

how to initialise a peewee.Model object? __init__() doesn't work

I am not able to initialise the fields of a "peewee.Model" descendant object with the usual init() method. How can I initialise alternatively?
import peewee
peewee_database = peewee.SqliteDatabase('example.db')
class Config():
def __init__(self, seats, cylinders):
self.seats = seats
self.cylinders = cylinders
class Car(peewee.Model):
magic_number = peewee.IntegerField()
color = peewee.TextField()
class Meta:
database = peewee_database
def __init__(self, config):
self.magic_number = config.seats / config.cylinders
self.color = None
peewee_database.connect()
peewee_database.create_tables([Car])
config = Config(7, 6)
car = Car(config)
car.color = "blue"
car.save()
produces this error in Python3:
File "test.py", line 27, in <module>
car = Car(config)
File "test.py", line 20, in __init__
self.magic_number = config.seats / config.cylinders
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/peewee.py", line 3764, in __set__
instance.__data__[self.name] = value
TypeError: 'NoneType' object does not support item assignment
help! :)
the Peewee author was so kind to answer himself. I think using a factory method is the cleanest solution, to avoid conflicting with the way peewee uses __init()__
You can still put it in __init__() with the caveat that __init__() is
going to be called not just when instantiating objects yourself, but
also every time a Car instance is read from a database cursor. I think
you probably could make a classmethod on your Car object and use that
as a factory for complex logic?
Refer to this.
what you doing is kinda wrong.
u can separate class Car that peewee use for database management and use other class like "class ACar():" to create your object car and after that u can save your data in database by calling Car.get_or_create(magic_number=car.magic_number , color=car.color).
see peewee documentation about creating record. because the way you are using is wrong.
you are saving car that is and object of Car and not the module that peewee suppose to return it to you after using Car.get_or_none(...).
even if you will use save, u need to use it in record that already exist in database. if u want to create new record use create(), and it's a class methode ( mean, Car.create()).
hope this gives you and idea about how to re-write your code.
even if you want one class Car, use Car.create(...) to create your record and not the object, if you already have a record, the object car = Car() it's not right, the right way it car = Car.get_or_none('your parameters').
Car.get_or_create(...) will create a record if not exist, see documentation

Making two classes reference eachother

I'm trying to make a text adventure where different "place" classes can point to eachother.
For instance, I have a Manager class that has a reference to each place. Then I have a Home class, and a Club class, with references to eachother through manager. The problem is that I can't instantiate them due to the circular reference.
Here's how I solved it, but it's ugly, because I have to create the places member inside of a method instead of __init__.
class Manager:
def __init__(self):
self.home = Home(self)
self.club = Club(self)
class Home:
def __init__(self, manager):
self.places = {}
self.manager = manager
def display_plot_and_get_option (self):
print "where do you want to go?"
return 'club' #get this from user
def get_next_place(self, place_name):
self.places = { #THIS IS THE BAD PART, which should be in __init__ but can't
'home':self.manaer.home
'club':self.manaer.club }
return self.places[place_name]
class Club:
#similar code to Home
pass
manager = Manager()
while (True):
place_name = manager.current_place.display_plot_and_get_option()
manager.current_place = manager.current_place.get_next_place(place_name)
In c++ I would set my dict up in the constructor, where it should be, and it would use the pointer of the Manager's home or club members, since I only want 1 instance of each place. How can I do this in python?
edit: expanded code example
You can just have a dictionary that holds the references, and call the methods straight from the Manager (which shouldn't really be named Manager, as it does not serve that purpose now) instance.
class Home(object):
pass
class Club(object):
pass
PLACES = {
'home': Home(),
'club': Club()
}
class Manager(object):
def display_plot_and_get_option(self):
return raw_input('Where do you want to go?')
def get_next_place(self, place_name):
return PLACES[place_name]
m = Manager()
while 1:
place_name = m.display_plot_and_get_option()
m.get_next_place(place_name)
Assuming that Home and Club are just a couple of the many places you plan to include in your game, it would probably be advantageous to create a Place class. Specific classes can either inherit from Place or have a name as a data member. Then you can model connections with a tree or graph.

Categories

Resources