Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3 static members

I am trying to achieve the following:

class A:
    username = None
    username = get_username()
    def get_username(self):
        if username is None:
            try:
                uname = os.environ["USER"]
            except:
                printf("Couldn't find a user name")
            return uname
        return username

Not sure how to achieve this. I'm sure I'm missing some "self." prefixes but this is the first time I'm working with python and static members.

In a sense I want a class with some members and functions to calculate values for these members but I don't want recalculations. I would also like these to be static functions and data members.

The problem is that the line "username = get_username()" the function hasn't already been defined. If I put username after the function then it's not

like image 703
s5s Avatar asked Nov 02 '12 19:11

s5s


People also ask

What are static members in Python?

Static means, that the member is on a class level rather on the instance level. Static variables exist only on class level and aren't instantiated. If you change a static variable in one instance of the class, the change will affect its value in all other instances.

Does Python have static members?

Python does not have a 'static' keyword to declare the static variable. In Python, you simply declare a variable inside the class, note that it should not be inside any method, and that variable will be known as a static or class variable.

How do you declare a static attribute in Python?

There are the two ways to define a static method in Python: Using the staticmethod() Method. Using the @staticmethod Decorator.

What is the equivalent of static in Python?

Python doesn't have static variables but you can fake it by defining a callable class object and then using it as a function. Also see this answer. Note that __call__ makes an instance of a class (object) callable by its own name. That's why calling foo() above calls the class' __call__ method.


2 Answers

First, there's no reason to assign None to username if you're just going to reassign it immediately after.

Second, if you want the method to be a static method, you can't give it a self argument. And if you want a real static method, you have to declare it explicitly.

    @staticmethod
    def get_username():
        if username is None:
        ...

Otherwise, you need an instance of the class (that self) to call it on, and you don't have one yet.

In Python 3, any regular method acts like a static method when called on the class, like an instance method when called on an instance. So, if you're sure you're never going to want to call a.get_username() on an instance a, you can skip the decorator. But you still need to get rid of the self parameter.

I think what you're actually trying to do is use a class variable to memoize the result of a static method. You can't do that, but you can use a class variable to memoize the result of a class method, which may be close enough. That would look like this:

class A:
    username = None
    @classmethod
    def get_username(cls):
        if cls.username is None:
            try:
                uname = os.environ["USER"]
            except:
                print("Couldn't find a user name")
            else:
                cls.username = uname
        return cls.username

On the other hand, there's no good reason username has to be a class member. You can memoize by adding a member to the function, by passing a mutable default variable, or in various other ways which don't require infecting the class, and which allow you to leave get_username as a static method instead of a class method.

But really, the best solution is to find a memoization library on PyPI, in ActiveState's recipe list, etc., so you can just write this:

class A:
    @memoize
    @staticmethod
    def get_username():
        try:
            return os.environ["USER"]
        except:
            print("Couldn't find a user name")
            return None

Again, you can drop the @staticmethod if you're sure nobody's ever going to try to create an instance of A and call get_username on it.

like image 191
abarnert Avatar answered Sep 26 '22 20:09

abarnert


if you don't want to lose the ability to refer to A.username, you can use class property with a little bit of metaclass:

class A(type):
    def __new__(cls, name, bases, attrs):
        # this allows B().username to also work
        attrs['username'] = property(lambda s: s.__class__.username)
        return type.__new__(cls, name, bases, attrs)
    @property
    def username(self):
        if not hasattr(self, '_username'):
            self._username = 'bar'
        return self._username

class B(object):
    __metaclass__ = A

print B.username
print B().username
like image 32
Lie Ryan Avatar answered Sep 25 '22 20:09

Lie Ryan