Python数据类型:类class、反射dataclasses
一、类
类型注解(typing)
属性可以指定类型注解和默认值。
Python中创建对象不使用new关键字。
class User:
name: str
country: str = "China"
# China
print(User().country)
// java创建对象使用new关键字
User user = new User();
# 很多编程语言创建对象都使用关键字new
user = User()
from typing import List, Dict, Optional, Union, Any
class User:
def __init__(
self,
user_id: int,
name: str,
tags: List[str], # 字符串列表
metadata: Dict[str, Any], # 键为字符串,值为任意类型的字典
age: Optional[int] = None, # 可以是 int 或 None
role: Union[str, int] = "user" # 可以是字符串或整数
) -> None:
self.user_id = user_id
self.name = name
self.tags = tags
self.metadata = metadata
self.age = age
self.role = role
# 使用示例
if __name__ == "__main__":
user = User(
user_id=1,
name="Alice",
tags=["admin", "premium"],
metadata={"signup_date": "2025-01-01", "score": 95},
age=30,
role="moderator"
)
print(user.name, user.tags)
实例类型判断
if isinstance(msg, AIMessage):
pass
elif isinstance(msg, HumanMessage):
pass
多重继承
多个继承使用逗号分隔。
from enum import Enum
class Intent(str, Enum):
"""用户意图枚举"""
CHAT = "chat" # 闲聊问答
MEETING = "meeting" #会议纪要
UNKNOWN = "unknown" # 未知
self
对象方法必须有参数,而且第一个参数必须是self。注意:self并不是Python的关键字,处于习惯大家都默认使用self,Java中使用关键字this。默认是继承 object ,可以省略。
public class User {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{name='" + name + '\'' + ", age=" + age + '}';
}
}
class User:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"User(name={self.name}, age={self.age})"
Python初始化方法 __init__ 相当于 Java的构造方法,只不过不用在最上面声明属性,相对来说更简洁。
import keyword
# 查看Python中的关键字列表
print(keyword.kwlist)
魔法方法
Python中方法名以双下划线__作为前缀和后缀的方法叫做魔法方法,魔法方法相当于Java的接口方法,具有特定的功能。
__new__:实例化方法,先执行__new__再执行__init__。__init__:初始化方法,常用于类的构造方法,例如给属性初始化None, 如 self.xxx = None。__str__、__repr__:toString()方法。__eq__:用于比较两个对象是否相等。__iter__:迭代器通常与__next__配合使用。__next__:表示迭代器对应的next()方法。__add__:加法运算符 +__or__:或运算符 |,langchain 中的管道运算符就是重写该方法,prompt | llm | str__mul__:乘法运算 *,如 字符串乘以数字,print(“-” * 20)__mod__: 取余,self % value,常见的字符串拼接,print(“name=%s age=%d” % (name, age))__gt__:大于 >__ge__:大于等于 > =__lt__:小于<__le__:小于等于 <=__call__:让“对象像函数一样可调用"__dict__:将对象转为dict__module__: 获取 定义类或函数的模块名__class__:获取当前类,可以调用类的__name__获取类名字符串__doc__:获取模块或者函数的文档注释__name__:获取类、函数、模块等的名称__annotations__:变量或函数注解的字典__bases__:获取类的基类
class Adder:
def __init__(self, n):
self.n = n
def __call__(self, x):
return x + self.n
add5 = Adder(5)
# 这里 add5 是对象,但可以像函数一样调用
print(add5(10)) # 15
有了魔法方法,只要类中实现了魔法方法就可以通过符号来操作类了,如 对象之间比较大小,重写__or__来实现管道 | 的作用。
class MyList:
def __init__(self, items=None):
self.items = items or []
def __or__(self, other):
"""实现 self | other 操作"""
# 创建新实例,避免修改原对象
new_list = MyList(self.items.copy())
new_list.items.append(other)
return new_list
def __repr__(self):
return f"MyList({self.items})"
# 使用示例
ml = MyList([1, 2, 3])
ml2 = ml | 4 | 5 | 6 # 链式调用
print(ml) # MyList([1, 2, 3]) - 原对象不变
print(ml2) # MyList([1, 2, 3, 4, 5, 6])
__str__和 __ repr __
__repr__:representation,面向开发者,必须显式调用 repr(obj) 触发,一般都要实现(兜底方案,生产环境也建议有)。__str__:string,面向用户,在 print(obj)、str(obj)、f-string 等场景下会自动触发,按需实现。
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
# 优先:返回可重建对象的表达式
return f"{self.__class__.__name__}({self.x!r}, {self.y!r})"
def __str__(self):
# 可选:返回用户友好的格式化字符串
return f"Value: {self.x}, {self.y}"
myclass = MyClass(1, 2)
# Value: 1, 2
print(myclass)
# MyClass(1, 2)
print(repr(myclass))
访问权限约定
Python所提倡的用更多的符号来代替关键字,在Java中定义私有变量要使用private关键字。
- 私有属性在属性名前使用双下划线命名规则。如:__password
- 类的私有方法也是在方法名前使用双下划线前缀。如 __set_password
- 访问私有属性或者私有方法的规范是:_类名__私有成员
class Person:
country = "China"
def say_hello(self):
print("I'm Chinese")
class Student(Person, Chinese):
name = None
age = 0
__weight = 60
def __init__(self):
pass
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def say_hello(self):
# 方式一:显式调用父类方法使用super()方法,而不是super关键字
super().say_hello()
# 方式二:通过类名指定父类的方法(多继承时此种方式更加直观)
Person.say_hello(self)
print("I'm Student")
def __private_func(self):
print("私有函数")
def __add__(self, other):
return Student(self.name + other.name, self.age + other.age)
zhangsan = Student("zhangsan", 26)
zhangsan.say_hello()
super(Student, zhangsan).say_hello()
lisi = Student("lisi", 24)
zhangli = zhangsan + lisi
print(zhangli.age)
# 访问私有属性和方法
print(zhangsan._Person__gender)
zhangsan._Person__private_func
# 多重继承时,当方法名重名时优先调用子类的方法,然后再按照继承的先后顺序优先使用前面的顺序,__mro__返回父类的继承顺序
# MRO(method resolution order)方法解析顺序
print(zhangsan.__mro__)
抽象方法 @abstractmethod
Python认为一个方法没有方法体,即方法体为pass就可以认为是一个抽象方法,Python一直在倡导约定大于语法,所以也没有提供什么语法强制校验,毕竟程序员要对自己写的代码负责。Python虽然没有把抽象方法作为一级语法,但是也可以在运行时检测抽象方法有没有实现,没有实现就抛异常,需要通过abc模块来检查。TypeError: Can't instantiate abstract class Chinese with abstract method hello。
Python中只有class关键字,没有接口interface关键字,Python认为一个类中的所有方法的方法体都是pass,那么这个类就算一个接口。Python中也没有接口,抽象类就是接口,这也是Python简化代码的一个重要提现。
from abc import ABC, abstractmethod
class Person(ABC):
def __init__(self, name=None, age=None):
self._name = name
self._age = age
@abstractmethod
def hello(self):
pass
class Chinese(Person):
pass
if __name__ == '__main__':
chinese = Chinese()
chinese.hello()
静态方法 @staticmethod 和类方法 @classmethod
- @staticmethod: 方法逻辑与类相关,但不需要任何类或实例数据时使用(如工具函数),参数列表中第一个参数不需要 cls或self,直接定义真实的参数,类似普通函数,类似于Java中的StringUtils.isBank()
class MathUtils:
@staticmethod
def is_even(number):
return number % 2 == 0
@staticmethod
def validate_email(email):
return "@" in email and "." in email
# 使用
print(MathUtils.is_even(10)) # True
print(MathUtils.validate_email("test@example.com")) # True
@classmethod: 需要访问或修改类状态、实现多态工厂方法时使用
class Person:
count = 0
def __init__(self, name):
self.name = name
Person.count += 1
@classmethod
def get_count(cls):
return cls.count # 访问类属性
@classmethod
def from_birth_year(cls, name, birth_year):
"""工厂方法:根据出生年份创建实例"""
age = 2026 - birth_year
return cls(name, age) # 创建实例
# 使用
print(Person.get_count()) # 0
person = Person.from_birth_year("张三", 2000)
多态(鸭子类型🦆)
鸭子类型(Duck Typing)是指如果它走起来像鸭子,叫起来叫鸭子,那么它就是鸭子。
在鸭子类型中,关注的是对象的行为而不是对象的类型。
在Python中多态不依赖是否有继承关系,只要有相同的方法即可。Python中的类型只是一种注释,一种提示,并不会导致编译错误,所以多态的所谓类型在Python中没有任何作用。
Python中的多态更像是Java中的接口中的多态,拥有相同的方法。
类型对象
在 Python 里,类本身也是对象,所以可以像普通值一样当作实参传进去。
“类型对象”传给了构造函数,供内部做检查/反射/实例化等。
class State:
name: str
def print_state(state: type):
print(state)
# <class '__main__.State'>
print_state(State)
dataclasses 类似于Java的反射,将类名作为参数传参 MiniGraph(State) ,类似于Java中的Class对象,MiniGraph(State.class)
from dataclasses import dataclass, fields
# 1) 定义一个“状态类型”
@dataclass
class State:
count: int
name: str
# 2) 一个接收“类型”的类
class MiniGraph:
def __init__(self, state_type: type):
self.state_type = state_type # 保存传入的类
# 用这个类做一些事情:读取字段信息(反射)
self.field_names = [f.name for f in fields(state_type)]
def create_state(self, **kwargs):
# 用传入的类来创建实例
return self.state_type(**kwargs)
def show_schema(self):
print("state_type:", self.state_type.__name__)
print("fields:", self.field_names)
# 3) 传入“类名”作为实参
graph = MiniGraph(State) # 注意:不是 State(),而是 State
graph.show_schema()
s = graph.create_state(count=1, name="Alice")
print(s)
print(type(s))
"""
state_type: State
fields: ['count', 'name']
State(count=1, name='Alice')
<class '__main__.State'>
"""
关键点:
- State 是类对象(type instance),可传参。
- State() 才是实例对象。
- 这种写法常用于框架里:传类型给框架,框架再基于类型做校验、序列化、自动建模等。
二、泛型 Generic
from datetime import datetime
from typing import TypeVar, Generic
T = TypeVar('T')
class Mapped(Generic[T]):
def __init__(self, value: T = None):
self.value = value
def get_value(self) -> T:
return self.value
def set_value(self, value: T):
self.value = value
def __repr__(self):
return f"Mapped[{type(self.value).__name__}]({self.value})"
create_time: Mapped[datetime] = Mapped[datetime](datetime.now())
print(create_time.get_value())
age: Mapped[int] = Mapped[int](18)
print(age)
name: Mapped[str] = Mapped[str]('melong')
print(name)
三、工厂方法
工厂方法的好处就是:高内聚,易维护。
- 工厂方法就是提供一个方法,这个方法用于返回一类相关对象的其中一个对象。
- 将一组相关的对象封装到一个方法中的好处就是在创建对象时只需要调用同一个方法即可,这样功能更加内聚,当需要修改创建对象时只需要修改这一处即可。
- 如果不使用工厂方法,那么创建对象将会散落在代码的各个角落,修改起来容易遗漏,也比较麻烦。
class Person:
pass
class Boy(Person):
pass
class Girl(Person):
pass
class PersonFactory:
def get_instance(self, gender):
if gender == 'F':
return Girl()
elif gender == 'M':
return Boy()
else:
return Person()
pf = PersonFactory()
girl = pf.get_instance('F')
boy = pf.get_instance('M')
更多推荐


所有评论(0)