Is there a function in Python that does the same thing as the equals operator

210 Views Asked by At

Due to my current understanding of Python's syntax, I have run into an issue where I need to set a variable to a value but without using any operators. I have to use functions.

Consider this senario

class Senario:
    x: str = ''
    y: str = ''
    
    set_global_variable(self, set_variable, val: str)
        # some verification code and modifications
        set_variable(val)

    set_x(self, val: str)
        self.set_global_variable(setX, val)

    set_x(self, val: str)
        self.set_global_variable(lambda new_x: self.x = new_x, val)

The benefit of setting variables like this is that adding a new variable doesn't require copying and pasting a bunch of verification code for the new setter method. It is more modular. The problem is that such a program doesn't run because lambdas can't use operators.

The error is self.set_global_variable(lambda new_x: self.x --> = <-- new_x, val)

It's not the proper syntax. In order to run a program like this, I need some sort of equals method that does the exact same thing as the = operator. The implementation would work as follows.

set_x(self, val: str)
    self.set_global_variable(lambda new_x: self.x.equals(new_x), val)

Is there a built-in method in Python to do this, if only for strings? If not, can a method be easily written? One that can take a variable as input and set that exact variable to a new value, and not a local copy of it?

3

There are 3 best solutions below

7
On BEST ANSWER

The easiest solution may be to use a local function that performs the assignment, as follows:

def set_x(self, val: str):
    def _set_variable(new_x):
        self.x = new_x
    self.set_global_variable(_set_variable, val)

However, if you want to use a lambda expression, you can try using the setattr built-in function of python, which does what you asked for:

def set_x(self, val: str):
    self.set_global_variable(lambda new_x: setattr(self, "x", new_x), val)

A more general solution could be to pass the field name to the set_global_variable and use setattr to perform the assignment, as follows:

def set_global_variable(self, variable_name, val):
    # some verification code and modifications
    setattr(self, variable_name, val)

def set_x(self, val: str):
    set_global_variable("x", val)
1
On

You can use global for this, like this:

def myfunc(x, y):
  exec(f"global {x}”)
  exec(f"{x} = {y}")

myfunc("x", "great")

print("Python is " + x)

However, I see that you are creating a setter that makes the property y a global value, meaning you can only have 1 (meaningful) object op the type Scenario.

2
On

So, you are using the term global incorrectly, you are simply trying to dynamically set an attribute. This can be accomplished with setattr, however, what you are actually trying to accomplish is to encapsulate setter logic. Python has the descriptor protocol. Here is how you would do something like this in Python:

class AlwaysCapitalized:
    def __get__(self, instance, owner=None):
        return getattr(instance, self.name)
    def __set__(self, instance, value):
        setattr(instance, self.name, value.capitalize())
    def __set_name__(self, owner, name):
        self.name = f"_{name}"

class MemberName:

    first_name = AlwaysCapitalized()
    last_name = AlwaysCapitalized()

    def __init__(self, first, last):
        self.first_name = first
        self.last_name = last

name  = MemberName("juan", "arrivillaga")  
print(f"Hello, {name.first_name} {name.last_name}!")

Outputs:

Hello, Juan Arrivillaga!

Note, this can be re-used in various classes, and is very flexible if you want to modularize. And look how much cleaner the client code is, if you want to set an attribute with your logic, you just do self.attribute = value, similarly, if you want to get an attribute, you just do self.attribute. No ugly set_attribute() and get_attribute() all over the place

Note, property objects are just descriptors, so are classmethod and staticmethod decorators. Actually, function objects are just descriptors, whose __get__ method essentially partially apply the instance as the first argument to itself.

See the Descriptor HOWTO