Attribute references and instantiation
In this link, that is part of the official Python documentation, I have found the following information:
Class objects support two kinds of operations: attribute references and instantiation.
Attribute references use the standard syntax used for all attribute references in Python. So if
MyClass
is the name of a class andfunc
is the name of one attribute ofMyClass
then:
MyClass.func
is a valid attribute reference.Class instantiation uses function notation. So
x = MyClass()
creates a new instance of the class and assigns this object to the local variablex
.
At the beginning of previous documentation the expression Class object
is used and this means that in Python a class is an object and
on this object we can execute only 2 operations and one of these is attribute references.
Up to now I have used the Attribute references only in one case to access a method of a class: for writing a unit-test which verified the exact sequence of method calls.
I show a simplified code of the test below (for details see here):
import unittest
from unittest import mock
class A:
def __f1(self):
pass
def __f2(self):
pass
def __f3(self):
pass
def method_1(self):
self.__f1()
self.__f2()
self.__f3()
class MyTestCase(unittest.TestCase):
def test_call_order(self):
mock_a = mock.create_autospec(A)
expected = [mock.call._A__f1(),
mock.call._A__f2(),
mock.call._A__f3()]
# call method_1 by reference
A.method_1(mock_a)
self.assertEqual(expected, mock_a.mock_calls)
if __name__ == '__main__':
unittest.main()
I generally create an instance of a class and invoke the methods of the class by this instance object.
On my opinion it's better to use a python module which contains functions and global variables than create a class and access its attributes by reference.
My question
When or why can it be useful to access the attributes of a class by Attribute references and without an instance of that class? What is the point of this language feature? I have a hard time to imagine a case where attribute references make sense without an instance.
An example where it is absolutely necessary the use of such an attribute reference (as in my example) will be appreciated.
2 Answers 2
That reference isn't describing a special case of the language rules, it's a natural result of everything being an object.
The special case is that MyClass(args...)
is wired up to create a new object and call MyClass.__init__
(among other things).
It allows you to change the state of the class after it is defined. This can be as simple as changing "static" data based on some configuration.
class EggsApiClient:
default_url = "example.com"
def connect(self):
# do stuff with default_url
if __name__ = "main":
EggsApiClient.default_url = parse_args("default_url")
-
Thanks. Please change
default_url: "example.com"
todefault_url = "example.com"
in your answer. Very interesting yuor sentence it's a natural result of everything being an object.User051209– User05120911/09/2023 17:12:53Commented Nov 9, 2023 at 17:12 -
When I start to program with Python I think I abused in the use of objects and classes because I was coming from OOP in Java language. Now I think that in many cases I have to use a module and put inside global variables (instead attributes of a class) and functions (methods of a class). I'm convincing that to use modules, functions, global variables is more pythonic than use attribute reference.User051209– User05120911/09/2023 17:22:43Commented Nov 9, 2023 at 17:22
-
Very interesting your example
MyClass.__init__
is what I'm looking for. Thank you very much you help me to better understand the hidden Python logic.User051209– User05120911/09/2023 17:44:21Commented Nov 9, 2023 at 17:44 -
2I'm not sure this really addresses the question. Also, you can do similar things with class level variables in, e.g., Java even though classes are not objects.JimmyJames– JimmyJames11/09/2023 18:11:46Commented Nov 9, 2023 at 18:11
-
2@JimmyJames my point is there's a simplicity in Python's design here. Rather than having separate language features for each case, everything is an object, so everything can be read and writtenCaleth– Caleth11/10/2023 09:01:35Commented Nov 10, 2023 at 9:01
This is not something that I think most Python users will ever need to do and almost surely shouldn't but it does have a distinct purpose and it's worth understanding.
Consider the following example:
class Foo:
def set_a(self, a):
self.a = a
class Bar:
def set_b(self, b):
self.b = b
foo = Foo()
foo.set_a(1)
print(foo.a)
bar = Bar()
# interesting part here!
Foo.set_a(bar, 2)
print(bar.a)
Through this feature, we have effectively called set_a
on a Bar
instance, despite the fact that Bar
doesn't have a set_a
method defined. That is, if we try:
bar.set_a()
We get an error: AttributeError: 'Bar' object has no attribute 'set_a'.
You might (quite reasonably) ask, "OK, but why would I do that?" Personally, I think I did something like this many moons ago but there was probably a simpler solution to whatever I was trying to accomplish.
I can imagine this be useful in various frameworks e.g. something like unit testing. But the main reason I think you might end up doing this is when you are using a more functional style. For example, you might have a function like this which has no knowledge of Foo or Bar:
def apply(obj, func, *params):
func(obj, *params)
Which you can then call like so:
apply(bar, Bar.set_b, 3)
print(bar.b)
A real example of the kind of thing you might actually do:
class Person:
def __init__(self, name: str, student: bool):
self.name = name
self.student = student
def is_student(self):
return self.student
def __repr__(self):
return f"{self.name} - student: {self.student}"
people = [Person("bob", False), Person("alice", True), Person("carl", True)]
def display(iter):
print("---")
for i in iter:
print(i)
display(people)
display(filter(Person.is_student, people))
Or maybe something like this:
people = map(Person, ["dave", "edith", "frank"], [True, False, True])
display(people)
Check out the functools module for more interesting functional-style approaches like this.
-
1Thank you very much. Your answer with the anwser of Caleth have added much to my my poor knowledge of Python. I agree with you that the use of attribute reference is inside framework or other special cases.User051209– User05120911/09/2023 18:20:13Commented Nov 9, 2023 at 18:20
-
My real difficult concern on the fact that sometimes I have to avoid to create class in Python and use module because classes are not so needed as for example in Java.User051209– User05120911/09/2023 18:22:28Commented Nov 9, 2023 at 18:22
-
3@frankfalse I consider this to be intermediate to advanced Python knowledge. The fact that you are even asking suggests you may be underestimating yourself. My opinion is that with Python, you should use module level code as long as it meets your needs and isn't becoming spaghetti code and only introduce classes when they provide a clear benefit.JimmyJames– JimmyJames11/09/2023 18:44:01Commented Nov 9, 2023 at 18:44
-
I agree with you and in the future I will use this approach to programming with the Python language. The code write in the past will remain as it is, but I think the use of Python class will decrease in my next new programs.User051209– User05120911/10/2023 08:34:21Commented Nov 10, 2023 at 8:34
-
The fact that you can do this in no way suggest you should. As to why it's possible requires an understanding of the descriptor protocol in Python and how it implements
foo.set_a(1)
asFoo.set_a(foo, 1)
(via an intermediate call toFoo.set_a.__get__(foo, Foo)
).chepner– chepner01/23/2024 21:48:43Commented Jan 23, 2024 at 21:48
Explore related questions
See similar questions with these tags.
static
members in C++ / C# / Java?