-1

I picked the example from here:

what does the "yield" keyword do

class Bank(): # Let's create a bank, building ATMs
        crisis = False
        def create_atm(self):
            while not self.crisis:
                yield "$100"

In the sample code above, crisis is a class variable. Why is it accessed as self.crisis vs Bank.crisis?

Neel
  • 9,913
  • 16
  • 52
  • 74
  • Because you can later set a `crisis` variable at instance level as well? – Willem Van Onsem Jul 27 '19 at 15:19
  • But can't you achieve the same with Bank.crisis? – Neel Jul 27 '19 at 15:20
  • not if one sets `some_bank.crisis = True` later no, since then there are two variables in place: a class-level one that is used by all banks except `some_bank`, and a `crisis` variable for `some_bank`. The `self.crisis` will first resolve to the local one. – Willem Van Onsem Jul 27 '19 at 15:20
  • But is that a good practice to change class variable inside instances? Does it need to be protected in that case? – Neel Jul 27 '19 at 15:21
  • If you do `self.crisis` , how does it have reference to `Bank.crisis`? Aren't they independent? – Neel Jul 27 '19 at 15:26
  • because it first looks if there is an attribute defined at the instance level with that name, if not it performs a fallback on the classlevel, and if that does not hold, it performs a fallback on the MRO. – Willem Van Onsem Jul 27 '19 at 15:28
  • So, is it a good practice, in general, to shadow class variables inside instances? – Neel Jul 27 '19 at 15:33
  • No it's not a good Practice to do something like that in Python – basilisk Jul 27 '19 at 15:37

1 Answers1

0

By instantiating the class and accessing self.crisis means that (among many things) the __init__() is called. The init in the class, or inherited classes will be "called" and consequences of the call could change crisis.

By contrast, Bank.crisis think of as a simple variable for a class in how it behaves. Not encapsulated, not modified from an original state.

Now that is the short and simple answer, there are a lot of other things to know about, but I am trying to highlight an easy and critical difference with respect to the question.

To elaborate on the code more, the use of crisis is a flag or escape from an iterable/while/generator type situation. Something else in the code, (possibly in an inherited class, probably not however) will flip crisis to True or some other value. To use crisis as a control self will be part of the use generally as that variable, via initialization, is encapsulated where only via self will the value "in the instance" be of value with respect to the code's desired flow. The self. "something" is inside the instantiated class and can change as needed in any operation providing functionality. This is the core of OOP, variables, etc, are not fixed, they can change dynamically in use, and that allows crisis to change and alter behavior in the instance safely (encapsulated).

To drive the point home:

b = Bank()
b.crisis  # starts off as false, probably

# is not the same (any more) as
Bank.crisis # False

# because now
b.crisis = "foo"
# is in the instance while

Bank.crisis # will always return False.
Marc
  • 1,895
  • 18
  • 25