Python warns that method has not been called

Suppose you want to call a method fooon an object bar, but somehow, when you enter a method call, you are intuitively referring to fooboth the property and you typed bar.fooinstead bar.foo()(with a bracket), Now both are syntactically correct, so the error does not occur, but it is semantically very different. This has happened to me several times already (my experience with Ruby makes it even worse) and called me with great difficulty in terms of lengthy and confusing debugging sessions.

Is there a way to get the Python interpreter to print a warning in such cases - whenever you access an attribute being called, but you didn't actually call it?

For the record - I was thinking about redefinition __getattribute__, but it is messy and, ultimately, will not reach the goal, because the function call through ()after the return __getattribute__.

+4
source share
2 answers

This is not possible in all cases, because sometimes you do not want to call a method, for example. you may want to save it as a callable, which will be used later, for example callback = object.method.

But you can use static analysis tools like pylint or PyCharm (my recommendation) that warn you if you write an expression that looks useless, for example. object.methodwithout any appointment.

, x = obj.get_x, get_x(), , x, ( ), x - x.

+2

, , ! , .

(WarnIfNotCalled.py):

class Notifier:                                                             
    def __init__(self, name, obj, callback):                                
        self.callback = callback                                            
        self.name = name                                                    
        self.obj = obj                                                      
        self.called = False                                                 
    def __call__(self, *args, **kwargs):                                    
        self.callback(self.obj, *args, **kwargs)                            
        self.called = True                                                  
    def __del__(self):                                                      
        if not self.called:                                                 
            print("Warning! {} function hasn't been called!".format(self.name))

class WarnIfNotCalled(type):                                                
    def __new__(cls, name, bases, dct):                                     
        dct_func = {}                                                       
        for name, val in dct.copy().items():                                
            if name.startswith('__') or not callable(val):                  
                continue                                                    
            else:                                                           
                dct_func[name] = val                                        
                del dct[name]                                               
        def getattr(self, name):                                            
            if name in dct_func:                                            
                return Notifier(name, self, dct_func[name])                 
        dct['__getattr__'] = getattr                                        
        return super(WarnIfNotCalled, cls).__new__(cls, name, bases, dct) 

-

from WarnIfNotCalled import WarnIfNotCalled

class A(metaclass = WarnIfNotCalled):                                       
    def foo(self):                                                          
        print("foo has been called")                                        
    def bar(self, x):                                                       
        print("bar has been called and x =", x)

,

a = A()                                                                         

a.foo()                                                                         
a.bar(5)

:

foo has been called
bar has been called and x = 5

:

a = A()                                                                         

a.foo                                                                           
a.bar  

Warning! foo function hasn't been called!
Warning! bar function hasn't been called!

!

+2

Source: https://habr.com/ru/post/1695624/


All Articles