预计阅读本页时间:-
Emulating Privacy for Instance Attributes: Part 1
The following code generalizes the previous example, to allow each subclass to have its own list of private names that cannot be assigned to its instances:
class PrivateExc(Exception): pass # More on exceptions later
class Privacy:
def __setattr__(self, attrname, value): # On self.attrname = value
if attrname in self.privates:
raise PrivateExc(attrname, self)
else:
self.__dict__[attrname] = value # self.attrname = value loops!
class Test1(Privacy):
privates = ['age']
class Test2(Privacy):
privates = ['name', 'pay']
def __init__(self):
self.__dict__['name'] = 'Tom'
x = Test1()
y = Test2()
x.name = 'Bob'
y.name = 'Sue' # Fails
y.age = 30
x.age = 40 # Fails
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
In fact, this is a first-cut solution for an implementation of attribute privacy in Python (i.e., disallowing changes to attribute names outside a class). Although Python doesn’t support private declarations per se, techniques like this can emulate much of their purpose. This is a partial solution, though; to make it more effective, it must be augmented to allow subclasses to set private attributes more naturally, too, and to use __getattr__ and a wrapper (sometimes called a proxy) class to check for private attribute fetches.
We’ll postpone a more complete solution to attribute privacy until Chapter 38, where we’ll use class decorators to intercept and validate attributes more generally. Even though privacy can be emulated this way, though, it almost never is in practice. Python programmers are able to write large OOP frameworks and applications without private declarations—an interesting finding about access controls in general that is beyond the scope of our purposes here.
Catching attribute references and assignments is generally a useful technique; it supports delegation, a design technique that allows controller objects to wrap up embedded objects, add new behaviors, and route other operations back to the wrapped objects (more on delegation and wrapper classes in Chapter 30).