Accessing Class attribute from a called function? - python-3.x

Let say I have something like this :
--module1
def called():
if caller.class.attrX == 1 : ...
--module2
class ABC:
attrX = 1
def method():
called()
I want to access caller Class-attribute ?
I know I have to use inspect somehow but can figure how exactly.
python3

Passing a variable to the function is the best (and only?) option.
--module1
def called(attrX):
if attrX == 1 : ...
--module2
class ABC:
self.attrX = 1
def method():
called(self.attrX)

This seems to work for object variable :
/if I can make it work for class-var it will be better/
import inspect
def say(*args, **kwargs) :
obj = inspect.currentframe().f_back.f_locals['self']
if hasattr(obj,'aaa') : print('hasit')
else : print("no")
class ABC:
aaa = 2
def test(self):
say(123)
i.e. if I dont have 'aaa' set in advance :
In [8]: a.test()
no
In [9]: ABC.aaa = 2
In [10]: a.test()
no
In [12]: a.aaa = 3
In [13]: a.test()
hasit

Related

print list like a table of 3 columns

Is there a way to make the list (self.produits) look like a table ?
class Stock :
def __init__(self) :
self.produits=[]
def ajouter_produit(self,nom,puht,qt):
self.produits.append(nom)
self.produits.append(puht)
self.produits.append(qt)
def saisir(self,n):
for i in range(n):
nom,puht,qt=produit.saisir_produit()
self.ajouter_produit(nom,puht,qt)
def afficher(self):
print("NOM |PUHT |QUANTITE")
print (self.produits)
output
desired output
def afficher(self):
start = 0
end = len(self.produits)
step = 3
print("NOM |PUHT |QUANTITE")
for i in range(start, end, step):
print("{:<8}|{:<8}|{}".format(self.produits[i],self.produits[i+1],self.produits[i+2]))

Why class atribute doesn't change on update

I am wondering why the class attribute doesn't change in the code below. As you can see the value remains the same, despite being changed in class A?
class A:
valueA = 1.05
class User:
def __init__(self,name):
self.name = name
self.value = A.valueA
user = User('Alice')
print(user.value)
A.valueA = 1.1
print(A.valueA)
print(user.value)
output:
1.05
1.1
1.05
I don't understand why it should? ValueA is an number which is an immutable object(everything is a object), so valueA is just some sort of referencethat points to value 1.05.
To make more clear, here is an example of how does it behave:
class A(object):
val = [1,2,3]
class B(object):
def __init__(self):
self.myval = A.val
print(A.val)
# prints [1,2,3]
obj = B()
print(obj.myval)
# prints [1,2,3] because its starts to point to the same list
A.val[0] = 5
print(obj.myval)
# prints [5,2,3] because both still points to the same list,
# and you just changed it fist value
A.val = [4,5,6,7]
print(A.val)
# prints new list [4,5,6,7]
print(obj.myval)
# prints [5,2,3] because it still points to old list.
obj2 = B()
print(obj2.myval)
# prints new list [4,5,6,7] because assignment was done after A.val changed
also here is a good article about variables in python https://realpython.com/python-variables/#object-references

Create a python Class inheriting from a Class created by a function

