Share variables between modules - python

I have this situation:
library_file1.py:
class A:
def foo(self):
print("bar")
def baz(self):
pass
project_file.py:
from library_file1 import A
class B(A):
def baz(self):
print(the_variable)
library_file2.py:
from project_file import B
the_variable = 7
b = B()
b.foo() # prints "bar"
b.baz() # I want this to print "7", but I don't know how
How do I allow code to be written in project_file.py that can access variables from library_file2.py? The only solution I can think of is this:
project_file.py:
from library_file1 import A
class B(A):
def baz(self, the_variable):
print(the_variable)
library_file2.py:
from project_file import B
the_variable = 7
b = B()
b.foo()
b.baz(the_variable)
but this feels awkward and doesn't scale to many variables like the_variable.

Quite easy: you need the variable to be in project_file.py instead of library_file2.py.
Change project_file to:
from library_file1 import A
the_variable = None
class B(A):
def baz(self):
print(the_variable)
And then in library_file2:
import project_file
from project_file import B
project_file.the_variable = 7
b = B()
b.foo() # prints "bar"
b.baz() # prints "7"
Using an argument is also a good solution (you should avoid globals as much as you can).
There is no such a thing as a truly global variable in python. Variables are always attached to a scope. We usually say that a variable is "global" when it's in the module scope.
The widest scope is the built-in scope, so it would be theoretically possible for you to add something as a built-in. However this is a really bad practice.
Also it doesn't complete fix the problem, because all files could access that new built-in, but they couldn't re-assign it without explicitly mentioning the scope.

Related

Correct way to have the same method defined differently between instances

I'm trying to create a class in Python whose methods are defined differently (under the same name) between various instances. The different definitions could be based on the input to the class when creating an instance.
For example:
Class A:
def __init__(self, a):
...
def foo(self):
...
a1 = A(input1)
a2 = A(input2)
a1.foo()
a2.foo()
I would want foo() to be defined differently for these two instances. I can code this logic into the foo method but would like to know if there's a cleaner or more Pythonic way to do this.
Thanks.
I would want foo() to be defined differently for these two instances
You really don't want that. I can't start imagining the debugging nightmare this will cause.
If a1.foo is different than a2.foo it means a1 and a2 should not be instances of the same class
Use subclasses and implement foo in each class as appropriate:
Class Common:
# common stuff
...
Class A1(Common):
def foo(self):
print('a1.foo')
Class A2(Common):
def foo(self):
print('a2.foo')
a1 = A1()
a2 = A2()
a1.foo()
# 'a1.foo'
a2.foo()
# 'a2.foo'
You can't do that. But you can always add custom attributes to objects on-the-fly.
class A:
def __init__(self, x):
self.x = x
a1 = A()
a2 = A()
def foo1():
# you can't use self.x
print("a1")
a1.foo = foo1
a2.foo = lambda : print("a2")
a1.foo() # a1
a2.foo() # a2
This is not a good practice though, use it at your own risk.
Also, as pointed out in the comments, you don't have access to instance attributes (because there is no implicit self parameter).

Python: looking for a short-hand way to setup setters/getters for lots of variables

I have one class (Bar) embedded inside another class (Foo).
class Foo():
class Bar():
def __init__(self):
self.a = 1
self.b = 2
...
self.z = 26
def __init__(self):
self.bar = Bar()
To access the attributes of class Bar, the user would need to the following:
>>> f = Foo()
>>> f.bar.a
1
How can I setup a short dot notation so that users can use BOTH:
>>> f.bar.a
1
and
>>> f.a
1
In my example, I'm trying to demonstrate that Bar class has a lot of variables. So I don't want to write a getter/setter for each one manually. So I was thinking to use the property() in a for loop like this:
def __init__(self):
self.bar = Bar()
# Allow shorter dot notation
for parm in self.bar.__dict__:
setattr(self, i, getattr(bar, i))
self.i = property(...)
But I'm unsure how to use property in this context without manually writing several setter functions.
Any suggestions on how to allow access to both shorter and longer notations?
That's what the __getattr__hook is ideally suited for:
class Foo:
# ...
def __getattr__(self, name):
return getattr(self.bar, name)
__getattr__ is only called for attributes that are missing; so only attributes that are not already present on instances of Foo() are passed to Foo().__getattr__(). The getattr() function then lets you use the same attribute name on self.bar; if the attribute doesn't exist there either, an AttributeError is thrown, as would be expected.

Why can't Python access a subfunction from outside?

