面向对象之双下方法,内置函数

一. 内置函数

1.1 isinstance(obj, cls)

# 检验 obj 是否是类 cls 的对象
    class Person(object):
        pass

    obj = Person()
    print(isinstance(obj, Person))       # True

1.2 issubclass(sub, super)

# 检查 sub 类是否是 super 类的派生类
class Person(object):
    pass

class Student(Person):
    pass

class Teacher:
    pass

obj = Person()
print(issubclass(Student, Person))
print(issubclass(Teacher, Person))

二.双下方法

2.1 __ new __

1. 对对象进行创建的操作,即对象创建完之前执行。

2. __new__必须要有返回值,返回实例化出来的实例,

class Student(object):
    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, *args, **kwargs)

2.2 __ init __

1. 对对象进行初始化操作, 比如添加属性。即在对象创建之后执行。

class Student:
    def __init__(self):
        print(self)

stu = Student()                           # <__main__.Student object at 0x000001BD930F8C10>

2.3 __ str __

1. 对象被执行打印(print、前端展示)操作的时候自动触发, 该方法必须返回字符串类型的数据

class Student:
    def __str__(self):
        return '打印对象了'

stu = Student()
print(stu)                               # 打印对象了

2.4 __ del __

1. 对象被执行(被动、主动)删除操作之后自动执行

class Student:
    def __del__(self):
        print('对象被删除了')

stu = Student()
print('----------------------')         # ----------------------
                                        # 对象被删除了     """程序正常运行结束 被动删除"""

2.5 __ getattr __

1. 对象查找不存在属性的时候自动触发 >>> 句点符 点不出对应属性

class Student:

    def __getattr__(self, item):
        print(f"我没有{item}这个属性")

obj = Student()
obj.name                                # 我没有name这个属性

2.6 __ setattr __

1. 对象在执行添加属性操作的时候自动触发 >>> obj.变量名=变量值

class Student:

    def __setattr__(self, key, value):
        print(f'你设置了一个属性为{key}, 值为{value}')

obj = Student()
obj.name = "孙悟空"                     # 你设置了一个属性为name, 值为孙悟空

2.7 __ call __

1. 对象被加括号调用的时候自动触发

class Student:

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

obj = Student()
obj("张三", 18, happy="看国漫")         # ('张三', 18)
                                       # {'happy': '看国漫'}

2.8 __ enter __, __ exit __

__ enter __

1. 对象被执行 with 上下文管理语法开始自动触发

2. 该方法返回什么 as 后面的变量名就会得到什么

__ exit __

1. 对象被执行 with 上下文管理语法结束之后自动触发

class Student:

    def __enter__(self):
        print('对象被执行with上下文管理语法自动触发')
        return "我是 __enter__ 还回的结果"

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('我是 __exit__ 打印的结果')
        pass

obj = Student()
with Student() as f:
    print('123')
    print(f)

"""执行结果如下"""

对象被执行with上下文管理语法自动触发
123
我是 __enter__ 还回的结果
我是 __exit__ 打印的结果

2.9 __ getattribute __

只要对象查找名字无论名字是否存在都会执行该方法

如果类中有__getattribute__方法 那么就不会去执行__getattr__方法

class Student(object):
    happy = "篮球"                                    # 类属性不会放到对象的__dict__中

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

    def __getattribute__(self, item):                # 注意:attr是传入的属性名,不是属性值
        print("执行了__getattribute__方法")
        print(item)
        if item == "name":
            print("调用了name属性")
        elif item == "age":
            print("调用了age属性")
        else:
            print("调用了其他属性")

        return object.__getattribute__(self, item)    # 返回属性名


obj = Student("孙悟空", 28)
print(obj.name)
print(obj.age)
print(obj.happy)

"""执行结果如下"""

执行了__getattribute__方法
name
调用了name属性
孙悟空

执行了__getattribute__方法
age
调用了age属性
28

执行了__getattribute__方法
happy
调用了其他属性
篮球

以下是针对每个魔法方法的小案例,用于展示它们的基本用法:

对象创建和初始化

class CustomObject:
    def __new__(cls, value):
        print("__new__ called with value", value)
        instance = super(CustomObject, cls).__new__(cls)
        return instance

    def __init__(self, value):
        print("__init__ called with value", value)
        self.value = value

    def __del__(self):
        print("__del__ called")

obj = CustomObject(10)  # 创建时会依次调用 __new__ 和 __init__
del obj  # 销毁时调用 __del__

对象表示

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

    def __str__(self):
        return f"Person(name={self.name})"

    def __repr__(self):
        return f"Person({self.name!r})"

p = Person("Alice")
print(str(p))  # 打印 Person(name=Alice)
print(repr(p))  # 打印 Person('Alice')

属性访问

class CustomClass:
    def __getattr__(self, item):
        return f"Attribute {item} not found"

    def __setattr__(self, key, value):
        print(f"Setting {key} to {value}")
        super().__setattr__(key, value)

    def __delattr__(self, name):
        print(f"Deleting attribute {name}")

