AttributeError: 'obj_2' object has no attribute 'var_1' - getattr - - python-3.x

I need to get data to second class from first class.
I Used - getattr - function to do it.
class obj_1:
def __init__(self):
self.var_1 = 'Hello'
self.var_2 = 'World'
def get_id(self):
i = self.var_1
j = self.var_2
return i, j
def vw(self):
print('Hello..')
class obj_2:
def __init__(self):
pass
def r_data(self):
print('called r_data')
x, y = getattr(obj_1, "get_id")(self)
print('x > ', x)
print('y > ', y)
def rd(self):
getattr(obj_1, 'vw')(self)
if __name__ == '__main__':
ob = obj_2()
ob.r_data()
It given error as - AttributeError: 'obj_2' object has no attribute 'var_1'

I think you are getting this error since the function get_id uses attributes of the class, i.e self.var_1 self.var_2
and these attributes are never initialized since the __init__ function was never called (and since you cant have attributes without an actual object )
so to fix your code I would create an object of "obj_1" and call the function
"get_id" with that object
class obj_1:
def __init__(self):
self.var_1 = 'Hello'
self.var_2 = 'World'
def get_id(self):
i = self.var_1
j = self.var_2
return i, j
def vw(self):
print('Hello..')
class obj_2:
def __init__(self):
self.o1 = obj_1()
def r_data(self):
print('called r_data')
x, y = self.o1.get_id()
print('x > ', x)
print('y > ', y)
def rd(self):
getattr(obj_1, 'vw')(self)
if __name__ == '__main__':
ob = obj_2()
ob.r_data()
hope i could help, please let me know in the comments if you didn't understand anything.
and if my comment helped you i would relly appreciate marking this comment as the answer :)

Related

Conflicts when find and "replace" a method dynamically

I have a class consisting of a "list" of static methods, A. I want to change its behavior with a class-decorator, Meta, which acts on a specific static method, in this example content, by performing the method m.
My original attempt, CASE=2, didn't work as expected, so I started I case study. I introduced a new class B, which has slightly different implementation of an other method, info but raised a funny error, and a new class C just without the method, info.
case 2: the greedy case
d[i] = classmethod(lambda cls, *args: mcs.m( getattr(target_cls, i)(*args)) ) it doesn't work properly, maybe too many nested dynamic expressions?
case 1: it essentially case 2 but the expression is divided in two lines, and it works
o = getattr(target_cls, i)
d[i] = classmethod(lambda cls, *args: mcs.m(o(*args)))
Here the code
class Meta:
def __new__(mcs, target_cls):
if CASE == 1:
print('case 1')
d = {}
for i in dir(target_cls):
if i == 'content':
o = getattr(target_cls, i)
d[i] = classmethod(lambda cls, *args: mcs.m(o(*args)))
if CASE == 2:
print('case 2')
d = {}
for i in dir(target_cls):
if i == 'content':
d[i] = classmethod(lambda cls, *args: mcs.m( getattr(target_cls, i)(*args)) )
return type('AAA', (target_cls,), d)
#classmethod
def m(mcs, p):
return '--> ', p
class A:
#staticmethod
def content(response):
return 'static_method', response
#staticmethod
def info(response):
return response
class B:
#staticmethod
def content(response):
return 'static_method', response
#staticmethod
def info(response):
response.sort()
return response
class C:
#staticmethod
def content(response):
return 'static_method', response
# call the "content" class-method of each class for all different cases
for cls in (A, B, C):
print(cls.__name__)
for case in range(1,3):
CASE = case
R = Meta(cls)
try:
print(R.content('ppp'))
except Exception as e: print(e)
print()
Output
A
case 1
('--> ', ('static_method', 'ppp'))
case 2
('--> ', 'ppp') # no decoration
B
case 1
('--> ', ('static_method', 'ppp'))
case 2
'str' object has no attribute 'sort' # <- complained about the other method
C # <- this is ok BUT I removed the other method!
case 1
('--> ', ('static_method', 'ppp'))
case 2
('--> ', ('static_method', 'ppp')) # <- here the decoration took place
The question is why case 2 doesn't work, if it is a limitation of the language then of what kind?
Extra question: how to explain the error of class B case 2
I guess that the issue is caused by the loop and the origin is the fact that each statement has not its own scope (in the loop). By passing i as a key parameter of the lambda fixed the problem.
class Meta:
def __new__(mcs, target_cls):
d = {}
for i in dir(target_cls):
if i == 'content':
d[i] = classmethod(lambda cls, *args, m_name=i: mcs.m( getattr(target_cls, m_name)(*args)) )
return type('AAA', (target_cls,), d)
#classmethod
def m(mcs, p):
return '--> ', p
class A:
#staticmethod
def content(response):
return 'static_method', response
#staticmethod
def info(response):
return response
print(A.content)
print(Meta(A).content)
print(Meta(A).content('a'))
print(Meta(A).info)
Output
<function A.content at 0x7f04500740d0> # original static method
<bound method Meta.__new__.<locals>.<lambda> of <class '__main__.AAA'>> # class method
('--> ', ('static_method', 'a'))
<function A.info at 0x7f0450074040>

