简体   繁体   中英

No value for argument 'self' in method call in python3 decorator

I'm trying to use decorator into class and get an error in pylint on line

@start_test_min_pg(min_version_pg="9.5")

No value for argument 'self' in method call

class TestsUnloggedTabled(BaseTester):
   some code

   def get_pg_version(self):
       pg_temp = Postgres(self.host, self.port, self.username, self.password, "postgres")
       current_pg_version = pg_temp.query("show server_version")[0][0].split(" ")[0]
       print('PG version is: ' + current_pg_version)
       return current_pg_version

   def start_test_min_pg(self, min_version_pg):
       def decorator_repeat(func):
           @functools.wraps(func)
           def wrapper_repeat(*args, **kwargs):
               if LooseVersion(self.get_pg_version()) > LooseVersion(min_version_pg):
                   value = func(*args, **kwargs)
                   return value
               return wrapper_repeat
           return decorator_repeat

   @start_test_min_pg(min_version_pg="9.5")
   def test_schema_hashing(self):
       do something

The way that you've written your decorator, it needs to be called on an instance of your class to work properly. That is, you'd need to be applying it with:

obj = TestsUnloggedTabled(...)

@obj.start_test_min_pg(min_version_pg="9.5")
def foo():
    pass

This obviously can't work when you're applying it to another method in the same class, since you can't create an instance until the class definition ends. So you clearly don't want to be calling the decorator as a method, which means you should not have self as one of its arguments.

But you do need self in the implementation of your code later. Where do you get it? Well, the wrapper_repeat function is what is going to be called on the actual instance, once the class is defined. So its first argument will be that instance, and you can name it self rather than letting it get collected with the other positional arguments in args . You do need to remember to pass it along when you call the original function.

def start_test_min_pg(min_version_pg):                            # no self here
   def decorator_repeat(func):
       @functools.wraps(func)
       def wrapper_repeat(self, *args, **kwargs):                 # put it here instead
           if LooseVersion(self.get_pg_version()) > LooseVersion(min_version_pg):
               value = func(self, *args, **kwargs)                # and pass it along
               return value
       return wrapper_repeat
   return decorator_repeat

Note that I fixed the indentation level of the last two lines of this code, the version in your question won't work correctly (since the decorator factory will return None ). I'm guessing that may be an artifact of copying the code into Stack Overflow, not something that's actually wrong in your real code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM