类和对象 
一切都是对象 
在 Python 中,“一切皆对象”是一个核心理念。简单来说,Python 中的所有东西都是对象 ,无论是数值、字符串、函数、类,甚至是模块和代码本身。Python 对象有三个特征:身份 、类型 和值 。
身份 :对象在内存中的地址,可以通过 id() 函数查看,例如 id(obj)。 
类型 :对象的类别,可以通过 type() 函数查看。例如,type(5) 返回 <class 'int'>。 
值 :对象的实际内容或数据,直接调用变量名即可查看。 
 
1 2 3 4 i = 2  print (id (i))      print (type (i))    print (i)          
 
一切皆对象意味着我们可以将几乎任何东西赋值给变量或作为参数传递给函数。把任何函数传给一个变量。
类(Class)与对象(Object)是不同的,类是没初始化的模板,定义了结构和行为;对象是初始化了的实例,内存中有具体的值。
类 :类是对象的蓝图或模板,用来描述一类事物的通用结构和行为。定义类时,指定了该类对象的属性和方法。 
对象 :对象是类的具体实例,表示某个具体的事物。 
 
但是从更加一般的角度来说,类也是一种对象,也是有具体的值。
1 2 3 4 5 6 class MyClass:     pass print(id(MyClass)) print(type(MyClass))  # 输出: <class 'type'> print(MyClass) # <class '__main__.MyClass'> 
 
重要的基类 
在 Python 中,type 和 object 是两个核心的基类:
object 是所有类的基类,所有类都继承自 object。 
type 是所有类的类型,也就是说,每个类都是 type 的实例 ,包括了 type 本身和 object。 
 
总的来说,type 是所有类的类型 :每个类都是 type 的实例,包括 MyClass、int 等。
type 也是创建类的工厂 :type 是一种创建类对象的机制,相当于类的构造器。
type 是一个类,且继承自 object :它可以创建类,并且它自己也是一个类,具有类的一切特性。
 
类的常见属性 
.__base__ 属性表示当前类的直接基类 ,即当前类继承的父类。如果一个类没有显式继承父类,则 .__base__ 为 object,因为所有类默认继承自 object。
1 2 3 4 5 6 7 8 class  Parent :    pass  class  Child (Parent ):    pass  print (Child.__base__)  print (Parent.__base__) 
 
在这里,Child.__base__ 是 Parent,而 Parent.__base__ 是 object,因为 object 是所有类的最终基类。
.__class__表示当前实例或类的类型 ,即这个对象是由哪个类创建的。对于类本身,.__class__ 通常会指向 type,因为类对象是 type 的实例。
1 2 3 4 5 6 7 class  MyClass :    pass  obj = MyClass() print (obj.__class__)   print (MyClass.__class__)  
 
在这个示例中,obj.__class__ 表明 obj 是 MyClass 的实例,而 MyClass.__class__ 表明 MyClass 是 type 的实例。
.__dict__ 属性是一个字典 ,包含类或实例的所有属性。对于实例,.__dict__ 包含该实例的所有实例属性。对于类,.__dict__ 包含该类的所有类属性和方法。
1 2 3 4 5 6 7 8 9 10 class  MyClass :    class_attr = "class attribute"      def  __init__ (self, value ):         self .instance_attr = value obj = MyClass("instance attribute" ) print (obj.__dict__)         print (MyClass.__dict__)     
 
在这个示例中,obj.__dict__ 仅包含实例属性,而 MyClass.__dict__ 包含类属性和方法。
.__subclasses__() 方法返回所有直接子类的列表 。这在需要递归遍历继承树或找到所有子类时非常有用。
1 2 3 4 5 6 7 8 9 10 class  Base :    pass  class  Child1 (Base ):    pass  class  Child2 (Base ):    pass  print (Base.__subclasses__())  
 
