1

I want to have a class and be able to change an object value and have it flow through to methods and objects created in the class. In the below example I am trying have the new value 3 flow through but I keep getting the original value 2. Am I doing it wrong?

class fun:
  g=2
  def a(c=g):
    return c
  z=g

fun.g = 3
fun.a()
fun.z

I have searched for __init__ functions but I don't see how they can help here. I tried created a new class making is the same as the fun class. That didn't work either.

4
  • 2
    You're facing a couple different issues here, but It sounds like you're seeking getters and setters. In python the @property decorator is used for this purpose. Commented Jul 20, 2021 at 15:44
  • 1
    Changing the default argument value of an existing function is possible, though not really recommended. Commented Jul 20, 2021 at 15:50
  • Be sure to read nedbatchelder.com/text/names.html as well. Commented Jul 20, 2021 at 15:52
  • Thanks for the info and reading material, super helpful. I have to approach in totally different way Commented Jul 20, 2021 at 16:01

4 Answers 4

3

as otheres mentioned, just want to point out that def a(c=g): the g has been replaced with 2 during class creation.

so after

fun.g = 3

print(fun.__dict__)
mappingproxy({'__module__': '__main__',
              'g': 3,
              'a': <function __main__.fun.a(c=2)>,
              'z': 2,
              '__dict__': <attribute '__dict__' of 'fun' objects>,
              '__weakref__': <attribute '__weakref__' of 'fun' objects>,
              '__doc__': None})

As you can see 'a': <function __main__.fun.a(c=2)>,

Sign up to request clarification or add additional context in comments.

Comments

2

In python, methods and functions have their default values calculated and stored when the method or function is declared.

You can defer that calculation by doing it inside the method at runtime:

class fun:
  g=2
  def a(c=None):  # None is used here as a sentinal value
    if c is None:
        c=fun.g
    return c
  z=g

4 Comments

This doesn't update the value of fun.z, though. I think the idea was to be able to update several things depending on the value of fun.g with only one change.
z = property(lambda self: self.g), perhaps.
Well, just omit z. Use g instead!
@chepner you are right, really just shorthand sample for how to make several updates with one change...unfortunately I can't seem to find a way to do this in a way that makes the code simple/readable. Essentially tons of methods/objects within a class need to inherit this value which will change from use to use
1

The problem is that parameters of a function is evaluated at compile time not runtime! Because in compile time the value of g is 2 and in your function you return that value, it's always going to be 2.

As a point, you call a() function on the class itself, so it's first parameter is not going to be filled with a reference to an instance. Story changes when you try to call it from instance of that class.

For demonstration take a look at this :

from datetime import datetime
from time import sleep

class C:
    def fn(self, date=datetime.now()):
        return date

obj = C()
print(obj.fn())
sleep(2)
print(obj.fn())

They both have same value.

The solution is to put g equal to None for default value and then inside the function check whether that value is passed or not:

from datetime import datetime
from time import sleep

class C:
    def fn(self, date=None):
        if date:
            return date
        return datetime.now()

obj = C()
print(obj.fn())
sleep(2)
print(obj.fn())

Comments

1

Not sure quite what you mean by reinitialize, __init__ occurs only on creation. If you create a new fun object it will be initialized in the same way with the same value.

$ cat fun.py

class fun(object):

    def __init__(self):
        self.g = 2

    def a(self, c=None):
        if c is None:
            c = self.g
        return c


first = fun()
second = fun()

first.g = 3

print(first.g)
print(first.a())
print(second.g)
print(second.a())
$ python3 fun.py
3
3
2
2

Comments

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.