Have a look at the following piece of code. In it, we create an object of Quote. Since the class has been declared in a factory method, it has access to its local variables, "txt" in this case.
def create(arg):
txt = str(arg)
class Quote:
def get_txt(self):
return txt
return Quote()
quote = create("My tables! Meet it is, I set it down, ...")
print(dir(quote))
print(quote.get_txt())
Since it is not a variable of Quote itself, "txt" is not accessible from the outside. Yet, Python keeps those variables around, even after create has returned. The script delivers the following output:
['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_txt']
My tables! Meet it is, I set it down, ...
Now, what about changing the value? Let us add a simple setter method.
def create(arg):
txt = str(arg)
class Quote:
def get_txt(self):
return txt
def set_text(self, quote):
txt = quote
return Quote()
hamlet = create("There is something rotten in the state of Denmark.")
print(hamlet.get_txt())
hamlet.set_text("I'll make a ghost of him who lets me.")
print(hamlet.get_txt())
Seems straightforward enough, but results in the following undesired output.
There is something rotten in the state of Denmark.
There is something rotten in the state of Denmark.
Apparently, Python does not use lexical scoping when doing a name lookup for write access. Instead, it creates a local variable - which is discarded the same moment the setter-method returns.
Read access works though, and we can use this for a work-around by modifying objects instead of assigning values to names.
class Privates:
pass
def create(arg):
privates = Privates()
setattr(privates, "txt", str(arg))
class Quote:
def get_txt(self):
return privates.txt
def set_text(self, quote):
privates.txt = quote
return Quote()
hamlet = create("There is something rotten in the state of Denmark.")
print(hamlet.get_txt())
hamlet.set_text("I'll make a ghost of him who lets me.")
print(hamlet.get_txt())
This produces:
There is something rotten in the state of Denmark.
I'll make a ghost of him who lets me.
All things considered, this is pretty ugly. Python is all about openness, and privates are not. Also, the class definition is hidden because of a technical necessity. This is bad.
Summing it up: Nice that you can do it, but ... please don't.
(Full code here.)