面向对象,内建函数getattr工厂模式

getattr()这个方法最主要的作用是实现反射机制。也就是说可以通过字符串获取方法实例。  传入不同的字符串,调用的方法不一样。

Python中用字符串调用函数或方法示例代码,python示例代码

前言

本文主要给大家介绍了关于Python用字符串调用函数或方法的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍:

先看一个例子:

>>> def foo():
    print "foo"

>>> def bar():
    print "bar"

>>> func_list = ["foo","bar"]
>>> for func in func_list:
    func()
TypeError: 'str' object is not callable

我们希望遍历执行列表中的函数,但是从列表中获得的函数名是字符串,所以会提示类型错误,字符串对象是不可以调用的。如果我们想要字符串变成可调用的对象呢?或是想通过变量调用模块的属性和类的属性呢?

以下有三种方法可以实现。

eval()

>>> for func in func_list:
    eval(func)()
foo
bar

eval() 通常用来执行一个字符串表达式,并返回表达式的值。在这里它将字符串转换成对应的函数。eval() 功能强大但是比较危险(eval is evil),不建议使用。

locals()和globals()

>>> for func in func_list:
    locals()[func]()
foo
bar

>>> for func in func_list:
    globals()[func]()
foo
bar

locals() 和 globals() 是python的两个内置函数,通过它们可以一字典的方式访问局部和全局变量。

getattr()

getattr() 是 python 的内建函数,getattr(object,name) 就相当于 object.name,但是这里 name 可以为变量。

返回 foo 模块的 bar 方法

>>> import foo
>>> getattr(foo, 'bar')() 

返回 Foo 类的属性

>>> class Foo:
  def do_foo(self):
    ...

  def do_bar(self):
    ...

>>> f = getattr(foo_instance, 'do_'   opname)
>>> f()

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对帮客之家的支持。

参考

Calling a function of a module from a string with the function's name in Python

How do I use strings to call functions/methods?

前言 本文主要给大家介绍了关于Python用字符串调用函数或方法的相关内容,分享...

反射

  • 反射:
    1. 通过字符串的形式导入模块
    2. 通过字符串的形式去模块中寻找制定的成员(属性、函数),并使用
# 1.创建index.py主程序
# 2.创建commoms模块提供函数
# 3.引入commons模块调用模块中的函数

# commoms.py
def f1():
    print('F1')
    return 'F1'

# index.py
import commons
if __name__ == '__main__':
    ret = commons.f1()
    print(ret) # F1
  • 上面的函数是正常导入并执行,如果想导入用户输入的模块名,并调用用户输入的函数,则:
# index.py
if __name__ == '__main__':
    module = input('请输入模块名:')
    mod = __import__(module)
    # ret = mod.f1() # 正常调用
    # print(ret) # 正常输出
    attr = input('请输入方法名:')
    meth = getattr(mod,attr)
    ret = meth()
    print(ret)
  • 上面的函数相当于调用了2个函数

    • __import__():通过字符串导入模块对象
    • getattr(module,attr):获取模块里的元素
  • 其实getattr()函数才叫反射,通过字符串的形式在模块中寻找相应的元素,如果元素不存在,则报错.

  • 可以通过给getattr(module,arrtib,def)设置默认值,防止报错

  • 反射函数

    • getattr():获取属性
    • delattr():删除属性
    • hasattr():判断实行是否存在
    • setattr():添加或修改属性
  • python中,一切皆对象,通过反射,根据字符串去对象中(模块,类)获取元素

  • 扩展

    • 通过__import__()导入的模块如果存在的路径为:libmodulesmoudle.py
    • 如果导入的方式为:__import__('lib.modules.moudle'),则导入的为lib文件夹
    • 如果想解决这个问题,导入的方式为:__import__('lib.modules.moudle', fromlist=True)

问题聚焦:

原型:getattr(对象,方法名)

基于反射模拟web框架路由系统

  • 根据用户发送不同的url,服务器执行不同的操作,返回不同的结果
  • 原始操作:
    1. 截取url最后的字段,如login,logout,pay等
    2. 通过if,elif,else判断字段,然后执行模块里面的方法
  • 优化:
    1. 如果网站很大,有成百上千个方法,都要if,elif,else来判断,则需要写大量的判断代码
    2. 通过反射来获取相应的方法,然后调用,则可以不用修改index.py方法,只需要在模块里面添加响应的方法,让url中的字段去匹配
  • 完善:
    1. 但是如果网站太大了,所有的方法都写在一个模块里面,维护起来会很麻烦,同时反射获取方法需要更长的时间
    2. 通过分模块来管理不同功能的方法,在url中把模块和方法名都加上,切割后通过__import__(path, fromlist = True)来导入模块,通过反射获取方法
