Making two classes reference eachother - python

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.

Related

Cross-classes manipulations of objects in 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.

Refactor the python design patterns

I have a class called resources and I have defined one method called get_connect. I want to use the data of which get_connect returns to the other classes. I need at least three classes and I use the data of get_connect and I have to parse that data. To implement this I have written the code below
class resources:
#staticmethod
def get_connect():
return 1 + 2
class Source1(resources):
def __init__(self):
self.response = resources.get_connect()
def get__details1(self):
print(self.response)
class Source2(resources):
def __init__(self):
self.response = resources.get_connect()
def get_details2(self):
print(self.response)
class Source3(resources):
def __init__(self):
self.response = resources.get_connect()
def get__detail3(self):
print(self.response)
source1 = Source1()
source2 = Source2()
source3 = Source3()
source1.get__details1()
source2.get_details2()
source3.get__detail3()
But the problem with the code is for every class in init method I am calling the get_connect method. I don't want to repeat the code. I need help for avoiding redundancy which I have asked below
Is there any way I can call get_connect in one place and use it for other classes maybe a decorator or anything? if yes how can I?
While creating objects also I am calling each class and calling each method every time. is there a way to use any design pattern here?
If anyone helps me with these oops concepts it will be useful.
First of all, is there any reason why you are using get_connect method as static?
Because what you can do here is declare it in the parent class:
class resources:
def __init__(self):
self.response = self.get_connect()
def get_connect(self):
return 1 + 2
This way you do not need to define the __init__ method on every class, as it will be automatically inherited from the parent.
Regarding the second question, it really depends on the context, but you can use a strategy pattern in order to retrieve the class that you require to call. For this rename the method of get details into the same for each of the classes, as basically they're used for the same purpose, but changed on the context of the class implementation:
class Source1(resources):
def get_details(self):
print(self.response)
class Source2(resources):
def get_details(self):
print(self.response)
class Source3(resources):
def get_details(self):
print(self.response)
classes = {
"source_1": Source1,
"source_2": Source2,
"source_3": Source3
}
source_class = classes["source_1"]
source = source_class()
source.get_details()
Hope this helped!

Python - automating the creation of class instances

I have dozens of classes built in this fashion:
class playlist_type_1(radio):
'''child class'''
def __init__(self,user, type):
radio.__init__(self, user, type)
class playlist_type_2(radio):
'''child class'''
def __init__(self,user,type):
radio.__init__(self, user, type)
they inherit from:
class radio(self, user, type):
'''parent class'''
since I will have many users, I'm trying build a model for creating instances like so:
thom = playlist_type1('Thom Yorke', 'playlist_type_1')
the user himself, thom, will chose his playlist_type_n at command line via:
string = raw_input('Choose a playlist type> ')
and instance will be created and run:
thom = playlist_type1('Thom Yorke', string)
can this be implemented within class scope?
Create a mapping of names to classes and then instantiate the class based on that:
class PlaylistType1(Radio):
pass
class PlaylistType2(Radio):
pass
playlist_types = {
PlaylistType1.__name__: PlaylistType1,
PlaylistType2.__name__: PlaylistType2,
}
...
playlist = playlist_types[chosen_type](user)

python inheritance __init__ confusion

I am using python 2.7 and confused about inheritance concept.
I want to make a script that can download from various manga (japanese comic site)
Every manga site uses a different method to save their file. So i have a "Manga_site" class and class called "mangacanblog" (this is a website manga).
Every manga site has a: homepage,collection,page,etc. and it's all different for each site. my question is. is this script correct to store those homepage,collection_page,etc variable? or should I use self.homepage in mangacanblog class and not in the Manga_site class?
class Manga_site:
def __init__(self,homepage,collection_page,base_manga_page,manga_title = ""):
self.homepage = homepage
self.collection_page = collection_page
self.base_manga_page = base_manga_page
self.manga_title = manga_title
class Mangacanblog(Manga_site):
def __init__(self,manga_title):
homepage = bloglink
collection_page = collectionpagelink
manga_title = manga_title.lower()
base_manga_page = basepagelink
In your Mangacanblog's __init__() function you are just setting local variables homepage, collection_page, etc, not instance variables, to make them instance variables you have to use self. , and this needs to be used in both super class as well as subclass.
But a better thing to do would be to call super(Manga_site).__init__() to let the super class handle its initialization, and then you can initialize sub class just the way you want to.
But for this, you would need to define Manga_site as a new style class, by inheriting from object class. Example -
class Manga_site(object):
def __init__(self,homepage,collection_page,base_manga_page,manga_title = ""):
self.homepage = homepage
self.collection_page = collection_page
self.base_manga_page = base_manga_page
self.manga_title = manga_title
class Mangacanblog(Manga_site):
def __init__(self,manga_title):
super(Mangacanblog, self).__init__(bloglink, collectionpagelink, basepagelink, manga_title.lower())
I have guessing you would define bloglink and collectionpagelink , before you use them in the subclass.
But this given, from the example you have given, what you are trying to achieve may be to use objects of class, and not inheritence.
Inheritence is used when the subclass has extra attributes/properties and extra methods.
You create different objects of same class if you want to store different data in them. Example -
class Manga_site:
def __init__(self,homepage,collection_page,base_manga_page,manga_title = ""):
self.homepage = homepage
self.collection_page = collection_page
self.base_manga_page = base_manga_page
self.manga_title = manga_title
mangacanblog = Manga_site('<homepage url>','<collection_page>',....)
anothermangasite = Manga_site('<another url>',....)
Then you can use these objects anyway you want to.

