Beginning Python - From Novice to Professional
Beginning Python - From Novice to Professional Beginning Python - From Novice to Professional
CHAPTER 9 ■ MAGIC METHODS, PROPERTIES, AND ITERATORS 185 private to the class—see the section “In Private” in Chapter 7). Encapsulating state variables (attributes) like this can be important if certain actions must be taken when accessing the given attribute. For example, consider the following Rectangle class: class Rectangle: def __init__(self): self.width = 0 self.height = 0 def setSize(self, size): self.width, self.height = size def getSize(self): return self.width, self.height Here is an example of how you can use the class: >>> r = Rectangle() >>> r.width = 10 >>> r.height = 5 >>> r.getSize() (10, 5) >>> r.setSize((150, 100)) >>> r.width 150 The getSize and setSize methods are accessors for a fictitious attribute called size— which is simply the tuple consisting of width and height. This code isn’t directly wrong, but it is flawed. The programmer using this class shouldn’t have to worry about how it is implemented (encapsulation). If you some day wanted to change the implementation so that size was a real attribute and width and height were calculated on the fly, you would have to wrap them in accessors, and any programs using the class would also have to be rewritten. The client code (the code using your code) should be able to treat all your attributes in the same manner. So what is the solution? To wrap all your attributes in accessors? That is a possibility, of course. However, it would be impractical (and kind of silly) if you had lots of simple attributes; you would have to write many accessors that did nothing but retrieve or set these attributes, with no useful action taken. This smells of copy-paste programming, or cookie-cutter code, which is clearly a bad thing (although quite common for this specific problem in certain languages). Luckily, Python can hide your accessors for you, making all of your attributes look alike. Those attributes that are defined through their accessors are often called properties. There are, in fact, two mechanisms for creating properties in Python. I’ll focus on the most recent one, the property function, which only works on new-style classes. Then, I’ll give you a short description of how to implement properties with magic methods. The property Function Using the property function is delightfully simple. If you have already written a class such as Rectangle from the previous section, you only have to add a single line of code (in addition to subclassing object):
186 CHAPTER 9 ■ MAGIC METHODS, PROPERTIES, AND ITERATORS class Rectangle(object): def __init__(self): self.width = 0 self.height = 0 def setSize(self, size): self.width, self.height = size def getSize(self): return self.width, self.height size = property(getSize, setSize) In this new version of Rectangle, a property is created with the property function with the accessor functions as arguments (the getter first, then the setter), and this property is stored under the name size. After this, you no longer have to worry about how things are implemented, but can treat width, height, and size the same way: >>> r = Rectangle() >>> r.width = 10 >>> r.height = 5 >>> r.size (10, 5) >>> r.size = 150, 100 >>> r.width 150 As you can see, the size attribute is still subject to the calculations in getSize and setSize, but it looks just like a normal attribute. ■Tip If your properties are behaving oddly, make sure your class subclasses object (either directly or indirectly—or by setting the metaclass directly). If it doesn’t, the getter part of the property will still work, but the setter part won’t. This can be a bit confusing. In fact, the property function may be called with zero, one, three, or four arguments as well. If called with no arguments, the resulting property is neither readable nor writable. If called with only one argument (a getter method), the property is readable only. The third (optional) argument is a method used to delete the attribute (it takes no arguments). The fourth (optional) argument is a documentation string. The parameters are called fget, fset, fdel, and doc—you can use them as keyword arguments if you want a property that, say, is only writable and has a docstring. Although this section has been short (a testament to the simplicity of the property function), it is very important. The moral is this: With new-style classes, you should use property rather than accessors.
- Page 165 and 166: 134 CHAPTER 6 ■ ABSTRACTION LAMBD
- Page 167 and 168: 136 CHAPTER 6 ■ ABSTRACTION In th
- Page 169 and 170: 138 CHAPTER 6 ■ ABSTRACTION Scope
- Page 171 and 172: 140 CHAPTER 7 ■ MORE ABSTRACTION
- Page 173 and 174: 142 CHAPTER 7 ■ MORE ABSTRACTION
- Page 175 and 176: 144 CHAPTER 7 ■ MORE ABSTRACTION
- Page 177 and 178: 146 CHAPTER 7 ■ MORE ABSTRACTION
- Page 179 and 180: 148 CHAPTER 7 ■ MORE ABSTRACTION
- Page 181 and 182: 150 CHAPTER 7 ■ MORE ABSTRACTION
- Page 183 and 184: 152 CHAPTER 7 ■ MORE ABSTRACTION
- Page 185 and 186: 154 CHAPTER 7 ■ MORE ABSTRACTION
- Page 187 and 188: 156 CHAPTER 7 ■ MORE ABSTRACTION
- Page 189 and 190: 158 CHAPTER 7 ■ MORE ABSTRACTION
- Page 191 and 192: 160 CHAPTER 8 ■ EXCEPTIONS >>> im
- Page 193 and 194: 162 CHAPTER 8 ■ EXCEPTIONS Custom
- Page 195 and 196: 164 CHAPTER 8 ■ EXCEPTIONS More T
- Page 197 and 198: 166 CHAPTER 8 ■ EXCEPTIONS try: x
- Page 199 and 200: 168 CHAPTER 8 ■ EXCEPTIONS Invali
- Page 201 and 202: 170 CHAPTER 8 ■ EXCEPTIONS If you
- Page 204 and 205: CHAPTER 9 ■ ■ ■ Magic Methods
- Page 206 and 207: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 208 and 209: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 210 and 211: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 212 and 213: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 214 and 215: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 218 and 219: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 220 and 221: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 222 and 223: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 224 and 225: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 226 and 227: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 228 and 229: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 230 and 231: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 232 and 233: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 234 and 235: CHAPTER 10 ■ ■ ■ Batteries In
- Page 236 and 237: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 238 and 239: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 240 and 241: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 242 and 243: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 244 and 245: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 246 and 247: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 248 and 249: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 250 and 251: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 252 and 253: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 254 and 255: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 256 and 257: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 258 and 259: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 260 and 261: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 262 and 263: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 264 and 265: CHAPTER 10 ■ BATTERIES INCLUDED 2
186 CHAPTER 9 ■ MAGIC METHODS, PROPERTIES, AND ITERATORS<br />
class Rectangle(object):<br />
def __init__(self):<br />
self.width = 0<br />
self.height = 0<br />
def setSize(self, size):<br />
self.width, self.height = size<br />
def getSize(self):<br />
return self.width, self.height<br />
size = property(getSize, setSize)<br />
In this new version of Rectangle, a property is created with the property function with the<br />
accessor functions as arguments (the getter first, then the setter), and this property is s<strong>to</strong>red<br />
under the name size. After this, you no longer have <strong>to</strong> worry about how things are implemented,<br />
but can treat width, height, and size the same way:<br />
>>> r = Rectangle()<br />
>>> r.width = 10<br />
>>> r.height = 5<br />
>>> r.size<br />
(10, 5)<br />
>>> r.size = 150, 100<br />
>>> r.width<br />
150<br />
As you can see, the size attribute is still subject <strong>to</strong> the calculations in getSize and setSize,<br />
but it looks just like a normal attribute.<br />
■Tip If your properties are behaving oddly, make sure your class subclasses object (either directly or<br />
indirectly—or by setting the metaclass directly). If it doesn’t, the getter part of the property will still work, but<br />
the setter part won’t. This can be a bit confusing.<br />
In fact, the property function may be called with zero, one, three, or four arguments as well.<br />
If called with no arguments, the resulting property is neither readable nor writable. If called with<br />
only one argument (a getter method), the property is readable only. The third (optional) argument<br />
is a method used <strong>to</strong> delete the attribute (it takes no arguments). The fourth (optional) argument<br />
is a documentation string. The parameters are called fget, fset, fdel, and doc—you can use them<br />
as keyword arguments if you want a property that, say, is only writable and has a docstring.<br />
Although this section has been short (a testament <strong>to</strong> the simplicity of the property function),<br />
it is very important. The moral is this: With new-style classes, you should use property<br />
rather than accessors.