Python: Factory attributes - python

Is setup.inQ different from complete.inQ?
If I put something in one queue, it wouldn't show up in the other queue, correct?
import Queue
class Factory:
name = ""
inQ = Queue.Queue()
outQ = Queue.Queue()
def worker(self): pass
#staticmethod
def getFactory(factory_name):
if factory_name == "setup":
return SetupFactory()
elif factory_name == "dispatch":
return DispatchFactory()
elif factory_name == "complete":
return CompleteFactory()
else:
return None
class SetupFactory(Factory):
name = "setup"
def worker(self):
#extend
class DispatchFactory(Factory):
name = "dispatch"
def worker(self):
#extend
class CompleteFactory(Factory):
name = "complete"
def worker(self):
#extend
setup = Factory.getFactory("setup")
complete = Factory.getFactory("complete")

This is easy enough to test:
>>> import Queue
>>> class A(object):
... q = Queue.Queue()
...
>>> class B(A):
... pass
...
>>> a = A()
>>> b = B()
>>> b.q is a.q
True
We see that the q attribute is indeed shared across subclasses. (putting things in b.q is the exact same things as putting things in a.q).
This makes sense because A.q is an attribute of the class, so it gets created when A gets created. Python doesn't create a new one when B gets created since B just inherits properties and methods from A.
Generally speaking, if you want to have a property that isn't shared across instances of a class, you'd put it in the class's initialization function (__init__) which gets called magically by python when you create an instance of a class:
class Factory(object):
name = ""
def __init__(self):
self.inQ = Queue.Queue()
self.outQ = Queue.Queue()

Related

Dynamically adopt the methods of an instance of another class

I have a case, where I have an instance of a class in python which holds instances of other classes. For my use case, I would like a way to use the methods of the "inner" classes from the outer class without referencing the attribute holding the inner class.
I have made a simplistic example here:
class A:
def __init__(self):
pass
def say_hi(self):
print("Hi")
def say_goodbye(self):
print("Goodbye")
class C:
def __init__(self, other_instance):
self.other_instance= other_instance
def say_good_night(self):
print("Good night")
my_a = A()
my_c = C(other_instance=my_a)
# How to make this possible:
my_c.say_hi()
# Instead of
my_c.other_instance.say_hi()
Class inheritance is not possible, as the object passed to C may be an instance of a range of classes. Is this possible in Python?
I think this is the simplest solution although it is possible with metaprogramming.
class A:
def __init__(self):
pass
def say_hi(self):
print("Hi")
def say_goodbye(self):
print("Goodbye")
class C:
def __init__(self, other_class):
self.other_class = other_class
C._add_methods(other_class)
def say_good_night(self):
print("Good night")
#classmethod
def _add_methods(cls, obj):
type_ = type(obj)
for k, v in type_.__dict__.items():
if not k.startswith('__'):
setattr(cls, k, v)
my_a = A()
my_c = C(other_class=my_a)
my_c.say_hi()
output :
Hi
First we get the type of passed instance, then we iterate through it's attribute (because methods are attributes of the class not the instance).
If self.other_class is only needed for this purpose, you can omit it as well.
So, because you have done:
my_a = A() and my_c = C(other_class=my_a).
my_c.other_class is the same as my_a asthey point to the same location in memory.
Therefore, as you can do my_a.say_hi() you could also do my_c.other_class.say_hi().
Also, just a note, as you are calling A() before you store it into other_classes, I would probably rename the variable other_classes to class_instances.
Personally, I think that would make more sense, as each of those classes would have already been instantiated.

Base class variable does not store value which is set by Derived class

I am new to python.
Base class/python file(Base.py).
SESSION_ID = ""
def m1():
print "SESSION_ID in base: ",SESSION_ID
Derived class(Derived.py)
from Base import *
class Derived():
def m2(self):
global SESSION_ID
SESSION_ID = 10
print "SESSION_ID in derived: ", SESSION_ID
def main():
c2 = Derived()
c2.m2()
m1()
if __name__ == "__main__":
main()
When I execute Derived.py file below is the output:
SESSION_ID in derived: 10
SESSION_ID in base:
I want the value which is set in m2() to be reflected in m1(). So the expected output is:
SESSION_ID in derived: 10
SESSION_ID in base: 10
Can you please help?
The global variable in a module is merely an attribute (i.e. a member
entity) of that module.
As result of that when you use import *, the new local module global SESSION_ID is created, so the SESSION_ID in the base is immune to the changes you are doing in the Derived.
Basically, modifying base.SESSION_ID don't require usage of the global statement in the Derived.py, adjusting import is enough, see code below:
from settings import base
class Derived():
def m2(self):
base.SESSION_ID = 10
print "SESSION_ID in derived: ", base.SESSION_ID
def main():
c2 = Derived()
c2.m2()
base.m1()
if __name__ == "__main__":
main()
Your Derived class is not derived from anything inside Base.py. Here, you are just calling a basic function from Base from within Derived, nothing more.
Here is an example on class inheritance in Python3 :
>>> class Base():
>>> SESSION = 42
>>>
>>> def print_session(self):
>>> print("Base session : %d" % self.SESSION)
>>>
>>> class Derived(Base):
>>> SESSION = 999
>>>
>>> d = Derived()
>>> d.print_session()
Base session : 999
I would avoid using global and class-scoped variables if at all possible. These can make your program harder to understand (if something else changes a global underneath you it's hard to notice) and test (you need to reset all global state between every test; it's often easier to just create new empty state).
I might restructure this example by creating a state object:
class State:
def __init__(self):
self.session_id = ''
And then making that explicitly be a property, say, of the base class:
class Base:
def __init__(self, state):
self.state = state
def m1(self):
print("SESSION_ID in base: " + str(self.state.session_id))
class Derived(Base):
def m2(self):
self.state.session_id = '10'
print("SESSION_ID in derived: " + str(self.state.session_id))
Then in your main function you need to explicitly create the state object and pass it in
def main():
state = State()
c2 = Derived(state)
c2.m2()
c2.m1()
But, critically, your tests don't need to worry about state leakage
def test_m2():
state = State()
obj = Derived(state)
obj.m2()
assert state.session_id == '10'
def test_m1():
state = State()
obj = Base(state)
obj.m1()
# If the session ID was a global or a class variable,
# you'd get a different result if m2() was called or not
assert state.session_id == ''