这里,Base.__subclasses__() 返回一个包含 Child1 和 Child2 的列表。
.__name__ 是类的简单名称,返回类的名称字符串。.__qualname__ 是类的完全限定名(Qualified Name),包含嵌套类或作用域信息。
1 2 3 4 5 6 7 class  Outer :    class  Inner :         pass  print (Outer.__name__)         print (Outer.Inner.__name__)    print (Outer.Inner.__qualname__)  
 
Inner.__qualname__ 以字符串形式描述了完整的嵌套路径信息。
__call__ 方法:类的可调用行为,使得类的实例可以像函数一样被调用。如果你在类中定义了 __call__ 方法,那么创建的实例可以被直接调用,并执行 __call__ 方法中的代码。
1 2 3 4 5 6 class  CallableClass :    def  __call__ (self, *args, **kwargs ):         print ("Instance is called like a function" ) obj = CallableClass() obj()   
 
__del__ 方法:实例的销毁,用于对象销毁时 执行清理工作。会在实例被垃圾回收时调用,通常用于关闭资源或执行清理操作。
1 2 3 4 5 6 class  MyClass :    def  __del__ (self ):         print ("Instance is being destroyed" ) obj = MyClass() del  obj  
 
对象的初始化 
类的初始化过程包括类的创建 和实例的初始化 。当我们创建一个类的实例时,会依次调用 __new__ 和 __init__ 等方法来完成实例化流程。理解这个过程不仅有助于掌握 Python 的类机制,还可以通过自定义这些方法,控制类的创建和初始化行为,实现更多高级功能(如单例模式 、池化对象 等)。
当我们调用 MyClass() 创建类的实例时,Python 会经过以下几个主要步骤:
__new__ 方法:创建实例。__new__ 是一个静态方法 ,负责创建实例 ,并分配内存空间,通常返回一个新的实例对象。
__new__ 的第一个参数是 cls,表示当前类,Python 会根据这个类来创建新实例。__new__(cls, name, bases, dct)
 
如果 __new__ 不返回实例(例如返回 None 或其他类型),则不会继续调用 __init__,实例化会中止。
 
 
需要注意,object 对象是一个空的对象,是所有对象的父类。所以 super 返回了一个新的空白的对象。
1 2 3 4 5 6 7 8 9 10 11 12 class  MyClass :    def  __new__ (cls, *args, **kwargs ):         print ("Calling __new__" )         instance = super ().__new__(cls)         return  instance     def  __init__ (self, value ):         print ("Calling __init__" )         self .value = value obj = MyClass(10 ) 
 
 
__init__ 方法:初始化实例。__init__ 的第一个参数是 self,表示新创建的实例对象。通常在 __init__ 中设置对象的属性,并完成实例的初始配置。
 
 
在类定义时,Python 实际上调用了**元类(MetaClass)**来创建类对象。默认情况下,Python 使用 type 作为元类,即 type 类是类的生成工厂。通过定义自定义的元类,可以在类创建时做更多的控制,例如在类生成前检查某些条件,或动态地添加方法和属性。
1 2 3 4 5 6 7 8 9 10 class  MyMeta (type ):    def  __new__ (cls, name, bases, dct ):         print (f"Creating class {name} " )         return  super ().__new__(cls, name, bases, dct) class  MyClass (metaclass=MyMeta):    pass  print (MyClass)  
 
元类编程 
通过重写 __new__ 方法,可以确保类只有一个实例,实现单例模式 。
1 2 3 4 5 6 7 8 class  Singleton :    _instance = None      def  __new__ (cls ):         if  not  cls._instance:             cls._instance = super ().__new__(cls)         return  cls._instance 
 
注意,元类的 __call__  和 对象的 __call__  是不一样的,它们的作用和用途是不同的。元类的 __call__ 方法用于控制类的实例化过程 ,返回一个对象。当使用 MyClass() 来实例化一个类时,Python 会调用元类的 __call__ 方法。在默认的实现中,元类的 __call__ 负责调用类的 __new__ 和 __init__ 方法,以完成实例的创建和初始化。对象的 __call__ 方法是定义在类实例 上的,它让实例像函数一样可以被调用 。
用元类来实现单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 class  SingletonMeta (type ):    _instances = {}     def  __call__ (cls, *args, **kwargs ):         if  cls not  in  cls._instances:             cls._instances[cls] = super ().__call__(*args, **kwargs)         return  cls._instances[cls] class  Singleton (metaclass=SingletonMeta):    def  __init__ (self, value ):         self .value = value 
 
