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

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

文章分类

全部博文(335)

文章存档

2016年(29)

2015年(18)

2014年(7)

2013年(86)

2012年(90)

2011年(105)

分类: Python/Ruby

2011-06-16 01:08:05

4.4. Getting Object References With getattr

通过getattr获得对象引用

You already know that Python functions are objects. What you don't know is that you can get a reference to a function without knowing its name until run-time, by using thegetattr function.

众所周知,Python函数是对象。但是你不知道的是,通过使用getattr函数,在程序未运行以前你就可以获得一个函数的引用,而不必知道函数的名字。

Example 4.10. Introducing getattr

L4.10 getattr 简介

4.10

  1. >>> li = ["Larry", "Curly"]
  2. >>> li.pop
  3. <built-in method pop of list object at 010DF884>
  4. >>> getattr(li, "pop")
  5. <built-in method pop of list object at 010DF884>
  6. >>> getattr(li, "append")("Moe")
  7. >>> li
  8. ["Larry", "Curly", "Moe"]
  9. >>> getattr({}, "clear")
  10. <built-in method clear of dictionary object at 00F113D4>
  11. >>> getattr((), "pop")
  12. Traceback (innermost last):
  13.   File "", line 1, in ?
  14. AttributeError: 'tuple' object has no attribute 'pop'

1

This gets a reference to the pop method of the list. Note that this is not calling the pop method; that would be li.pop(). This is the method itself.

获取列表pop方法的一个引用。注意:这不是调用Pop方法,调用列表方法是li.pop().这只是方法本身。

2

This also returns a reference to the pop method, but this time, the method name is specified as a string argument to the getattr function. getattr is an incredibly useful built-in function that returns any attribute of any object. In this case, the object is a list, and the attribute is the pop method.

同样返回pop方法的一个引用,但是这次,方法的名字是作为getattr函数的参数,通过字符串来说明。Getattr是一个十分有用的内置函数,它可以返回任意对象的任意属性。在本例中,对象是一个列表,而对应的属性是Pop方法。

3

In case it hasn't sunk in just how incredibly useful this is, try this: the return value of getattr is the method, which you can then call just as if you had saidli.append("Moe") directly. But you didn't call the function directly; you specified the function name as a string instead.

在本例中,并没有说明函数的功能有多么强大,只是在进行尝试:函数getattr的返回值是方法,这样你就可以如同平常直接调用li.append(“moe)那样,进行调用该函数。如果你不是直接调用函数,你可以将函数名用一个字符串来代替。

4

getattr also works on dictionaries.

Getattr 同样适用于字典。

5

In theory, getattr would work on tuples, except that tuples have no methods, so getattr will raise an exception no matter what attribute name you give.

理论上,getattr同样适用与tuple。但是tuple没有任何方法,不论属性名是什么,getattr都抛出异常。

4.4.1. getattr with Modules

4.4.1getattr 同模块

getattr isn't just for built-in datatypes. It also works on modules.

Getattr不仅适用于内置数据类型,它同样适用与模块。

Example 4.11. The getattr Function in apihelper.py

4.11 apihelper.py 中的getattr 函数

  1. >>> import odbchelper
  2. >>> odbchelper.buildConnectionString
  3. <function buildConnectionString at 00D18DD4>
  4. >>> getattr(odbchelper, "buildConnectionString")
  5. <function buildConnectionString at 00D18DD4>
  6. >>> object = odbchelper
  7. >>> method = "buildConnectionString"
  8. >>> getattr(object, method)
  9. <function buildConnectionString at 00D18DD4>
  10. >>> type(getattr(object, method))
  11. <type 'function'>
  12. >>> import types
  13. >>> type(getattr(object, method)) == types.FunctionType
  14. True
  15. >>> callable(getattr(object, method))
  16. True

1

This returns a reference to the buildConnectionString function in the odbchelper module, which you studied in Chapter 2, Your First Python Program. (The hex address you see is specific to my machine; your output will be different.)