Modifying library function after importing

Say I'm importing a library which has some core functionality for the program I'm writing. It looks like:
class dothing(object):
def __init__(self):
# stuff
def main(self):
self.thing = []
self.option = []
How can I modify the contents of its variables, without touching the library itself - in other words, from my local code. Or, how can I modify the function "main"?
I've heard of "monkey patching" but I'm not sure this is the right thing
If you want to alter the main function, you can indeed use monkey patching. This is the preferred strategy if you want to alter how the whole class donothing behaves.
class dothing(object):
def __init__(self):
# stuff
def main(self):
self.thing = []
self.option = []
def my_new_main(self):
print("Hello")
self.thing = {}
self.option = ["Foo"]
donothing.main = my_new_main
dn = donothing()
dn.main()
# Hello
dn.thing
# {}
dn.option
# ["Foo"]
You can also use this strategy to attach new methods to donothing.
donothing.bar = lambda self, x: x + 3
dn.bar(1)
# 4
Define another class that inherits from your original class and override the "main" method as follows:
class doOtherThing(dothing):
def main(self):
self.thing = [1] # this is just a value different from [] in the original "main"

python using __init__ vs just defining variables in class - any difference?

I'm new to Python - and just trying to better understand the logic behind certain things.
Why would I write this way (default variables are in __init__):
class Dawg:
def __init__(self):
self.previousWord = ""
self.root = DawgNode()
self.uncheckedNodes = []
self.minimizedNodes = {}
def insert( self, word ):
#...
def finish( self ):
#...
Instead of this:
class Dawg:
previousWord = ""
root = DawgNode()
uncheckedNodes = []
minimizedNodes = {}
def insert( self, word ):
#...
def finish( self ):
#...
I mean - why do I need to use __init__ -> if I can just as easily add default variables to a class directly?
When you create variables in the Class, then they are Class variables (They are common to all the objects of the class), when you initialize the variables in __init__ with self.variable_name = value then they are created per instance and called instance variables.
For example,
class TestClass(object):
variable = 1
var_1, var_2 = TestClass(), TestClass()
print var_1.variable is var_2.variable
# True
print TestClass.variable is var_1.variable
# True
Since variable is a class variable, the is operator evaluates to True. But, in case of instance variables,
class TestClass(object):
def __init__(self, value):
self.variable = value
var_1, var_2 = TestClass(1), TestClass(2)
print var_1.variable is var_2.variable
# False
print TestClass.variable is var_1.variable
# AttributeError: type object 'TestClass' has no attribute 'variable'
And you cannot access an instance variable, with just the class name.
When you write this:
class Dawg:
previousWord = ""
root = DawgNode()
uncheckedNodes = []
minimizedNodes = {}
Those are not instance variables, they're class variables (meaning: the same variables with the same values are shared between all instances of the class.) On the other hand, this:
class Dawg:
def __init__(self):
self.previousWord = ""
self.root = DawgNode()
self.uncheckedNodes = []
self.minimizedNodes = {}
... Is declaring instance variables, meaning: the values are different for each instance of the class. As you see, each snippet means a completely different thing, and you have to pick the one that is appropriate for you. Hint: most of the time you're interested in instance variables, because class variables define a kind of shared global state for your objects, which is error prone.

Creating an object with a reference to the object that created it

I have a program where an object creates another object. However, the second object that gets created needs to be able to access the first. Is this possible?
EG (pseudocode)
class parentObject():
parentVar = 1
# Create Child
x = childObject()
class childObject():
#Assign Var to the Var of the childs parent
childVar = parent.parentVar
>>> x.childVar = 1
is there a straitforward way to do this?
UPDATE:
I don't want to inheret the class, I need to be able to access the actual object that created it, as each object created from that class has different values.
Why not inherit the class?
class parentObject():
parentVar = 1
class childObject(parentObject):
childVar = parentObject.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you are going to have different instances of the class, you should do it as this instead:
class parentObject(object):
def __init__(self):
self.parentVar = 1
class childObject(parentObject):
def __init__(self):
super(childObject, self).__init__()
self.childVar = self.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you want a reference to the "parent" class, but inheritance is illogical, consider sending self in to the constructor:
class Room:
def __init__(self, name):
self.name = name
self.furniture = []
def add_chair(self):
self.furniture.append(Chair(self))
def __str__(self):
return '{} with {}'.format(self.name, self.furniture)
class Chair:
def __init__(self, room):
self.room = room
def __str__(self):
return 'Chair in {}'.format(self.room.name)
r = Room('Kitchen')
r.add_chair()
r.add_chair()
print r
print r.furniture[0]
Output:
Kitchen with [<__main__.Chair instance at 0x01F45F58>, <__main__.Chair instance at 0x01F45F80>]
Chair in Kitchen

Categories

Resources