在多线程环境下,可能会出现多个线程同时创建实例的情况。通过在元类中加入线程锁,可以确保多线程下单例的唯一性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import  threadingclass  ThreadSafeSingletonMeta (type ):    _instances = {}     _lock = threading.Lock()       def  __call__ (cls, *args, **kwargs ):         with  cls._lock:             if  cls not  in  cls._instances:                 cls._instances[cls] = super ().__call__(*args, **kwargs)         return  cls._instances[cls] class  ThreadSafeSingleton (metaclass=ThreadSafeSingletonMeta):    def  __init__ (self, value ):         self .value = value 
 
ORM 映射 :在 ORM 框架中,将数据库表结构映射为类结构,简化数据库操作。这个真的非常常见,而且 dct 字段还包括了传进来的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 class  TableMeta (type ):    def  __new__ (cls, name, bases, dct ):         columns = {key: value for  key, value in  dct.items() if  isinstance (value, str )}         dct['columns' ] = columns           return  super ().__new__(cls, name, bases, dct) class  User (metaclass=TableMeta):    id  = 'INTEGER PRIMARY KEY'      name = 'TEXT'      email = 'TEXT'  print (User.columns)  
 
为什么 Python 是动态语言 
Python 是一门典型的动态语言 ,这意味着它能够在运行时对对象的结构和行为进行修改,甚至可以动态地生成、修改和删除对象的属性和方法。这种动态性在开发业务逻辑密集型的应用时尤为高效,能够帮助程序员以更简洁、灵活的方式快速实现功能。
Python 对象通过 __dict__ 属性(属性字典)管理自身的所有可动态改变的属性,这让 Python 对象能够随时添加、修改或删除属性和方法。
1 2 3 4 5 6 7 8 9 10 11 12 class  MyClass :    pass  def  new_class_method (self ):    print ("New method for MyClass!" ) MyClass.new_method = new_class_method obj = MyClass() obj.new_method()   
 
动态语言因其灵活性和开发效率而备受欢迎,尤其在业务逻辑密集的应用场景中,动态语言能够帮助程序员快速写出产品。比如说 Web 开发,数据科学和机器学习,自动化和脚本,核心在于业务逻辑。
动态语言的灵活性也带来了一个明显的缺点,即缺少静态类型 。由于类型的缺失,动态语言的代码在复杂项目中可能变得难以理解和维护,尤其对于不熟悉项目或代码的新手来说。:许多 IDE 会依赖静态类型信息来提供智能提示、自动补全和类型检查。动态语言由于没有类型信息,IDE 很难准确地推断变量的类型,导致开发者得不到准确的智能提示。
所以建议多使用类型提示(Type Hints)。
面向对象 
需求分析 
我们的目标是构建一个基于代码的 RAG(Retrieval-Augmented Generation)系统,专注于代码辅助工作。这个系统的核心流程包括将项目源代码转化为可检索的知识库(codebase),利用检索器进行相关性查询,并基于对话系统与用户交互,利用 LLM(大型语言模型)提供回答。
根据需求,我们可以提取以下名词 ,每个名词可能对应一个类或对象:
项目 (Project):表示用户输入的项目源代码集合。 
Codebase :代码知识库,用于存储和管理项目的源代码,使得其内容可被检索。 
检索器 (Retriever):一个工具类,用于在 Codebase 中执行搜索和相关性检索。 
对话 (Conversation):支持用户与 LLM 间的交互,对话会调用检索器在 Codebase 中查询答案。 
LLM (大型语言模型):处理用户的自然语言问题并生成响应。与检索器结合以形成 RAG 系统。 
 
核心需求:
输入项目的源代码并构建 Codebase 
 
基于问题检索相关的源代码 
 