这返回了一个odbchelper模块中对函数buildConnectionString的一个引用,我们在第二章研究过。(你看到的16进制的地址是相对于我的机器而言,不同的机器输出可能会不同。

2

Using getattr, you can get the same reference to the same function. In general, getattr(object, "attribute") is equivalent to object.attribute. If object is a module, thenattribute can be anything defined in the module: a function, class, or global variable.

通过使用getattr,对同一个函数你能获得相同的引用。通常getattr(object,’attribute’)object.attribute的效果是等价的。如果object是一个模块,那么attribute 可以使模块中定义的任何对象:函数,类,或是全局变量

3

And this is what you actually use in the info function. object is passed into the function as an argument; method is a string which is the name of a method or function.

这就是info函数的实际使用方法。对象作为一个参数传递给函数,方法是一个字符串,它是一个方法或是函数。

4

In this case, method is the name of a function, which you can prove by getting its type.

本例中函数的名字是方法,可以通过type来验证。

5

Since method is a function, it is callable.

既然方法是一个函数,因此它是可调用的。

4.4.2. getattr As a Dispatcher

4.4.2 getattr作为一个分发器(分配器)

A common usage pattern of getattr is as a dispatcher. For example, if you had a program that could output data in a variety of different formats, you could define separate functions for each output format and use a single dispatch function to call the right one.

Getattr的一个通常使用模式是作为一个分配器。比如你有一个程序,它能以不同的格式进行输出,你可以对每一种输出格式定义一个单独的函数,并使用一个单独的分发函数根据不同的输出调用不同的函数。

For example, let's imagine a program that prints site statistics in HTML, XML, and plain text formats. The choice of output format could be specified on the command line, or stored in a configuration file. A statsout module defines three functions, output_htmloutput_xml, and output_text. Then the main program defines a single output function, like this:

比如,我们来构造一个程序,它能用html,xml,普通的文本格式来打印网站统计数据。输出格式的选择可以通过命令行来说明,或是存放在一个配置文件中。Statsout模块定义了三个函数,out_html,out_xml,&out_text。接着主程序定义一个单独的输出函数,比如下面的这个:

Example 4.12. Creating a Dispatcher with getattr

4.12 使用getattr 创建分发器

 

  1. import statsout
  2.  
  3. def output(data, format="text"):
  4.     output_function = getattr(statsout, "output_%s" % format)
  5.     return output_function(data)

1

The output function takes one required argument, data, and one optional argument, format. If format is not specified, it defaults to text, and you will end up calling the plain text output function.

函数需要一个必须赋值的参数,data以及一个可选的参数,format.如果格式参数没有明确给出,默认值将是文本格式,最后调用文本格式化输出函数。

2

You concatenate the format argument with "output_" to produce a function name, and then go get that function from the statsout module. This allows you to easily extend the program later to support other output formats, without changing this dispatch function. Just add another function to statsout named, for instance, output_pdf, and pass "pdf" as the format into the output function.

你通过连接format参数和字符串’output_’来创建一个函数名字,然后再模块statout中调用该该函数。这使得你稍后在不需要修改分发器函数的前提下,更容易的扩展该程序来支持其它输出格式。你仅仅需要增加一个函数到statsout模块,比如output_pdf 并传递’pdf’作为format的值到输出函数。

3

Now you can simply call the output function in the same way as any other function. The output_function variable is a reference to the appropriate function from the statsoutmodule.

现在你就像调用其它函数一样来调用输出函数。输出函数变量是statsout模块中对应函数的一个引用。

Did you see the bug in the previous example? This is a very loose coupling of strings and functions, and there is no error checking. What happens if the user passes in a format that doesn't have a corresponding function defined in statsout? Well, getattr will return None, which will be assigned to output_function instead of a valid function, and the next line that attempts to call that function will crash and raise an exception. That's bad.

你看的出前面程序的漏洞么?字符串和函数的结合非常的松散,并且也没有错误检查。如果用户穿进去的格式没有对应的定义在模块statasout中,会发生什么呢?哦,getattr将会返回None,该值将赋给变量output_function,而不是一个合法值下一步尝试调用函数将会使程序崩溃并抛出异常。这是非常糟糕的。

Luckily, getattr takes an optional third argument, a default value.

幸运的是,getattr能接受一个可选参数,一个默认值

Example 4.13. getattr Default Values

4.13.函数getattr的默认值

 

  1. import statsout
  2.  
  3. def output(data, format="text"):
  4.     output_function = getattr(statsout, "output_%s" % format, statsout.output_text)
  5.     return output_function(data)

1

This function call is guaranteed to work, because you added a third argument to the call to getattr. The third argument is a default value that is returned if the attribute or method specified by the second argument wasn't found.

这次函数的调用是有保证的,因为当调用getattr是,增加了第三个参数。第三个参数是一个默认值,如果第二个参数所确定的方法或是属性不存在则返回默认值。

As you can see, getattr is quite powerful. It is the heart of introspection, and you'll see even more powerful examples of it in later chapters.

正如你所看到的,getattr是十分强大的,它是内省机制的核心。在稍后的章节,你将会看到更多功能强大的例子。

 

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