Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python function of a default argument

How can I access qux inside methods? Do I really have to define it again inside the body of foo(), or is there a way to import it from self?

class Baz(object):

    qux = lambda x : x + '_quux'

    def foo(self, bar=qux('fred')):
        print bar

        print qux('waldo')
        # NameError: global name 'qux' is not defined

        print Baz.qux('waldo')
        # TypeError: unbound method <lambda>() must be called with Baz instance as first argument (got str instance instead)

        print Baz.qux(self, 'waldo')
        # TypeError: <lambda>() takes exactly 1 argument (2 given)

        print self.qux('waldo')
        # TypeError: <lambda>() takes exactly 1 argument (2 given)                
like image 221
wim Avatar asked Jan 19 '23 13:01

wim


2 Answers

If you want to be able to access a method off the class then you must use classmethod or staticmethod.

class Baz(object):
  qux = staticmethod(lambda x : x + '_quux')

But don't do that.

like image 140
Ignacio Vazquez-Abrams Avatar answered Jan 28 '23 09:01

Ignacio Vazquez-Abrams


qux is being treated like an instance method, because that's the default handling for class members that look like functions (more specifically, Baz.qux has a __get__ that is implicitly called to "bind" the first parameter to the instance, when you look it up via an instance). However, you haven't provided a self parameter at the start. Accordingly, baz gets bound to the x lambda parameter instead.

There is nothing magical about the name 'self' in Python; it's just convention. Method binding always works by binding to the first argument of a function.

You can see this for yourself, if you're clever:

class Baz(object):
    qux = lambda x: x + '_quux'
    def foo(self): return self.qux()

Baz().foo() # TypeError: unsupported operand type(s) for +: 'Baz' and 'str'
# because after binding Baz() to 'x', we get Baz() + '_quux'

One solution is to explicitly make qux a staticmethod, as in Sven Marnach's answer. (You can also make it a classmethod, which is a Python-specific concept that's more powerful; staticmethod more closely parallels the behaviour of the static keyword in languages like Java.) Note that, as in Java, you can also access the staticmethod as self.qux within foo. This works by replacing the normal __get__ machinery for functions with new machinery installed by staticmethod.

Another solution is to provide for the self parameter in the lambda parameters. This is useful if you actually don't want "static" behaviour (i.e. will need to actually do something with self) - but it looks very much as if you do. Just for completeness, this would look like:

qux = lambda self, x: x + '_quux'
def foo(self):
    return self.qux('foo')
like image 37
Karl Knechtel Avatar answered Jan 28 '23 09:01

Karl Knechtel