实现基于对话的交互,使用 Codebase 作为知识库 
Conversation :表示与用户的交互,管理对话流程,并与 LLM 进行通信。负责在需要时调用 Retriever 从 Codebase 中获取信息,以增强 LLM 的回答。 
 
 
 
类的设计 
根据以上分析,可以划分出以下主要类及其职责:
类名 
职责描述 
 
 
Project 
表示用户输入的源代码项目,负责加载和管理项目文件。 
 
Codebase 
作为知识库,负责存储和管理项目源代码,并提供索引、解析等操作,使之可被 Retriever 查询。 
 
Retriever 
提供在 Codebase 中执行检索的功能,通过索引和关键词匹配找到相关代码片段。 
 
Query(可选) 
封装用户的查询请求,提供查询预处理功能,如关键词提取。 
 
Conversation 
支持用户与 LLM 的交互,管理对话流并在需要时调用 Retriever 从 Codebase 中查询信息。 
 
LLM 
代表大型语言模型,负责接收用户的自然语言问题,结合 Retriever 的结果生成增强回答。 
 
 
类间关系和交互 
根据类的职责和需求,我们可以进一步细化类之间的关系:
Project -> Codebase :Project 提供源代码内容,Codebase 接收并存储这些内容。Codebase 需要从 Project 获取代码文件内容,解析后生成索引。 
Codebase <-> Retriever :Retriever 需要访问 Codebase 中的内容,执行搜索操作以找到与查询相关的代码片段。Codebase 提供检索接口以支持 Retriever 进行查询。 
Conversation -> Retriever :Conversation 接收用户的自然语言问题,如果涉及代码查询,会将问题转化为 Query,并调用 Retriever 从 Codebase 检索答案。Retriever 的返回内容将传递给 LLM 以生成回答。 
Conversation -> LLM :Conversation 与 LLM 交互,将用户的问题及 Retriever 返回的代码上下文传递给 LLM,由 LLM 生成回答并回复给用户。 
 
设计模式 
工厂模式  
用于创建 Project 实例,封装实例化细节。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  Project :    def  __init__ (self, name: str , source_files: List [str ] ):         self .name = name         self .source_files = source_files     def  load_files (self ):                  print (f"Loading files for project: {self.name} " ) class  ProjectFactory :    @staticmethod     def  create_project (name: str , source_files: List [str ] ) -> Project:                  project = Project(name, source_files)         project.load_files()         return  project 
 
策略模式 
Codebase 支持不同的存储方式(如内存或数据库),可使用策略模式动态选择存储方案。下面还可以看到我们抽象出了存储层当作接口,设计了两种存储方式,接着作为参数传入 codebase,实现不同策略的使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 class  StorageStrategy (ABC ):    @abstractmethod     def  save_codebase (self, code_data: Dict  ):         pass      @abstractmethod     def  load_codebase (self ) -> Dict :         pass  class  InMemoryStorage (StorageStrategy ):    def  __init__ (self ):         self ._data = {}     def  save_codebase (self, code_data: Dict  ):         self ._data = code_data         print ("Codebase stored in memory." )     def  load_codebase (self ) -> Dict :         print ("Loading codebase from memory." )         return  self ._data class  DatabaseStorage (StorageStrategy ):    def  __init__ (self ):         self ._data = {}       def  save_codebase (self, code_data: Dict  ):                  self ._data = code_data           print ("Codebase stored in database." )     def  load_codebase (self ) -> Dict :                  print ("Loading codebase from database." )         return  self ._data class  Codebase :    def  __init__ (self, storage_strategy: StorageStrategy ):         self .storage_strategy = storage_strategy         self .index = {}     def  build_codebase (self, project: Project ):                  for  file in  project.source_files:                          self .index[file] = f"Indexed content of {file} "          self .storage_strategy.save_codebase(self .index)     def  search (self, query: str  ) -> List [str ]:                  results = [content for  file, content in  self .index.items() if  query in  content]         return  results 
 
