3

I have an issue where I'm trying to use a static variable as a required named default argument in init of a class:

class Foo:
    bar = 1
    rab = 2
    
    def __init__(self, /, def_arg=Foo.bar):
        if def_arg == self.bar:
            pass
        elif def_arg == self.rab:
            pass

Foo()
Foo(Foo.rab)

4: NameError: name 'Foo' is not defined

I also tried without Foo. and also tried self. but it doesn't work. It has to be specifically static, so I don't want to use self.bar. Is this at all possible?

Jack Avante
  • 1,405
  • 1
  • 15
  • 32
  • If `Foo.bar` is reassigned to a different value, do you want `def_arg` to also change? – tdelaney Nov 21 '20 at 23:42
  • No. But it turns out this was actually a weird Jupyter issue, and it works correctly now when `Foo.` is excluded – Jack Avante Nov 21 '20 at 23:44
  • Does this answer your question? [Can I use a class attribute as a default value for an instance method?](https://stackoverflow.com/questions/4041624/can-i-use-a-class-attribute-as-a-default-value-for-an-instance-method) – Jeyekomon Sep 16 '22 at 11:28

4 Answers4

3

If you use only bar it works.

def __init__(self, def_arg=bar):
    print(def_arg)
1

You could probably do like this...

class Foo:
    bar = 1

    def __init__(self, def_arg=bar):
        self.def_arg = def_arg

    def __repr__(self):
        return "{self.def_arg}".format(self=self)

foo = Foo()
print(foo) # should print 1
Dharman
  • 30,962
  • 25
  • 85
  • 135
syohey
  • 156
  • 1
  • 1
  • 6
1

Default keyword assignments are made when the method is compiled. That happens before the class has been assigned to Foo, so Foo.bar doesn't exist yet. But bar does exist in the enclosing namespace at this point. def_arg=bar will grab the current object in bar and make that the default argument for __init__. Note that once a default argument has been set, it can't be changed. If Foo.bar is reassigned, that doesn't affect the default value already placed in the function object for __init__.

class Foo:
    bar = 1
    rab = 2
    
    def __init__(self, def_arg=bar):
        if def_arg == self.bar:
            pass
        elif def_arg == self.rab:
            pass

Foo()
Foo(Foo.rab)
tdelaney
  • 73,364
  • 6
  • 83
  • 116
0

I think if you made a another func with the @classmethod decorator, you could use the variable as static, like so:

class Foo:
   bar = 1

   def __init__(self):
       print(self.func())
   @classmethod
   def func(cls):
       return cls.bar

bar will still be a static variable

Ian vos
  • 39
  • 5
  • The point isn't to print it. I'm just providing a minimal reproducible example. In my large code I am using 'string' macros to determine the functionality. And I am using one of the defined static variables as the default functionality, and want to give capability of choosing via macros so users don't have to remember strings. Just like opencv does with cv.adaptive_threshold, for instance – Jack Avante Nov 21 '20 at 23:32
  • I've changed my answer, sorry for the previous one, I think this one should be more adequate. – Ian vos Nov 21 '20 at 23:35
  • That would work yes, but it still isn't what I'm asking. I know how to work around putting it into __init__ (avoiding it), but I'm curious if it's possible to do it without avoiding it in __init__ – Jack Avante Nov 21 '20 at 23:38