Table of contents
Three ways to create generator objects
Which methods will be called in turn when python creates a class
__new__ and __init__ realize the hungry and lazy style of the singleton mode
select_related
and prefetch_related
select_related
and prefetch_related
are two query optimization methods provided by Django ORM to reduce the number of database queries and improve performance.
select_related
The method is used to obtain the associated foreign key object at one time when querying. It can avoid querying the database multiple times to obtain associated objects, thereby reducing the number of database accesses. Works for queries on one-to-one and many-to-one relationships. Methods as below:
# 获取单个对象并关联查询外键对象
obj = MyModel.objects.select_related('related_field').get(id=1)
# 获取多个对象并关联查询外键对象
objs = MyModel.objects.select_related('related_field')
# 在连续的关联字段上进行关联查询
objs = MyModel.objects.select_related('related_field__another_related_field')
prefetch_related
The method is used to obtain the associated many-to-many or one-to- many object collection at one time when querying. This avoids querying the database multiple times to obtain a collection of associated objects, thereby reducing the number of database accesses. The method of use is as follows:
# 获取单个对象并关联查询多对多关系的对象集合
obj = MyModel.objects.prefetch_related('many_to_many_field').get(id=1)
# 获取多个对象并关联查询多对多关系的对象集合
objs = MyModel.objects.prefetch_related('many_to_many_field')
# 在连续的关联字段上进行关联查询
objs = MyModel.objects.prefetch_related('related_field__another_related_field')
Note: Both select_related
the and prefetch_related
methods need to be used on queries, not on objects. In addition, these two methods are not suitable for all situations, which method to use depends on your data model and query requirements. In some cases, it may be desirable to use a combination of these two methods to maximize query performance.
There is also a Subquery subquery, a Coalesce function that assigns a default value to annotate, and uses OuterRef to call the external ID of the parent query. For example, for a table A, table A has a foreign key B, and table B has a foreign key C, and C needs to be counted, then this is You can use:
query_set.annotate(
result_count=Coalesce(
Subquery(
A.filter(B__C=OuterRef('pk'), enabled=True).values("A").annotate.count=Count('pk')).values('count')
), 0)
)
# 最后就是query_set多带了个result_count字段值处理,就是count就是子查询列表的数,再由value取出
Three ways to create generator objects
A generator is a special kind of iterator that allows you to generate values on demand during iteration
(1) Generator function : yield
A function defined with keywords. When this function is called, a generator object is returned. next()
A function or loop can be used to for
iterate over the values in a generator.
def simple_generator():
yield "Hello"
yield "World"
gen = simple_generator()
for value in gen:
print(value)
(2) Generator expressions : Similar to list comprehensions, but use parentheses ()
instead of square brackets []
. A generator expression returns a generator object, not a list. This is very useful when dealing with large amounts of data as it saves memory.
numbers = range(10)
square_gen = (x ** 2 for x in numbers)
for square in square_gen:
print(square)
(3) Using itertools
modules : Python itertools
modules provide many generator functions that can be used to create various complex generators. For example, itertools.count()
a function can create a generator of an infinitely increasing sequence.
import itertools
counter = itertools.count(1) # 从1开始的无限递增序列
for i in range(5):
print(next(counter))
Note: Generators save memory because they generate values on-demand as they iterate, rather than all values at once. This means that at any given point in time, the generator only needs to store in memory the currently generated value, not the entire sequence. This is very useful when dealing with large amounts of data or infinite sequences, as it can significantly reduce memory usage.
classmethod和staticmethod
classmethod
and staticmethod
are both decorators for methods defined in Python classes, classmethod
and staticmethod
are both decorators for methods defined in Python classes.
classmethod
classmethod
Pass the class itself as the first argument, usually namedcls
.- Class attributes can be accessed and modified within class methods .
- Class methods can be overridden by subclasses, so if a subclass defines a class method with the same name, the subclass will use its own implementation.
class MyClass:
_count = 0
@classmethod # 装饰器
def increment_count(cls): # cls代表类本身
cls._count += 1 # 可访问类属性
@classmethod
def get_count(cls):
return cls._count
MyClass.increment_count() # 类本身访问
print(MyClass.get_count()) # 输出:1
staticmethod
staticmethod
Does not accept a special first argument, meaning it cannot access class properties and methods .- Static methods cannot be overridden by subclasses , meaning subclasses cannot provide their own implementations.
- Often used to implement utility functionality associated with a class, but without requiring access to the class's properties or methods .
class MyClass:
@staticmethod
def add(a, b):
return a + b
result = MyClass.add(1, 2)
print(result) # 输出:3
classmethod
The class itself is passed as a parameter, and class properties can be accessed and modified; it can also be overridden by subclasses. staticmethod
Does not accept a special first argument, and cannot access class properties and methods; it is typically used to implement class-related utility functions.
__class__ attribute
Represents the attributes of the class itself
class MyClass:
def __new__(cls, *args, **kwargs):
# 创建一个新的实例
instance = super().__new__(cls)
# 可以在这里对实例进行一些初始化操作
return instance
def __init__(self):
print("Initializing the instance")
cls = self.__class__ # 通常建议用class,提高可维护性和可读性,因为类名可能不固定
print("Instance belongs to", cls)
cls = MyClass
print("Instance belongs to", cls)
Which methods will be called in turn when python creates a class
__new__
Method : __new__
A method is responsible for creating an instance of a class . It's a static method whose first parameter is the class itself, usually named cls
. __new__
Methods usually call __new__
methods of the parent class to create an instance and return this instance.
_init__
Method : __init__
A method is responsible for initializing an instance of a class . It's an instance method whose first argument is the instance itself, usually named self
. __init__
The method is called automatically after the instance is created . Instance properties can be initialized and assigned.
class MyClass:
def __new__(cls, *args, **kwargs):
print("Creating an instance of", cls)
instance = super().__new__(cls)
return instance
def __init__(self, value):
print("Initializing the instance")
self.value = value
# 创建MyClass的实例
my_instance = MyClass(42)
print("Instance value:", my_instance.value)
__new__ and __init__ realize the hungry and lazy style of the singleton mode
Hungry Chinese style :
Instances are created when the class is loaded . This means that the instance always exists whether it is needed or not. The advantage of the hungry Chinese style is that the instance is created thread-safely, because the instance is created when the class is loaded, and the class loading is thread-safe . The downside is that resources are wasted if the instance is not needed or.
class Singleton2:
__instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls) # 创建类的时候就被创建可返回实例
return cls._instance
def __init__(self):
pass
@classmethod
def get_instance(cls): # 类方法
return cls.__instance # 直接返回
# 使用Singleton
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # 输出:True
Lazy style :
Instances are created on first use . This means that instances are only created when needed, saving resources . The disadvantage of the lazy style is that in a multi-threaded environment, you need to pay attention to thread safety issues .
class Singleton1:
__instance = None
@classmethod
def get_instance(cls):
if cls.__instance is None:
__instance = Singleton1() # 调用获取实例时才去创建
return cls.__instance
# 使用Singleton
singleton1 = Singleton1()
singleton2 = Singleton1()
print(singleton1 is singleton2) # 输出:True
To ensure thread safety, you can use locks or double-check locking mechanisms ( the lazy PLUS version ).
import threading
class Singleton:
_instance = None
_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
pass
# 使用Singleton
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # 输出:True