Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way for a class to reference itself in a class attribute?

Tags:

python

Unfortunately, in Python, a class attribute cannot reference its class name. The following raises a NameError:

class Foo(object):
    bar = Foo

In a situation where a class attribute must reference its class name (in my case, it's part of a validation scheme for a library). What is the clearest way to do so?

The following is my current attempt:

class Foo(object):
    bar = None
Foo.bar = Foo

This works, but even with comments is likely to cause confusion, since you expect a class attribute to be initialized when declared, not after the class is declared.

Does anyone have a better workaround?

like image 572
JustinLovinger Avatar asked Dec 06 '15 17:12

JustinLovinger


People also ask

How do you reference a class attribute in Python?

A class attribute is shared by all instances of the class. To define a class attribute, you place it outside of the __init__() method. Use class_name. class_attribute or object_name.

Which method is used to display the attributes of a class?

Accessing the attributes of a classgetattr() − A python method used to access the attribute of a class. hasattr() − A python method used to verify the presence of an attribute in a class. setattr() − A python method used to set an additional attribute in a class.

What are the attributes of a class?

Class attributes are the variables defined directly in the class that are shared by all objects of the class. Instance attributes are attributes or properties attached to an instance of a class. Instance attributes are defined in the constructor. Defined directly inside a class.

What does the attribute and method of a class refers to?

Any variable that is bound in a class is a class attribute . Any function defined within a class is a method . Methods receive an instance of the class, conventionally called self , as the first argument.

What is the use of a class attribute?

Class attributes are useful in some cases such as storing class constants, tracking data across all instances, and defining default values. Since a constant doesn’t change from instance to instance of a class, it’s handy to store it as a class attribute.

When to use Python class attributes?

When to use Python class attributes 1 Storing class constants#N#Since a constant doesn’t change from instance to instance of a class, it’s handy to store it... 2 Tracking data across of all instances More ...

How to access an attribute from an instance of a class?

When you try to access an attribute from an instance of a class, it first looks at its instance namespace. If it finds the attribute, it returns the associated value. If not, it then looks in the class namespace and returns the attribute (if it’s present, throwing an error otherwise). For example:

What is the X attribute of the test class in Java?

The Test class has two attributes with the same name ( x) one is the instance attribute and the other is a class attribute. When we access the x attribute via the instance of the Test class, it returns 20 which is the variable of the instance attribute.


3 Answers

Use a meta class to automatically set it.

def my_meta(name, bases, attrs):
    cls = type(name, bases, attrs)
    cls.bar = cls
    return cls


class Foo(object):
    __metaclass__ = my_meta


>>> print Foo.bar
<class '__main__.Foo'>
like image 54
Brendan Abel Avatar answered Oct 05 '22 16:10

Brendan Abel


You could define a class decorator that replaced placeholder strings with the class being defined:

def fixup(cls):
    placeholder = '@' + cls.__name__
    for k,v in vars(cls).items():
        if v == placeholder:
            setattr(cls, k, cls)
    return cls

@fixup
class Foo(object):
    bar = '@Foo'

print('Foo.bar: {!r}'.format(Foo.bar))  # -> Foo.bar: <class '__main__.Foo'>

Another alternative would be to use the __init_subclass__() special method which was introduced in Python 3.6 to create a base class and then derive your class from it instead of the generic object:

class Base(object):
    def __init_subclass__(cls, /, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.bar = cls

class Foo(Base):
    pass

print('Foo.bar: {!r}'.format(Foo.bar))  # -> Foo.bar: <class '__main__.Foo'>
like image 43
martineau Avatar answered Oct 05 '22 18:10

martineau


You can use a class decorator

def moi(fieldname):
    def _selfref(cls):
        setattr(cls, fieldname, cls.__name__)
        return cls

    return _selfref

usage:

@moi('bar')
class Foo(object):
    pass

then:

>>> print Foo.bar
Foo
like image 44
thebjorn Avatar answered Oct 05 '22 18:10

thebjorn