Files
Cloud-book/Python/Python面向对象/反射与双下方法.md
2025-08-27 17:10:05 +08:00

6.9 KiB
Raw Blame History

反射

Python 中反射Reflection是一种能力使得程序能够在运行时查看和修改自身的结构和行为。通过反射您可以动态地访问和操作类的属性和方法而无需在编写代码时确定它们的确切名称。这在某些情况下非常有用例如在框架、库或插件系统中。

对对象的反射

class Foo:
    f = "类的静态变量"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_hi(self):
        print("Hi %s" % self.name)


obj = Foo("EaglesLab", 18)

# 检测是否含有某属性
print(hasattr(obj, "name"))
print(hasattr(obj, "say_hi"))

# 获取属性
print(getattr(obj, "name"))
func = getattr(obj, "say_hi")
func()

print(getattr(obj, "job", "不存在啊"))  # 报错


# 设置属性
setattr(obj, "job", "teacher")
setattr(obj, "show_name", lambda self: self.name + " 真帅")
print(obj.__dict__)
print(obj.show_name(obj))

# 删除属性
delattr(obj, "age")
delattr(obj, "show_name")
# delattr(obj,'show_name111') # 不存在,则报错
print(obj.__dict__)

对类的反射

class Foo(object):
    staticField = "test"

    def __init__(self):
        self.name = "陈松"

    def func(self):
        return "func"

    @staticmethod
    def bar():
        return "bar"


print(getattr(Foo, "staticField"))
print(getattr(Foo, "func"))
print(getattr(Foo, "bar"))

案例:基于反射的用户管理

使用反射前

class User:
    def login(self):
        print('欢迎来到登录页面')

    def register(self):
        print('欢迎来到注册页面')

    def save(self):
        print('欢迎来到存储页面')

user = User()
while 1:
    choose = input('>>>').strip()
    if choose == 'login':
        user.login()

    elif choose == 'register':
        user.register()

    elif choose == 'save':
        user.save()

用了反射之后

class User:
    def login(self):
        print('欢迎来到登录页面')

    def register(self):
        print('欢迎来到注册页面')

    def save(self):
        print('欢迎来到存储页面')

user = User()
while 1:
    choose = input('>>>').strip()
    if hasattr(user, choose):
        func = getattr(user, choose)
        func()
    else:
        print('输入错误...')

函数 vs 方法

通过打印函数(方法)名确定

def func():
    pass

print(func)

class A:
    def func(self):
        pass

print(A.func)
obj = A()
print(obj.func)

通过 types 模块验证

from types import FunctionType
from types import MethodType

def func():
    pass

class A:
    def func(self):
        pass

obj = A()

print(isinstance(func,FunctionType))
print(isinstance(A.func,FunctionType))
print(isinstance(obj.func,FunctionType))
print(isinstance(obj.func,MethodType))

静态方法是函数

from types import FunctionType
from types import MethodType


class A:

    def func(self):
        pass

    @classmethod
    def func1(self):
        pass

    @staticmethod
    def func2(self):
        pass


obj = A()

# 静态方法其实是函数
print(isinstance(A.func2,FunctionType))
print(isinstance(obj.func2,FunctionType))

函数与方法的区别

那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。

  1. 函数的是显式传递数据的。如我们要指明为len()函数传递一些要处理数据。
  2. 函数则跟对象无关。
  3. 方法中的数据则是隐式传递的。
  4. 方法可以操作类内部的数据。
  5. 方法跟对象是关联的。如我们在用 strip() 方法是,是不是都是要通过 str 对象调用,比如我们有字符串 s,然后 s.strip() 这样调用。是的strip()方法属于str对象。

我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。

在其他语言中,如 Java 中只有方法C 中只有函数C++ 则取决于是否在类中。

双下方法

__init__

用于初始化类的实例,接收参数并设置实例属性。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

__len__

class B:
    def __len__(self):
        return 666

b = B()
print(len(b)) # len一个对象就会触发 __len__方法。

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))

__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))

__str__

如果一个类中定义了 __str__ 方法,那么在 print(obj) 时,默认输出该方法的返回值。

class A:
    def __init__(self):
        pass
    def __str__(self):
        return '陈松'
a = A()
print(a)
print('%s' % a)

__repr__

如果一个类中定义了 __repr__ 方法,那么在 repr(obj) 时,默认输出该方法的返回值。

class A:
    def __init__(self):
        pass
    def __repr__(self):
        return '陈松'
a = A()
print(repr(a))
print('%r'%a)

__call__

通过 obj() 触发执行。

class Foo:

    def __init__(self):
        print('__init__')

    def __call__(self, *args, **kwargs):
        print('__call__')


obj = Foo()  # 执行 __init__
obj()  # 执行 __call__

__eq__

通过 == 触发类中的 __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)

__del__

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

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

__new__

在 Python 中,__new__ 是一个控制对象创建过程的魔术方法,它比 __init__ 更早执行。

  • 优先级:__new__ 是对象创建的第一步,负责生成实例;__init__ 是第二步,负责初始化实例。
  • 返回值:__new__ 必须返回实例对象(否则 __init__ 不会执行),而 __init__ 无返回值。
  • 静态方法:__new__ 隐式作为静态方法存在,第一个参数是类本身 cls,而非实例 self
  • ​​继承链​​:若未重写 __new__Python 会沿继承链调用父类的 __new__,直至 object.__new__
class A:
    def __new__(cls, *args, **kwargs):
        print("in new function")
        return object.__new__(A, *args, **kwargs)   # 调用父类的 __new__ 创建实例并返回实例

    def __init__(self):
        self.x = 1
        print("in init function")


a = A()
print(a.x)