# 1.创建主程序index.py
# 2.创建功能模块
# 3.截取url,获取里面的地址参数执行不同的方法

# url = input("请输入url:")
url = 'www.yuhhcompany.com/account/login'
regex = 'www.yuhhcompany.com'
ret = re.match(regex, url)
if ret != None:
    # 匹配成功
    host, module, method = url.split('/')
    mod = __import__(module, fromlist=True)
    if hasattr(mod, method):
        ret = getattr(mod, method)()
  • 所有的web框架:php,c#,java,Django本质都是这个道理

熟悉getattr的应该知道,getattr(a, 'b')的作用就和a.b是一样的

那么这个内建函数有什么作用呢,最方便的无疑是使用它来实现工厂方法(Factory Method)模式

另外,在回调函数里也经常使用这个函数,对回调理解不深,这里不再举例

 

面向对象

  • 编程语言:

    • java、c#只能通过面向对象编程
    • Python可以通过函数式编程,也可以通过面向对象编程
  • Python面向对象:

    • class:创建类关键字
    • 定义的函数,在函数式编程时称函数,面向对象编程称为方法
    • 方法参数self:每个方法都需要加上self参数,值为调用该方法的对象,点用方法时python会自动传入该参数,不需要自己传
    class Cat:
        def fun1(self):
            pass
        def fun2(self):
            pass
    
    cat1 = Cat()
    cat1.fun1()
    cat1.fun2()
    
  • 方法的参数self:

    • self代表调用方法的对象,不需要自己传入,当调用方法时,python自动帮我们传入该self参数
    class Cat:
        def fun1(self):
            print(self)
    cat1 = Cat()
    print(cat1) # <__main__.Cat object at 0x10073fc50>
    cat1.fun1() # <__main__.Cat object at 0x10073fc50>
    
    • 封装:

      • 如果一个类中多个方法需要用到同一个参数,每次都穿的话,太麻烦
      class Cat:
          def fun1(self, name, age):
              print(name, age)
          def fun2(self, name, age):
              print(name, age)
          def fun3(self, name, age):
              print(name, age)
      
      cat1 = Cat()
      cat1.fun1('yhh', 23)
      cat1.fun2('yhh', 23)
      cat1.fun3('yhh', 23)
      
      • 可以将重复的变量作为对象的属性:
        • 把参数赋值给对象,在方法中调用--封装
      class Cat:
          def fun1(self):
              print(self.name, self.age)
          def fun2(self):
              print(self.name, self.age)
          def fun3(self):
              print(self.name, self.age)
      
      cat1 = Cat()
      cat1.name = 'yhh'
      cat1.age = 23
      cat1.fun1()
      cat1.fun2()
      cat1.fun3()
      
      • 封装使用场景:

        • 连接操作数据库,对数据库的操作(curd)都需要用到ip,port,user,password,content等,如果每个方法都传ip,port,user,passowrd,这样方法的参数重复且调用的时候很麻烦,如果把它们都封装到对象里,直接在对象里调用,这样重复的参数只需要穿一遍即可.
      • 封装步骤

        • 上面的封装过程不够好,因为如果别人看你的代码,别人不一定知道调用方法前需要封装数据,可以优化为:
        • 创建对象时会调用构造方法__init__(),对象销毁的时候会调用__del__()方法(析构方法)
      class Cat:
          def __init__(self, name, age):
              self.name = name
              self.age = age
          def fun1(self):
              print(self.name, self.age)
          def fun2(self):
              print(self.name, self.age)
          def fun3(self):
              print(self.name, self.age)
      
    • 对象序列化

      • 在python中,对象可以通过pickle序列化,然后在本地持久化,可以用来存档
      • 不能用json,因为json只能转成python的基本类型,自定义类不属于基本类型
      import pickle
      
      # 存档
      with open('object.pickle', mode='wb') as file:
          pickle.dump(cat1,file)
      
      # 读档
      with open('object.pickle', mode='rb') as file:
          cat1 = pickle.load(file)
          cat1.fun1() # YHH 23
      
    • 继承

      • python中继承是需要在子类的类名后跟上:(父类类名)
      • 父类--子类
      • 基类--派生类
      • 派生类和父类有相同的方法时,以派生类为主
      class Father:
          def fun1(self):
              print('Father')
      
      class Son(Father):
          def fun2(self):
              print('Son')
      
      son = Son()
      son.fun1()  # Father
      son.fun2()  # Son
      
    • 多继承

      • java、c#只支持单继承
      • python可以多继承
      • 如果A继承B和C,B和C都有相同的方法,则以继承时写在左边的为主,如果A也有这个方法,则以A为主
    • 多继承面试题:

    在pytho3.5中:
    # 如果继承关系
    class E(C,D):
        pass
    # A --> C --> E
    # B --> D --> E
    # E继承CD,C继承A,D即成B
    # 则调用的顺序为:E --> C --> A --> D --> B(顶层没有同一个基类)
    
    # 如果A和B同时又继承BASE基类,则调用顺序为:
    E --> C --> A --> D --> B --> BASE(顶层有同一个基类)
    python2.7不一样
    
    • 多态

      • python本身语言特性就支持多态,像java,c#等因为是强类型语言,比较复杂
      lass Cat():
          def fun1(self):
              print('fun1')
      
      class Dog():
          def fun1(self):
              print('fun1')
      
      def function(animal):
          animal.fun1()
      
      function(Cat())
      function(Dog())
      
      • 其他语言有重载,python不支持
    • 接口

      • python语言没有接口一说
      • 接口类型:
        • 代码级别:interface
        • 业务级别:访问后台的地址