What works :
I am using the module recordtype to store global parameters for the different functions of my program.
Each parameter is a class instance of :
class Parameter(object):
def __init__(self, name, value, info):
self.name = name
self.value = value
self.info = info
Then the global structure is defined like this :
The individual parameters :
parameter_1 = Parameter('param_1', 10, 'Value for the parameter 1, usage...')
parameter_2 = Parameter('param_2', 20, 'Value for the parameter 2, usage...')
...
parameter_m = Parameter('param_n', 50, 'Value for the parameter m, usage...')
parameter_n = Parameter('param_n', 100, 'Value for the parameter n, usage...')
Parameter sub sets :
parameter_set_1 = recordtype('parameter_set_1', [(parameter_1.name, parameter_1),
(parameter_2.name, parameter_2), ...])
...
parameter_set_n = recordtype('parameter_set_n', [(parameter_m.name, parameter_m),
(parameter_n.name, parameter_n)]
The global parameter structure is then :
GlobalParametersFunction = recordtype('GlobalParameters', [('parameter_set_1', parameter_set_1()),
('parameter_set_2', parameter_set_2()), ('parameter_set_n', parameter_set_n())])
Which needs to be instantiated :
GlobalParameters = GlobalParameterFunction()
This all works well, the GlobalParameterFunction creates a class where I can access individual parameters and change their values, Ex:
GlobalParameters.parameter_set_1.parameter_1.value = 20
From the GlobalParameters class instance I can then make a function that prints the values and their names :
def print_parameter_info(GP):
for field, val in zip(GP._asdict(), GP._asdict().values()):
print(field, ':')
for key, entry in zip(val._asdict(), val._asdict().values()):
print('\t', entry.name, ':', entry.value)
Which does a nice print for the user :
>>> print_parameter_info(GlobalParameters)
parameter_set_1 :
parameter_1 : 10
parameter_2 : 20
parameter_set_n :
parameter_m : 50
parameter_n : 100
I would also like to create a function such that :
change(GlobalParameters, 'name', new_value)
does :
GlobalParameters.parameter_set_1.name.value = new_value
Which seems easily doable with the class created by recordtype
The problem :
I would like to create a class methods for the GlobalParameters class instance, from the print_parameter_info() function such that :
GlobalParameters.print_parameter_info()
and
GlobalParameters.change(name, new_value)
works
because GlobalParameters is a class instance of recordtype, I tried :
class GlobalParameterClass(recordtype):
def __init__(self):
self = GlobalParameterFunction()
But because recordtype is a function creating a class ?
I get the following error :
TypeError: function() argument 'code' must be code, not str
I found this question (2231427)
But after trying to import the right thing and looking at the source code of recordtype I think I understood that recordtype does not define a class clearly and creates it by parsing a string of code ?
Thus I do not understand how to create a class inheriting from the class created by recordtype
I also tried
class GlobalParameterClass(object):
def __init__(self, *args):
self = GlobalParameterFunction(*args)
This does not raise any errors but the class instance created is empty.
TLDR/Conclusion
How can I add custom methods to the class created by the recordtype function from the recordtype module ?
Or
Perhaps, there is there a better way to manage the GlobalParameters object ?
Thank you !
I found a solution without using the recordtype object, by creating a custom classes with the desired behavior :
class Parameter(object):
"""
A class to store the individual sound parameters
"""
def __init__(self, name, value, info):
self.name = name
self.value = value
self.info = info
class ParameterSet(object):
"""
A class to store multiple parameters as a set
"""
def __init__(self, name, *parameters):
self.name = name
for parameter in parameters:
setattr(self, parameter.name, parameter)
class GlobalParameters(object):
"""
A class to store the parameter sets and to be used to assign parameter values to the different functions
"""
def __init__(self, *parameter_sets):
for parameter_set in parameter_sets:
setattr(self, parameter_set.name, parameter_set)
The methods of the GlobalParameters classes go as follow :
def info(self):
for parameter_set in self.__dict__.values():
print(parameter_set.name)
parameters = [parameter for parameter in parameter_set_1.__dict__.values() if type(parameter) != str]
for parameter in parameters:
print('\t', parameter.name, ':', parameter.value)
def change(self, name, value):
for parameter_set in self.__dict__.values():
parameters = [parameter for parameter in parameter_set_1.__dict__.values() if type(parameter) != str]
for parameter in parameters:
if parameter.name == name:
parameter.value = value
With this example code :
# Individual parameters
parameter_1 = Parameter('parameter_1', 10, 'Value for the parameter 1, usage...')
parameter_2 = Parameter('parameter_2', 20, 'Value for the parameter 2, usage...')
parameter_n = Parameter('parameter_n', 50, 'Value for the parameter n, usage...')
parameter_m = Parameter('parameter_m', 100, 'Value for the parameter m, usage...')
# Parameter sets
parameter_set_1 = ParameterSet('parameter_set_1', parameter_1, parameter_2)
parameter_set_2 = ParameterSet('parameter_set_n', parameter_n, parameter_m)
# Global parameter set
GP = GlobalParameters(parameter_set_1, parameter_set_2)
I get the desired behavior :
>>> GP.info()
parameter_set_1
parameter_1 : 10
parameter_2 : 20
parameter_set_n
parameter_1 : 10
parameter_2 : 20
As well as with the .change method :
>>> GP.parameter_set_1.parameter_1.value
10
GP.change('parameter_1', 15)
>>> GP.parameter_set_1.parameter_1.value
15

I am getting the error : ValueError: not enough values to unpack (expected 2, got 1). What could be the problem?

Im running a mapreduce job, but it keeps failing saying missing input. Unfortunately its not showing where its missing either
from mrjob.job import MRJob
from mrjob.step import MRStep
import re
class flight_combination(MRJob):
def steps(self):
return [MRStep(mapper=self.mapper_1,reducer=self.reducer_1)]
def mapper_1(self,_,value):
group1 = {}
group2 = {}
parts = value.split(",")
destination = parts[0]
origin = parts[1]
count = parts[2]
group1[destination] = {'Origin': origin, 'count': count}
group2[origin] = {'Destination':destination,'count':count}
yield group1
yield group2
def reducer_1(self,key,value):
g1,g2 = data
for key1 in g1:
for key2 in g2:
if g1[key1]['Origin'] == g2[key2]['Destination']:
total = int(g1[key1]['count'])*int(g2[key2]['count'])
yield (key1,key2,total)
if __name__ == '__main__':
flight_combination.run()
Following is the error:
`File "wd.py", line 35, in <module>
flight_combination.run()
…...
File "/usr/lib/python3.6/site-packages/mrjob/job.py", line 536, in run_mapper
for out_key, out_value in mapper(key, value) or ():
ValueError: not enough values to unpack (expected 2, got 1)`
The run method of the object type flight_combination is expecting 2 arguments, but provided with 1 argument. ( Python by default takes self as the first argument for methods invoked on object)
To fix this -
as the method run is defined in the parent class, go through its definition and pass the other argument.
Override the run method by redefining it flight_combination class and provide your logic.

Can you generate new self names inside a class?

Trying to figure out how to use a function to generate new self named variables inside a class.
I've played around with it in IDLE, and searched online docs. Solution is alluding me.
>>> import random
>>> abc = [(map(chr,range(ord('A'),ord('Z')+1)))+(map(chr,range(ord('a'),ord('z')+1)))]
>>> class Test():
def __init__(self, abc):
self.a = 0
self.abc = abc
def newSelf(self):
for i in range(2):
b = random.choice(abc)
c = random.choice(abc)
globals()['self.'+b+c] = 0
#or
locals()['self.'+b+c] = 0
print(b+c,0)
>>> example = Test(abc)
>>> example.a
0
>>> example.newSelf() #say it generates
An 0
ze 0
>>> example.An #calling new self variable of example object returns
Traceback (most recent call last):
File "<pyshell#221>", line 1, in <module>
example.An
AttributeError: 'Test' object has no attribute 'An'
# I'm hoping for...
>>> example.An
0
Using setattr:
You can use setattr to set the new attribute:
>>> class Test():
... def __init__(self, abc):
... self.a = 0
... self.abc = abc
... def newSelf(self):
... for i in range(2):
... b = random.choice(abc)
... c = random.choice(abc)
... setattr(self, b+c, 0)
... print(b+c,0)
And the attribute will again be available:
>>> example = Test(abc)
>>> example.newSelf()
zM 0
Ja 0
>>> example.zM
0
>>> example.Ja
0
Using exec:
You can use exec function to execute a python statement stored in a string. As, you are generating the variable name randomly, you can create the whole python statement in a string, and execute that statement using exec like below:
>>> class Test():
... def __init__(self, abc):
... self.a = 0
... self.abc = abc
... def newSelf(self):
... for i in range(2):
... b = random.choice(abc)
... c = random.choice(abc)
... exec('self.'+b+c+' = 0')
... print(b+c,0)
Here, I have created the new attribute using exec('self.'+b+c+' = 0'). Now, after calling this method, the attribute will be available:
>>> example = Test(abc)
>>> example.newSelf()
Tw 0
Xt 0
>>> example.Tw
0
>>> example.Xt
0

Resources