73

This is what my code looks like

class InviteManager():
    ALREADY_INVITED_MESSAGE = "You are already on our invite list"
    INVITE_MESSAGE = "Thank you! we will be in touch soon"

    @staticmethod
    @missing_input_not_allowed
    def invite(email):
        try:
            db.session.add(Invite(email))
            db.session.commit()
        except IntegrityError:
            return ALREADY_INVITED_MESSAGE
        return INVITE_MESSAGE

When I run my tests, I see

NameError: global name 'INVITE_MESSAGE' is not defined

How can I access INVITE_MESSAGE inside @staticmethod?

daydreamer
  • 87,243
  • 191
  • 450
  • 722

6 Answers6

69

You can access it as InviteManager.INVITE_MESSAGE, but a cleaner solution is to change the static method to a class method:

@classmethod
@missing_input_not_allowed
def invite(cls, email):
    return cls.INVITE_MESSAGE

(Or, if your code is really as simple as it looks, you can replace the whole class with a bunch of functions and constants in a module. Modules are namespaces.)

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • 1
    Or just make it a module-level function. –  Aug 25 '13 at 16:52
  • 1
    @delnan: yes. Sometimes you need a class or static method, though, in particular in situations involving inheritance or duck typing. – Fred Foo Aug 25 '13 at 16:52
  • 1
    Any idea why python allows to access `class variable` via `staticmethod`? If so why do we need `classmethod`? What is the different use case between `classmethod` and `staticmethod` if they both can access the class variables? – JavaSa Apr 24 '19 at 09:11
  • class methods get a reference to the subclass, so they can be written in a baseclass but work differently in different subclasses, as they behaviour can depend on the class. also, static methods don't get a reference to the class, so using cls is cleaner if you need to refer the class at all, for example as the code does not break if the name of the class changes. – antont May 05 '23 at 21:06
13

Try:

class InviteManager():
    ALREADY_INVITED_MESSAGE = "You are already on our invite list"
    INVITE_MESSAGE = "Thank you! we will be in touch soon"

    @staticmethod
    @missing_input_not_allowed
    def invite(email):
        try:
            db.session.add(Invite(email))
            db.session.commit()
        except IntegrityError:
            return InviteManager.ALREADY_INVITED_MESSAGE
        return InviteManager.INVITE_MESSAGE

The InviteManager is in the scope of it's staticmethods.

Maciej Gol
  • 15,394
  • 4
  • 33
  • 51
5

Just realized, I needed @classmethod

class InviteManager():
    ALREADY_INVITED_MESSAGE = "You are already on our invite list"
    INVITE_MESSAGE = "Thank you! we will be in touch soon"

    @classmethod
    @missing_input_not_allowed
    def invite(cls, email):
        try:
            db.session.add(Invite(email))
            db.session.commit()
        except IntegrityError:
            return cls.ALREADY_INVITED_MESSAGE
        return cls.INVITE_MESSAGE

You can read about it here

Community
  • 1
  • 1
daydreamer
  • 87,243
  • 191
  • 450
  • 722
5

It is much simpler than all of that:

Just added __class__ to the class variables. Like so:

return __class__.ALREADY_INVITED_MESSAGE
        return __class__.INVITE_MESSAGE

There is no need to mention the ClassName (InviteManager) and there is no need to use a classmethod

Mohsen Banan
  • 85
  • 1
  • 5
  • More information: The `__class__` [cell](https://stackoverflow.com/q/23757143/8944057) was introduced in [PEP 3135](https://www.python.org/dev/peps/pep-3135/). – eugenhu Oct 14 '21 at 03:26
3

Simply, understand the concept of class level variables/methods and instance level variables/methods.

While working with static methods, you won't use self keyword as self keyword is used to represent instance of the class or to use instance variables of the class. In fact one use class_name, see below example:

class Myclass():
    msg = "Hello World!"

    @staticmethod
    def printMsg():
        print(Myclass.msg)



Myclass.printMsg() #Hello World!
print(Myclass.msg) #Hello World!
Myclass.msg = "Hello Neeraj!"
Myclass.printMsg() #Hello Neeraj!
print(Myclass.msg) #Hello Neeraj!
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Neeraj Bansal
  • 2,580
  • 16
  • 8
2

You can access to yours attributes with InviteManager.INVITE_MESSAGE and InviteManager.ALREADY_INVITED_MESSAGE without changing anything in their declaration.

Maxime Lorant
  • 34,607
  • 19
  • 87
  • 97