def A():
def B():
#do something
a = A()
a.B()
Why isn't the above (such simple code) possible in Python? Is there a 'pythonic' (legible, unsurprising, non-hacky) workaround that does not turn A() into a class?
Edit 1: The above was explained to me that B is local to A, thus it only exists as long as A is being evaluated. So if we make it global (and be sure not to have it overriden), then why doesn't this work?
def A():
def B():
#do something
return A()
a = A()
a.B()
It says it's returning a 'NoneType' object.
Because a function definition just creates a name in the local namespace. What you are doing is no different than:
def f():
a = 2
and then asking why you can't access a from outside the function. Names bound inside a function are local to the function.
In addition, your proposed code is strange. when you do a = f(), you are setting a to the return value of the function. Your function returns nothing, so you can't hope to access anything through the return value. It is possible to return the inner function directly:
def f():
def g():
return "blah"
return g
>>> func = f()
>>> func()
'blah'
And this can indeed be useful. But there isn't a generic way to access things inside the function from outside except by modifying global variables (which is usually a bad idea) or returning the values. That's how functions work: they take inputs and return outputs; they don't make their innards available to the outside word.
To call B with the syntax you want, use:
def A():
def B():
print("I'm B")
A.B = B
return A
a = A()
a.B()
A.B()

What is and isn't available to class methods in python?

My limited understand is that the second argument to types.FunctionTypes (dict) determines what is available to the function code. I'm curious how it gets gets decided when instantiating functions internally. To illustrate what I mean, if I try to copy a function dynamically:
a = 'test'
def foo():
print(a)
bar = types.FunctionType(
foo.__code__,
globals(),
'bar',
foo.__defaults__,
foo.__closure__
)
This seems to work fine with globals(), but am I missing anything? More confusing is a class method. If I do something like this:
a = 'test'
class Foo(object):
b = 'Foo prints this'
def myfunc():
print(a, self.b)
Bar = type('Bar', tuple(), dict())
Bar.b = 'Bar prints this'
ns = globals()
#should I do ns.update(something) here?
f = Foo.myfunc
Bar.myfunc = types.FunctionType(f.__code__, ns, 'myfunc', ...)
That example works, but not this more complicated one:
import imp
import builtins
class Foo(object):
def __init__(self):
super().__init__() # super(Foo, self) also fails
mod = imp.new_module('test')
mod.__builtins__ = builtins
mod.Foo = type('Foo', tuple(), dict())
f = Foo.__init__
ns = {}
ns.update(mod.__dict__) #missing something here
mod.Foo.__init__ = types.FunctionTypes(f.__code__, ns, '__init__', ...)
Could someone illuminate what should be in ns? What is available to a class method, and what isn't?
I'm not specifically trying to get the above code to work, I'm more looking for an explanation of why it doesn't.
The problem seems to be that "copying" the __closure__ attribute doesn't create a copy; that's the execution context in which the function body, (the def __init__) was itself executed; in support of the lexical scoping rules in the python language. Taking a look:
>>> [cell.cell_contents for cell in f.__closure__]
[<class '__main__.Foo'>]
Unsurprisingly, it's the class it was defined in. I'm not sure of a simple way of creating a new cell object besides using exec, to create a new class and method; You could probably copy the new cell around to additional methods to be added to the new class, but both the cell and the class would be brand new.

Python object instance inheriting changes to parent class by another instance

I am confused by this behaviour of Python(2.6.5), can someone shed light on why this happens?
class A():
mylist=[]
class B(A):
j=0
def addToList(self):
self.mylist.append(1)
b1 = B()
print len(b1.mylist) # prints 0 , as A.mylist is empty
b1.addToList()
print len(b1.mylist) # prints 1 , as we have added to A.mylist via addToList()
b2 = B()
print len(b2.mylist) # prints 1 !!! Why ?????
You need to do:
class A:
def __init__(self):
self.mylist=[]
That way self.mylist is an instance variable. If you define it outside of a method it is a class variable and so shared between all instances.
In B if you define a constructor you'll have to explicitly call A's constructor:
class B(A):
def __init__(self):
A.__init__(self)
This is explained (not very clearly) in the Python tutorial.
This code creates a shared mylist among all instances of A (or subclasses)
class A():
mylist=[]
What you want to do is:
class A():
def __init__(self):
self.mylist=[]
What you've probably seen is people who do:
class A():
somevariable = a
def doit(self):
self.somevariable = 5
This works because it creates a new "somevariable" attribute because you are doing an assignment. Before that all A instances share the same copy of somevariable. As long as you don't change the copy that is fine. When the variable is assigned to, then it gets replaced rather then modified. So that technique is only really safe when the values in question are immutable (i.e. you can't change them, you can only replace them) However, I think that's a really bad idea and you should always assign all variables in init

Categories