Accessing functions of another class without referencing in every instance? - python

In the code below the User class needs to access a function get_user inside an instance of WebService class, as that contains other functions required for authentication with the web server (last.fm). Actual code is here.
class WebService:
def __init__(self, key):
self.apikey = key
def get_user(self, name):
pass # Omitted
class User:
def __init__(self, name, webservice):
self.name = name
self.ws = webservice
def fill_profile(self):
data = self.ws.GetUser(self.name)
# Omitted
The problem is that a reference needs to be held inside every ´User´. Is there another way of doing this? Or is it just me overcomplicating things, and this is how it actually works in the real world?

As requested:
As to handling things like get_top_albums and get_friends, that depends on how you want to model the system. If you don't want to cache the data locally, I'd say just call the service each time with a user ID. If you do want to cache the data locally, you could pass a User object to the method in WebService, then have the method populate the members of the User. You do have to make a design decision though to either have a WebService and a User (what would probably be best), or just a UserWebService.

You can certainly make the reference a static variable, if the web service object is the same for all users.
The syntax is:
class User:
webservice = ...
...
You will then even be able to access it from User instances, but not to assign to it that way, that would require User.webservice syntax.
You are also getting good design alternatives suggested in the comments.

Related

How can I reference an object in a class method without passing it as an argument?

I'm writing a module to make requests to a work-related website easier. I have one class that initializes the session and has the URL as a variable. I wrote an abstract class to encapsulate the logic of the requests, and one subclass for each of the data-types. Ideally, most of the methods should be class methods, so I can call them by writing module.subclass1.get(params). My problem is that all of these methods need a session, and an URL to make the requests, and I can't figure out a good way to implement this. My code is looking something like this at the moment.
#This class I make an instance of, to have the session and url at hand.
class Website:
def __init__(self, username, password, url):
self.session = getSession(username, password)
self.url = url
#The abstract class that handles the requests
class AbstractClass(abc.ABC):
classvar1 = ""
classvar2 = ""
#classmethod
def get(cls, website, params):
website.session.get(website.url + cls.classvar1, params)
class Subclass1(AbstractClass):
classvar1 = "Something else"
classvar2 = "Something else"
Some of my (suboptimal) solutions are:
1. Passing an instance of Website as an argument to the class methods
This works and is what I do for now, but I would have to pass the website object as a parameter all the time.
All calls would end up looking like this:
module.subclass1.method(website, params)
2. Making the website object a class variable in the abstract class.
This works and makes the method calls look pretty: module.Subclass1.get(params) But it seems like very bad practice, and I would like to always have to specify a username, password, and URL, so different scripts can use different logins and so I can change the URL to test or prod environment.
3. Initializing all the subclasses with a website object in the Website class
This also makes the method calls look pretty website.Subclass1.method(params), but I would have to initialize every single subclass in the Website __init__ method, and would have to change the abstract class to add an__init__ method that takes a Website object as an argument.
Is there any smarter way to accomplish this? Any help is much appreciated.

in Django, can I use a class only to group functions?

I am creating an application using Django. The application has user registration and login functionality.
I have three functions related to user authentication as of now, login, registration, and email_check (which is called when the user types email address to see if it is available). I was trying to group these functions under a class for better organisation and easy accessibility.
So I wrote a class and function like so:
class user_auth:
def check_email(email):
with connection.cursor() as conn:
conn.execute('select count(*) from user_info where email = %s', [email])
row = conn.fetchall()
response = bool(row[0][0])
return(response)
However, when I do this, I get a pylint error saying Method should have "self" as the first argument.
If I save this and call it as user_auth.check_email('abc#xyz.com'), it works just fine. But if I add self as the first argument, it stops working.
Am I using classes in an incorrect way? If yes, what is a better way to create a group of functions like this which can be easily imported using a single statement in other files?
As in the comments said, you could use a module for it.
Otherwise if you want to group them inside a class you just need to use the staticmethod or classmethod decorator.
Example:
class user_auth:
#classmethod
def check_email(cls, email):
...
#staticmethod
def static_check_email(email):
...

Python when to use instance vs static methods