custom_instance = CustomClass()
custom_instance.new_attribute = "value"  # 调用 __setattr__
del custom_instance.new_attribute  # 调用 __delattr__

容器类型协议

class MyList:
    def __init__(self, data):
        self.data = data

    def __len__(self):
        return len(self.data)

    def __getitem__(self, key):
        return self.data[key]

    def __setitem__(self, key, value):
        self.data[key] = value

    def __delitem__(self, key):
        del self.data[key]

    def __iter__(self):
        return iter(self.data)

    def __next__(self):
        return next(self.data)

    def __reversed__(self):
        return reversed(self.data)

    def __contains__(self, item):
        return item in self.data

my_list = MyList([1, 2, 3, 4])
print(len(my_list))  # 4
print(my_list[0])  # 1
my_list[0] = 10  # 10
del my_list[0]  # 删除第一个元素
for item in my_list:  # 遍历
    print(item)
print(3 in my_list)  # True

数值和类型转换

class IntegerString:
    def __init__(self, value):
        self.value = str(value)

    def __int__(self):
        return int(self.value)

    def __float__(self):
        return float(self.value)

    def __complex__(self):
        return complex(self.value)

    def __oct__(self):
        return oct(self.value)

    def __hex__(self):
        return hex(self.value)

    def __index__(self):
        return int(self.value)

int_string = IntegerString("42")
print(int(int_string))  # 42
print(float(int_string))  # 42.0
print(complex(int_string))  # (42+0j)
print(oct(int_string))  # 0o52
print(hex(int_string))  # 0x2a
print(int_string.index())  # 42

比较操作

class Version:
    def __init__(self, major, minor):
        self.major = major
        self.minor = minor

    def __eq__(self, other):
        return (self.major, self.minor) == (other.major, other.minor)

    def __ne__(self, other):
        return not self.__eq__(other)

v1 = Version(1, 0)
v2 = Version(1, 0)
v3 = Version(2, 0)
print(v1 == v2)  # True
print(v1 != v3)  # True

运算符重载

class Rational:
    def __init__(self, numerator, denominator):
        self.numerator = numerator
        self.denominator = denominator

    def __add__(self, other):
        return Rational(self.numerator * other.denominator + self.denominator * other.numerator,
                        self.denominator * other.denominator)

    # 其他运算符重载方法...

r1 = Rational(1, 2)
r2 = Rational(1, 3)
r3 = r1 + r2  # 使用 __add__ 方法

增强赋值运算符

class Vector:
    def __init__(self, components):
        self.components = components

    def __iadd__(self, other):
        self.components += other.components
        return self

vector = Vector([1, 2, 3])
vector += Vector([1, 1, 1])  # 使用 __iadd__ 方法

上下文管理器

class FileHandler:
    def __enter__(self):
        print("Entering context...")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exiting context...")
        if exc_type:
            print(f"Exception: {exc_value}")

with FileHandler() as handler:
    print("Working inside context manager...")

反射

class Base:
    pass

class Derived(Base):
    pass

def is_instance(obj, cls):
    return isinstance(obj, cls)

def is_subclass(cls1, cls2):
    return issubclass(cls1, cls2)

base_instance = Base()
derived_instance = Derived()

print(is_instance(base_instance, Base))  # True
print(is_subclass(Derived, Base))  # True

序列化

import pickle

class Serializable:
    def __init__(self, data):
        self.data = data

    def __getstate__(self):
        return self.data

    def __setstate__(self, state):
        self.data = state

serializable = Serializable([1, 2, 3])
pickled = pickle.dumps(serializable)
unpickled = pickle.loads(pickled)
print(unpickled.data)  # 输出 [1, 2, 3]

其他

class Calculator:
    def __call__(self):
        return 42

    def __format__(self, format_spec):
        return "The answer is {}".format(42)

calculator = Calculator()
print(calculator())  # 输出 42
print("{:.0f}".format(calculator))  # 输出 The answer is 42

三. 双下方法相关面试题

3.1 让字典具备句点符查找值的功能

1. 正常使用
    dict_01 = {'name': '孙悟空', 'age': 28}
    print(dict_01.name)                        # 报错
    print(dict_01.get('name'))                 # 孙悟空

2. 功能使用
    # 定义一个类继承字典
    class MyDict(dict):
        def __getattr__(self, item):
            return self.get(item)

        def __setattr__(self, key, value):
            self[key] = value

    dict_02 = MyDict({'name': '孙悟空', 'age': 28})

    print(dict_02.name)                       # 孙悟空

3.2 补全下列代码 使其运行不报错

class Context:
    pass

with Context() as ctx:
    ctx.do_something()

以下是功能完成

posted @ 2023-05-07 00:25  codegjj  阅读(3)  评论(0编辑  收藏  举报