![]() |
how to get around recursive method call - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: how to get around recursive method call (/thread-27969.html) Pages:
1
2
|
how to get around recursive method call - Skaperen - Jun-29-2020 i did this: ... def __getattr__(self,*args): print(f'attribute {args[0]!r}') return getattr(self,*args) ...and got the recursion error. i left "self." off the call, but it got many recursion errors, anyway. rethinking about it, it would have to come back here. is there a way around this? RE: how to get around recursive method call - Yoriz - Jun-29-2020 Do you mean to use __getattribute__ class YourObject: def __getattribute__(self, name): print(f'attribute {name}') return object.__getattribute__(self, name) your_instance = YourObject() your_instance.this = 'This' print(your_instance.this) Note: __getattr__ is called when there is no attributehttps://docs.python.org/3/reference/datamodel.html#object.__getattr__ Wrote:object.__getattr__(self, name) RE: how to get around recursive method call - Skaperen - Jun-29-2020 i tried to juggle things around with a __getattr__() method and finally eliminated the recursion. but it still ran a finite 2 times. no idea why that happens. but i will try __getattribute__() and see if i can make that work.the class is emulating open() and is intercepting close(). it needs to pass everything else straight through. it's a no-compress version of the class described here. i know you want to see my code. please focus on this issue in this thread. this it class topen in file "topen.py": import io,os,sys,time _separator = '_' class topen(io.IOBase): """Class for opening a file with temporary output name and automatic rename on close if write.""" # this class also adds the name= keyword argument (no default) # name is require by positional args or by keyword args # this class is like ztopen but without compression def __init__(self,*args,**kwargs): if args: args = list(args) if 'name' in kwargs: raise TypeError('name given twice') fname = args.pop(0) if args: if 'mode' in kwargs: raise TypeError('mode given twice') modes = args.pop(0) elif 'mode' in kwargs: modes = kwargs.pop('mode') else: raise TypeError('mode not given') elif 'name' in kwargs: fname = kwargs.pop('name') modes = kwargs.pop('mode','r') else: raise TypeError('name not given') if 'x' in modes and isinstance(fname,(str,bytes)) and os.path.exists(fname): raise TypeError(f'{fname!r} refers to a name that already exists') fname = os.fspath(fname) if isinstance(fname,bytes): fname = ''.join(chr(x)for x in fname) if isinstance(modes,bytes): modes = ''.join(chr(x)for x in modes) if isinstance(fname,str) and '+' not in modes: rname = 'x' in modes or 'w' in modes oname = fname+_separator+str(int(time.time()*3906250)) if rname else fname elif isinstance(fname,int): rname = False oname = fname else: raise TypeError() print(f'opening file {oname!r} with mode {modes!r}',file=sys.stderr,flush=1) ofile = open(oname,modes,*args,**kwargs) if ofile is None: raise(f'failed to open file {oname!r}') self.rname = rname self.ofile = ofile self.oname = oname self.fname = fname def close(self): if self.rname: print(f'close {self.oname!r} and rename it to {self.fname!r}',file=sys.stderr,flush=1) self.ofile.close() return os.rename(self.oname,self.fname) else: print(f'close {self.oname!r}',file=sys.stderr,flush=1) return self.ofile.close() def __getattr__(self,*args): print(f'__getattr__ for {args!r}',file=sys.stderr,flush=1) return getattr(self.ofile,*args)here is the test script in file "trytopen.py": from topen import topen f=topen('foo','w') print('bar',file=f) f.close()i plan to try with with in test 2 or 3. here is the output i get:
RE: how to get around recursive method call - Skaperen - Jun-30-2020 i added some more points of output and made repeated calls in a loop. now it shows things that are more strange. the extra 2nd call of close() happens in the next loop cycle or for the last one, after the script reached its end. the code has been updated. topen.py: # -*- coding: utf-8 -*- import io,os,sys,time def _sep(): return '_'+str(int(time.time()*3906250)) class topen(io.IOBase): """Class for opening a file with temporary output name and automatic rename on close if write.""" # name is require by positional args or by keyword args # this class is like ztopen but without compression def __init__(self,*args,**kwargs): if args: args = list(args) fname = args.pop(0) if args: modes = args.pop(0) else: modes = kwargs.pop('mode',None) else: fname = kwargs.pop('file',None) modes = kwargs.pop('mode',None) if fname is None: raise('file is missing') if modes is None: raise('mode is missing') if 'x' in modes and isinstance(fname,(str,bytes)) and os.path.exists(fname): raise TypeError(f'{fname!r} refers to a name that already exists') fname = os.fspath(fname) if isinstance(fname,bytes): fname = ''.join(chr(x)for x in fname) if isinstance(modes,bytes): modes = ''.join(chr(x)for x in modes) if ('x' in modes or 'w' in modes) and isinstance(fname,str): rname = 1 oname = fname+_sep() else: rname = 0 oname = fname args = [oname,modes]+list(args) print(f'CALLING open(*{args!r},**{kwargs!r}',file=sys.stderr,flush=1) ofile = open(*args,**kwargs) if ofile is None: raise(f'failed to open file {oname!r}') self.rname = rname self.ofile = ofile self.oname = oname self.fname = fname def close(self): if self.rname: print(f'close {self.oname!r} and rename it to {self.fname!r}',file=sys.stderr,flush=1) self.ofile.close() return os.rename(self.oname,self.fname) else: print(f'close {self.oname!r}',file=sys.stderr,flush=1) return self.ofile.close() def __getattr__(self,*args): # print(f'__getattr__ for {args!r}',file=sys.stderr,flush=1) return getattr(self.ofile,*args)trytopen.py: # -*- coding: utf-8 -*- from sys import stderr from topen import topen for n in range(4): print(f'--------------------------------------------------- start{n}',file=stderr,flush=1) f=topen(f'foo{n}','w') print(f'bar{n}',file=f) f.close() print(f'---------------------------------------------------- done{n}',file=stderr,flush=1) print('ALL DONE NOW ENDED',file=stderr,flush=1)topen.out:
RE: how to get around recursive method call - Skaperen - Jun-30-2020 how do i get the attribute value in def __getattribute__(self,attr): when it would be calling itself? isn't that the infinite recursion problem?
RE: how to get around recursive method call - Yoriz - Jun-30-2020 (Jun-30-2020, 01:57 PM)Skaperen Wrote: how do i get the attribute value in That is what is shown in my replyhttps://python-forum.io/Thread-how-to-get-around-recursive-method-call?pid=119313#pid119313 by using objects __getattribute__ method RE: how to get around recursive method call - Skaperen - Jun-30-2020 your reply code shows it getting the attribute of something else using the name object. but i don't have that. i need to have it return the attribute of itself. thus, i need to find a way to get the attribute of itself without calling itself. i want to have object A behave like object B except for intended differences. i implement the methods intended to be different. for the remaining methods, i don't even know what all they are, or will be in the future, so i implement __getattribute__ to pass references. that method ends up referencing itself to reference object B. because it references itself, it ends up calling itself. def __getattribute__(self,attr): print(f'getting attribute {attr!r}',flush=True) # so i can see what is happening return self.objectb.__getattribute__(attr)output will be one line for the first attribute then a few hundred for 'objectb', hence the recursion loop. even your code will have this problem since it gets attributes inside itself. RE: how to get around recursive method call - Yoriz - Jul-01-2020 import io class YourObject(io.IOBase): def __init__(self): self.value = 'this value' def some_method(self): return 'some_method' def __getattribute__(self, name): print(f'attribute {name}') return object.__getattribute__(self, name) your_instance = YourObject() print(your_instance.value) print(your_instance.some_method()) print('finished with YourObject') Accessing attributes does not happen recursively in the above codeThe following are called when the class is done with
RE: how to get around recursive method call - Skaperen - Jul-01-2020 when object is self? RE: how to get around recursive method call - Yoriz - Jul-01-2020 (Jul-01-2020, 08:16 PM)Skaperen Wrote: when object is self? ![]() ![]() call the baseclass method __getattribute__ class BaseClass(object): def __getattribute__(self, name): print('Calling object') return object.__getattribute__(self, name) class MiddleClass(BaseClass): def __getattribute__(self, name): print('Calling BaseClass') return BaseClass.__getattribute__(self, name) class SuperClass(MiddleClass): def __getattribute__(self, name): print('Using Super to Call MiddleClass') return super().__getattribute__(name) my_class = SuperClass() my_class.value = 'Spam' print(my_class.value)
|