Learning Python - Mark Lutz [505]
To read files encoded in a different encoding than the default for your platform, simply pass the name of the file’s encoding to the open built-in in 3.0 (codecs.open() in 2.6); data will be decoded per the specified encoding when it is read from the file. You can also read in binary mode and manually decode the bytes to a string by giving an encoding name, but this involves extra work and is somewhat error-prone for multibyte characters (you may accidentally read a partial character sequence).
To create a Unicode text file in a specific encoding format, pass the desired encoding name to open in 3.0 (codecs.open() in 2.6); strings will be encoded per the desired encoding when they are written to the file. You can also manually encode a string to bytes and write it in binary mode, but this is usually extra work.
ASCII text is considered to be a kind of Unicode text, because its 7-bit range of values is a subset of most Unicode encodings. For example, valid ASCII text is also valid Latin-1 text (Latin-1 simply assigns the remaining possible values in an 8-bit byte to additional characters) and valid UTF-8 text (UTF-8 defines a variable-byte scheme for representing more characters, but ASCII characters are still represented with the same codes, in a single byte).
The impact of Python 3.0’s string types change depends upon the types of strings you use. For scripts that use simple ASCII text, there is probably no impact at all: the str string type works the same in 2.6 and 3.0 in this case. Moreover, although string-related tools in the standard library such as re, struct, pickle, and xml may technically use different types in 3.0 than in 2.6, the changes are largely irrelevant to most programs because 3.0’s str and bytes and 2.6’s str support almost identical interfaces. If you process Unicode data, the toolset you need has simply moved from 2.6’s unicode and codecs.open() to 3.0’s str and open. If you deal with binary data files, you’ll need to deal with content as bytes objects; since they have a similar interface to 2.6 strings, though, the impact should again be minimal.
Chapter 37. Managed Attributes
This chapter expands on the attribute interception techniques introduced earlier, introduces another, and employs them in a handful of larger examples. Like everything in this part of the book, this chapter is classified as an advanced topic and optional reading, because most applications programmers don’t need to care about the material discussed here—they can fetch and set attributes on objects without concern for attribute implementations. Especially for tools builders, though, managing attribute access can be an important part of flexible APIs.
Why Manage Attributes?
Object attributes are central to most Python programs—they are where we often store information about the entities our scripts process. Normally, attributes are simply names for objects; a person’s name attribute, for example, might be a simple string, fetched and set with basic attribute syntax:
person.name # Fetch attribute value
person.name = value # Change attribute value
In most cases, the attribute lives in the object itself, or is inherited from a class from which it derives. That basic model suffices for most programs you will write in your Python career.
Sometimes, though, more flexibility is required. Suppose you’ve written a program to use a name attribute directly, but then your requirements change—for example, you decide that names should be validated with logic when set or mutated in some way when fetched. It’s straightforward to code