面向对象之双下方法,内置函数
一. 内置函数
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()
以下是功能完成