I am new to classes and writing one to perform a tracking and timing task. Have looked at this but still having trouble getting one aspect of the functionality to work.
Here's the part of what I've got to demonstrate the problem:
class seperate_trackers():
def __init__(self):
print ("class initiated")
def print_instance_name(self):
print (self.__class__.__name__)
Create an instance of it:
track_task1 = separate_trackers()
>> class initiated
Run the method in there:
track_task1.print_instance_name()
>> separate_trackers
That's not what I want!
How can that method be fixed so it returns track_task1 when it is run?
This is not a good idea. If you want your instance to have a name, that should be an attribute of the instance itself (the name of the variabe is just a pointer and it should not represent the object's state).
Try this instead:
# We don't usually use snake case for class names in python (and its 'separate')
class SeparateTrackers():
def __init__(self, name):
self.name = name
instance1 = SeparateTrackers("instance_name")
print(instance1.name) # instance_name
Objects don't know what variables refer to them. There can be any number of references to an object, and none of them is "the real one," they are all equally valid as names for the object. Furthermore, there may be no references that are simple names:
things = [1, "hello", separate_trackers(), 3.14]
There's no useful way to find out what variables refer to an object.
class SeparateTrackers:
def __init__(self, instance_name):
self.instance_name = instance_name
def __str__(self):
return self.instance_name
So you can use something like
a = SeparateTracker("first instance")
print(a) # print instance's name
Related
I am trying to find the best way of accessing an instance variable from another instance. So far I've been able to pass that variable as an argument and save it in the new instance. But I am wondering if there is some sort of "Global" variable that will work best. Specially if the classes are from different modules.
Here is my example:
class A(object):
def __init__(self):
self.globalObject = "Global Object"
self.listB = self.generateBList()
def generateBList(self):
return [B(self.globalObject, i) for i in range(10)]
class B(object):
def __init__(self, globalObject, index):
self.index = index
self.globalObject = globalObject
def splitGlobalObject(self):
return self.globalObject.split(" ")
a = A()
firstB = a.listB[0]
print firstB.splitGlobalObject()
Here when I generateBList() I need to pass always that globalObject as an argument B(self.globalObject, i), and then this object gets saved into B.globalObject, butif i had many classes that needed to access that global object im not sure if passing it always as an argument would be the best option. What would be the best way of accessing it without having to pass it always as an argument when you create instances?
I hope I explained my way properly.
Your example seems unnecessarily complicated, so I'll try to illustrate one way I've used before that I think may do what you want. If you think of creating a "world" that is the stage for what you want to happen, you can have each class instance inside the world, know the world. Like this:
class Thing(object):
def __init__self(self, world, name):
self.world = world
self.name = name
class Word(object):
def __init__(self):
self.everyone = [Thing(self, i) for i in range(10)]
if __name__ == '__main__':
world = World()
In this example, the World class instance carries around an attribute called everyone that is a list of ten Thing objects. More importantly for your example, each instance of Thing now carries around a pointer called self.world that points to the world class. So all Things can access all other Things via self.world.everyone, as well as anything else in the world. I also passed i into each Things init so they have a unique name in the form of an integer between 0 and 9, but that may be extra for what you need.
From here there's basically nothing that your instances can't do to each other via methods, and all without using lots of globals.
Edit: I should add that being from different modules will make no difference here, just import as many as you want and create instances of them that pass knowledge of the World instance into them. Or obviously tailor the structure to your needs while using the same idea.
It's possible to use global variables in python.
class A(object):
def __init__(self):
global globalObject
globalObject = "Global Object"
self.listB = self.generateBList()
def generateBList(self):
return [B(i) for i in range(10)]
class B(object):
def __init__(self, index):
self.index = index
def splitGlobalObject(self):
return globalObject.split(" ")
Usually you want to avoid globals. Visit http://www.python-kurs.eu/python3_global_lokal.php for more examples.
For different data types, like string, there are methods that you call by adding a dot after, such as:
"string {0}".format(stringy)
or
listx.remove(x)
How is the information being passed to the method? How can I write a function like that?
class YourObject(object):
def do_something(self):
print('doing something')
Then you can use your object:
your_object = YourObject()
your_object.do_something()
This shows how to create an object, and call a method on it (like theexamples you provided in your post).
There are way more in-depth tutorials/blogs about object creation and custom classes. A good place to start is always the standard documentation.
You can create a custom class and then include whatever methods you want. Below is an example:
>>> class MyClass(object): # Define class MyClass
... def __init__(self): # Define MyClass' constructor method
... self.name = "Me" # Make an attribute
... def getName(self): # Define method getName
... return self.name # Return MyClass' attribute name (self.name)
...
>>> test = MyClass() # Initialize (create an instance of) MyClass
>>> print test.getName() # Print the name attribute by calling the getName method
Me
>>>
Basically, you are working with OOP (Object-Oriented Programming). However, since this concept is so large, I can't demonstrate/explain everything you can do with it here (otherwise my post would be enormous). My advice is to research OOP and Python classes. There are many good tutorials you can find. I gave one above; here is another:
Assuming i have a class that implements several methods. We want a user to chose to which methods to run among the exisiting methods or he can decide to add any method on_the_fly.
from example
class RemoveNoise():
pass
then methods are added as wanted
RemoveNoise.raw = Raw()
RemoveNoise.bais = Bias()
etc
he can even write a new one
def new():
pass
and also add the new() method
RemoveNoise.new=new
run(RemoveNoise)
run() is a function that evaluates such a class.
I want to save the class_with_the_methods_used and link this class to the object created.
Any hints on how to solve this in python?
Functions can be added to a class at runtime.
class Foo(object):
pass
def bar(self):
print 42
Foo.bar = bar
Foo().bar()
There is no solving needed, you just do it. Here is your code, with the small changes needed:
class RemoveNoise():
pass
RemoveNoise.raw = Raw
RemoveNoise.bias = Bias
def new(self):
pass
RemoveNoise.new=new
instance = RemoveNoise()
It's that simple. Python is wonderful.
Why on earth you would need this is beyond me, though.
Well, here's some code that does what I think you're asking for -- although I'm not really sure what you meant by "save" when you wrote "I want to save the class_with_the_methods_used". Also note that using an exec statement on user input can be extremely dangerous if it comes from an untrusted source.
import copy
# an empty "template" class
class Generic():
pass
# predefined functions that create common methods
def Raw():
def raw(self):
print 'in Raw method of instance', id(self)
return raw
def Bias():
def bias(self):
print 'in Bias method of instance', id(self)
return bias
def user_new_function(definition):
tempdict = {}
exec definition in tempdict
return tempdict['new']
# create a new class
RemoveNoise = copy.deepcopy(Generic)
RemoveNoise.__name__ = 'RemoveNoise' # change the class name of the copy
# add a couple of predefined methods
RemoveNoise.raw = Raw()
RemoveNoise.bias = Bias()
# add user defined 'new' method
user_new_def = """\
def new(self):
print 'in user defined method "new" of instance', id(self)
"""
RemoveNoise.new = user_new_function(user_new_def)
# create and use an instance of dynamically defined class
instance = RemoveNoise()
print 'RemoveNoise instance "{}" created'.format(id(instance))
# RemoveNoise instance "11974736" created
instance.raw()
# in Raw method of instance 11974736
instance.bias()
# in Bias method of instance 11974736
instance.new()
# in user defined method "new" of instance 11974736
I am doing something like this:
class Class(object):
def __init__(self):
self.var=#new instance name string#
How do I make the __ init __ method of my instance to use the instance name string for 'c'? Say in case:
c=Class()
I want c.var equal to 'c'.
Thanks for your replies, I am implementing persistence and Class is persistent object's class. I want __ init __ to add an entry to the database when:
c=Class()
Then, suppose:
del c
Later on:
c=Class()
sholuld create an instance using data from database if there already is an entry 'c', otherwise create new entry.
Thanks for your replies, I am implementing persistence and Class is persistent object's class. I want __ init __ to add an entry to the database when:
c=Class()
Then, suppose:
del c
Later on:
c=Class()
sholuld create an instance using data from database if there already is an entry 'c', otherwise create new entry.
Python doesn't have variables, it has objects and names. When you do
c = Class()
you're doing two things:
Creating a new object of type Class
Binding the object to the name c in the current scope.
The object you created doesn't have any concept of a "variable name" -- If later you do
a = c
then the same object is accessible in exactly the same way using the names a and c. You can delete the name a, and the object would still exist.
If the objects you create need to have a name, the best way is to pass it to them explicitly,
class Class(object):
def __init__(self, name):
self.name = name
var = Class('var')
You can't do this. The reason for this is that the object of the class is created first, and only afterwards is this object bound to the name of the instance.
You can't (short of incredible hacks like examining the stack frame and inspecting the bytecode). There may not even be a name, or there could be multiple such names. What should be given for the following code fragments for instance:
l = [Class(), Class()]
a=b=c=d=Class()
I don't think this would be possible because the assignment to the variable of your new instance occours after the object is fully constructed and initialized and so you don't know the variable name it will be assigned to within init method
To persist data objects you need to use the database record's unique ID.
pesudo code because I don't know what database module you're using
import db # assume this is your db module
class Class(object):
def __init__(self):
self.id = None
self.name = None
def get_by_id(self, id):
records = db.execute('select * from table where id=%s' % str(id))
if records:
self.id = records[0]['id']
self.name = records[0]['name']
def save(self):
db.execute('update table set name=%s where id=%s' % (self.name, str(self.id)))
Again, this is pseudo code, the string injection technique I'm using is NOT advised as its fairly insecure, its just there to illustrate how to persist using classes with a db.
I am unaware of a way to access a variable's name programmatically without using deep reflection and a debugger. I do not think the information is available at runtime.
If you want to give instances a (unique?) name, you should probably make the initializer accept an extra argument.
def __init__(self, name):
self.name = name
And the caller should pass in the appropriate name:
c = Class("c")
This is a scope issue, you can't do what you're asking. Because c would be declared outside your class' scope, your instance is unaware of what its been named in code.
Perhaps if you can provide a broader explanation of what you're trying to accomplish a better solution can be suggested.
That isn't possible. You seem to be confusing variables and objects.
In any case there may well not be a variable:
e.g.
foo(Class())
Class().arbitraryMethod()
Or multiple:
a = b = Class()
I have the same thought several years ago. This is somekind of neat feature, but the language creator doesn't provide it. And I thought they are all fool to not discover this great feature.
But then come to think about that. I think the logic is impossible. say:
class Class(object):
def __init__(self):
self.instance_name.move() # self.instance_name refer to var
def move(self):
print "move"
var = Class()
now if the var is an array is that possible too ?
var[0] = Class() # i think it will get confused a bit
that's what i think of, i don't think that assigning the instance into itself is possible. and in some language I just sent the instance string into the object then using eval to execute the function
With a class in Python, how do I define a function to print every single instance of the class in a format defined in the function?
I see two options in this case:
Garbage collector
import gc
for obj in gc.get_objects():
if isinstance(obj, some_class):
dome_something(obj)
This has the disadvantage of being very slow when you have a lot of objects, but works with types over which you have no control.
Use a mixin and weakrefs
from collections import defaultdict
import weakref
class KeepRefs(object):
__refs__ = defaultdict(list)
def __init__(self):
self.__refs__[self.__class__].append(weakref.ref(self))
#classmethod
def get_instances(cls):
for inst_ref in cls.__refs__[cls]:
inst = inst_ref()
if inst is not None:
yield inst
class X(KeepRefs):
def __init__(self, name):
super(X, self).__init__()
self.name = name
x = X("x")
y = X("y")
for r in X.get_instances():
print r.name
del y
for r in X.get_instances():
print r.name
In this case, all the references get stored as a weak reference in a list. If you create and delete a lot of instances frequently, you should clean up the list of weakrefs after iteration, otherwise there's going to be a lot of cruft.
Another problem in this case is that you have to make sure to call the base class constructor. You could also override __new__, but only the __new__ method of the first base class is used on instantiation. This also works only on types that are under your control.
Edit: The method for printing all instances according to a specific format is left as an exercise, but it's basically just a variation on the for-loops.
You'll want to create a static list on your class, and add a weakref to each instance so the garbage collector can clean up your instances when they're no longer needed.
import weakref
class A:
instances = []
def __init__(self, name=None):
self.__class__.instances.append(weakref.proxy(self))
self.name = name
a1 = A('a1')
a2 = A('a2')
a3 = A('a3')
a4 = A('a4')
for instance in A.instances:
print(instance.name)
You don't need to import ANYTHING! Just use "self". Here's how you do this
class A:
instances = []
def __init__(self):
self.__class__.instances.append(self)
print('\n'.join(A.instances)) #this line was suggested by #anvelascos
It's this simple. No modules or libraries imported
Very nice and useful code, but it has a big problem: list is always bigger and it is never cleaned-up, to test it just add print(len(cls.__refs__[cls])) at the end of the get_instances method.
Here a fix for the get_instances method:
__refs__ = defaultdict(list)
#classmethod
def get_instances(cls):
refs = []
for ref in cls.__refs__[cls]:
instance = ref()
if instance is not None:
refs.append(ref)
yield instance
# print(len(refs))
cls.__refs__[cls] = refs
or alternatively it could be done using WeakSet:
from weakref import WeakSet
__refs__ = defaultdict(WeakSet)
#classmethod
def get_instances(cls):
return cls.__refs__[cls]
Same as almost all other OO languages, keep all instances of the class in a collection of some kind.
You can try this kind of thing.
class MyClassFactory( object ):
theWholeList= []
def __call__( self, *args, **kw ):
x= MyClass( *args, **kw )
self.theWholeList.append( x )
return x
Now you can do this.
object= MyClassFactory( args, ... )
print MyClassFactory.theWholeList
Python doesn't have an equivalent to Smallktalk's #allInstances as the architecture doesn't have this type of central object table (although modern smalltalks don't really work like that either).
As the other poster says, you have to explicitly manage a collection. His suggestion of a factory method that maintains a registry is a perfectly reasonable way to do it. You may wish to do something with weak references so you don't have to explicitly keep track of object disposal.
It's not clear if you need to print all class instances at once or when they're initialized, nor if you're talking about a class you have control over vs a class in a 3rd party library.
In any case, I would solve this by writing a class factory using Python metaclass support. If you don't have control over the class, manually update the __metaclass__ for the class or module you're tracking.
See http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html for more information.
In my project, I faced a similar problem and found a simple solution that may also work for you in listing and printing your class instances. The solution worked smoothly in Python version 3.7; gave partial errors in Python version 3.5.
I will copy-paste the relevant code blocks from my recent project.
```
instances = []
class WorkCalendar:
def __init__(self, day, patient, worker):
self.day = day
self.patient = patient
self.worker= worker
def __str__(self):
return f'{self.day} : {self.patient} : {self.worker}'
In Python the __str__ method in the end, determines how the object will be interpreted in its string form. I added the : in between the curly brackets, they are completely my preference for a "Pandas DataFrame" kind of reading. If you apply this small __str__ function, you will not be seeing some machine-readable object type descriptions- which makes no sense for human eyes. After adding this __str__ function you can append your objects to your list and print them as you wish.
appointment= WorkCalendar("01.10.2020", "Jane", "John")
instances.append(appointment)
For printing, your format in __str__ will work as default. But it is also possible to call all attributes separately:
for instance in instances:
print(instance)
print(instance.worker)
print(instance.patient)
For detailed reading, you may look at the source: https://dbader.org/blog/python-repr-vs-str