0

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?

8
  • 2
    I'm pretty sure you want setattr but your question isn't really clear to me. Note, you could simply just not use lambda expressions, and regular function definition statements, which allow assignment statements. Commented Aug 4, 2020 at 5:57
  • What is set_global_variable supposed to do? It looks like you actually want to set an instance variable, again, your example is very confusing Commented Aug 4, 2020 at 5:59
  • "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." Can you give an example of what exactly you are trying to avoid? There are probably better ways to accomplish what you are trying to do in Python, for example, writing a custom descriptor to modularize setter logic. Commented Aug 4, 2020 at 6:00
  • Ah I come from java where all of your variables must be in a class so I get global variable and instance variable confused a lot. The main idea is that I want to generalize a setter function that I can easily reuse with all of my variables Commented Aug 4, 2020 at 6:01
  • NoI thought eq returns a boolean @AlexanderLekontsev Commented Aug 4, 2020 at 6:02

3 Answers 3

1

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)
Sign up to request clarification or add additional context in comments.

7 Comments

It took me a little bit to understand setattr but yes this is what I am looking for. Essentially x = 3 is the same as setattr(self, "x", 3) right?
@KNOBPersonal no. x = 3 sets a variable in whateer scope you are in. setattr sets an attribute on an object
Oops yep so being inside a class with the variable in the first place is important. Otherwise, it won't work.
I added a reference to the setattr built-in. Essentially, setattr(self, "x", 3) is the same of self.x = 3.
If you want a more general assignment, also to local variables (for some reason), the first solution with the local function _set_variable has no limitations on the kind of operations you can perform inside.
|
1

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

2 Comments

Technically the answer I marked as correct was more relevant to how I was trying to solve the problem, however, I think this completely new approach is also worth checking out. My project has a backend that I code and a front end that the users code so this would make it much easier on them. Even so, I don't like how you are no longer dealing with strings but objects of classes. Still, +1 to this answer!
@KNOBPersonal no, you are dealing with strings. Notice, I passed strings: MemberName("juan", "arrivillaga") And note, strings are objects of classes too...
0

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.

1 Comment

Is there a way I can generalize that to any variable from one function. Ex. set(varname: str): global varname; varname = "fantastic"?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.