Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1792126
  • 博文数量: 335
  • 博客积分: 4690
  • 博客等级: 上校
  • 技术积分: 4341
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-08 21:38
个人简介

无聊之人--除了技术,还是技术,你懂得

文章分类

全部博文(335)

文章存档

2016年(29)

2015年(18)

2014年(7)

2013年(86)

2012年(90)

2011年(105)

分类: Python/Ruby

2011-08-05 18:14:17

5.6. Special Class Methods

In addition to normal class methods, there are a number of special methods that Python classes can define. Instead of being called directly by your code (like normal methods), special methods are called for you by Python in particular circumstances or when specific syntax is used.

除了通常的方法以外,Python还可以定义一定数量的特殊方法。这些方法不是直接被你的方法调用(比如通常的方法),这些特殊方法在特殊的环境下被Python调用或是在你使用特殊语法的时候被调用。

As you saw in the previous section, normal methods go a long way towards wrapping a dictionary in a class. But normal methods alone are not enough, because there are a lot of things you can do with dictionaries besides call methods on them. For starters, you can get and set items with a syntax that doesn't include explicitly invoking methods. This is where special class methods come in: they provide a way to map non-method-calling syntax into method calls.

正如你在前一节看到的一样,在类中为了包装一个字典使用了很多正常方法。但是仅有通常方法是不够的,这是因为对于字典对了调用字典的方法以外,你可以使用字典做更多的事情。对于初学者,你可以使用setget语法,该语法不必显示的调用方法。这就是特殊方法的来由:它提供了一种映射方法来讲一个非方法调用映射成方法调用。

5.6.1. Getting and Setting Items 5.61 获取和设置项目 Example 5.12. The __getitem__ Special Method 5.12  __getitem__方法。    
  1. def __getitem__(self, key): return self.data[key]
  2. >>> f = fileinfo.FileInfo("/music/_singles/kairo.mp3")
  3. >>> f
  4. {'name':'/music/_singles/kairo.mp3'}
  5. >>> f.__getitem__("name")
  6. '/music/_singles/kairo.mp3'
  7. >>> f["name"]
  8. '/music/_singles/kairo.mp3'

1

The __getitem__ special method looks simple enough. Like the normal methods clear, keys, and values, it just redirects to the dictionary to return its value. But how does it get called? Well, you can call __getitem__ directly, but in practice you wouldn't actually do that; I'm just doing it here to show you how it works. The right way to use__getitem__ is to get Python to call it for you.

__getitem__方法看起来很简单,同通常的方法clearKeyvalues,该方法重定向到字典的值。但是它是如何调用的?哦,你可以直接调用__getitem__,但是实际中你通常不会这么做;这里我只是展示它是如何工作的。正确的方法是使用__getitem__python来替你调用。

2

This looks just like the syntax you would use to get a dictionary value, and in fact it returns the value you would expect. But here's the missing link: under the covers,Python has converted this syntax to the method call f.__getitem__("name"). That's why __getitem__ is a special class method; not only can you call it yourself, you can getPython to call it for you by using the right syntax.

这种语法看起来你在使用一个字典值,但是实际上它确实返回了你所期望的值。但是这里缺少了联系:在转换的背后,Python将这种语法转换成了方法调用f.__getitem__(“name”)。这就是__getitem__为什么是一个特殊方法的原因,不仅你可以调用它,你也可以使用正确的语法让Python来调用它。

Of course, Python has a __setitem__ special method to go along with __getitem__, as shown in the next example.

当然,正如在下面例子中展示的一样,Python同时还有一个__setitem__方法同方法__getitem__相对应。

Example 5.13. The __setitem__ Special Method 5.13 __setitem__方法    
  1. def __setitem__(self, key, item): self.data[key] = item
  2. >>> f
  3. {'name':'/music/_singles/kairo.mp3'}
  4. >>> f.__setitem__("genre", 31)
  5. >>> f
  6. {'name':'/music/_singles/kairo.mp3', 'genre':31}
  7. >>> f["genre"] = 32
  8. >>> f
  9. {'name':'/music/_singles/kairo.mp3', 'genre':32}

1

