CodeQL queries 1.25
Skip to end of metadata
Go to start of metadata

Name: First parameter of a method is not named 'self'

Description: Using an alternative name for the first parameter of an instance method makes code more difficult to read; PEP8 states that the first parameter to instance methods should be 'self'.

ID: py/not-named-self

Kind: problem

Severity: recommendation

Precision: very-high

Query: NonSelf.ql
/**
 * @name First parameter of a method is not named 'self'
 * @description Using an alternative name for the first parameter of an instance method makes
 *              code more difficult to read; PEP8 states that the first parameter to instance
 *              methods should be 'self'.
 * @kind problem
 * @tags maintainability
 *       readability
 *       convention
 * @problem.severity recommendation
 * @sub-severity high
 * @precision very-high
 * @id py/not-named-self
 */

import python
import semmle.python.libraries.Zope

predicate is_type_method(FunctionValue fv) {
  exists(ClassValue c | c.declaredAttribute(_) = fv and c.getASuperType() = ClassValue::type())
}

predicate used_in_defining_scope(FunctionValue fv) {
  exists(Call c | c.getScope() = fv.getScope().getScope() and c.getFunc().pointsTo(fv))
}

from Function f, FunctionValue fv, string message
where
  exists(ClassValue cls, string name |
    cls.declaredAttribute(name) = fv and
    cls.isNewStyle() and
    not name = "__new__" and
    not name = "__metaclass__" and
    not name = "__init_subclass__" and
    not name = "__class_getitem__" and
    /* declared in scope */
    f.getScope() = cls.getScope()
  ) and
  not f.getArgName(0) = "self" and
  not is_type_method(fv) and
  fv.getScope() = f and
  not f.getName() = "lambda" and
  not used_in_defining_scope(fv) and
  (
    (
      if exists(f.getArgName(0))
      then
        message =
          "Normal methods should have 'self', rather than '" + f.getArgName(0) +
            "', as their first parameter."
      else
        message =
          "Normal methods should have at least one parameter (the first of which should be 'self')."
    ) and
    not f.hasVarArg()
  ) and
  not fv instanceof ZopeInterfaceMethodValue
select f, message

Normal methods should have at least one parameter and the first parameter should be called self. This makes the purpose of the parameter clear to other developers.

Recommendation

If there is at least one parameter, then change the name of the first parameter to self as recommended by the style guidelines in PEP 8.

If there are no parameters, then it cannot be a normal method. It may need to be marked as a staticmethod or it could be moved out of the class as a normal function.

Example

The following methods can both be used to assign values to variables in a point object. The second method makes the association clearer because the self parameter is used.

class Point:
    def __init__(val, x, y):  # first parameter is mis-named 'val'
        val._x = x
        val._y = y

class Point2:
    def __init__(self, x, y):  # first parameter is correctly named 'self'
        self._x = x
        self._y = y

References