Home > front end >  Class method as default __init__ argument
Class method as default __init__ argument

Time:08-24

I am trying to set a default function in the class constructor. Caveat is that the function is from within the same class.

Class MyClass:
    def __init__(self, filename, file_rename_func=filename_parser):
        self.filename = filename
        self.file_rename_func = file_rename_func

    def filename_parser(self, filename)
        return filename   '. Hi, StackOverflow!'

This keeps giving me the error: NameError: name 'filename_parser' is not defined

If I were to instead have the __init__ function look like this:

def __init__(self, filename, file_rename_func=self.filename_parser):

I get NameError: name 'self' is not defined

How can I get around this issue if I must have this done in the constructor?

CodePudding user response:

You can fix this as follows:

class MyClass:
    def __init__(self, filename, file_rename_func=None):
        self.filename = filename
        self.file_rename_func = file_rename_func or self.filename_parser

    def filename_parser(self, filename)
        return filename   '. Hi, StackOverflow!'

this works on the basis that file_rename_func should be a function object and thus evaluate to true. Thus this value is used, when file_rename_func it evaluates to false and the second value is used.

EDIT:

using self will not fix the issue since self is a parameter to the function __init__ (and when the default value is calculated it's not known what self is(think of self as just any parameter).

CodePudding user response:

You can do two things to make this work:

  1. Define filename_parser first so you can refer to it (unqualified) when defining the default for __init__
  2. Decorate it as a staticmethod so it is always invoked without passing self (since you don't use self anyway)

The following will do that:

class MyClass:
    @staticmethod                   # Add staticmethod decorator so self never passed
    def filename_parser(filename):  # Remove self from prototype
        return filename   '. Hi, StackOverflow!'

    def __init__(self, filename, file_rename_func=filename_parser):
        self.filename = filename
        self.file_rename_func = file_rename_func

Note that as written, this will only work on Python 3.10, the first version where staticmethod objects themselves are callable without invoking the descriptor protocol on them first (by looking them up on a class or instance of the class). Pre 3.10, it's a little uglier, as you have to manually extract the underlying function for the default argument, while leaving it a staticmethod otherwise. The only change is to the prototype of __init__, which becomes:

    def __init__(self, filename, file_rename_func=filename_parser.__func__):

explicitly looking up the wrapped function inside the staticmethod object.

  • Related