Global vars in python [closed] - python

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I currently have some class foo() with some variables that are not only shared among all instances of the foo class, but also by other classes bar.
i.e.
class foo():
__init__(self, a, b):
self.a = a
self.b = b
class bar():
__init__(self, a, b):
self.a = a
self.b = b
One solution would be to make a and b class variables, but how do I do that cleanly during construction? Could I just put both classes in the same file and have them reference some global variables a and b? Is that bad practice?

Since you did not provide your intention or real-world situation, I'll just provide some ways of sharing variable access.
1st option: global.
a=b=None
class foo():
def __init__(self, _a, _b):
global a, b
a, b = _a, _b
class bar():
def __init__(self, _a, _b):
global a, b
a, b = _a, _b
2nd option: foo's class vars
class foo():
a = b = None
def __init__(self, a, b):
foo.a, foo.b = a, b
class bar():
def __init__(self, a, b):
foo.a, foo.b = a, b
3rd option: inheritance
class foo():
def __init__(self, a, b):
self.a, self.b = a, b
class bar(foo):
pass
4th option: outer class
class outer():
a = b = None
class foo():
def __init__(self, a, b):
outer.a, outer.b = a, b
class bar():
def __init__(self, a, b):
outer.a, outer.b = a, b
5th option: compsition
class foo():
def __init__(self, a, b):
self.a, self.b = a, b
class bar():
def __init__(self, a, b):
self.foo = foo(a,b)
6th option: closure over outer-function local variables
def outer():
a = b = None
class foo():
def __init__(self, _a, _b):
nonlocal a, b
a, b = _a, _b
class bar():
def __init__(self, _a, _b):
nonlocal a, b
a, b = _a, _b
... #things with foo and bar
7th option: closure over foo's __init__ local variables.
class foo():
def __init__(self, a, b):
self.a, self.b = a, b
class bar():
nonlocal a, b
#do things with a and b directly
self.bar = bar()

You could do this:
class Foo(object):
def __init__(self, a, b):
self.a = a
self.b = b
class Bar(Foo):
pass
By inheriting from Foo, you'll be adopting Foo's construction method as well so it will act the same way. If you need to override it, you can set it up this way in Bar:
def __init__(self, a, b, c):
super(Bar, self).__init__(a, b)
self.c = c
super will call your base class' method first (in this case, Foo) and then allow you to add on if you'd like. Here's the documentation on super, if you're interested.