适配器模式  
适合不更改老系统,和新的设计保持一致性。假设我们的系统中引入了一个新组件 LegacyRetriever,这是一个旧的检索系统,用于检索代码片段,但它的接口设计不同,只有 search_code(query) 方法,而我们当前的系统需要通过 Retriever 的 retrieve(query) 方法来调用它。
那么设置一个适配器,包裹一层,那么 LegacyRetrieverAdapter 就满足了 Retriever 的接口要求了。甚至我们还能使用 self.__dict__.update(dict(execute=music_player.play)) 的方式动态地给类增加函数,那么更加灵活了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class  LegacyRetriever :    def  __init__ (self, codebase ):         self .codebase = codebase     def  search_code (self, query ):                  return  [content for  file, content in  self .codebase.index.items() if  query.lower() in  content.lower()] class  LegacyRetrieverAdapter (Retriever ):    def  __init__ (self, legacy_retriever ):         self .legacy_retriever = legacy_retriever     def  retrieve (self, query ):                  return  self .legacy_retriever.search_code(query) 
 
代理模式 
在代理模式(Proxy Pattern)中,代理对象作为访问其他对象的接口,通常用于在不改变目标对象的前提下,为其提供控制访问 、懒加载 、缓存 或日志记录 等附加功能。
假设我们希望增强 Retriever 的功能,可以使用代理模式来实现如下扩展:
访问控制 :限制非授权用户的查询访问。 
缓存 :缓存上次查询的结果,避免重复计算或检索。 
日志记录 :记录每次查询的日志,便于后续查看或调试。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class  AccessControlProxyRetriever :    def  __init__ (self, retriever, authorized_users ):         self .retriever = retriever         self .authorized_users = authorized_users     def  retrieve (self, query, user ):         if  user not  in  self .authorized_users:             print (f"Access denied for user: {user} " )             return  []         print (f"Access granted for user: {user} " )         return  self .retriever.retrieve(query) class  CachingProxyRetriever :    def  __init__ (self, retriever ):         self .retriever = retriever         self .cache = {}     def  retrieve (self, query ):         if  query in  self .cache:             print (f"Returning cached result for query: {query} " )             return  self .cache[query]         result = self .retriever.retrieve(query)         self .cache[query] = result         return  result class  LoggingProxyRetriever :    def  __init__ (self, retriever ):         self .retriever = retriever         self .logs = []     def  retrieve (self, query ):         print (f"Logging query: {query} " )         self .logs.append(query)         return  self .retriever.retrieve(query)     def  get_logs (self ):         return  self .logs 
 
代理模式的牛逼之处,就是可以直接组合起来,因为这些类都实现了 retriever 函数。
1 2 3 4 5 6 7 8 9 10 11 12 project = Project("MyProject" , ["file1.py" , "file2.py" ]) codebase = Codebase(project) retriever = Retriever(codebase) log_proxy = LoggingProxyRetriever(retriever) cache_proxy = CachingProxyRetriever(log_proxy)   access_proxy = AccessControlProxyRetriever(cache_proxy, authorized_users) print (access_proxy.retrieve("file1" , "Alice" ))
 
单例模式 
参考元类编程。
观察者模式 
观察者模式(Observer Pattern)是一种行为型模式,它定义了一种一对多的依赖关系,让多个观察者对象监听某一个主题对象。主题在状态发生变化时会通知所有观察者,观察者可以随时动态增删。这种设计使得观察者与主题解耦,提高了代码的灵活性和可维护性。
这种模式在事件订阅,pub-sub 系统非常常见,非常实用。pub 和 sub 可以非常干净的解耦。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class  Subject :    def  __init__ (self ):         self .__observers = []     def  register (self, observer ):         self .__observers.append(observer)     def  unregister (self, observer ):         self .__observers.remove(observer)     def  notifyAll (self, *args, **kwargs ):         for  observer in  self .__observers:             observer.notify(self , *args, **kwargs) class  Observer :    def  __init__ (self, subject ):         subject.register(self )     def  notify (self, subject, *args, **kwargs ):         print (f"{self}  received {args}  {kwargs}  from {subject} " ) subject = Subject() observer1 = Observer(subject) observer2 = Observer(subject) subject.notifyAll("First notification" ) subject.unregister(observer1)   subject.notifyAll("Second notification" )   
 
