How can an object access its owner's global? - python

If we have something like:
foo.py
from bar import bar
class foo:
global black;
black = True;
bar = bar()
bar.speak()
f = foo()
bar.py
class bar:
def speak():
if black:
print "blaaack!"
else:
print "whitttte!"
when we run
python foo.py
we get
NameError: global name 'black' is not defined
What's the best practise for doing something like this?
Should I pass it in the method?
Have the bar class have a parent variable?
For context, in practise the black global is for a debugging step.

In Python, globals are specific to a module. So the global in your foo.py is not accessible in your bar.py--not the way you have it written at least.
If you want every instance of foo to have its own value of black, then use an instance variable as Ivelin has shown. If you want every instance of foo to share the same value of black use a class variable.
Using an instance variable:
# foo.py
from bar import bar
class foo:
# Python "constructor"..
def __init__(self):
# Define the instance variables
self.bar = bar()
# Make bar talk
self.bar.speak()
# Create a function for making this foo's bar speak whenever we want
def bar_speak(self):
self.bar.speak()
################################################################################
# bar.py
class bar:
# Python "constructor"..
def __init__(self):
# Define the instance variables
self.black = True
def speak(self):
if self.black:
print "blaaack!"
else:
print "whitttte!"
Playing with the code:
>>> f = foo()
blaaack!
>>> b = foo()
blaaack!
>>> b.bar.black = False
>>> b.bar_speak()
whitttte!
>>> f.bar_speak()
blaaack!
Using a class variable:
# foo.py
from bar import bar
class foo:
# Python "constructor"..
def __init__(self):
# Define the instance variables
self.bar = bar()
# Make bar talk
self.bar.speak()
# Create a function for making this foo's bar speak whenever we want
def bar_speak(self):
self.bar.speak()
################################################################################
# bar.py
class bar:
black = True
def speak():
if bar.black:
print "blaaack!"
else:
print "whitttte!"
Playing with the code:
>>> f = foo()
blaaack!
>>> b = foo()
blaaack!
>>> bar.black = False
>>> b.bar_speak()
whitttte!
>>> f.bar_speak()
whitttte!

Here is what I would do:
foo.py
from bar import bar
class foo:
bar = bar(black=True)
bar.speak()
f = foo()
bar.py
class bar:
def __init__(black):
self.black = black
def speak():
if self.black:
print "blaaack!"
else:
print "whitttte!”

Related

Python: Using modules as classes

As I try to use more and more functional programming (i.e. use classes less), I have noticed I start to use modules as classes:
#File foomod.py
foo = None
def get_foo():
global foo
if foo is None:
foo = 1 + 1
return foo
# main.py
import foomod
x = foomod.get_foo()
This might as well be
#File foo.py
class foo:
foo = None
#staticmethod
def get_foo(cls):
if cls.foo is None:
cls.foo = 1 + 1
return cls.foo
# main.py
from foo import Foo
x = Foo.get_foo()
Is there any reason to favour one over the other? E.g. speed or something else?

Python doctest: have a common initialization for several tests

