160 lines
4.4 KiB
Plaintext
160 lines
4.4 KiB
Plaintext
This rule raises an issue when a property getter, setter or deleter does not have the correct number of arguments.
|
|
|
|
== Why is this an issue?
|
|
|
|
Creating property accessors and mutators is quite common in Object-Oriented Programming. Python provides two main ways of implementing getters, setters and deleters; either with the ``++@property++`` decorator, or with the ``++property++`` function.
|
|
|
|
----
|
|
class WithPropertyDecorator(object):
|
|
@property
|
|
def foo(self)
|
|
return self._foo
|
|
|
|
@foo.setter
|
|
def foo(self, value):
|
|
self._foo = value
|
|
|
|
@foo.deleter
|
|
def foo(self):
|
|
del self._foo
|
|
|
|
class WithPropertyMethod(object):
|
|
def get_foo(self):
|
|
return self._foo
|
|
|
|
def set_foo(self, value):
|
|
self._foo = value
|
|
|
|
def del_foo(self):
|
|
del self._foo
|
|
|
|
foo = property(get_foo, set_foo, del_foo, "'foo' property.")
|
|
----
|
|
|
|
The following program illustrates how using the built-in operations will call the custom methods defined above.
|
|
|
|
----
|
|
with_decorator = WithPropertyDecorator()
|
|
with_decorator.foo = 1 # the method defined under @foo.setter will be called.
|
|
some_var = with_decorator.foo # the method defined under @foo.getter will be called.
|
|
del with_decorator.foo # the method defined under @foo.deleter will be called.
|
|
|
|
|
|
with_method = WithPropertyMethod()
|
|
with_method.foo = 1 # the method set_foo will be called.
|
|
some_var = with_method.foo # the method get_foo will be called.
|
|
del with_method.foo # the method del_foo will be called.
|
|
----
|
|
|
|
Defining a property this way allows for flexibility when refactoring the implementation of the getters, setters and deleters method, as all the accesses and modifications are done through the Python built-in operators (``++=++``,``++.++``) and keyword (``++del++``).
|
|
|
|
Property getter, setter and deleter methods are called by the Python interpreter with a specific number of arguments:
|
|
|
|
* Property getter and deleter methods only require a "self" argument.
|
|
* Property setter methods require a "self" argument as well as a value.
|
|
|
|
Adding any other parameters, or removing these mandatory parameters will throw a ``++TypeError++`` exception at runtime when trying to access or modify the property.
|
|
|
|
== How to fix it
|
|
|
|
Make sure to specify the correct number of argument for each setter, getter and deleter methods.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,python,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
class A:
|
|
@property
|
|
def foo(self, unexpected, unexpected2): # Noncompliant: too many parameters.
|
|
return self._foo
|
|
|
|
@foo.setter
|
|
def foo(self): # Noncompliant: a parameter is missing.
|
|
self._foo = 42
|
|
|
|
@foo.deleter
|
|
def foo(self, unexpected): # Noncompliant: too many parameters.
|
|
del self._foo
|
|
|
|
class B:
|
|
def get_foo(self, unexpected): # Noncompliant: too many parameters.
|
|
return self._foo
|
|
|
|
def set_foo(self, value, unexpected): # Noncompliant: too many parameters.
|
|
self._foo = value
|
|
|
|
def del_foo(self, unexpected): # Noncompliant: too many parameters.
|
|
del self._foo
|
|
|
|
foo = property(get_foo, set_foo, del_foo, "'foo' property.")
|
|
----
|
|
|
|
|
|
==== Compliant solution
|
|
|
|
[source,python,diff-id=1,diff-type=compliant]
|
|
----
|
|
class A:
|
|
@property
|
|
def foo(self):
|
|
return self._foo
|
|
|
|
@foo.setter
|
|
def foo(self, value):
|
|
self._foo = value
|
|
|
|
@foo.deleter
|
|
def foo(self):
|
|
del self._foo
|
|
|
|
class B:
|
|
def get_foo(self):
|
|
return self._foo
|
|
|
|
def set_foo(self, value):
|
|
self._foo = value
|
|
|
|
def del_foo(self):
|
|
del self._foo
|
|
|
|
foo = property(get_foo, set_foo, del_foo, "'foo' property.")
|
|
----
|
|
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* https://docs.python.org/3/library/functions.html#property[Built-in Functions - property] - Python Documentation
|
|
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
* Remove XXX parameters; property getter methods receive only "self".
|
|
* Remove XXX parameters; property deleter methods receive only "self".
|
|
* Remove XXX parameters; property setter methods receive "self" and a value.
|
|
* Add the value parameter; property setter methods receive "self" and a value.
|
|
|
|
|
|
=== Highlighting
|
|
|
|
The method signature.
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== on 11 Feb 2020, 18:24:23 Nicolas Harraudeau wrote:
|
|
Note that we don't raise any issue for missing "self" parameter because this is already covered by RSPEC-5720.
|
|
|
|
endif::env-github,rspecator-view[]
|