命令模式 
命令模式(Command Pattern)是一种行为型设计模式,它的核心思想是将请求封装成对象 ,从而让你可以独立地传递、保存、撤销和重做请求 。每一个命令对象代表一个请求或操作,比如“创建文件”、“删除文件”、“重命名文件”等等。
在命令模式中,通常包含以下几个角色:
命令(Command)接口 :定义执行操作的接口,所有的命令类都应该实现这个接口。 
具体命令(Concrete Command)类 :实现命令接口,封装具体的操作行为,比如“创建文件”、“删除文件”等。 
接收者(Receiver) :执行具体操作的对象,命令对象通过接收者来完成操作。 
调用者(Invoker) :负责执行命令的类,通常会记录所有命令,并提供撤销、重做等功能。 
 
定义命令接口 :首先,我们定义 Command 接口,它包含了所有命令必须实现的 execute 和 undo 方法。
1 2 3 4 5 6 class  Command :    def  execute (self ):         raise  NotImplementedError("Subclasses must implement 'execute' method" )     def  undo (self ):         raise  NotImplementedError("Subclasses must implement 'undo' method" ) 
 
定义接收者 (家电设备):接收者是实际执行命令的家电设备。我们以灯、音响和空调为例,给每个接收者定义具体的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class  Light :    def  turn_on (self ):         print ("Light is turned ON" )     def  turn_off (self ):         print ("Light is turned OFF" ) class  Stereo :    def  play_music (self ):         print ("Stereo is playing music" )     def  stop_music (self ):         print ("Stereo stopped playing music" ) class  AC :    def  set_temperature (self, temperature ):         print (f"AC temperature set to {temperature} °C" )     def  turn_off (self ):         print ("AC is turned OFF" ) 
 
定义具体命令类 :接下来,定义具体的命令类,每个命令类都会实现 Command 接口,并且封装特定设备的操作。每个命令对象会持有接收者的引用,以便在调用 execute 和 undo 时,执行接收者的具体操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class  LightOnCommand (Command ):    def  __init__ (self, light ):         self .light = light     def  execute (self ):         self .light.turn_on()     def  undo (self ):         self .light.turn_off() class  LightOffCommand (Command ):    def  __init__ (self, light ):         self .light = light     def  execute (self ):         self .light.turn_off()     def  undo (self ):         self .light.turn_on() class  PlayMusicCommand (Command ):    def  __init__ (self, stereo ):         self .stereo = stereo     def  execute (self ):         self .stereo.play_music()     def  undo (self ):         self .stereo.stop_music() class  StopMusicCommand (Command ):    def  __init__ (self, stereo ):         self .stereo = stereo     def  execute (self ):         self .stereo.stop_music()     def  undo (self ):         self .stereo.play_music() 
 
定义调用者(Invoker) ,调用者负责管理和执行命令对象,提供操作执行、撤销等功能。调用者类 RemoteControl 可以持有一组命令,并支持批量撤销操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 class  RemoteControl :    def  __init__ (self ):         self .history = []       def  press_button (self, command ):         command.execute()         self .history.append(command)     def  undo_last (self ):         if  self .history:             command = self .history.pop()             command.undo() 
 
控制的主程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 light = Light() stereo = Stereo() ac = AC() light_on_cmd = LightOnCommand(light) light_off_cmd = LightOffCommand(light) play_music_cmd = PlayMusicCommand(stereo) stop_music_cmd = StopMusicCommand(stereo) set_ac_temp_cmd = SetACTemperatureCommand(ac, 22 ) remote = RemoteControl() remote.press_button(light_on_cmd)       remote.press_button(play_music_cmd)     remote.press_button(set_ac_temp_cmd)    remote.undo_last()                      remote.undo_last()                      
 
参考