I want to have a doctest for a class, where the use of the class needs a somehow lengthy setup. Like:
class MyClass
def __init__(self, foo):
self.foo = foo
def bar(self):
"""Do bar
>>> # do a multiline generation of foo
... ...
>>> myoby = MyClass(foo)
>>> print(myobj.bar())
BAR
"""
…
def foobar(self):
"""Do foobar
>>> # do a multiline generation of foo
... ...
>>> myoby = MyClass(foo)
>>> print(myobj.foobar())
FOOBAR
"""
…
My real case has ~8 methods that I want to document and pytest. Repeating the generation of foo everywhere contradicts the DRY principle, and also generated quite lengthy and unreadable documentation. Is there a way to avoid it?
Optimally would be like
class MyClass
"""My class
An example way to create the 'foo' argument is
>>> # do a multiline generation of foo
... ...
"""
def __init__(self, foo):
self.foo = foo
def bar(self):
"""Do bar
>>> myoby = MyClass(foo)
>>> print(myobj.bar())
BAR
"""
…
def foobar(self):
"""Do foobar
>>> myoby = MyClass(foo)
>>> print(myobj.foobar())
FOOBAR
"""
…
After some struggling, I found the following solution, (ab)using a submodule of my own module:
class MyClass
"""My class
An example way to create the 'foo' argument is::
>>> # do a multiline generation of foo
>>> foo = ...
.. only:: doctest
>>> import mymodule.tests
>>> mymodule.tests.foo = foo
"""
def __init__(self, foo):
self.foo = foo
def bar(self):
"""Do bar
.. only:: doctest
>>> import mymodule.tests
>>> foo = mymodule.tests.foo
Here is a good example, using the initialization above::
>>> myoby = MyClass(foo)
>>> print(myobj.bar())
BAR
"""
…
The "tricks":
I abuse my mypackage.tests submodule to store the results of the initialization. This works, since the modules are not re-initialized in subsequent tests
Doctest (at least in pytest) doesn't care about code blocks, it just looks for the appropriate patterns and indentions. Any block is fine, even a conditional one (.. only::). The condition (doctest) is arbitrary, it just needs to be evaluated to false so that the block isn't displayed.
I am still not sure how robust this is with respect to future developments of doctest/pytest and sphinxdoc.
This answer assumes you are using pytest --doctest-modules which is hinted at in the question/comments, but isn't explicit. See pytest using fixtures. If you don't need the documentation to include the steps to make foo argument, a fixture will work. getfixture is mentioned in the documentation for doctest, but it is hard to find documentation specifically for it.
# conftest.py
import pytest
#pytest.fixture()
def foo_setup():
foo = [100, 10] # make a complex foo
return foo
# my_module.py
class MyClass:
"""
My class.
>>> foo = getfixture('foo_setup')
>>> # consider printing details of foo here
>>> myobj = MyClass(foo)
>>> myobj.foo
[100, 10]
"""
def __init__(self, foo):
self.foo = foo
def foobar(self):
"""
foobar appends 0 to foo.
>>> foo = getfixture('foo_setup')
>>> myobj = MyClass(foo)
>>> myobj.foobar()
>>> myobj.foo
[100, 10, 0]
"""
self.foo.append(0)
You can inject foo into the namespace using a fixture. This avoids having any extraneous lines in each doctest. Documentation.
# mymodule.py
import pytest
#pytest.fixture(autouse=True)
def foo_setup(doctest_namespace):
doctest_namespace["foo"] = [100, 10] # make a complex foo
# my_module.py
class MyClass:
"""
My class.
>>> # consider printing details of foo here
>>> myobj = MyClass(foo)
>>> myobj.foo
[100, 10]
"""
def __init__(self, foo):
self.foo = foo
def foobar(self):
"""
foobar appends 0 to foo.
>>> myobj = MyClass(foo)
>>> myobj.foobar()
>>> myobj.foo
[100, 10, 0]
"""
self.foo.append(0)

Create an object of the same class within the class

I want to have an object of a class within a class, because I need to pass it to a method, similarly to the example below. I would like the example below to print out 1, or fooObj.fooNum, but I keep getting a NameError: name 'foo' is not defined.
class bar:
def fooDef(self, fooObj):
print fooObj.fooNum
class foo:
fooNum = 1
b = bar()
f = foo()
b.fooDef(f)
Please, can you be more specific about what you are trying to do?
The error you see is normal, because the code immediately below class foo will be executed during the definition of foo and therefore the class is not defined yet.
If I understand well you want to define some method foobar of the class foo, which will use a foo instance. The correct procedure would then be
class foo:
def foobar(self,):
f = foo()
...
Again, with more details about what you are trying to do it would be easier to help you.
Although it's unclear what you are asking, but the following changes do what you want to have.
But the code uses the instance of foo() not the class:
class bar:
def fooDef(self, fooObj):
print fooObj.fooNum
class foo:
def __init__(self):
self.fooNum = 1
b = bar()
f = self
b.fooDef(f)
f = foo()
Prints:
1

changing values inside a local space by a function in that local space