Two Python classes identical except for superclass - how to avoid duplication?

I have some functionality wrapped up in a Python class (classa). classa inherits from another class supera.
I want exactly the same functionality as classa except that I want to inherit from superb.
I could just copy the class classa to a new class classb and then change the superclass for classb but obviously this very tacky, a maintenance headache and and I'm quite sure there's much better way - can anyone tell me what it is ?
EDIT: Thanks for answers so far. I should have said initially the my classa invokes super in its methods in order to invoke supera methods. It seems that this has some significance when looking at mixins as an option
This can be done with Python's multiple inheritance if none of the methods need to invoke super().
class Dog(object):
name = "Spot"
class Cat(object):
name = "Whiskers"
class SpeakingAnimalMixin(object):
def speak(self):
print "My name is", self.name, "and I can speak!"
class SpeakingDog(SpeakingAnimalMixin, Dog):
pass
class SpeakingCat(SpeakingAnimalMixin, Cat):
pass
SpeakingDog().speak()
My name is Spot and I can speak!
If you do need to invoke super() from a method then you need to create the class dynamically. This works fine, but the generated class's name will be less helpful and IDEs and other static analysis tools may be less useful.
You can create the class using a function, passing the superclass as an argument:
def make_speaking_animal_class(SpeechlessAnimal):
class SpeakingAnimal(SpeechlessAnimal):
def get_name(self):
return "Speaking " + super(SpeakingAnimal, self).get_name()
def speak(self):
print "My name is", self.get_name()
return SpeakingAnimal
class Dog(object):
def get_name(self):
return "Spot"
class Cat(object):
def get_name(self):
return "Whiskers"
SpeakingDog = make_speaking_animal_class(Dog)
SpeakingCat = make_speaking_animal_class(Cat)
SpeakingCat().speak()
My name is Speaking Whiskers
However as mentioned, the class's __name__ attribute may not be what you expect.
print SpeakingDog
print SpeakingDog()
<class '__main__.SpeakingAnimal'>
<__main__.SpeakingAnimal object at 0x1004a3b50>
You can fix this by assigning them unique __name__ attributes yourself:
SpeakingDog.__name__ = 'SpeakingDog'
print SpeakingDog
<class '__main__.SpeakingDog'>
(Credit to Andrew Jaffe for suggesting this in an answer, but he deleted it.)
There's another way to create a class dynamically, but I discourage you from using it unless you need to; it's even less clear. The type function has a second use, apart from its main one of determining the class of an object: it can be used to dynamically create a new class.
When used this way, the type function takes three parameters:
name, the __name__ the new class will have.
bases, a tuple of of base classes that the new class will inherit from.
dict, a dictionary containing the methods and attributes the new class will have.
You could use it like this:
def make_speaking_animal_class(SpeechlessAnimal, name):
def get_name(self):
return "Speaking " + super(SpeakingAnimal, self).get_name()
def speak(self):
print "My name is", self.get_name()
bases = (SpeechlessAnimal,)
# We need to define SpeakingAnimal in a variable so that get_name can refer
# to it for the super() call, otherwise we could just return it directly.
SpeakingAnimal = type(name, bases, {
'get_name': get_name,
'speak': speak
})
return SpeakingAnimal
class Dog(object):
def get_name(self):
return "Spot"
class Cat(object):
def get_name(self):
return "Whiskers"
SpeakingDog = make_speaking_animal_class(Dog, 'SpeakingDog')
SpeakingCat = make_speaking_animal_class(Cat, 'SpeakingCat')
SpeakingDog().speak()
SpeakingCat().speak()
My name is Speaking Spot
My name is Speaking Whiskers

Categories

Resources