Related
I know the question has been asked before, but I find myself bumping into situations where a staticmethod is most appropriate, but there is also a need to reference an instance variable inside this class. As an example, lets say I have the following class:
class ExampleClass(object):
def __init__(self, filename = 'defaultFilename'):
self.file_name = filename
#staticmethod
def doSomethingWithFiles(file_2, file_1 = None):
#if user didn't supply a file use the instance variable
if file_1 is None:
# no idea how to handle the uninitialized class case to create
# self.file_name.
file_1 = __class__.__init__().__dict__['file_name'] <--- this seems sketchy
else:
file_1 = file_1
with open(file_1, 'r') as f1, open(file_2, 'w') as f2:
.....you get the idea...
def moreMethodsThatUseSelf(self):
pass
Now suppose I had a few instances of the ExampleClass (E1, E2, E3) with different filenames passed into __init__, but want to retain the ability to use either an uninitialized class ExampleClass.doSomethingWithFiles(file_2 = E1.file_name, file_1 = E2.file_name) or E1.doSomethingWithFiles(file_2 = E2.file_name, file_1 = 'some_other_file') as the situation requires.
Is there any reason for me to trying to find a way to do what I am thinking, or am I making a mess?
UPDATE
I think the comments are helpful and I also think it's an issue I'm encountering due to bad design.
The issue started out as a way to prevent concurrent access to HDF5 files by giving each class instance an rlock that I could use as a context manager for preventing any other attempts to access the file while it was in use. Each class instance had it's own rlock it acquired and released when done with whatever it needed to do. I was also using #staticmethod to perform a routine that then generated a file which was passed into it's own init() and was unique to each class instance. At the time it seemed clever, but I regret it. I also think I am entirely unsure of when #staticmethods are ever appropriate and maybe was confusing it with #classmethods, but a class variable would no longer make the rlocks and files that are unique to my class instances possible. I think I should probably just think more about design vs. trying to justify using a class definition I do not really understand in a manner it was designed to protect against.
If you think you keep bumping into situations where a staticmethod is most appropriate, you're probably wrong—good uses for them are very rare. And if your staticmethod needs to access instance variables, you're definitely wrong.
A staticmethod cannot access instance variables directly. There can be no instances of the class, or a thousands; which one would you access the variables from?
What you're trying to do is to create a new instance, just to access its instance variables. This can occasionally be useful—although it's more often a good sign you didn't need a class in the first place. (And, when it useful, it's unusual enough to be usually worth signaling, by having the caller write ExampleClass().doSomethingWithFiles instead of ExampleClass.doSomethingWithFiles.)
That's legal, but you do it by just calling the class, not by calling its __init__ method. That __init__ never returns anything; it receives an already-created self and modifies it. If you really want to, you can call its __new__ method, but that effectively just means the same thing as calling the class. (In the minor ways in which they're different, it's calling the class that you want.)
Also, once you've got an instance, you can just use it normally; you don't need to look at its __dict__. (Even if you only had the attribute name as a string variable, getattr(obj, name) is almost always what you want there, not obj.__dict__[name].)
So:
file_1 = __class__().file_name
So, what should you do instead?
Well, look at your design. The only thing an ExampleClass instance does is hold a filename, which has a default value. You don't need an object for that, just a plain old string variable that you pass in, or store as a global. (You may have heard that global variables are bad—but global variables in disguise are just as bad, and have the additional problem that they're in disguise. And that's basically what you've designed. And sometimes, global variables are the right answer.)
why not input the instance as parameter to static method. I hope this code will be helpful.
class ClassA:
def __init__(self, fname):
self.fname = fname
def print(self):
print('fname=', self.fname)
#staticmethod
def check(f):
if type(f)==ClassA :
print('f is exist.')
f.print()
print('f.fname=', f.fname)
else:
print('f is not exist: new ClassA')
newa = ClassA(f)
return newa
a=ClassA('temp')
b=ClassA('test')
ClassA.check(a)
ClassA.check(b)
newa = ClassA.check('hello')
newa.print()
You cannot refer to an instance attribute from a static method. Suppose multiple instances exist, which one would you pick the attribute from?
What you seem to need is to have a class attribute and a class method. You can define one by using the classmethod decorator.
class ExampleClass(object):
file_name = 'foo'
#classmethod
def doSomethingWithFiles(cls, file_2, file_1 = None):
file_1 = cls.file_name
# Do stuff
Maybe I'm misunderstanding what your intentions are but I think you're misusing the default parameter.
It appears you're trying to use 'defaultFilename' as the default parameter value. Why not just skip the awkward
if file_1 is None:
# no idea how to handle the uninitialized class case to create
# self.file_name.
file_1 = __class__.__init__().__dict__['file_name'] <--- this seems sketchy
and change the function as follows,
def doSomethingWithFiles(file_2, file_1='defaultFilename'):
If hardcoding that value makes you uncomfortable maybe try
class ExampleClass(object):
DEFAULT_FILE_NAME = 'defaultFilename'
def __init__(self, filename=DEFAULT_FILE_NAME):
self.file_name = filename
#staticmethod
def doSomethingWithFiles(file_2, file_1=DEFAULT_FILE_NAME):
with open(file_1, 'r') as f1, open(file_2, 'w') as f2:
# do magic in here
def moreMethodsThatUseSelf(self):
pass
In general, though, you're probably modeling your problem wrong if you want to access an instance variable inside a static method.
here is a part of my code :
class projet(object):
def nameCouche(self):
valLissage = float(ui.valLissage.displayText())
return (valLissage)
valCouche = nameCouche() # asks for a positional argument but 'self' doesnt work
def choixTraitement(self):
ui.okLissage.clicked.connect(p.goLissage)
def goLissage(self, valCouche):
if ui.chkboxLissage.isChecked():
print(valCouche) # result is False
os.system(r'"C:\Program Files\FME\fme.exe" D:\Stelios\..... --MAX_NUM_POINTS {0}'.format(valCouche))
So I would like to use valCouche in goLissage method but it doesnt work.
I thought that valCouche would have the argument of valLissage but instead it gives False as a value.
I've tried different alternatives but still doesnt work.
You've got multiple problems here.
First, if you write this in the middle of a class definition:
valCouche = nameCouche()
... you're creating a class attribute, which is shared by all instances, not a normal instance attribute.
Also, you're running this at class definition time. That means there is no self yet--there aren't any instances yet to be self--so you can't call a method like nameCouche, because you don't have anything to call it on.
What you want to do is call the method at instance initialization time, on the instance being initialized, and store the return value in an instance attribute:
def __init__(self):
self.valCouche = self.nameCouche()
Then, when you want to access this value in another method later, you have to access it as self.valCouche.
If you make those changes, it will work. But your object model still doesn't make much sense. Why is nameCouche a method when it doesn't have anything to do with the object, and doesn't access any of its attributes? Maybe it makes sense as a #staticmethod, but really, I think it makes more sense just as a plain function outside the class. In fact, none of the code you've written seems to have anything to do with the class.
This kind of cram-everything-into-the-class design is often a sign that you're trying to write Java code in Python, and haven't yet really understood how Python does OO. You might want to read a good tutorial on Python classes. But briefly: if you're writing a class just to have somewhere to dump a bunch of vaguely-related functions, what you want is a module, not a class. If you have some reason to have instances of that class, and the functions all act on the data of each instance, then you want a class.
You have to declare variabile in the __init__ method (constructor) and then use it in your code
ex:
class projet(object):
def __init__(self):
self.valCouche = ''
def nameCouche(self):
valLissage = float(ui.valLissage.displayText())
return (valLissage)
def choixTraitement(self):
ui.okLissage.clicked.connect(p.goLissage)
def goLissage(self, valCouche):
if ui.chkboxLissage.isChecked():
self.valCouche = self.nameCouche()
print(self.valCouche) # result is False
os.system(r'"C:\Program Files\FME\fme.exe" D:\Stelios\..... --MAX_NUM_POINTS {0}'.format(self.valCouche))
you have to define an initialization function: def__init__(self)
defining valCouche as an instance attribute make it accessible on all the method so we have the following
class projet(object):
def __init__(self):
self.valCouche = ''
def nameCouche(self):
self.valCouche = float(ui.valLissage.displayText())
#staticmethod #here there is no need for self so it is a method of class
def choixTraitement():
ui.okLissage.clicked.connect(p.goLissage)
def goLissage(self):
if ui.chkboxLissage.isChecked():
print(self.valCouche) # result is False
os.system(r'"C:\Program Files\FME\fme.exe" D:\Stelios\..... --MAX_NUM_POINTS {0}'.format(self.valCouche))
I have started writing a simple module for mongodb to use. I am new to python and I have been a problem with the code I wrote:
import pymongo
class mongoDB():
conn = object
def __init__(self):
global conn
self.conn = pymongo.Connection("localhost",27017)
def CreateCollection(self,name =""):
self.dbCollection = conn.name
return self.dbCollection
if __name__ == '__main__':
database = mongoDB
collection = database.CreateCollection("Hello")
Firstly I think there are probably few things wrong with my code if you can spot it and correct me. Also I am keep getting this erro:
collection = database.CreateCollection("Hello")
TypeError: unbound method CreateCollection() must be called with mongoDB
instance as first argument (got str instance instead)
I want to be able to create the connection in the constructor of the class and then have a method for creating a collection and returning it, and also another method to insert delete and update the entities
So, syntax wise you have a number of problems. It looks like you're mixing a couple of tutorials in different ways. So, firstly I'll explain what is going on with your code and explain why you're seeing what you're seeing:
import pymongo
class mongoDB(): # you don't need ()'s here - only if you are inheriting classes
# you could inherit from object here, which is a good practice
# by doing class mongoDb(object):, otherwise you can just take
# them out
conn = object # here, you're defining a class member - global for all instances
# generally, you don't instantiate an object pointer like this,
# you would set it to None instead. It won't fail doing this,
# but it's not "right"
def __init__(self):
# the __init__ method is the constructor method - this will
# allow you to initialize a particular instance of your class, represented
# by the self argument. This method is called when you call the class, i.e.
# inst = mongoDb()
# in this case, the conn variable is not a global. Globals are defined
# at the root module level - so in this example, only pymongo is a global
# conn is a class member, and would be accessed by doing mongoDB.conn
global conn
# with that being said, you're initializing a local variable here called conn
# that is not being stored anywhere - when this method finishes, this variable
# will be cleaned up from memory, what you are thinking you're doing here
# should be written as mongoDB.conn = pymongo.Connection("localhost", 27017)
conn = pymongo.Connection("localhost",27017)
def CreateCollection(name =""):
# there is one of two things you are trying to do here - 1, access a class
# level member called conn, or 2, access an instance member called conn
# depending on what you are going for, there are a couple of different ways
# to address it.
# all methods for a class, by default, are instance methods - and all of them
# need to take self as the first argument. An instance method of a class
# will always be called with the instance first. Your error is caused because
# you should declare the method as:
# def CreateCollection(self, name = ""):
# The alternative, is to define this method as a static method of the class -
# which does not take an instance but applies to all instances of the class
# to do that, you would add a #staticmethod decorator before the method.
# either way, you're attempting to access the global variable "conn" here,
# which again does not exist
# the second problem with this, is that you are trying to take your variable
# argument (name) and use it as a property. What python is doing here, is
# looking for a member variable called name from the conn object. What you
# are really trying to do is create a collection on the connection with the
# inputed name
# the pymongo class provides access to your collections via this method as a
# convenience around the method, create_collection. In the case where you
# are using a variable to create the collection, you would call this by doing
# conn.create_collection(name)
# but again, that assumes conn is what you think it is, which it isn't
dbCollection = conn.name
return dbCollection
if __name__ == '__main__':
# here you are just creating a pointer to your class, not instantiating it
# you are looking for:
# database = mongoDB()
database = mongoDB
# this is your error, because of the afore mentioned lack of 'self' argument
collection = database.CreateCollection("Hello")
I'd say have a look through the Pep-8 (http://www.python.org/dev/peps/pep-0008/) coding style guides (very helpful) to learn about how to make your code "flow" pythonically.
Having gone through your code to explain what is going on - this is what you are ultimately trying to do:
import pymongo
class MongoDB: # Classes generally are camel-case, starting with uppercase
def __init__(self, dbname):
# the __init__ method is the class constructor, where you define
# instance members. We'll make conn an instance member rather
# than a class level member
self._conn = pymongo.Connection("localhost", 27017)
self._db = self._conn[dbname]
# methods usually start with lowercase, and are either camel case (less desirable
# by Python standards) or underscored (more desirable)
# All instance methods require the 1st argument to be self (pointer to the
# instance being affected)
def createCollection(self, name=""):
return self._db[name]
if __name__ == '__main__':
# you want to initialize the class
database = MongoDB("Hello")
collection = database.createCollection("MyTable")
Given that tho - what is the goal of writing this class wrapper? The same could be written as:
import pymongo
conn = pymongo.Connection('localhost', 27017)
database = conn["Hello"]
collection = database["MyTable"]
If you're trying to create a larger API wrapped around the pymongo database, then I'd recommend looking into some ORM modules that have already been built. There are some out there - not 100% sure which ones are available for MongoDB, but the one I use (I am biased, I wrote it) is called ORB, and can be found at http://docs.projexsoftware.com/api/orb
This is not a specific answer to how to solve your problem, but instead an answer for how to step through what you want to do and work on simpler problems as they arise:
1) Forget about classes at first, and instead
2) Use the Python command line or a Python program like IDLE,
3) To establish your goals by writing calls to open the MongoDB database to accomplish your task or tasks. In other words, write the simplest code to accomplish your goals before worrying about classes.
4) Once you get that done, and feel good to move on, then write a test class using the documentation. My link is one of many you could find.
5) I think part, but not all, of your problem is your class is not set up correctly. My class -- not shown completely -- is as follows:
class GlobalData:
def set_xfer_date(self, value):
self.xfer_date = value
self.date_str = str(value)
self.xfer_date_base = self.date_str[0:10] + " " + "00:00:00"
# Now build tomorrow.
self.xfer_date_tomorrow = datetime.today() + timedelta(1)
self.date_str_tomorrow = str(self.xfer_date_tomorrow)
self.xfer_date_tomorrow = \
self.date_str_tomorrow[0:10] + " " + "00:00:00"
self.section_totals = {}
self.billable_reads = {}
def set_xfer_fnam_out(self, value):
self.xfer_fnam_out = value
def set_xfer_dir_in(self, value):
self.xfer_dir_in = value
.
.
.
def get_billable_reads(self):
return self.billable_reads
One of the problems I see is you are not referring to data using self.
Good luck.
When I write class in python, most of the time, I am eager to set variables I use, as properties of the object. Is there any rule or general guidelines about which variables should be used as class/instance attribute and which should not?
for example:
class simple(object):
def __init(self):
a=2
b=3
return a*b
class simple(object):
def __init(self):
self.a=2
self.b=3
return a*b
While I completely understand the attributes should be a property of the object. This is simple to understand when the class declaration is simple but as the program goes longer and longer and there are many places where the data exchange between various modules should be done, I get confused on where I should use a/b or self.a/self.b. Is there any guidelines for this?
Where you use self.a you are creating a property, so this can be accessed from outside the class and persists beyond that function. These should be used for storing data about the object.
Where you use a it is a local variable, and only lasts while in the scope of that function, so should be used where you are only using it within the function (as in this case).
Note that __init is misleading, as it looks like __init__ - but isn't the constructor. If you intended them to be the constructor, then it makes no sense to return a value (as the new object is what is returned).
class Person(object):
def __init__(self, name):
# Introduce all instance variables on __init__
self.name = name
self.another = None
def get_name(self):
# get_name has access to the `instance` variable 'name'
return self.name
So if you want a variable to be available on more than one method, make
it an instance variable.
Notice my comment on introducing all instance vars on __init__.
Although the example below is valid python don't do it.
class Person(object):
def __init__(self):
self.a = 0
def foo(self):
self.b = 1 # Whoa, introduced new instance variable
Instead initialize all your instance variables on __init__ and set
them to None if no other value is appropriate for them.
I try to imagine what I want the API of my class to look like prior to implementing it. I think to myself, If I didn't write this class, would I want to read the documentation about what this particular variable does? If reading that documentation would simply waste my time, then it should probably be a local variable.
Occasionally, you need to preserve some information, but you wouldn't necessarily want that to be part of the API, which is when you use the convention of appending an underscore. e.g. self._some_data_that_is_not_part_of_the_api.
The self parameter refers to the object itself. So if you need to use on of the class attributes outside of the class you would it call it as the name of class instance and the attribute name. I don't think there is any guideline on when to use self, it all depends on your need. When you are building a class you should try to think about what you will use the variables you creating for. If you know for sure that you will need that specific attribute in the program you are importing your class, then add self.
Let's say you have an object that was instantiated from a class inside a module.
Now, you reload that module.
The next thing you'd like to do is make that reload affect that class.
mymodule.py
---
class ClassChange():
def run(self):
print 'one'
myexperiment.py
---
import mymodule
from mymodule import ClassChange # why is this necessary?
myObject = ClassChange()
myObject.run()
>>> one
### later, i changed this file, so that it says print 'two'
reload(mymodule)
# trick to change myObject needed here
myObject.run()
>>> two
Do you have to make a new ClassChange object, copy myObject into that, and delete the old myObject? Or is there a simpler way?
Edit: The run() method seems like a static class style method but that was only for the sake of brevity. I'd like the run() method to operate on data inside the object, so a static module function wouldn't do...
To update all instances of a class, it is necessary to keep track somewhere about those instances -- typically via weak references (weak value dict is handiest and general) so the "keeping track" functionality won't stop unneeded instances from going away, of course!
You'd normally want to keep such a container in the class object, but, in this case, since you'll be reloading the module, getting the old class object is not trivial; it's simpler to work at module level.
So, let's say that an "upgradable module" needs to define, at its start, a weak value dict (and an auxiliary "next key to use" int) with, say, conventional names:
import weakref
class _List(list): pass # a weakly-referenceable sequence
_objs = weakref.WeakValueDictionary()
_nextkey = 0
def _register(obj):
_objs[_nextkey] = List((obj, type(obj).__name__))
_nextkey += 1
Each class in the module must have, typically in __init__, a call _register(self) to register new instances.
Now the "reload function" can get the roster of all instances of all classes in this module by getting a copy of _objs before it reloads the module.
If all that's needed is to change the code, then life is reasonably easy:
def reload_all(amodule):
objs = getattr(amodule, '_objs', None)
reload(amodule)
if not objs: return # not an upgraable-module, or no objects
newobjs = getattr(amodule, '_objs', None)
for obj, classname in objs.values():
newclass = getattr(amodule, classname)
obj.__class__ = newclass
if newobjs: newobjs._register(obj)
Alas, one typically does want to give the new class a chance to upgrade an object of the old class to itself more finely, e.g. by a suitable class method. That's not too hard either:
def reload_all(amodule):
objs = getattr(amodule, '_objs', None)
reload(amodule)
if not objs: return # not an upgraable-module, or no objects
newobjs = getattr(amodule, '_objs', None)
for obj, classname in objs:
newclass = getattr(amodule, classname)
upgrade = getattr(newclass, '_upgrade', None)
if upgrade:
upgrade(obj)
else:
obj.__class__ = newclass
if newobjs: newobjs._register(obj)
For example, say the new version of class Zap has renamed an attribute from foo to bar. This could be the code of the new Zap:
class Zap(object):
def __init__(self):
_register(self)
self.bar = 23
#classmethod
def _upgrade(cls, obj):
obj.bar = obj.foo
del obj.foo
obj.__class__ = cls
This is NOT all -- there's a LOT more to say on the subject -- but, it IS the gist, and the answer is WAY long enough already (and I, exhausted enough;-).
You have to make a new object. There's no way to magically update the existing objects.
Read the reload builtin documentation - it is very clear. Here's the last paragraph:
If a module instantiates instances of a class, reloading the module that defines the class does not affect the method definitions of the instances — they continue to use the old class definition. The same is true for derived classes.
There are other caveats in the documentation, so you really should read it, and consider alternatives. Maybe you want to start a new question with why you want to use reload and ask for other ways of achieving the same thing.
My approach to this is the following:
Look through all imported modules and reload only those with a new .py file (as compared to the existing .pyc file)
For every function and class method that is reloaded, set old_function.__code__ = new_function.__code__.
For every reloaded class, use gc.get_referrers to list instances of the class and set their __class__ attribute to the new version.
Advantages to this approach are:
Usually no need to reload modules in any particular order
Usually only need to reload the modules with changed code and no more
Don't need to modify classes to keep track of their instances
You can read about the technique (and its limitations) here:
http://luke-campagnola.blogspot.com/2010/12/easy-automated-reloading-in-python.html
And you can download the code here:
http://luke.campagnola.me/code/downloads/reload.py
You have to get the new class from the fresh module and assign it back to the instance.
If you could trigger this operation anytime you use an instance with this mixin:
import sys
class ObjDebug(object):
def __getattribute__(self,k):
ga=object.__getattribute__
sa=object.__setattr__
cls=ga(self,'__class__')
modname=cls.__module__
mod=__import__(modname)
del sys.modules[modname]
reload(mod)
sa(self,'__class__',getattr(mod,cls.__name__))
return ga(self,k)
The following code does what you want, but please don't use it (at least not until you're very sure you're doing the right thing), I'm posting it for explanation purposes only.
mymodule.py:
class ClassChange():
#classmethod
def run(cls,instance):
print 'one',id(instance)
myexperiment.py:
import mymodule
myObject = mymodule.ClassChange()
mymodule.ClassChange.run(myObject)
# change mymodule.py here
reload(mymodule)
mymodule.ClassChange.run(myObject)
When in your code you instanciate myObject, you get an instance of ClassChange. This instance has an instance method called run. The object keeps this instance method (for the reason explained by nosklo) even when reloading, because reloading only reloads the class ClassChange.
In my code above, run is a class method. Class methods are always bound to and operate on the class, not the instance (which is why their first argument is usually called cls, not self). Wenn ClassChange is reloaded, so is this class method.
You can see that I also pass the instance as an argument to work with the correct (same) instance of ClassChange. You can see that because the same object id is printed in both cases.
I'm not sure if this is the best way to do it, or meshes with what you want to do... but this may work for you. If you want to change the behavior of a method, for all objects of a certain type... just use a function variable. For example:
def default_behavior(the_object):
print "one"
def some_other_behavior(the_object):
print "two"
class Foo(object):
# Class variable: a function that has the behavior
# (Takes an instance of a Foo as argument)
behavior = default_behavior
def __init__(self):
print "Foo initialized"
def method_that_changes_behavior(self):
Foo.behavior(self)
if __name__ == "__main__":
foo = Foo()
foo.method_that_changes_behavior() # prints "one"
Foo.behavior = some_other_behavior
foo.method_that_changes_behavior() # prints "two"
# OUTPUT
# Foo initialized
# one
# two
You can now have a class that is responsible for reloading modules, and after reloading, setting Foo.behavior to something new. I tried out this code. It works fine :-).
Does this work for you?
There are tricks to make what you want possible.
Someone already mentioned that you can have a class that keeps a list of its instances, and then changing the class of each instance to the new one upon reload.
However, that is not efficient. A better method is to change the old class so that it is the same as the new class.