here's a sample code:
def foo():
def bar():
foobar = 'foobaz'
foobar = 'foobar'
print foobar
bar()
print foobar
foo()
I want to change variable foobar inside foo by function bar. The code above will not work, since foobar inside bar is in separate namespace with foobar in foo. A simple workaround would be making a global foobar and have both foo and bar can access it, but I hope there would be simpler workarounds.
On python 3.x you can use nonlocal and for python 2.x try using function attributes:
def foo():
def bar():
foo.foobar = 'foobaz' #change the function attribute
foo.foobar = 'foobar' #declare as function attribute
print foo.foobar
bar()
print foo.foobar
foo()
output:
foobar
foobaz
You are looking for the nonlocal keyword, which exists in 3.x.
def f():
x = None
def g():
nonlocal x
x = 1
If you are stuck in 2.x, you can do it by having a list or similar mutable data container and accessing that as a work around.
def f():
x = [None]
def g():
x[0] = 1
This works as variables do fall into scope, but won't leak out of scope. With mutable objects, we can change them inside the scope, and those changes propagate out.
Not possible in python 2.7. In python 3:
def foo():
def bar():
nonlocal foobar
foobar = 'foobaz'
foobar = 'foobar'
print foobar
bar()
print foobar
foo()
In 2.x, you can do:
def foo():
foobar = []
def bar():
foobar[0] = 'foobaz'
foobar[0] = 'foobar'
print foobar[0]
bar()
print foobar[0]
foo()
def foo():
def bar():
foobar = 'foobaz'
return foobar
foobar = 'foobar'
print foobar
foobar = bar()
print foobar
foo()
Even though functions are already first class objects in Python, you can create your own "functor" or function object something like this:
class Foo(object):
def bar(self):
self.foobar = 'foobaz'
def __call__(self):
self.foobar = 'foobar'
print self.foobar
self.bar()
print self.foobar
foo = Foo()
foo()

How do I pass variables between class instances or get the caller?

class foo():
def __init__(self)
self.var1 = 1
class bar():
def __init__(self):
print "foo var1"
f = foo()
b = bar()
In foo, I am doing something that produces "var1" being set to 1
In bar, I would like to access the contents of var1
How can I access var1 in the class instance f of foo from within the instance b of bar
Basically these classes are different wxframes. So for example in one window the user may be putting in input data, in the second window, it uses that input data to produce an output. In C++, I would have a pointer to the caller but I dont know how to access the caller in python.
As a general way for different pages in wxPython to access and edit the same information consider creating an instance of info class in your MainFrame (or whatever you've called it) class and then passing that instance onto any other pages it creates. For example:
class info():
def __init__(self):
self.info1 = 1
self.info2 = 'time'
print 'initialised'
class MainFrame():
def __init__(self):
a=info()
print a.info1
b=page1(a)
c=page2(a)
print a.info1
class page1():
def __init__(self, information):
self.info=information
self.info.info1=3
class page2():
def __init__(self, information):
self.info=information
print self.info.info1
t=MainFrame()
Output is:
initialised
1
3
3
info is only initialised once proving there is only one instance but page1 has changed the info1 varible to 3 and page2 has registered that change.
No one has provided a code example showing a way to do this without changing the init arguments. You could simply use a variable in the outer scope that defines the two classes. This won't work if one class is defined in a separate source file from the other however.
var1 = None
class foo():
def __init__(self)
self.var1 = var1 = 1
class bar():
def __init__(self):
print var1
f = foo()
b = bar()
Same as in any language.
class Foo(object):
def __init__(self):
self.x = 42
class Bar(object):
def __init__(self, foo):
print foo.x
a = Foo()
b = Bar(a)
Alternatively you could have a common base class from which both derived classes inherit the class variable var1. This way all instances of derived classes can have access to the variable.
Something like:
class foo():
def __init__(self)
self.var1 = 1
class bar():
def __init__(self, foo):
print foo.var1
f = foo()
b = bar(foo)
You should be able to pass around objects in Python just like you pass around pointers in c++.
Perhaps this was added to the language since this question was asked...
The global keyword will help.
x = 5
class Foo():
def foo_func(self):
global x # try commenting this out. that would mean foo_func()
# is creating its own x variable and assigning it a
# value of 3 instead of changing the value of global x
x = 3
class Bar():
def bar_func(self):
print(x)
def run():
bar = Bar() # create instance of Bar and call its
bar.bar_func() # function that will print the current value of x
foo = Foo() # init Foo class and call its function
foo.foo_func() # which will add 3 to the global x variable
bar.bar_func() # call Bar's function again confirming the global
# x variable was changed
if __name__ == '__main__':
run()

Categories