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"
Related
I have a question regarding the classes in python3. In my programm i have a "main" class that is getting started first and sets some parameters that are needed for the other parts of the programm. But now my other classes need some objects of the main class. How can i use the objects of the main class without initialising the main class everytime the subclass needs the object ? I looked into python inheritance but maybe i didnt understand it correctly
class Chunk(main.Main):
def __init__(self,pos_in_world_x,pos_in_world_y):
#self.chunksize = settings.blocks_per_chunk
self.prog = main.Main.prog
self.ctx = main.Main.ctx
this is my code for the subclass
You can use class variables:
class Main():
prog = 1
ctx = 2
def __init__(self):
pass
class Chunk(Main):
def __init__(self, pos_in_world_x, pos_in_world_y):
self.prog = Main.prog
self.ctx = Main.ctx
a = Chunk(3, 4)
print(a.prog) # 1
print(a.ctx) # 2
If you can't change Main to move your definitions outside __init__, then what you're asking for is impossible. If your variable is defined in __init__, you can't access it before calling __init__, i.e. initialising the class. You can't get round this.
You need a super __init__ call in your subclass and if you have that you only need to do:
class Chunk(main.Main):
def __init__(self,pos_in_world_x,pos_in_world_y):
super().__init__()
#self.chunksize = settings.blocks_per_chunk
Both of the assignments are done by Main's __init__.
But I think that Chunk has not an is-a but rather a has-a relation with Main so Main should actually be an argument rather than a super class:
class Chunk(object):
def __init__(self, main, pos_in_world_x,pos_in_world_y):
#self.chunksize = settings.blocks_per_chunk
self.prog = main.prog
self.ctx = main.ctx
Any one that creates a Chunk must pass a Main instance.
It is actually difficult to hide information in Python, so here are a few options which don't require inheritance (see jpp's answer for the inheritance option). In general, the code is easier to understand when you pass information explicitly (option 1 below, or inheritance), but there may be cases where you'd prefer the other options.
Option 1: The needed info can simply be passed as additional arguments to Chunk's __init__ (either by passing the prog and ctx values themselves, or by passing the Main class or its instance - depending on whether the needed info is stored as class or instance variables). Here's an example of passing Main as an argument:
class Main():
prog = 1
ctx = 2
def __init__(self):
pass
class Chunk():
def __init__(self, pos_in_world_x, pos_in_world_y, M):
#self.chunksize = settings.blocks_per_chunk
self.prog = M.prog
self.ctx = M.ctx
c = Chunk(3, 4, Main)
print(c.prog) # 1
print(c.ctx) # 2
Option 2: Chunk can access Main's class variables directly:
class Main():
prog = 1
ctx = 2
def __init__(self):
pass
class Chunk():
def __init__(self, pos_in_world_x, pos_in_world_y):
#self.chunksize = settings.blocks_per_chunk
self.prog = Main.prog
self.ctx = Main.ctx
c = Chunk(3, 4)
print(c.prog) # 1
print(c.ctx) # 2
Option 3: Chunk can access the instance variables of the Main instance directly (Main needs to be instantiated before Chunk is instantiated):
class Main():
def __init__(self):
self.prog = 1
self.ctx = 2
class Chunk():
def __init__(self, pos_in_world_x, pos_in_world_y):
#self.chunksize = settings.blocks_per_chunk
self.prog = m.prog
self.ctx = m.ctx
m = Main()
c = Chunk(3, 4)
print(c.prog) # 1
print(c.ctx) # 2
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()
how do i use variable in class function, which i created in other, without using global and return? there is some other ways?
class functions:
def func1():
x=[1,2]
def func2():
print x
func1()
func2()
output:
[1,2]
the real problem:
class WebPage:
def __init__(self, filename):
self.filename=filename
def process(self):
toproc=open(self.filename,'r')
lines=toproc.readlines()
for i in range(len(lines)):
lines[i] = lines[i].rstrip()
head=[]
body=[]
process....
head=[headline]
body=[sitebody]
def printedheadbody:
print head
print body
Make them attributes and use self.head, self.body, you also don't need to call readlines, you can iterate directly over the file object and call line.rstrip() as you go if you want to strip. You should also inherit from object in python2 to support new style classes.
class WebPage(object):
def __init__(self, filename):
self.filename = filename
self.head = []
self.body = []
def process(self):
with open(self.filename) as f:
for line in f:
# use self.head,self.body
def printedheadbody(self):
print self.head
print self.body
Without using self in your methods, you basically have static methods which won't allow you to refer to the attributes with self.
To access the methods create an instance and call the methods in order:
w = WebPage("foo.html")
w.process()
w.printedheadbody()
You also don't need the print method, you could access the attributes with the instance and just print each:
w = WebPage("foo.html")
w.process()
print(w.head)
print(w.body)
The attributes could also be created in the process method:
def process(self):
self.head=[]
self.body=[]
with open(self.filename) as f:
for line in f:
....
but you would need to make sure you called process before you ever tried to acesss them.
You need to use self in a class. This variable is an instance of itself.
class functions:
def func1(self):
self.x = [1,2]
def func2(self):
print self.x
functions_1 = functions()
functions_1.func1()
functions_1.func2()
>> [1,2]
I want to share a variable value between a function defined within a python class and an externally defined function. So in the code below, when the internalCompute() function is called, self.data is updated. How can I access this updated data value inside a function that is defined outside the class, i.e inside the report function?
Note:
I would like to avoid using of global variable as much as possible.
class Compute(object):
def __init__(self):
self.data = 0
def internalCompute(self):
self.data = 5
def externalCompute():
q = Compute()
q.internalCompute()
def report():
# access the updated variable self.data from Compute class
print "You entered report"
externalCompute()
report()
It's a good idea to avoid magic globals, but your report() function must have some way to know where to look. If it's ok to pass it the object doing the computation, i.e. q, it can simply print out q.data. If not, then you can arrange for q to save its data in the class itself-- obviously this means that the class can only be instantiated once, so I would go with the first option.
You can't do that unless you instantiate the class somewhere.
Currently in your implementation you instantiate the Compute class here:
def externalCompute():
q = Compute()
q.internalCompute()
But as soon as the function finishes q goes out of scope and is destroyed so you will lose all information that the class contains. In order to do what you want to do the Compute class has to be instantiated to not be local to a function (or your function needs to return the instance of the Compute class as to preserve its state.)
Usually you would do that by having one "main" if your python file in this way:
class Compute(object):
def __init__(self):
self.data = 0
def internalCompute(self):
self.data = 5
def externalCompute(q):
q.internalCompute()
def report(q):
# access the updated variable self.data from Compute class
data = q.data
print "You entered report"
if __name__ == '__main__':
q = Compute()
externalCompute(q)
report(q)
You actually have access to the data through q.data, you just have to return it.
Change your code to reflect that fact:
class Compute(object):
def __init__(self):
self.data = 0
def internalCompute(self):
self.data = 5
def externalCompute():
q = Compute()
q.internalCompute()
return q.data
def report():
print externalCompute()
report() # 5
If you don't like this approach, you have only a few other options:
Global variable.
Instantiating another class.
Updating the same class you instantiated.
Database.
Pickle.
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.