how can i iterate class objects while using generator in python?

i want to compare the 2000 pairs of a and b, and print the matching pairs and count of them.can anyone help me to get rid of it.it shows this error TypeError: 'seq_generator' object is not iterable at line 34
class generator(object):
def __init__(self,s,start_A,fact_A):
self.s=s
self.start_A=start_A
self.fact_A = fact_A
def seq_gen_A(self):
while self.s>0:
self.gen_A=(self.start_A*self.fact_A)%2147483647
self.g=self.gen_A
self.start_A=self.gen_A
self.bin_A=(bin(self.gen_A)[-16:])
yield self.bin_A
self.s=self.s-1
def next(self):
for i in self.seq_gen_A():
return i
def main():
s=200
count=0
a=generator(s,65,16807)
b=generator(s,8921,48271)
print("Matching pair")
print("*************")
for i in range(0,s):
if next(a)==next(b):
count+=1
print(a,b)
print('Matching pair count',count)
You are defining your generator not correctly. You need methods __iter__ and __next__:
class generator(object):
def __init__(self, s, start_A, fact_A):
self.s = s
self.start_A = start_A
self.fact_A = fact_A
def __iter__(self):
return self
def __next__(self):
if self.s <= 0:
raise StopIteration()
gen_A = (self.start_A*self.fact_A)%2147483647
self.start_A = gen_A
yield bin(gen_A)[-16:]
self.s -= 1

Get function object from stack (Frame) object

I have written a custom logging class for module logging that I called call. With this class I hope to place it in any function/method and it logs the function name with its arguments and all values the function was called with.
This works fine for class methods
Foo.bar(self, a=1, b=2, c=3, *args=(), **kwargs={'something': 4})
using this minimal example
import logging
import inspect
def call(logger):
fname = [] # Function name including module and class
fargs = [] # Arguments of function including positional and named arguments
parentframe = inspect.stack()[1][0]
module = inspect.getmodule(parentframe)
if module and module.__name__ != "__main__":
fname.append(module.__name__)
codename = parentframe.f_code.co_name
if "self" in parentframe.f_locals:
fname.append(parentframe.f_locals["self"].__class__.__name__)
fobj = getattr(parentframe.f_locals["self"].__class__, codename)
if codename != "<module>":
fname.append(codename)
argspec = inspect.formatargspec(*inspect.getfullargspec(fobj))
args = argspec[1:-1].split(",")
for arg in args:
argkey = arg.strip().replace("*", "").split("=")[0]
if arg == "self":
fargs.append("self")
else:
fargs.append(arg.split("=")[0] + "=" + str(parentframe.f_locals[argkey]))
del parentframe
msg = ".".join(fname) + "(" + ",".join(fargs) + ")"
if logger.isEnabledFor(30):
logger.log(30, msg)
class Foo:
def __init__(self, l):
self.logger = l
def bar(self, a, b, c=3, *args, **kwargs):
call(self.logger)
if __name__ == "__main__":
logging.addLevelName(30, "CALL")
logger = logging.getLogger('blub')
logger.level = 20
f = Foo(logger)
f.bar(1, 2, something=4)
print("done...")
My problem is when I use the same functionality on static methods or simple functions. It fails at the line where I get the function object (fobj = getattr(parentframe.f_locals["self"].__class__, codename)
) using self.
parentframe is the Frame object of the function in questions I presume. I have not yet found a way to get the function object from that object. Is there a way?
Use getattr(module, codename) to get the function-object of functions that are not contained in classes.
Here the full code:
import logging
import inspect
def call(logger):
fname = [] # Function name including module and class
fargs = [] # Arguments of function including positional and named arguments
parentframe = inspect.stack()[1][0]
module = inspect.getmodule(parentframe)
if module and module.__name__ != "__main__":
fname.append(module.__name__)
codename = parentframe.f_code.co_name
if "self" in parentframe.f_locals:
fname.append(parentframe.f_locals["self"].__class__.__name__)
fobj = getattr(parentframe.f_locals["self"].__class__, codename)
else:
fobj = getattr(module, codename)
if codename != "<module>":
fname.append(codename)
argspec = inspect.formatargspec(*inspect.getfullargspec(fobj))
args = argspec[1:-1].split(",")
for arg in args:
argkey = arg.strip().replace("*", "").split("=")[0]
if arg == "self":
fargs.append("self")
else:
fargs.append(arg.split("=")[0] + "=" + str(parentframe.f_locals[argkey]))
del parentframe
msg = ".".join(fname) + "(" + ",".join(fargs) + ")"
if logger.isEnabledFor(30):
logger.log(30, msg)
class Foo:
def __init__(self, l):
self.logger = l
def bar(self, a, b, c=3, *args, **kwargs):
call(self.logger)
def boo(a, b, c=3, *args, **kwargs):
call(logger)
if __name__ == "__main__":
logging.addLevelName(30, "CALL")
logger = logging.getLogger('blub')
logger.level = 20
f = Foo(logger)
f.bar(1, 2, something=4)
boo(1, 2, something=4)
print("done...")
Taking ideas from both, I wrote this function to find the function object from a frame. I'm sure there's some edge cases around inherited staticmethods, and obviously any code not using the cls and self conventions for param names. This also doesn't work for lambdas... but you shouldn't be logging anything out in a lamba anyway :-P
def _get_func_obj(f):
"""
Get function object from a frame. If it can't find it, return None
"""
codename = f.f_code.co_name
fobj = None
try:
if "self" in f.f_locals: # regular method
fobj = getattr(f.f_locals["self"].__class__, codename)
elif "cls" in f.f_locals: # class method
fobj = getattr(f.f_locals["cls"], codename)
else:
module = inspect.getmodule(f) # only fetch module if we need it
if hasattr(module, codename): # regular module level function
fobj = getattr(module, codename)
else: # static method
classes = [
getattr(module, name)
for name in dir(module)
if inspect.isclass(getattr(module, name))
]
for cls in classes:
if (
hasattr(cls, codename)
and getattr(cls, codename).__code__ == f.f_code
):
fobj = getattr(cls, codename)
break
if fobj is None:
"""it's likely some nested function/method or a lambda, who logs in a lambda?"""
return fobj
except Exception:
"""never break logging"""