The usual solution is to make an object that stores the shared information, then pass that when instantiating the classes that need it. Often this is some kind of configuration information, so we'll call the class Config:
class Config(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
# default values
number = 0
text = "Nothing"
Since Python is duck-typed, any object can be used to hold this configuration; it can be an instance of a class or the class itself. The former is handy when the data is specified at runtime. The latter can be convenient since it allows the programmer to define the various bundles of attributes using inheritance at coding time. The Config class here lets you have it either way: you can instantiate it, passing keyword arguments with the shared values, or you can subclass it, providing the shared values as class attributes.
In your Foo and Bar classes you then just accept the shared data in the constructor:
# these classes both need certain pieces of data
# but are not related by inheritance
class Foo(object):
def __init__(self, shared):
self.shared = shared
class Bar(object):
def __init__(self, config):
self.config = config
And then you can either instantiate the Config class, or define a subclass, and pass the resulting object to the new objects:
# use an instance
adams_config = Config(text="Don't Panic", number=42)
foo1, bar1 = Foo(adams_config), Bar(adams_config)
# use a subclass
class LincolnConfig(Config):
number = 87
text = "Four score and seven years ago"
foo2, bar2 = Foo(LincolnConfig), Bar(LincolnConfig)
Now methods of your Foo and Bar class can get self.shared.number or self.config.text (and so on) to access the data.
Since the instances of your various classes are all holding references to the same object, a change to e.g. adams_config or LincolnConfig would be seen by any instance of any class that holds a reference to one of these objects. If this isn't the behavior you want, you could fish the data you want to "freeze" out of the config object at instantiation and set it as attributes of your instance.
You could also just use a dictionary for data you want to access in various places, but I think the benefits of inheritance and attribute-access syntax are a good argument for doing it with classes.
You could even have a global configuration object that is used as a default value so you don't need to explicitly specify it if you want things to "just work." Here we'll just use the Config class itself for that, since it already has default values for the attributes we're interested in:
class Baz(object):
def __init__(self, config=Config):
self.config = config
By using this approach instead of global variables, you make it easier for clients using your objects to have numerous instances with different settings, rather than being limited to one "bundle" of settings for all instances.

I'm not sure what you mean by "cleanly during construction"
You can use class variables by defining them outside the function like:
class A:
x = 1
def __init__(self):
pass
And just call A.x whenever you need the variable, within other classes or wherever

Related

Instances of class A as class attributes of A in Python?

Are there Python versions that allow defining your class like this:
class Foo:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
and then adding class attributes, such as BAR_1, BAR_2, etc.:
class Foo:
BAR_1 = ...
BAR_2 = ...
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
which are actually "special cases of Foo", such as:
class Foo:
BAR_1 = Foo(4, 9, 16)
BAR_2 = Foo(2, 3, 5)
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
so that, in my code, I can either make my own Foos or get common, predefined Foos by working directly with Foo.BAR_1 and Foo.BAR_2?
The code above obviously does not work, otherwise I would not post the question (Foo is an unresolved reference when defining BAR_1 and BAR_2). I found a trick on SO how to sort-of achieve this -> defining a custom ClassProperty class:
class ClassProperty(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, owner):
return self.f(owner)
which then allows me to define Foo as
class Foo:
#ClassProperty
def BAR_1(cls):
return Foo(4, 9, 16)
#ClassProperty
def BAR_2(cls):
return Foo(2, 3, 5)
...
and that works, but the issue is that Foo.__init__ is called everytime whenever Foo.BAR_1 or Foo.BAR_2 is retrieved, which can be useful in certain situations (precisely those where you always want separate instances), but in the special case where Foo is simply a messenger class which is coincidentally hard to load (like a result of a computation for example), this solution is unfeasible. I'd like for the constructor of Foo to be called exactly once for BAR_1, exactly once for BAR_2 (ideally lazily, during the first retrieval, that would be fantastic), and after that it would only return the created instances. So, is there a way to do this?
I use Python 3.8.6.
During the time I composed the question body, I figured out I can just define Foo like this:
class Foo:
#ClassProperty
def BAR_1(cls):
if not hasattr(cls, '_Foo__BAR_1'):
cls.__BAR_1 = Foo(4, 9, 16)
return cls.__BAR_1
#ClassProperty
def BAR_2(cls):
if not hasattr(cls, '_Foo__BAR_2'):
cls.__BAR_2 = Foo(2, 3, 5)
return cls.__BAR_2
Now, I can call Foo.BAR_X for retrieval of a defined Foo.__BAR_X which is actually an instance of Foo, which is always created only once.

Asking some tips for using init in python

I tried to find out with googling, but it seems not explained.
There are four classes, for example, which are A, B, C, and D.
C is sub-class of D. A and B is calling C.
Class A:
def __init__(self):
self.c = C()
Class B:
def __init__(self):
self.c = C()
Class C(D):
def __init__(self):
print('it is C')
Class D:
def __init__(self):
print('it is D')
a = A()
b = b()
In this case, it will initiate twice for Class C. So, 'it is C' and 'it is D' strings represent twice. And.. I think it's ... not normal.
Unlike Java, it seems that Python doesn't support constructor overloading.
In this case, can I call C only though? Or, could I get an advice for using init in Python?
Thank you.
You have several errors in your code: class not Class, checkout indentation, class definition order... see this:
class D:
def __init__(self):
print('it is D')
class C(D):
def __init__(self):
print('it is C')
class A:
def __init__(self):
self.c = C()
class B:
def __init__(self):
self.c = C()
a = A()
b = B()
method 1
you can use the *args and **kwargs
args and kwargs
you can get the len(args) and len(kwargs.keys()) (kwargs is a dict) and program different parts depending on the number of arguments. this can work like a constructor overloading
example:
__init__(self, *args):
if len(args)==0:
# constructor one
if len(args)==1:
# constructor two
method 2
use default arguments, most likely argname=None. then use if-else with the value of that argument
simple example :
__init__(self, arg1=None):
if arg1==None:
# constructor one
else:
# constructor two

Get variable name from argument/parameter in class function

I try to get the name of the variable, which I passed to a function.
class A():
def __init__(self):
self.a = 1
class B():
def __init__(self):
self.b = A()
self.c = A()
def doSomething(self, hello):
print(hello)
B().doSomething(B().b)
<__main__.A object at 0x7f67571a3d68>
What I want is that I can identify in the function B().doSomething(), that the variable is b. Is this possible? One restriction is that in the function B().doSomething() only instance variables of B are passed.
For example in peewee (https://github.com/coleifer/peewee), a MySQL ORM in python, they build expressions for filtering like:
B.select().where(B.b == True)
And somehow they are able to identify, that b is passed. Because otherwise the query can not be build properly.
I know they are using static variables in the class, is this maybe the trick?
Thanks for helping! :)
Going by your B().doSomething(B().b) example call I'm going to assume you're attempting to determine if the variable hello is equivalent to the variable b declared on the class B object.
In which case, all you need to do is call the self reference. self refers to the instance of the object that you're working with and every method defined within a class automatically gets reference to the object's self as a method attribute.
Thus, to determine if the the object b variable is equal to the hello parameter all you need to do is if self.b == hello: #do code
B().b is not an instance variable of B; rather, it is an instance variable of A. In your constructor in B, you may have meant self.a to be an instance of B or self.a to be an instance of B. If this is your general idea, you can implement a boolean overloading method to destinguish between the two. In the case of your code, it may be best to create a third class, C, to check what class an attribute that is passed to doSomething belongs to:
class A():
def __init__(self):
self.a = 1
def __bool__(self):
return True
class B():
def __init__(self):
self.b = 1
def __bool__(self):
return False
class C():
def __init__(self):
self.a = A()
self.b = B()
def doSomething(self, hello):
if not hello:
print("instance of a got passed")
else:
print("instance of b got passed")
C().doSomething(C().b)
Output:
instance of b got passed

How to instantiate classes that depend on each other?

I have a PlayoffCreator class to create playoff matches. This class has a Bracket instance which generates the structure of the bracket, and each match in this structure is a Node, made up of two instances of the class Element.
Then the PlayoffCreator goes through each Node the Bracket has and processes it, creating the match and doing other necessary operations. When processing a Node, both Elements are processed: this Element class has multiple subclasses and each define a different process() behavior.
The problem is a Node is instantiated by passing two Elements:
class Node:
def __init__(self, bracket, home_element, away_element):
pass
But an Element is also instantiated by passing a Node, because the process() method acts on data found both in Bracket and PlayoffCreator, both accessible through the Node.
class Element:
def __init__(self, node):
pass
How does one usually deal with this circular dependency on instantiation issue?
I see two possibilities.
1 - Instantiate the two elements, then setup the dependency
class A:
def __init__(self):
self.b = None
class B:
def __init__(self):
self.a = None
a = A()
b = B()
a.b = b
b.a = a
You can push this further by adding a b optional parameter in A's constructor, that defaults to None, and doing the same for B:
class A:
def __init__(self, b=None):
self.b = b
class B:
def __init__(self, a=None):
self.a = a
This allows you to instantiate the second by passing the first's instance:
a = A()
b = B(a)
a.b = b
2 - Instantiate B at A instantiation, then get that instance
class A:
def __init__(self):
self.b = B(self)
class B:
def __init__(self, a):
self.a = a
a = A()
b = a.b
Both method have their advantages and drawbacks.
I would prefer n°1, for it's more flexible, because symmetrical.
However, if there is a logical hierarchy between the two classes, n°2 might be used as well.

Python object conversion

Assume that we have an object k of type class A. We defined a second class B(A). What is the best practice to "convert" object k to class B and preserve all data in k?
This does the "class conversion" but it is subject to collateral damage. Creating another object and replacing its __dict__ as BrainCore posted would be safer - but this code does what you asked, with no new object being created.
class A(object):
pass
class B(A):
def __add__(self, other):
return self.value + other
a = A()
a.value = 5
a.__class__ = B
print a + 10
a = A() # parent class
b = B() # subclass
b.value = 3 # random setting of values
a.__dict__ = b.__dict__ # give object a b's values
# now proceed to use object a
Would this satisfy your use case? Note: Only the instance variables of b will be accessible from object a, not class B's class variables. Also, modifying variables in a will modify the variable in b, unless you do a deepcopy:
import copy
a.__dict__ = copy.deepcopy(b.__dict__)
class A:
def __init__(self, a, b):
self.a = a
self.b = b
class B(A):
def __init__(self, parent_instance, c):
# initiate the parent class with all the arguments coming from
# parent class __dict__
super().__init__(*tuple(parent_instance.__dict__.values()))
self.c = c
a_instance = A(1, 2)
b_instance = B(a_instance, 7)
print(b_instance.a + b_instance.b + b_instance.c)
>> 10
Or you could have a sperate function for this:
def class_converter(convert_to, parent_instance):
return convert_to(*tuple(parent_instance.__dict__.values()))
class B(A):
def __init__(self, *args):
super().__init__(*args)
self.c = 5
But using the 2nd method, I wasn't able to figure out how to pass additional values

Categories