I am struggling to understand when it makes sense to use an instance method versus a static method. Also, I don't know if my functions are static since there is not a #staticmethod decorator. Would I be able to access the class functions when I make a call to one of the methods?
I am working on a webscraper that sends information to a database. It’s setup to run once a week. The structure of my code looks like this
import libraries...
class Get:
def build_url(url_paramater1, url_parameter2, request_date):
return url_with_parameters
def web_data(request_date, url_parameter1, url_parameter2): #no use of self
# using parameters pull the variables to look up in the database
for a in db_info:
url = build_url(a, url_parameter2, request_date)
x = requests.Session().get(url, proxies).json()
#save data to the database
return None
#same type of function for pulling the web data from the database and parsing it
if __name__ == ‘__main__’:
Get.web_data(request_date, url_parameter1, url_parameter2)
Parse.web_data(get_date, parameter) #to illustrate the second part of the scrapper
That is the basic structure. The code is functional but I don’t know if I am using the methods (functions?) correctly and potentially missing out on ways to use my code in the future. I may even be writing bad code that will cause errors down the line that are impossibly hard to debug only because I didn’t follow best practices.
After reading about when class and instance methods are used. I cannot see why I would use them. If I want the url built or the data pulled from the website I call the build_url or get_web_data function. I don’t need an instance of the function to keep track of anything separate. I cannot imagine when I would need to keep something separate either which I think is part of the problem.
The reason I think my question is different than the previous questions is: the conceptual examples to explain the differences don't seem to help me when I am sitting down and writing code. I have not run into real world problems that are solved with the different methods that show when I should even use an instance method, yet instance methods seem to be mandatory when looking at conceptual examples of code.
Thank you!
Classes can be used to represent objects, and also to group functions under a common namespace.
When a class represents an object, like a cat, anything that this object 'can do', logically, should be an instance method, such as meowing.
But when you have a group of static functions that are all related to each other or are usually used together to achieve a common goal, like build_url and web_data, you can make your code clearer and more organized by putting them under a static class, which provides a common namespace, like you did.
Therefore in my opinion the structure you chose is legitimate. It is worth considering though, that you'd find static classes more in more definitively OOP languages, like Java, while in python it is more common to use modules for namespace separation.
This code doesn't need to be a class at all. It should just be a pair of functions. You can't see why you would need an instance method because you don't have a reason to instantiate the object in the first place.
The functions you have wrote in your code are instance methods but they were written incorrectly.
An instance method must have self as first parameter
i.e def build_url(self, url_paramater1, url_parameter2, request_date):
Then you call it like that
get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)
This self parameter is provided by python and it allow you to access all properties and functions - static or not - of your Get class.
If you don't need to access other functions or properties in your class then you add #staticmethod decorator and remove self parameter
#staticmethod
def build_url(url_paramater1, url_parameter2, request_date):
And then you can call it directly
Get.build_url(url_paramater1, url_parameter2, request_date)
or call from from class instance
get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)
But what is the problem with your current code you might ask?
Try calling it from an instance like this and u will see the problem
get_inst = Get()
get_inst.build_url(url_paramater1, url_parameter2, request_date)
Example where creating an instance is useful:
Let's say you want to make a chat client.
You could write code like this
class Chat:
def send(server_url, message):
connection = connect(server_url)
connection.write(message)
connection.close()
def read(server_url):
connection = connect(server_url)
message = connection.read()
connection.close()
return message
But a much cleaner and better way to do it:
class Chat:
def __init__(server_url):
# Initialize connection only once when instance is created
self.connection = connect(server_url)
def __del__()
# Close connection only once when instance is deleted
self.connection.close()
def send(self, message):
self.connection.write(message)
def read(self):
return self.connection.read()
To use that last class you do
# Create new instance and pass server_url as argument
chat = Chat("http://example.com/chat")
chat.send("Hello")
chat.read()
# deleting chat causes __del__ function to be called and connection be closed
delete chat
From given example, there is no need to have Get class after all, since you are using it just like a additional namespace. You do not have any 'state' that you want to preserve, in either class or class instance.
What seems like a good thing is to have separate module and define these functions in it. This way, when importing this module, you get to have this namespace that you want.

How to instantiate class in python dynamically?

I'm using method dispatcher in CherryPy. In the server/start.py part of the server, I need to instantiate the API classes.
To make it more modular, and not to put everything in the start.py file, I coded it like this.
So, I've a dict which has all the instantiated api classes.
services = {}
user = UserResource() #api class
foo = FooResource() #api class
services = {"user":user, "foo":foo}
class Server(object):
"""Initialise the Cherrypy app"""
#for service in services:
user = services.values()[0]
cherrypy.quickstart(Server())
That works. But, if I do services.keys()[0] = services.values()[0] it doesn't work at all. No routes.
How do I do such a thing? Where I don't have to assign it to a particular class inside the server class, but rather use the keys to add routes.
services.keys() simply returns a list. Setting the first element of that list to anything will have no effect.
I expect you want to do services[services.keys()[0]] = services.values()[0], although I can't imagine what you are trying to do with that code.
Edit
OK, I think I understand what you want to do. It seems that CherryPy relies on class-level attributes to define the routes it will serve. The docs show how to do this dynamically. In your case, you could do something like this:
class Server(object):
pass
for k, v in services:
setattr(Server, k, v)
Note that the setattr has to be done outside the class definition itself, as the Server name doesn't exist inside the class body.
If you want to have more routing flexibility, use RoutesDispatcher.

How can I decide which declarative model to instantiate, based on row information

I'm building a webapp that has optional Facebook Login. The users created through the Facebook API are handled differently at several points in my application. I want to encapsulate these differences in a subclass of Person that overrides methods.
class Person(Model):
def get_profile_picture(self):
return profile_pictures.url(self.picture)
class FacebookPerson(Person):
def get_profile_picture(self):
return 'http:/.../%s.jpg' % self.graph_id
I would like to avoid the nasty if self.graph_id and just query the Person model and get the right object for each user.
I've thought of hacking the metaclass to add the FacebookPerson as a base. Obviously I would like to avoid such voodoo.
I'm using Flask and Flask-SQLAlchemy.
The general idea would be to store the model's class name as metadata in each row, and when you instantiate the object, do something like:
def query(self):
# stuff
return model_class(data)
To do this in SQLAlchemy, you might look at making Person the base class to something like BasicPerson and FacebookPerson, and in Person.init(), use the metadata to initialize to the proper subclass.
For example, the idea would be than when this query returns, user will have been initialized to the proper subclass:
user = session.query(Person).filter_by(name='james').first()
You will probably need to modify this concept a bit for SQLAlchemy (I haven't used it in a while), but that's the general idea.
Or, you could do something like store the metadata in a cookie with the user_id, and then when they log in again, use the metadata to pass the proper class to the user query:
user = session.query(FacebookPerson).filter_by(name='james').first()
If you want this to be generic so that the metatdata is meaningful to non-Python clients, instead of storing the model's class name, store the model's "object_type" and have something in each client library that maps object_types to classes.

Categories