How super() works with private variables?

There is an interesting question on python 3.5. For example I've smth like:
class A:
__x = 0
def __init__(self, x):
self.__x = x
def set_x(self,x): __x=x
def get_x(self): return x
class B(A):
__y = 0
def __init(self, x, y)
self.__y = y
super(B, self).__init__(x)
def set_y(self,y): __y=y
def get_y(self): return y
def toString(self): return "x = {} and y = {}".format(self.__x,
self.__y);
test = B(7,3)
test.toString()
Why do I have an error here: "B object has no attribute _B__x", if the method super() let me to use all methods of parante class?
Sure, if I write, like:
def toString(self): return "x = {} and y = {}".format(self.get_x(),
self.__y);
It works well!
You do not get access to private variables/members through super().
So in order to access B.__x, you will have to do
def toString(self): return "x = {} and y = {}".format(self._B__x,
self.__y);

Python Binary Tree

I'm working on a binary tree in Python3 and so far almost everything has been working like expected; however, I have a function that is supposed to return a list of all children for any given node and for whatever reason I'm only getting a list of the object addresses, and not calling my overridden __str__(self) method.
from collections import deque # http://docs.python.org/3.1/tutorial/datastructures.html
class BinaryNode: # binary tree functionality via iterative means
def __init__(self, name, data):
self.Left = None
self.Right = None
self.Parent = None
self.Name = name
self.Data = data
return
def AddNew(self, name, data):
q = []
q.append(self)
while q:
i = q.pop()
if i.Name == name:
i.Data = data
return i
elif name < i.Name:
if i.Left:
q.append(i.Left)
else:
i.Left = BinaryNode(name, data)
i.Left.Parent = i
return i.Left
else:
if i.Right:
q.append(i.Right)
else:
i.Right = BinaryNode(name, data)
i.Right.Parent = i
return i.Right
def Find(self, name):
q = deque()
q.append(self)
'''if self.Left: q.append(self.Left)
if self.Right: q.append(self.Right)'''
while q:
i = q.pop()
print(i)
if i.Name == name:
return i
elif name < i.Name:
if i.Left: q.append(i.Left)
else: return None
else:
if i.Right: q.append(i.Left)
else: return None
def Children(self):
children = []
q = deque()
if self.Left: q.append(self.Left)
if self.Right: q.append(self.Right)
while q:
i = q.popleft()
if i.Left: q.append(i.Left)
if i.Right: q.append(i.Right)
children.append(i)
return children
def Parents(self):
lst = []
i = self.Parent
while i is not None:
lst.append(i)
i = i.Parent
return lst
def __str__(self): return "{} : {}".format(self.Name, self.Data)
and I'm testing it by calling
test = BinaryNode("Jesse", 21)
print(test)
print(test.AddNew("David", 22))
print(test.AddNew("Marli", 23))
print(str(test.Children()))
print(test.Find("David"))
print(test.Find("David").Children())
print(test.Find("Gary")) #Will return None
with the resulting console output
Jesse : 21
David : 22
Marli : 23
[<__main__.BinaryNode object at 0x000000000333E160>, <__main__.BinaryNode object at 0x000000000333E1D0>, <__main__.BinaryNode object at 0x000000000333E198>]
David : 22
[<__main__.BinaryNode object at 0x000000000333E1D0>]
None
UPDATE:
Here is the answer I implemented:
def __repr__ (self): return str(self)
Python containers always use the representation of contained objects.
Implement a __repr__ method too and that'll be used when printing the list; you can make it an alias for __str__ if you wish:
__repr__ = __str__
or explicitly print each element in your list:
print(', '.join(map(str, test.Children())))

Resources