先看一下官方文档:

举个栗子:

getattr(object, name[, default])

pyMethod类下定义了三个方法,getattr(pyMethod(),'out%s'%str)()   传入的方法名不同,调用不同的方法。些处方法名为字符串。

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, defaultis returned if provided, otherwise AttributeError is raised.

这样的话,想想是不是用途很多,我可以把方法名配置到文件中,读取时使用getattr动态去调用。

参数说明:

#coding=utf-8

class pyMethod(object):
    def outstr(self):
        print('this is string')

    def outint(self):
        print('this is number')

    def outdate(self):
        print('this is date')


if __name__=="__main__":
    str = 'int'
    getattr(pyMethod(),'out%s'%str)()     
    str = 'str'
    getattr(pyMethod(),'out%s'%str)()
    str = 'date'
    getattr(pyMethod(),'out%s'%str)()

 

try:
    func = getattr(obj, "method")
except AttributeError:
    ...... deal
else:
    result = func(args)

// 或指定默认返回值
func = getattr(obj, "method", None)
if func:
    func(args)
 getattr(pyMethod(),'out%s'%str)()  注意pyMethod()和最后的()   这里之所以这么写pyMethod()加括号是实例化类对象,最后的括号,因为getattr函数反射后,是一个方法对象。

TypeError: 不可调用

 

func = getattr(obj, "method", None)
if callable(func):
    func(args)

运行结果:

用getattr实现工厂方法:

C:Python27python.exe D:/weixin/python_getattr.py
this is number
this is string
this is date

Process finished with exit code 0

Demo:一个模块支持html、text、xml等格式的打印,根据传入的formate参数的不同,调用不同的函数实现几种格式的输出

 

import statsout 
def output(data, format="text"):                           
    output_function = getattr(statsout, "output_%s" %format) 
    return output_function(data)

Linux and python学习交流1,2群已满.

这个例子中可以根据传入output函数的format参数的不同 去调用statsout模块不同的方法(用格式化字符串实现output_%s)

Linux and python学习交流3群新开,欢迎加入,一起学习.qq 3群:563227894

参考资料:

不前进,不倒退,停止的状态是没有的.

Python找那个的getattr()函数详解

一起进步,与君共勉,

python2.7文档

熟悉getattr的应该知道,getattr(a, 'b')的作用就和a.b是一样的 那么这个内建函数有什么作用呢,最方便的无疑是使用它来实现工厂...

本文由星彩网app下载发布于计算机编程,转载请注明出处:面向对象,内建函数getattr工厂模式

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。