Python内置函数getattr()的介绍及实例

getattr() 函数用于根据属性名称返回一个对象属性值。

其实getattr()这个方法最主要的作用是实现反射机制。也就是说可以通过字符串获取方法实例。这样,你就可以把一个类可能要调用的方法放在配置文件里,在需要的时候动态加载。

在python的官方文档中:getattr()的解释如下:

getattr(object, name[, default])
Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object's attributes, the result is the value of that attribute. For example, getattr(x, 'foobar') is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.

参数介绍:

  • object – 对象。
  • name – 字符串,对象属性。
  • default – 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。

返回值:返回对象属性值。

例如以下代码中,如果"name"是对对象属性的名称,则返回对应属性的值。

'# -*- coding: utf-8 -*-'
 
class attrtest(object):
 
  def __init__(self):
    pass
 
  def trygetattr0(self):
    self.name = 'beijing'
    print self.name
    #equals to self.name
    print getattr(self,'name')
 
  def attribute1(self,para1):
    print 'attribute1 called and '+ para1+' is passed in as a parameter'
 
  def trygetattr(self):
    fun = getattr(self,'attribute1')
    print type(fun)
    fun('crown')
 
if __name__=='__main__':
  test = attrtest()
  print 'getattr(self,\'name\') equals to self.name '
  test.trygetattr0()
  print 'attribute1 is indirectly called by fun()'
  test.trygetattr()
  print 'attrribute1 is directly called'
  test.attribute1('tomato')

这段代码执行的结果是:

getattr(self,'name') equals to self.name 
beijing
beijing
attribute1 is indirectly called by fun()
<type 'instancemethod'>
attribute1 called and crown is passed in as a parameter
attrribute1 is directly called
attribute1 called and tomato is passed in as a parameter
 
Process finished with exit code 0

第一个函数tryattribute0()非常好理解,就如同定义里说的一样。第二个函数tryattribute1()就有一点费解了。其实原理并不复杂,我们看到fun的type是 instancemethod,这里你可以认为:对于函数,getattr()的返回值是一个指针,指针赋值给接受它的变量,以后call这个变量就等于调用变量指向的函数。

原理我们知道了,那getattr的作用是什么呢?

你熟悉java或者c#中的反射么?反射的一个重要作用就是延迟加载,这样可以解耦,这样可以让系统运行的更有效率。作为动态语言,python显然在这方面要更加强大,

getattr()就是实现python反射的一块积木,结合其它方法如setattr(),dir() 等,我们可以做出很多有趣的事情。
我们看以下场景:

我需要在一个类中动态添加其它类中有的方法:

#如果类A中有如下方法:
def addnewattributesfromotherclass(self,class_name):
    func_names = dir(class_name)
    for func_name in func_names:
      if not func_name.startswith('_'):
        new_func = getattr(class_name,func_name)
        self.__setattr__(func_name,new_func())

我们只需要:

a = A()
b = B()
a.addnewattributesfromotherclass(b)

这样a就可以调用B中的’非私有’方法啦。

getattr() 与点语法的对比

对于以下代码,getattr(alex,'age') 和 alex.age都能获取alex对象的age属性的值,那我们使用后者不就行了吗?毕竟点语法看起来比getattr函数简单多了,不用写那么多字。确实,一般情况下,使用点语法来获取属性值非常方便。但是也存在一些场景,点语法无能为力,只好使用getattr函数来获取属性值。

究竟应该使用谁,关键就在于,编写代码的时候程序员是否能够确定要获取哪个属性的值。

如果我明确地知道,我就是想要获取age这个属性的值,那么alex.age就满足了我的需求。但是,试想如下的场景:

alex对象有name,age,job,weight,height五个属性,我们要根据用户的选择来展示相应的属性。也就是说,用户告诉程序“给我看看alex的身高吧!”,程序就要把height属性的值展示给用户看。

上面这个场景中,程序员写代码的时候无法确定要访问哪个属性值,选择权是交给用户的。而用户的输入是一个字符串"height",字符串在alex.height这样的点语法里并没有容身之处。这个需求用点语法不太合适了(如果非要用点语法,也不是不可以。比如,用一个字典把alex所有的属性值都存起来。键就是“height”这样的字符串,值就是alex.height这样的属性值。那么,就可以用“height"这样的字符串把对应的属性值取出来了。不过这个方法没有接下来要说到的getattr好。)这时候,用getattr就非常合适了。因为,getattr的第二个参数类型正是字符串!我们可以用getattr(alex,“height”)来取出身高的值。我们甚至还可以使用default参数很好地解决用户输入的属性不存在的问题。


示例代码如下:

from typing import NamedTuple
 
class Person(NamedTuple):
    '''人类'''
    name: str
    age: int
    job: str
    weight: float
    height: float
 
alex = Person('Alex', 32, 'actor', 60, 178)
 
# 把用户输入的字符串赋值给变量attribute_name
attribute_name = input('''What do you want to know about Alex? 
Enter an attribute name>>>''')
# 注意,上述字符串被传进了这个函数作为第二个参数
# 第三个参数是属性不存在时返回的字符串
print(getattr(alex,attribute_name, 'Sorry, this attribute does not exist.'))

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值