• Python反射和内置方法(双下方法)


    Python反射和内置方法(双下方法)

    一、反射

    1. 什么是反射

      反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

    2. Python面向对象中的反射

      通过字符串的形式操作对象相关的属性。Python中的一切事物都是对象(都可以使用反射)

      四个可以实现自省的函数:

      1. hasattr():检测是否含有某属性

        class Foo:
            def __init__(self, name, age):
                self.name = name
                self.age = age
        
            def func(self):
                pass
        
        # 检测是否含有某属性
        print(hasattr(Foo, "func"))		# True
        f = Foo("dogfa", 18)
        print(hasattr(f, "name"))		# True
        print(hasattr(f, "gender"))		# False
        
      2. getattr():获取属性

        class Foo:
            def __init__(self, name, age):
                self.name = name
                self.age = age
        
            def func(self):
                pass
        
            @staticmethod
            def staticfunc():
                print("嘿嘿嘿")
        
        # 获取属性
        f = getattr(Foo, "staticfunc")
        print(f)	# <function Foo.staticfunc at 0x0000028DD8EB9D08>
        f()		    # 嘿嘿嘿
        
        # 如果要获取的属性不存在那么就会报错
        f2 = getattr(Foo, "func1")	# AttributeError: type object 'Foo' has no attribute 'func1'
        
      3. setattr():设置属性

        class Foo:
            def __init__(self, name, age):
                self.name = name
                self.age = age
        
            def func(self):
                pass
        
            @staticmethod
            def staticfunc():
                print("嘿嘿嘿")
        
        
        f = Foo("dogfa", 18)
        print(f.__dict__)		# {'name': 'dogfa', 'age': 18}
        setattr(f, "name", f.name + "sb")
        print(f.__dict__)		# {'name': 'dogfa_sb', 'age': 18}
        
      4. defattr():删除属性

        class Foo:
            def __init__(self, name, age):
                self.name = name
                self.age = age
        
            def func(self):
                pass
        
            @staticmethod
            def staticfunc():
                print("嘿嘿嘿")
        
        f = Foo("dogfa", 18)
        print(f.__dict__)		# {'name': 'dogfa', 'age': 18}
        delattr(f, "name")
        print(f.__dict__)		# {'age': 18}
        
        # delattr(f, "gender")	# 删除不存在的属性时会报错
        
    3. 使用反射的场景

      1. 对对象的反射
      2. 对类的反射
      3. 其它模块的反射
      4. 当前模块的反射

    二、内置方法

    1. 函数与方法的区别

      在说方法之前我们先来说一下在Python中函数和方法的区别。

      # 通过导入types模块来验证
      from types import FunctionType, MethodType
      
      def func():
          pass
      
      class A:
          def func(self):
              pass
      
          @staticmethod
          def func2():
              pass
      
      obj = A()
      
      # FunctionType:函数	MethodType:方法
      print(isinstance(func, FunctionType))		# True
      print(isinstance(A.func, FunctionType))		# True
      print(isinstance(obj.func, FunctionType))	# False
      print(isinstance(obj.func, MethodType))		# True
      print(isinstance(A.func2, FunctionType))	# True
      print(isinstance(obj.func2, FunctionType))	# True
      
      
      
      # 通过打印函数(方法)名验证
      from types import FunctionType, MethodType
      def func():
          pass
      
      class A:
          def func(self):
              pass
      
          @staticmethod
          def func2():
              pass
      
      obj = A()
      
      print(func)		# <function func at 0x000002013BC32E18>
      print(A.func)	# <function A.func at 0x000002013BF6A598>
      print(obj.func)	# <bound method A.func of <__main__.A object at 0x000002013BDF7DD8>>
      

      总结:

      (1)函数的是显式传递数据的。如我们要指明为len()函数传递一些要处理数据。

      (2)函数则跟对象无关。

      (3)方法中的数据则是隐式传递的。

      (4)方法可以操作类内部的数据。

      (5)方法跟对象是关联的。如我们在用strip()方法时,都是要通过str对象调用,比如我们有字符串s,然后s.strip()这样调用。是的,strip()方法属于str对象。

      (6)静态方法就是函数

    2. 内置方法(双下方法)

      定义:双下方法是特殊方法,他是解释器提供的 由爽下划线加方法名加双下划线 __方法名__的具有特殊意义的方法,双下方法主要是Python源码程序员使用的,我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。

      调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:__init__

      1. item系列

        class Foo:
            def __init__(self, name, age):
                self.name = name
                self.age = age
        
            def __getitem__(self, item):
                print("执行obj['key']时会执行我")
                return getattr(self, item)
        
            def __setitem__(self, key, value):
                print("执行obj['key'] = value 时会执行我")
                setattr(self, key, value)
        
            def __delitem__(self, key):
                print("执行del['key']时会执行我")
                delattr(self,  key)
        
        obj = Foo("oldwang", 20)
        print(obj["name"])
        # 执行obj['key']时会执行我
        # oldwang
        
        obj["name"] = "oldniu"
        print(obj["name"])
        # 执行obj['key'] = value 时会执行我
        # 执行obj['key']时会执行我
        # oldniu
        
        print(obj.__dict__)
        del obj["name"]
        print(obj.__dict__)
        # {'name': 'oldniu', 'age': 20}
        # 执行del['key']时会执行我
        # {'age': 20}
        
      2. __del__

        析构方法,当对象在内存中被释放时,自动触发执行。

        注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

        class FileHandle:
            def __init__(self, file_path):
                self.f = open(file_path, mode="r", encoding="utf-8")
        
            def read(self):
                return self.f.read(1024)
        
            def __del__(self):
                # 在程序执行完时释放文件句柄
                self.f.close()
        
        f = FileHandle("file/userinfo")
        print(f.read())
        
      3. __new__

        # 单例类
        class Single:
            __isinstance = None
        
            def __new__(cls, *args, **kwargs):
                if not cls.__isinstance:
                    cls.__isinstance = object.__new__(cls)
                    return cls.__isinstance
                return cls.__isinstance
        
        one = Single()
        two = Single()
        print(one is two)	# True
        
      4. __call__

        对象后面加括号,触发执行。

        注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

        class Foo:
            def __call__(self, *args, **kwargs):
                print("执行__call__")
        
        f = Foo()
        f()			# 执行__call__
        
        # 还可以这样写
        Foo()()
        
      5. __len__

        class Foo:
            def __init__(self, name, age):
                self.name = name
                self.age =age
        
            def __len__(self):
                return len(self.__dict__)
        
        f = Foo("dogfa", 18)
        print(len(f))	# 2
        
      6. __hash__

        class A:
            def __init__(self):
                self.a = 1
                self.b = 2
        
            def __hash__(self):
                return hash(str(self.a)+str(self.b))
        a = A()
        print(hash(a))
        
      7. __eq__

        class A:
            def __init__(self):
                self.a = 1
                self.b = 2
        
            def __eq__(self,obj):
                if  self.a == obj.a and self.b == obj.b:
                    return True
        a = A()
        b = A()
        print(a == b)	# True
        

    三、其它

    # 有一个员工类,1000个员工对象,对象属性有姓名,性别,年龄,部门,
    # 按姓名,性别对1000个对象去重
    class Employee:
    	def __init__(self, name, age, gender, department):
    		self.name = name
    		self.age = age
    		self.gender = gender
    		self.department = department
    		
    	def __hash__(self):
    		return hash("{0}{1}".format(self.name, self.gender))
    		
    	def __eq__(self, other):
    		if self.name == other.name and self.gender == other.gender:
    			return True
    			
    employee_list = []
    
    for i in range(250):
    	employee_list.append(Employee("dogfa", i, "male", "python" + str(i)))
    	
    for i in range(250):
    	employee_list.append(Employee("djb", i, "female", "php" + str(i)))
    	
    for i in range(250):
    	employee_list.append(Employee("oldniu", i, "male", "java" + str(i)))
    	
    for i in range(250):
    	employee_list.append(Employee("cdj", i, "female", "go" + str(i)))
    	
    for employee_obj in set(employee_list):
    	print(employee_obj.__dict__)
    
  • 相关阅读:
    /etc/nginx/nginx.conf配置文件详解
    kvm之十二:虚拟机迁移
    KVM之十一:调整cpu和内存
    KVM之十:虚拟机在线添加网卡
    KVM之八:快照创建、恢复与删除
    KVM之七:KVM克隆
    kvm之六:配置kvm虚拟机通过VNC访问
    前端自定义 上传文件
    django 实现 导航栏的变化
    python操作腾讯对象存储 cos
  • 原文地址:https://www.cnblogs.com/wangyueping/p/11111899.html
Copyright © 2020-2023  润新知