Like the __getitem__ method, __setitem__ simply redirects to the real dictionary self.data to do its work. And like __getitem__, you wouldn't ordinarily call it directly like this; Python calls __setitem__ for you when you use the right syntax.

__getitem__类似,__setitem_简单的重定向到真正的起作用的字典self.data。同__getitem__一样,你不必像上面一样直接调用。当你在使用正确语法的时候,Python帮你进行调用

2

This looks like regular dictionary syntax, except of course that f is really a class that's trying very hard to masquerade as a dictionary, and __setitem__ is an essential part of that masquerade. This line of code actually calls f.__setitem__("genre", 32) under the covers

这种语法看起来很像字典的语法,除了本身的f是一个类,这个类尽量将自己伪装成一个类,而方法__setitem__则是成功伪装的一个核心部分。在伪装下面,调用代码行实际上市调用f.__setitem(“genre”,”32”)

__setitem__ is a special class method because it gets called for you, but it's still a class method. Just as easily as the __setitem__ method was defined in UserDict, you can redefine it in the descendant class to override the ancestor method. This allows you to define classes that act like dictionaries in some ways but define their own behavior above and beyond the built-in dictionary.

__setitem__是一个特殊的方法这是因为Python替你调用,但是他仍然是一个类方法。正如__setitem__方法定义在UserDict中的方法一样简单,你可以在后代类中重新定义该方法来覆盖祖先方法。这使得你可以按照某种方式定义功能类似字典的一个类,该类具有自己的行为同时超出字典的内置功能。

This concept is the basis of the entire framework you're studying in this chapter. Each file type can have a handler class that knows how to get metadata from a particular type of file. Once some attributes (like the file's name and location) are known, the handler class knows how to derive other attributes automatically. This is done by overriding the__setitem__ method, checking for particular keys, and adding additional processing when they are found.

这个概念是本章你正在研究框架的基础。每一个文件类型都有一个句柄类,该句柄类知道如何从一个特定的文件获取元数据。一旦某些属性(比如文件名称和位置)已知,句柄类就知道如何自动的推导出衍生属性。这可以通过重写__setitem__方法来实现,当发现时增加一个特殊的处理过程就行。

For example, MP3FileInfo is a descendant of FileInfo. When an MP3FileInfo's name is set, it doesn't just set the name key (like the ancestor FileInfo does); it also looks in the file itself for MP3 tags and populates a whole set of keys. The next example shows how this works.

比如MP#FileInfo就是FileInfo 的一个后代类。一旦一个MP3FileInfo的文件名被设置,__setiem__方法就设置键值(如同祖先类FileInfo一样);该方法同时还查找文件本身以便查找MP3标签以及产生整套键值。下面的例子演示它是如何工作的。

Example 5.14. Overriding __setitem__ in MP3FileInfo    
  1. def __setitem__(self, key, item):
  2.         if key == "name" and item:
  3.             self.__parse(item)
  4.         FileInfo.__setitem__(self, key, item)

1

