A somewhat simple question, but I'd like some help understanding exactly how classes work in Python. Specifically, when are class variables set, and are they overwritten every time an instance of that class is created?
Here is the general situation. I have a table of data that I would like all instances of a certain class to be able to access. The problem is that this table sits on a database server. I want to connect to the database automatically and retrieve this table into memory the first time a instance of this class is created, but not any time after that.
It seems like a class variable would work, but I just wanted to verify that this would be the case. My program is going to be creating hundreds of instances of this class so I definitely don't want to be accidentally making hundreds of database calls for the same table or storing hundreds of copies of the same table in memory.
Would I be able to write something like the following? Assume that "get_table_from_db" is a function that connects to a database and returns a pandas dataframe with the relevant table.
class ExampleClass:
table1 = get_table_from_db(arguments)
def __init__(self, x, y):
self.value = self.table1.iloc[x, y]
obj1 = ExampleClass(0, 0)
obj2 = ExampleClass(0, 1)
Basically, when I run this script, I want to run "get_table_from_db" once, either before or when obj1 is created and store the relevant dataframe to table1. When obj2 is created, I do not want to call "get_table_from_db" again because table1 already exists. However, I still want it to have access to table1 for some of its methods because it will need that data available to it (as an example, I assigned self.value equal to a specific cell in the table, but my actual code is going to be more complicated than that).
Also, a similar question. If the above method works, can I then reset a class variable from within the class? For example, will something like the following allow me to modify (and by modify I mean redownload) the class variable for all instances of the class?
class ExampleClass:
table1 = get_table_from_db(arguments)
def __init__(self, x, y):
self.value = self.table1.iloc[x, y]
def reset_table(self):
ExampleClass.table1 = get_table_from_db(arguments)
The class variable will be initialized once, when the class is declared (so before either obj1 or obj2 are created), so your code will work the way you think.
With regards to your second question, you should do it like this:
class ExampleClass:
#classmethod
def reset_table(cls):
cls.table1 = get_table_from_db(arguments)
That way you can call either obj.reset_table() or ExampleClass.reset_table() without needing an instance of ExampleClass.
Related
I have a class that has several methods and I would like to write unit tests for them. The problem I'm facing is that this class has an __init__ method that queries a database, imagine something like this:
class MyClass:
accepted_values = ['a', 'b', 'c']
def __init__(self, database_name):
self.database = database_name
self.data = self.query_database()
def query_database(self):
data = query_this_database(self.database)
# clean data
return data
def check_values_in_db(self, column_name):
column = data.column_name
if any(item not in self.accepted_values for item in column):
print('Oh noes!')
else:
print('All good')
Now, given this, I would like to unit test the last method using some mock data, but I can't because if I initialize the class, it will want to query the database. This is further complicated by the fact that to actually make the query, one needs an API key, permissions, etc., which is exactly what I want to avoid during unit testing.
I'm relatively new to OOP and unit testing in general, so I'm not even sure if I structured my class properly: maybe the method query_database() should only be called at a later stage and not in __init__?
EDIT:
Asked to add some details so here goes:
This class belongs to an AWS lambda function that runs on a schedule. Every hour, this class queries the DB for the last hour, and checks a specific column against some pre-defined values.
If any value in the column does not belong to those pre-defined values, it sends an alert email. I would like to test this specific functionality, but without having to query the database, but just using mock values.
I edited the code accordingly to reflect what I mean.
You can still call a class method without making an instance of it, but you will have problems if you're trying to call attributes that you have defined in __init__.
You might also want to think about making a blank variable data outside of the __init__ and then call classinstance.data = classinstance.query_database() in your main code.
You can use unittest.mock to do this kind of stuff.
An uglier way is to override your class's init method in a mock class like:
class MyMockedClass(MyClass):
def __init__(self):
self.database = not_a_real_database()
self.data = not_real_data()
and then use this new class in your tests.
For your last question, it depends on your project structure and frameworks you might be using. You should ask codereview for advice on your project structure.
i created this class for my homework:
class sayfa():
isim=" "
def __init__(self,bSayisi,ySayisi,pSayisi,iSayisi,tSayisi):
self.bSayisi=bSayisi
self.ySayisi=ySayisi
self.pSayisi=pSayisi
self.iSayisi=iSayisi
self.tSayisi=tSayisi
if ((((bSayisi+ySayisi+pSayisi)/iSayisi)/tSayisi)*100)>0.2:
print(isim,"başarılı")
else:
print(isim,"başarısız")
then i called it in another .py file:
from eRate import sayfa
ybs1=sayfa(365000,65000,870,500,1125000)
ybs1.isim="YBS-1"
then i tried to work it and it gave me this error:
NameError: name 'isim' is not defined
I think i did something wrong when i'm writing class but i don't know what i actually done wrong.Can you help me?
edit:
My code worked when i put isim variable in def init but it looks weird.It looks like this:
class sayfa():
def __init__(self,bSayisi,ySayisi,pSayisi,iSayisi,tSayisi,isim):
self.isim=str(isim)
self.bSayisi=bSayisi
self.ySayisi=ySayisi
self.pSayisi=pSayisi
self.iSayisi=iSayisi
self.tSayisi=tSayisi
if ((((bSayisi+ySayisi+pSayisi)/iSayisi)/tSayisi)*100)>0.2:
print(isim,"başarılı")
else:
print(isim,"başarısız")
and when i'm adding data in class it gets weirder:
from eRate import sayfa
ybs1=sayfa(365000,65000,870,500,1125000,"YBS-1")
The error isn't with the way you're assigning things, but with the way you're accessing them.
Just as you have to do self.bSayisi to set an attribute, you have to do self.isim to access one. So:
print(self.isim, "başarılı")
(and the same for the other line…)
If you're wondering why you were able to access other values like bSayisi without self.bSayisi—that's just because you happen to have a parameter named bSayisi that happens to have the same value as self.bSayisi (because you just made that true a few lines earlier). If you changed it to, say, self.bSayisi = bSayisi*2, or you renamed the parameter to myBSayisi and did self.bSayisi = myBSayisi, you'd see that just using bSayisi instead of self.bSayisi was no longer correct.
However, while this eliminates the error, I'm not sure it actually does what you want. At the time you're doing this print, you haven't assigned an isim value to the object yet, so it's going to get the class value as a default, so it's always just going to be " ". Is that really what you wanted?
If not, you need to move the print calls to some other method that you can call later, after having assigned isim. For example:
class sayfa():
isim=" "
def __init__(self,bSayisi,ySayisi,pSayisi,iSayisi,tSayisi):
self.bSayisi=bSayisi
self.ySayisi=ySayisi
self.pSayisi=pSayisi
self.iSayisi=iSayisi
self.tSayisi=tSayisi
def displaystuff(self):
if ((((self.bSayisi+self.ySayisi+self.pSayisi)/self.iSayisi)/self.tSayisi)*100)>0.2:
print(self.isim,"başarılı")
else:
print(self.isim,"başarısız")
ybs1=sayfa(365000,65000,870,500,1125000)
ybs1.isim="YBS-1"
ybs1.displaystuff()
Of course moving the isim into the constructor works, by avoiding the problem you were running into. It's not an answer to how to add data after the __init__ method, of course, because you're instead adding the data in the __init__ method. When that's appropriate, it's the simplest answer.
But if it looks weird in this case (I'll take your word for it; I don't know exactly what this code is trying to do), it's probably the wrong answer for this particular class.
In which case, you do need to know how to add data after the __init__ method, as you asked. Or, rather, you need to know how to access that data—because you were already adding it correctly.
This is the difference between class attributes (when it is outside of the __init__ with no self.) and instance attributes (when you added it inside the __init__ with the self.).
Class attributes are a little more complicated since they pertain to all the instances of that class (you could overwrite them within some instances, but then they'd become instance attributes in those cases)... and so if you changed a class attribute, it would affect all other instances you may have created or will create in the future.
For a more in-depth discussion of class attributes vs instance attributes see this answer that summarizes this post.
Normall __init__(..) is used to initialize / instantiate your instance. I would not print in it, nor calculate (unless you calculate some other class-variables and set them).
You need to prefix your variables of the instance by self. and the static class variable with the class name to acess it:
class sayfa():
isim=" " # this is a shared class variabl (aka static)
def __init__(self,bSayisi,ySayisi,pSayisi,iSayisi,tSayisi):
self.bSayisi=bSayisi # these are all instance variables, not shared
self.ySayisi=ySayisi
self.pSayisi=pSayisi
self.iSayisi=iSayisi
self.tSayisi=tSayisi
self.unusedSum = ySayisi + pSayisi + iSayisi
def printMe(self): # lookup __str__() and __repr__() for how to output your instance
if ((((self.bSayisi+self.ySayisi+self.pSayisi)/self.iSayisi)/self.tSayisi)*100)>0.2:
print(sayfa.isim,"some text") # use the static class variable
else:
print(sayfa.isim,"some other text")
sayfa.isim = "Coffee " # you set static class variables by prefixing class name
my_sayfa_instance = sayfa(365000,65000,870,500,1125000)
other_sayfa_instance = sayfa(3600,65000,870,500,10)
my_sayfa_instance.printMe()
other_sayfa_instance.printMe()
Output:
Coffee some other text
Coffee some text
I have a question regarding return convention in Python. I have a class that has some data attributes and I have several functions that perform some analysis on the data and then store the results as results attributes (please see the simplified implementation below). Since, the analysis functions mainly update the results attribute, my question is what is the best practice in terms of return statements. Should I avoid updating class attributes inside the function (as in process1), and just return the data and use that to update the results attribute (as in process2)?
Thanks,
Kamran
class Analysis(object):
def __init__(self, data):
self.data = data
self.results = None
def process1(self):
self.results = [i**2 for i in self.data]
def process2(self):
return [i**2 for i in self.data]
a = Analysis([1, 2, 3])
a.process1()
a.results = a.process2()
It all depends on the use case.
First of all, You are not changing the class attributes there. You are changing the instance attributes.
Python: Difference between class and instance attributes
Secondly, If you are planning to share the results of your process among the various instances of the class,Then you can use class variables.
Third, If you are asking about instance variables, Then it depends on design choice.
Besides that, This is unnecessary I guess:-
a.results = a.process2()
You simply made allocation to be part of object itself. You can use a.process2 function for displaying results if you need that functionality.
I am currently trying to implement a python class that automatically synchronized with a NoSQL database with implicit buffering, quite to the image of the SLQAlchemy.
In order to do this, I need to track attribute updates issued by the user and, on each attribute update, call functions that keep that object in synchronization with the database or buffer.
What is the best way of doing this in Python? If it passes through __setattr__ and __delattr__, how do I do it correctly, to avoid messing up with garbage collector?
One way to do it (the way I would recommend) is to use descriptors.
First you make a class for your properties, something like:
class Property:
def __init__(self, *args, **kwargs):
#initialize the property with any information it needs to do get and set
def __get__(self,obj, type=None):
#logic to get from database or cache
def __set__(self,obj, value):
#logic to set the value and sync with database if necessary.
And then in your class entity class you have something like this:
class Student:
student_id = Property(...)
name = Property(...)
classes = Property(...)
Of course in practice you may have multiple Property types. My guess is that SQLAlchemy does something like this, where Column types are descriptors.
This is probably a basic question but I am new to programming. I am working with a third party python code and it provides a class with event and event delegates. The syntax for the events and event delegates are follows:
public Delegate Sub RequestEventDelegate (request As MDNPRequest, _
response as MDNPResponseParser)
public Event RequestEvent As MDNPRequest.RequestEventDelegate
I wrote the following code to subcribe to the event but is not working. I do not know what I am
doing wrong.
Mreq = MDNPRequest()
Mreq.RequestEvent += Mreq.RequestEventDelegate(handleResponseEvent)
def handleResponseEvent (request, response):
print ' event fired'
I am adding the two lines of code to the end of a function that opens up the communication channel. I also tested adding the two lines of code to a function that send a poll on the communication channel. In the second scenario the event fires and every time I execute the polling function. Does this defeat the purpose of event subscription?
I think that my problem maybe due to different functions creating instances of the same class. I would like to consolidate some of the functions into a class using the outline shown below. Method1 creates an instance 'a' of a class1 that I would like the other methods in myClass to use. I tried using a class variable which I set to a class1 instance but this is not working. I reference the class variable using the class name for example myClass.variable.somemethod from class1 but I get "Object reference not set to an instance of an object" error. What is the best approach so that all methods in myClass can have access to a? Eventually I would like to call myClass from another module.
from file1 import *
myClass:
class_variable = class1() # class1 from file1
def __init__(self)
...
def Method1(self, argument list):
# this method instantiates a
...
a = class1()
def Method2 (self):
...
a.class1method1
...
def Method3 (self):
...
a.class1method2
...
If this is actually your code:
Mreq.RequestEvent += Mreq.RequestEventDelegate(handleResponseEvent)
def handleRequestEvent (request, response):
print ' event fired'
… handleResponseEvent is not the same thing as handleRequestEvent.
As a side note, you almost never need to create an explicit delegate. It's sometimes a useful optimization, but it's one more thing you can get wrong, and one more thing that can disguise useful debugging information when you do, so it's usually simpler to write the code without it first, and only add wrap it as a delegate after it's working, if you find yourself creating a whole lot of them and want to save some memory.
From your later edits, I suspect that you're missing the fundamentals of how classes work in Python. You may want to read through the tutorial chapter, or maybe search for a friendlier/more detailed tutorial.
In particular:
I would like to consolidate some of the functions into a class using the outline shown below. Method1 creates an instance 'a' of a class1 that I would like the other methods in myClass to use. I tried using a class variable which I set to a class1 instance but this is not working.
That's not the way to do it. Class attributes, like your class_variable, are created at class creation time (that is, generally, as soon as you import the module or run the script), not instance creation time. If you want something created when instances of your class are created, you use instance attributes, not class attributes, and you set them in the __init__ method. In your case, you don't want the instance created until Method1 is called on an instance—again, that means you use an instance attribute; you just do it inside Method1 rather than __init__.
Also, class attributes are shared by all instances of the class; instance attributes, each instance has its own one. Thing about dogs: each dog has its own tail, there's not one tail shared by all dogs, so tail is an instance attribute. Often, in simple scripts, you don't notice the difference, because you only happen to ever create one instance of the class. But if you can't figure out the difference practically, think about it conceptually (like the Dog example)—and if you still can't figure it out, you almost always want an instance attribute.
I reference the class variable using the class name for example myClass.variable.somemethod from class1 but I get "Object reference not set to an instance of an object" error.
Most likely this is because class1 is a COM/interop or .NET class, and you're trying to create and use it before doing any of the relevant setup, which is only happening because you're trying to do it as soon as you import the module/run the script. If so, if you create it when you actually intended to, there won't be a problem.
What is the best approach so that all methods in myClass can have access to a?
Create an instance attribute in Method1, like this:
def Method1(self, argument list):
# this method instantiates a
...
self.a = class1()
And then use it the same way:
def Method2 (self):
...
self.a.class1method1()
...
Just doing a = whatever just creates a local variable that goes away at the end of the method. Even if it happens to have the same name as a class attribute, instance attribute, or global, you're still creating a new local variable, not modifying the thing you want to modify. Unlike some other languages, Python requires you to be explicit about what you're trying to overwrite—self.a for an instance attribute, myClass.a for a class attribute, etc.—so you don't do it by accident.
Also, note the parentheses at the end of that last expression. If you want to call a function or method, you need parentheses; otherwise, you're just referencing the method itself as a value.
Eventually I would like to call myClass from another module.
I'm not sure what you mean by "class myClass". When you call a class, that constructs a new instance of the class. You can then call that instance's methods the same way you would any other object. It doesn't matter what module it was defined in (except that you obviously have to write my_instance = mymodule.MyClass()).
Look at how you use the standard library; it's exactly the same. For example, if you import csv, you can construct a DictWriter by writing my_writer = csv.DictWriter(my_file). And then you call its methods by writing my_writer.writerow(my_row). Once you've constructed it, it doesn't matter what module it came from.
One more thing:
You've tried to define a class like this:
myClass:
You obviously can't do that; you need the class keyword. But also, in Python 2.x, you always want to give base classes, using object if you don't need anything else. Otherwise, you get an old-style class, which causes all kinds of weird quirks and limitations that you don't want to learn about and have to debug. So:
class myClass(object):