webots
webots copied to clipboard
Use more setters and getters in the Python API
Python users are used to using getters and setters to access properties of objects. See for example #1687. Such getters and setters are not implemented in the Webots Python API. They could be easily added. See https://www.geeksforgeeks.org/getter-and-setter-in-python for reference.
This is, unfortunately, one more drawback of using Swig, our Python API comes from the C++ one and this is clearly visible (not pythonic at all) :disappointed:
My suggestion is to add (and maintain) python getters and setters in addition to the functions derived from Swig (to keep backwards compatibility).
Maybe, this could be a good opportunity to go from camel-case to underscore notation (recommended by PEP 8).
it can be solved by replacing every setter and getter in the code with its structure attribute by a scripting file in webots api layer before generating c++ api with swig, it could be temporary solution to avoid backwards compatibility
@AhmedMoamen62: can you provide a simple example to explain what you mean?
if i understand right, the problem is, camera_recognition_object struct for example
typedef struct {
int id;
double position[3];
double orientation[4];
double size[2];
int position_on_image[2];
int size_on_image[2];
int number_of_colors;
double *colors;
char *model;
} WbCameraRecognitionObject;
and in python we want to access attributes of the struct by setters and getters as
camera_recognition_object.get_id()
instead of
camera_recognition_object.id
but If you wrap a C structure with SWIG , it is wrapped by a Python class so it will work with just
camera_recognition_object.id
as in this swig tutorial http://www.swig.org/Doc1.3/Python.html#Python_nn19
so we can write a script to check if python file have any setter or getter function and replace it with the opposite attribute so SWIG can work and compile
OK, I see. But WbCameraRecognitionObject is a special case. In most cases, we have API functions like webots::Camera::getImage() (in C++) which we would like to translate in Python to Camera.image instead of Camera.getImage(). But we would like to keep the later option for backwards compatibility.
For conversion from camel-case to underscore notation we can use SWIG regex: http://www.swig.org/Doc2.0/SWIG.html#SWIG_advanced_renaming
For getters and setters, we can implement generating implementation in Python with setattr() and getattr():
https://docs.python.org/3/library/functions.html#setattr
Just ideas, not sure if they are going to work. I can make a minimal proof-of-concept if needed
Yes, if you can quickly make a minimal proof-of-concept, that would be helpful.
import re
import random
def add_setter_getters(class_type):
"""Function for adding getters and setters."""
for full_attr_name in dir(class_type):
# Find getter and setter methods
parsed_attr = re.findall(r'^(get|set)([A-Z].*?)$', full_attr_name)
if parsed_attr:
# Get relavant data getter and setter methods
property_suffix = parsed_attr[0][1]
attr_name = property_suffix.lower()
# Get set[Something] and get[Something] methods
fget = None
fset = None
if hasattr(class_type, 'get' + property_suffix):
fget = getattr(class_type, 'get' + property_suffix)
if hasattr(class_type, 'set' + property_suffix):
fset = getattr(class_type, 'set' + property_suffix)
# Create a property
setattr(class_type, attr_name, property(
fget=fget,
fset=fset
))
# Our class
class DistanceSensor:
def __init__(self):
self.__name = 'distance_sensor'
def getValue(self):
return random.randint(1, 100)
def getName(self):
return self.__name
def setName(self, name):
self.__name = name
# Apply Pythonic setters and getters
add_setter_getters(DistanceSensor)
# Do a few tests
ds = DistanceSensor()
print(ds.value)
print(ds.value)
print(ds.value)
print(ds.name)
ds.name = 'new_distance_sensor'
print(ds.name)
add_setter_getters() is important part that we would put in controller.i, the rest is only for testing purposes. Also, it probably could be simplified.
Similar could be done for camel-case to underscore conversion, but that part could be also done with SWIG regex I believe.
Now that we got rid of SWIG, the setters and getters could be implemented more easily.