Notice that this __setitem__ method is defined exactly the same way as the ancestor method. This is important, since Python will be calling the method for you, and it expects it to be defined with a certain number of arguments. (Technically speaking, the names of the arguments don't matter; only the number of arguments is important.)

值得注意的是,__setitem__方法的定义同祖先类完全相同。这是十分重要的,这是因为Python将替你调用,她期望该方法被定义成含有一定参数的方法。(从技术层面上讲,参数的名字无关紧要,参数的个数十分重要)

 

 

2

Here's the crux of the entire MP3FileInfo class: if you're assigning a value to the name key, you want to do something extra.

这个是一个MP3FileInfo类的难点所在:如果你给键name赋值,那也就意味着你还想做其它的事情。

 

 

3

The extra processing you do for names is encapsulated in the __parse method. This is another class method defined in MP3FileInfo, and when you call it, you qualify it with self. Just calling __parse would look for a normal function defined outside the class, which is not what you want. Calling self.__parse will look for a class method defined within the class. This isn't anything new; you reference data attributes the same way.

替你做的额外的处理过程就死将name包装到_parse方法中。这是另一个定义在MP3FileInfo类中的方法。当你调用它的时候,你使用self来限定它。对于一个定定义在类外部的方法_parse的调用将不是你想要的。对于一个类方法,对_parse方法的调用将会只在类内部查找。这里没有新的内容:你可以类似的参考data attribute.

 

 

4

After doing this extra processing, you want to call the ancestor method. Remember that this is never done for you in Python; you must do it manually. Note that you're calling the immediate ancestor, FileInfo, even though it doesn't have a __setitem__ method. That's okay, because Python will walk up the ancestor tree until it finds a class with the method you're calling, so this line of code will eventually find and call the __setitem__ defined in UserDict.

经过了额外的处理过程,你会调用祖先类方法。不过需要记住的是:在Python中这是不可能实现的;你必须手工的调用。值得注意的是你直接调用祖先类FileInfo,即使该类没有__setitem__方法。这样就没有问题,这是因为Python将会遍历祖先树知道在一个类中发现你所调用的方法,这样这行代码最终将会调用定义在Userdict中的__setitem__方法。

 

 

 

Note

 

 

When accessing data attributes within a class, you need to qualify the attribute name: self.attribute. When calling other methods within a class, you need to qualify the method name: self.method.

当你访问一个祖先类的数据属性时,你需要限定属性的名字:self.attribute。在一个类中调用其它方法时,你需要限定方法的名字:self.method

 

 

Example 5.15. Setting an MP3FileInfo's name 5.15 设置MP3FileInfo的名字
  1. >>> import fileinfo
  2. >>> mp3file = fileinfo.MP3FileInfo()
  3. >>> mp3file
  4. {'name':None}
  5. >>> mp3file["name"] = "/music/_singles/kairo.mp3"
  6. >>> mp3file
  7. {'album': 'Rave Mix', 'artist': '***DJ MARY-JANE***', 'genre': 31,
  8. 'title': 'KAIRO****THE BEST GOA', 'name': '/music/_singles/kairo.mp3',
  9. 'year': '2000', 'comment': ''}
  10. >>> mp3file["name"] = "/music/_singles/sidewinder.mp3"
  11. >>> mp3file
  12. {'album': '', 'artist': 'The Cynic Project', 'genre': 18, 'title': 'Sidewinder',
  13. 'name': '/music/_singles/sidewinder.mp3', 'year': '2000',
  14. 'comment': ''}

1

First, you create an instance of MP3FileInfo, without passing it a filename. (You can get away with this because the filename argument of the __init__ method is optional.) Since MP3FileInfo has no __init__ method of its own, Python walks up the ancestor tree and finds the __init__ method of FileInfo. This __init__ method manually calls the __init__ method of UserDict and then sets the name key to filename, which is None, since you didn't pass a filename. Thus, mp3file initially looks like a dictionary with one key, name, whose value is None.

首先你创建MP3FileINfo的一个实例,不传递文件名字。(你之说以可以这样做的原因是因为文件名字参数是可选的)。既然MP3FileInfo类没有自己的__init_方法,Python将会遍历祖先类来发现__init__方法。这个__init__方法自己手动的调用UserDict__init__方法,然后将键name的值设置为filename,值为None.因为你没有传递一个文件名,因此mp3fiel最初看起来像仅一个键值的字典,其值为None

2

Now the real fun begins. Setting the name key of mp3file triggers the __setitem__ method on MP3FileInfo (not UserDict), which notices that you're setting the name key with a real value and calls self.__parse. Although you haven't traced through the __parse method yet, you can see from the output that it sets several other keys: album, artist,genre, title, year, and comment.

现在开始真正的函数了:设置mp3file的键name,触发了__setitem__方法(不是UserDict),值得注意的是,你在使用一个真实的值来设键name,然后调用self._parse。尽管你没有追踪_parse方法,你可以从输出看出它设置了其他的键album,artist,genre,title,year,comment.

3

Modifying the name key will go through the same process again: Python calls __setitem__, which calls self.__parse, which sets all the other keys.

修改键name将会经历同样的过程:Python调用__setitem__,这将调用self._parse来设置其它的键值。

 

阅读(745) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~