news 2026/2/4 14:10:34

掌握这10个核心差异,Java开发者轻松上手Python!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
掌握这10个核心差异,Java开发者轻松上手Python!

文章目录

  • 一、核心差异概览
  • 二、关键语法对比
    • 1、基础结构对比
    • 2、数据类型对应表
    • 3、集合操作对比
  • 三、面向对象编程差异
    • 1、类定义对比
    • 2、访问控制对比
  • 四、异常处理对比
  • 五、方法与函数对比
    • 1、函数定义差异
    • 2、Lambda 表达式对比
  • 六、并发编程对比
    • 1、多线程对比
    • 2、异步编程对比
  • 七、Java 开发者常见陷阱
    • 1、可变默认参数
    • 2、相等性比较
    • 3、循环变量作用域
    • 4、浅拷贝与深拷贝
  • 八、实用工具对比
  • 九、Pythonic 编程风格
    • 1. 列表推导式替代循环
    • 2. 使用生成器节省内存
    • 3. 上下文管理器(替代try-finally)
    • 4. 使用枚举(Enum)
  • 十、wheel + pyproject.toml 案例
    • 工具概述
    • 案例
      • 编写 pyproject.toml 文件
      • 编写 my_math.py
      • 编写 README.md
      • 构建 Wheel 包
  • 参考

🚀 目标:非常熟悉 Java 的开发者,想要快速转换到 Python 开发。

一、核心差异概览

维度Java 语言Python 语言
类型系统静态强类型,编译时检查动态强类型,运行时检查
语法风格显式声明,分号结束,大括号代码块缩进定义块,简洁语法
执行方式编译为 class 字节码,JVM 运行解释执行(也有字节码编译)
性能特点通常更快,尤其计算密集型开发速度快,标准场景够用
哲学理念“明确优于隐晦”,提供多种明确选择“做一件事只有一种明显的方式”,约定优于配置
包管理Maven/Gradle,依赖管理严格pip + pyproject.toml,更灵活
并发模型基于线程,JVM 管理GIL 限制,多进程/asyncio

😭 怎么理解呢?😭

1、类型系统:Java 中的所有类型,都需要在编写代码时定义好类型,称之为静态强类型。Python 则不同,直接声明变量,不需要指定类型,其类型是动态的。

2、语法风格:Java 必须分号结束,用大括号表示代码块。Python 中则不需要分号,直接定义缩进来实现代码块。

3、执行方式:Java 是编译型语言,先编写源文件(.java)然后使用 javac 编译为字节码( .class)文件,最后 JVM 加载字节码来运行。Python 则是解释型语言,直接利用解释器解释并执行。也有字节码编译(Jython)。

4、性能特点:Java 性能高于 Python,Java 适合 CPU 密集型任务,一般是企业级开发常用语言。Python 开发速度快,标准场景够用。

5、哲学理念:Java 中提供多种解决方案来解决一件事情。Python 有 Pythonic 哲学。

6、包管理:Java 一般使用 Ant、Maven、Gradle 管理依赖。Python 使用 pip + pyproject.toml 管理依赖。

7、并发模型:Java 支持多种创建线程的方式(含线程池),JVM 会管理线程。Python 的多线程会受到 Global Interpreter Lock 这个全局锁的限制,导致多线程实际运行变成了串行执行,适合 IO 密集型的任务。

二、关键语法对比

1、基础结构对比

Java 中会定义一个类,在类中使用 main() 方法来运行程序。

publicclassHello{publicstaticvoidmain(String[]args){System.out.println("Hello");intx=5;Stringname="Java";if(x>0){System.out.println("Positive");}}}

Python 中可以写一个入口函数,类似于 main 方法。写法上更加简洁,不需要静态指定类型,使用缩进来替代大括号。直呼,简洁!😃

defmain():print("Hello")# 简洁输出x=5# 不需要声明类型name="Python"# 不需要声明类型ifx>0:# 缩进替代大括号print("x is positive")# 类似main方法的入口if__name__=="__main__":main()

2、数据类型对应表

Java 类型Python 类型关键差异
int,longintPython 整数无大小限制,自动处理大数
float,doublefloatPython 只有双精度浮点数
booleanbooltrue -> True,false -> False
charstr(长度 1)Python 没有单独的字符类型
StringstrPython 的字符串不可变(同 Java)
ArrayListlistPython 列表可包含不同类型元素
LinkedListcollections.deque双端队列,使用双向链表实现
HashMap<K, V>dict键值对集合,语法更简洁
HashSetset无序不重复集合
T[]list 或 tuple元组不可变,列表可变
nullNonePython 的空值对象

😭 怎么理解呢?😭

1、int、long 类型:Java 处理大数,就不能用 int,得换成 BigInteger 了。Python 的 int 特别牛逼,自动处理大数。

2、float,double 类型:Java 有单精度和双精度浮点数。Python 直接就是双精度浮点数。

3、boolean 类型:Java 的布尔值是 true 和 false。Python 的布尔值是 True 和 False,变成大写开头了。

4、char 类型:Java 有字符类型。Python 直接就是字符串类型,只是长度为 1 罢了。

5、String 类型:Java 和 Python 的字符串都是不可变的。

6、ArrayList:Java 中的线性表。Python 中不需要静态定义类型,直接 list 即可。

7、LinkedList:Java 中的链表。Python 中使用 collections.deque 双端队列(Double-Ended Queue),其本质是双向链表实现的,可以实现链表的所有功能。

8、HashMap<K, V>:Java 中的键值对是 Map。Python 中使用 dict 字典来实现,按 key 来存储 value。

9、HashSet:Java 中的集合。Python 使用 set 来实现。集合,是数学中的集合,里面的元素唯一。

10、T[]:Java 中的对象数组。Python 可以使用 list 列表实现或者 tuple 元组来实现。需注意的是元组 tuple 是不可变的,其内部元素的引用不可变。

11、null:Java 中的 null。Python 中是 None。

3、集合操作对比

Java 中 List、Map、Set,以及迭代方式:

importjava.util.*;publicclassCollectionExample{publicstaticvoidmain(String[]args){// ListList<String>list=newArrayList<>();list.add("Java");list.add("Python");Stringfirst=list.get(0);intsize=list.size();// MapMap<String,Integer>scores=newHashMap<>();scores.put("Alice",95);scores.put("Bob",87);IntegeraliceScore=scores.get("Alice");// SetSet<Integer>uniqueNumbers=newHashSet<>();uniqueNumbers.add(1);uniqueNumbers.add(2);uniqueNumbers.add(1);// 重复,不会添加// 迭代for(Stringitem:list){System.out.println(item);}for(Map.Entry<String,Integer>entry:scores.entrySet()){System.out.println(entry.getKey()+": "+entry.getValue());}}}

Python 中对应 list、dict、set 的基本操作、迭代。同时 Python 特有的推导式 + 切片数据获取。

defmain():#### 列表、字典、集合的基本操作 ##### 列表,类似于ArrayListmy_list=[]# 或 list()my_list.append("Java")my_list.append("Python")my_list.insert(1,"C++")first_item=my_list[0]last_item=my_list[-1]length=len(my_list)print("列表:",my_list)print("列表第一个元素:",first_item)print("列表最后一个元素:",last_item)print("列表长度:",length)print()# 字典(类似HashMap)scores={}# 或 dict()scores["张三"]=95scores["李四"]=87zhangsan_score=scores.get("张三")# 安全访问lisi_score=scores["李四"]# 直接访问,如果不存在会报错KeyErrorprint("字典:",scores)print("张三的成绩:",zhangsan_score)print("李四的成绩:",lisi_score)try:wang_score=scores["王二五"]exceptKeyError:print("王二五的成绩:不存在")print()# 集合(类似于HashSet)unique_numbers=set()unique_numbers.add(1)unique_numbers.add(2)unique_numbers.add(2)# 重复,不会被添加print("集合:",unique_numbers)print()#### 迭代操作 ##### 列表,常规迭代foriteminmy_list:print(item)print()# 列表,带索引的迭代forindex,iteminenumerate(my_list):print(f"index{index}{item}")print()# 字典迭代forkey,valueinscores.items():print(f"{key}{value}")print()# 同时迭代多个序列names=["张三","李四","王二五"]ages=[25,30,35]forname,ageinzip(names,ages):print(f"{name}is{age}years old")#### Python特有:推导式 + 切片 ##### 列表推导式## range(10)生成0~9的整数序列## for x in ...上面的序列进行遍历,每次取出一个值赋给x## if x % 2 == 0 是筛选条件,x的值必须是偶数## x**2 是输出表达式,对符合要求的x取平方运算squares=[x**2forxinrange(10)ifx%2==0]print(squares)# [0, 4, 16, 36, 64]# 字典推导式## x从0~4遍历## x: x**2 是字典项的构造规则square_dict={x:x**2forxinrange(5)}print(square_dict)# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}# 集合推导式square_chars={charforcharin"hello world"ifchar!=' '}print(square_chars)# {'e', 'o', 'l', 'w', 'r', 'd', 'h'}# 切片操作(Python特有)## 基本语法:list[start:stop:step]## start起始索引(包含该位置),不填则默认为0## stop 结束索引(不包含该位置),不填则默认为列表长度## step 步长,下取位置 = 当前位置 + 步长numbers=[xforxinrange(10)]# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]first_three=numbers[:3]last_three=numbers[-3:]middle=numbers[2:6]# [2, 3, 4, 5]every_other=numbers[::2]# [0, 2, 4, 6, 8]reversed_list=numbers[::-1]print(numbers)print(f"前三个:{first_three}")print(f"后三个:{last_three}")print(f"中间的:{middle}")print(f"偶数位:{every_other}")print(f"反序:{reversed_list}")if__name__=="__main__":main()

Python 中特有的元组示例:和列表的区别是元组是不可变的。

# 1、创建元组,使用圆括号,而非中括号t1=(1,2,"Hello",True)# 元组:(1, 2, 'Hello', True),类型:<class 'tuple'>print(f"元组:{t1},类型:{type(t1)}")# 特例:只有一个元素的元组,必须加逗号t_one=(1,)t_num=(1)print(f"(1,)的类型:{type(t_one)}")# (1,)的类型:<class 'tuple'>print(f"(1)的类型:{type(t_num)}")# (1)的类型:<class 'int'># 2、访问元素,同listprint(f"t1的第一个元素:{t1[0]}")# t1的第一个元素:1print(f"t1切面:{t1[1:3]}")# t1切面: (2, 'Hello')# 3、不可变性(核心特征),即元组的值定义后不可修改。try:t1[0]=999exceptTypeErrorase:print(f"修改元组数据报错:{e}")# 修改元组数据报错:'tuple' object does not support item assignment# 4、可变的元组?如果元组中包含可变对象(比如列表),则列表是可变的。t_mutable=(1,[2,3])t_mutable[1].append(4)# 元组引用的指向没有变,所以可以修改print(f"元组:{t_mutable}")# 元组:(1, [2, 3, 4])# 5、元组解包 - 非常有用point=(10,20)x,y=point# 自动把元组中的值赋给变量print(f"x={x}, y={y}")# x=10, y=20

三、面向对象编程差异

Java 是面向对象编程语言,Python 同样支持面向对象编程。

1、类定义对比

Java 中定义一个类:私有属性、构造方法、静态属性、私有属性的 setter/getter 方法、实例方法、静态方法、方法覆盖、类的继承机制。

// JavapublicclassPerson{// 字段privateStringname;privateintage;publicstaticintcount=0;// 构造方法publicPerson(Stringname,intage){this.name=name;this.age=age;count++;}// 实例方法publicStringgetName(){returnthis.name;}publicvoidsetName(Stringname){this.name=name;}publicvoidgreet(){System.out.println("Hello, I'm "+name);}// 静态方法publicstaticintgetCount(){returncount;}// toString方法@OverridepublicStringtoString(){returnString.format("Person{name='%s', age=%d}",name,age);}}// 继承publicclassEmployeeextendsPerson{privateStringemployeeId;publicEmployee(Stringname,intage,StringemployeeId){super(name,age);this.employeeId=employeeId;}@Overridepublicvoidgreet(){System.out.println("Hello, I'm employee "+employeeId);}}

Python 中同样支持上述能力,且代码更加简洁。

classPerson:# 类变量(类似于静态变量)count=0# 构造方法(非必须,可省略)def__init__(self,name:str,age:int=0):"""初始化方法,类似Java构造器"""self.name=name# 会调用后面的setter方法self.age=age self._protected_var="protected"# 单下划线表示protectedself.__private_var="private"# 双下划线表示privatePerson.count+=1# 属性装饰器(类似于getter)@propertydefname(self)->str:returnself._name# setter方法@name.setterdefname(self,value:str):ifnotvalue:raiseValueError("Name cannot be empty")self._name=value# 实例方法,self类似于thisdefgreet(self)->str:returnf"Hello, my name is{self.name}and I am{self.age}years old."# 类方法@classmethoddefget_count(cls)->int:"""类方法,第一个参数是cls,表示类本身"""returncls.count# 静态方法@staticmethoddefis_audit(age:int)->bool:"""静态方法,无需self或cls参数"""returnage>=18# 特殊方法(类似于Java中的toString)## str,给用户看的,可读性好,样式美观def__str__(self)->str:returnf"Person(name='{self.name}', age={self.age})"## repr,给开发者看的,准确性高,消除歧义【默认会使用repr】def__repr__(self)->str:returnf"Person('{self.name}',{self.age})"# 继承classEmployee(Person):def__init__(self,name:str,age:int,employee_id:str):# 调用父类的构造方法super().__init__(name,age)self.employee_id=employee_id# 方法重写defgreet(self)->str:returnf"Hello, I am employee{self.employee_id}."# 方法重写def__str__(self)->str:returnf"Employee(name='{self.name}', id={self.employee_id})"if__name__=="__main__":# 创建实例person=Person("张三",20)print(str(person))# 获取属性值print(person.name)print(person.age)# 设置属性值person.name="张三2"# 直接赋值,会自动触发setterperson.age=23# 直接赋值,就是个普通的公开实例变量print(str(person))# Person(name='张三2', age=23)# 调用方法(实例方法、类方法、静态方法)print(person.greet())# Hello, my name is 张三2 and I am 23 years old.print(Person.get_count())# 1print(Person.is_audit(18))# True# 特殊方法调用print(str(person))# Person(name='张三2', age=23)print(repr(person))# Person('张三2', 23)# 继承employee=Employee("李四",30,"EMP001")# 类型检查print(isinstance(employee,Person))# Trueprint(isinstance(employee,Employee))# Trueprint(type(employee))# <class '__main__.Employee'># 继承中的方法重写print(employee.greet())# Hello, I am employee EMP001.print(str(employee))# Employee(name='李四', id=EMP001)print(repr(employee))# Person('李四', 30)

2、访问控制对比

访问控制JavaPython
公共public无修饰符(默认)
保护protected_单下划线(约定,非强制)
私有private__双下划线(名称修饰)
包私有无修饰符无对应概念

四、异常处理对比

Java 中的异常处理,包括捕获异常、抛出异常、自定义异常等功能。=> try-catch-finally

// Javaimportjava.io.*;publicclassExceptionExample{publicstaticvoidmain(String[]args){try{// 可能抛出异常的代码BufferedReaderreader=newBufferedReader(newFileReader("file.txt"));Stringline=reader.readLine();System.out.println(line);reader.close();// 自定义异常intresult=divide(10,0);}catch(FileNotFoundExceptione){System.err.println("文件未找到: "+e.getMessage());}catch(IOExceptione){System.err.println("IO错误: "+e.getMessage());}catch(ArithmeticExceptione){System.err.println("算术错误: "+e.getMessage());}finally{System.out.println("清理资源");}}publicstaticintdivide(inta,intb)throwsArithmeticException{if(b==0){thrownewArithmeticException("除数不能为零");}returna/b;}}

Python 中也支持异常处理,无非是语法不同。try-except-else-finally,其中 else 表示 try 过程中没有异常产生且没有 return 返回值时执行。

importrandomdefdivide(a:int,b:int)->float:"""除法运算"""ifb==0:# 显式抛出 ValueError,更具语义化raiseValueError("除数不能为0")returna/bdefread_file(filename:str)->str:"""读取文件内容"""content=""# 初始化默认值,防止作用域问题try:# 自动资源管理withopen(filename,'r',encoding='utf-8')asf:content=f.read()# 模拟业务逻辑result=divide(10,random.randint(0,1))print(f"除法结果:{result}")exceptFileNotFoundErrorase:print(f"文件{filename}未找到,{e}")raise# 向上抛出,让调用者感知except(IOError,PermissionError)ase:print(f"IO错误:{e}")return""# 吞掉异常,返回空串exceptValueErrorase:# 对应 divide 函数抛出的 ValueErrorprint(f"计算逻辑错误:{e}")return""exceptExceptionase:# 兜底捕获print(f"未知异常:{e}")return""else:# 只有 try 块完全成功(无异常且无 return)才执行print(f"文件{filename}读取及计算均成功")returncontentfinally:# 无论成功失败都会执行print("finally 语句块,无论是否发生异常都会执行")classMyCustomException(Exception):"""自定义异常类"""def__init__(self,message:str,error_code:int):super().__init__(message)self.error_code=error_codedef__str__(self)->str:# self.args[0]是父类Exception存储message的地方returnf"{self.args[0]}(错误码:{self.error_code})"if__name__=="__main__":try:# 创建一个测试文件,方便演示成功情况withopen("1.txt","w",encoding="utf-8")asf:f.write("Hello Python Exception")file_content=read_file("1.txt")print(f"文件内容:{file_content}")exceptExceptionase:print(f"主程序捕获异常:{e}")# 自定义异常捕获try:raiseMyCustomException("数据库连接异常",500)exceptMyCustomExceptionase:print(e)

五、方法与函数对比

Java 中称之为方法,Python 中称之为函数。

1、函数定义差异

Java 方法:方法名称、方法参数、方法返回值、静态方法、可变参数、方法重载等能力。

// JavapublicclassMathUtils{// 必须指定返回类型,void表示无返回值publicstaticintadd(inta,intb){returna+b;}// 可变参数publicstaticintsum(int...numbers){inttotal=0;for(intnum:numbers){total+=num;}returntotal;}// 方法重载publicstaticdoubleadd(doublea,doubleb){returna+b;}}

Python 函数,同样地。多加了关键字参数、参数解包能力。

# Python 函数defadd(a:int,b:int)->int:"""加法函数 参数: a:第一个加数 b:第二个加数 返回值: 两个加数的和 """returna+b# 参数带默认值defgeeet(name:str,greeting:str="Hello")->str:"""问候函数"""returnf"{greeting},{name}"# 可变参数,类似于Java中的...defsum_all(*args:int)->int:"""计算所有参数的和"""returnsum(args)# 关键字参数defcreate_person(**kwargs)->dict:"""创建一个Person对象"""person={"name":kwargs.get("name","unknown"),"age":kwargs.get("age",0),"city":kwargs.get("city","unknown")}returnperson# 参数组合(参数、参数带默认值、可变参数、关键字参数)defcomplex_function(a,b=10,*args,**kwargs):"""复杂的参数组合"""print(f"a={a}, b={b}")ifargs:print(f"额外位置参数:{args}")ifkwargs:print(f"关键字参数:{kwargs}")if__name__=="__main__":print(add(1,1));print(geeet("张三"))print(geeet("张三","您好"))print(sum_all(1,2,3,4,5))person=create_person(name="张三",age=25,city="上海")print(person)# 参数解包## 如果直接传入,相当于传入了一个列表,是一个参数## 利用解包,可以将列表元素解开,变成多个参数传入numbers=[1,2,3,4,5]print(sum_all(*numbers))## 同样地,解包后,相当于 create_person(name="张三", age=30)params={"name":"张三","age":30}print(create_person(**params))

2、Lambda 表达式对比

Java 提供 Lambda 表达式。

// Java 8+List<String>names=Arrays.asList("Alice","Bob","Charlie");names.sort((a,b)->a.compareTo(b));names.forEach(name->System.out.println(name));// 函数式接口Function<Integer,Integer>square=x->x*x;intresult=square.apply(5);// 25

Python 同样支持 Lambda 表达式。

# Python Lambda(匿名函数)names=["Alice","Bob","Charlie"]names.sort(key=lambdax:x.lower())# 忽略大小写排序# 使用lambdasquared=list(map(lambdax:x**2,[1,2,3,4]))# [1, 4, 9, 16]# 过滤even_numbers=list(filter(lambdax:x%2==0,range(10)))# [0, 2, 4, 6, 8]# 排序复杂对象people=[{"name":"Alice","age":25},{"name":"Bob","age":30},{"name":"Charlie","age":20}]people.sort(key=lambdap:p["age"])# 按年龄排序

六、并发编程对比

1、多线程对比

Java 中创建线程(继承 Thread、实现 Runnable 接口、使用线程池等方式)。

// JavapublicclassThreadExample{publicstaticvoidmain(String[]args){// 继承Thread类classMyThreadextendsThread{@Overridepublicvoidrun(){System.out.println("Thread running: "+Thread.currentThread().getId());}}// 实现Runnable接口classMyRunnableimplementsRunnable{@Overridepublicvoidrun(){System.out.println("Runnable running: "+Thread.currentThread().getId());}}// 创建线程Threadthread1=newMyThread();Threadthread2=newThread(newMyRunnable());thread1.start();thread2.start();// 使用线程池ExecutorServiceexecutor=Executors.newFixedThreadPool(5);for(inti=0;i<10;i++){executor.submit(()->{System.out.println("Task executed by: "+Thread.currentThread().getName());});}executor.shutdown();}}

Python 多线程,受 GIL 限制

1、在标准 Python(CPython)中,多线程不能利用多核 CPU 进行并行计算,同一时刻只能有一个线程在执行 Python 字节码。

2、什么是 GIL(Global Interpreter Lock)?全局解释器锁,是一把大锁,它是 Python 解释器设计上的一个限制。

  • 作用:保护 Python 解释器的内部内存管理(不是线程安全的)
  • 规则:任何 Python 线程想要执行代码(CPU 密集型任务),必须先拿到这把锁
  • 流程:如果多线程去跑,那么同一时刻只有一个线程在跑,其它线程等待,本质上是串行

3、Python 多线程没用?有用,仅限于 I/O 密集型任务。比如写爬虫、请求 API、读取数据库时,Python 多线程效率很高。

4、总结

  • 计算密集型(CPU 密集型):不要使用多线程,会被 GIL 锁死,要用多进程。
  • I/O 密集型(等网络/磁盘):可以用多线程,GIL 影响不大。
importthreadingimporttimedefprint_numbers():"""打印数字"""foriinrange(5):print(f"Number:{i}from{threading.current_thread().name}")time.sleep(0.1)defprint_letters():"""打印字母"""forletterin['A','B','C','D','E']:print(f"Letter:{letter}from{threading.current_thread().name}")time.sleep(0.1)if__name__=="__main__":# 方法1: 直接创建线程thread1=threading.Thread(target=print_numbers,name="NumbersThread")thread2=threading.Thread(target=print_letters,name="LettersThread")thread1.start()thread2.start()thread1.join()thread2.join()# 执行结果:很尴尬吧,就是串行执行的...# Number:0 from NumbersThread# Letter: A from LettersThread# Number:1 from NumbersThread# Letter: B from LettersThread# Number:2 from NumbersThread# Letter: C from LettersThread# Number:3 from NumbersThread# Letter: D from LettersThread# Number:4 from NumbersThread# Letter: E from LettersThread# 所有线程执行完毕print("所有线程执行完毕")

Python 线程池示例:同样地,多线程执行变成了串行执行。

importthreadingimporttimefromconcurrent.futuresimportThreadPoolExecutordefprint_numbers():"""打印数字"""foriinrange(5):print(f"Number:{i}from{threading.current_thread().name}")time.sleep(0.1)if__name__=="__main__":# 方法2: 使用线程池(推荐)withThreadPoolExecutor(max_workers=3)asexecutor:# 提交任务futures=[]foriinrange(5):future=executor.submit(print_numbers)futures.append(future)# 等待所有任务完成forfutureinfutures:future.result()

输出结果:从如下结果来看,也能看出是串行执行。。。

# 前面3个任务,使用3个线程,每个线程里循环输出5次,共15次Number:0fromThreadPoolExecutor-0_0 Number:0fromThreadPoolExecutor-0_1 Number:0fromThreadPoolExecutor-0_2 Number:1fromThreadPoolExecutor-0_0 Number:1fromThreadPoolExecutor-0_1 Number:1fromThreadPoolExecutor-0_2 Number:2fromThreadPoolExecutor-0_0 Number:2fromThreadPoolExecutor-0_2 Number:2fromThreadPoolExecutor-0_1 Number:3fromThreadPoolExecutor-0_0 Number:3fromThreadPoolExecutor-0_2 Number:3fromThreadPoolExecutor-0_1 Number:4fromThreadPoolExecutor-0_0 Number:4fromThreadPoolExecutor-0_1 Number:4fromThreadPoolExecutor-0_2# 最后还剩2个任务,只需要使用2个线程Number:0fromThreadPoolExecutor-0_0 Number:0fromThreadPoolExecutor-0_1 Number:1fromThreadPoolExecutor-0_0 Number:1fromThreadPoolExecutor-0_1 Number:2fromThreadPoolExecutor-0_0 Number:2fromThreadPoolExecutor-0_1 Number:3fromThreadPoolExecutor-0_0 Number:3fromThreadPoolExecutor-0_1 Number:4fromThreadPoolExecutor-0_0 Number:4fromThreadPoolExecutor-0_1

Python 互斥锁:加锁,使得某一时刻只有一个线程能拿到锁,能进行操作。

importthreadingif__name__=="__main__":"""线程同步:通过互斥锁Lock来保证多线程安全地修改同一个共享变量"""# 创建一把互斥锁lock=threading.Lock()# 共享变量shared_counter=0defincrement_counter():globalshared_counter# 通过with语句自动获取和释放锁,等同于lock.acquire()和lock.release()## 确保同一时刻只有一个线程可以执行临界区withlock:for_inrange(1000):shared_counter+=1# 创建多个线程修改共享变量threads=[]for_inrange(10):thread=threading.Thread(target=increment_counter)threads.append(thread)thread.start()forthreadinthreads:thread.join()print(f"最终计数器值:{shared_counter}")# 应该是10000

2、异步编程对比

Java 异步编程:异步提交任务,然后获取执行结果。

// Javaimportjava.util.concurrent.*;publicclassAsyncExample{publicstaticvoidmain(String[]args)throwsException{ExecutorServiceexecutor=Executors.newFixedThreadPool(2);CompletableFuture<String>future=CompletableFuture.supplyAsync(()->{try{Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}return"Hello";},executor).thenApply(result->{returnresult+" World";}).thenAccept(result->{System.out.println("Result: "+result);});future.get();// 等待完成executor.shutdown();}}

Python 异步编程:和 Java 很相似,使用 async + await 关键字实现。

# Python 异步编程importasyncioimportaiohttpasyncdeffetch_url(url:str)->str:"""异步获取URL内容 1、async def 定义了一个协程(coroutine)函数,它不会立即执行,而是返回一个协程对象。 这种函数可以在等待耗时(比如http请求)操作时,让出CPU,让其他任务执行。而不是像普通函数那样阻塞等待。 2、async with 是异步版本的上下文管理器,保证在进入和退出代码块时正确地初始化和关闭资源 3、async with session.get(url) 异步http请求,并非直接拿到响应体,而只是拿到响应头确认连接建立。 4、return await response.text() 这里await是异步编程的关键,它会让出CPU,让其他任务执行。 等下载完成后,在叫醒我,继续往下执行。 """asyncwithaiohttp.ClientSession()assession:asyncwithsession.get(url)asresponse:returnawaitresponse.text()asyncdefprocess_data(data:str)->dict:"""异步处理数据"""awaitasyncio.sleep(1)# 模拟耗时操作return{"length":len(data),"processed":True}asyncdefmain():"""主异步函数"""urls=["https://www.java.com","https://www.python.org"]# 创建任务tasks=[fetch_url(url)forurlinurls]# 并发执行任务## 异步任务并行执行,且出现异常时返回一个异常对象,而不是程序报错results=awaitasyncio.gather(*tasks,return_exceptions=True)# 处理结果forurl,resultinzip(urls,results):ifisinstance(result,Exception):print(f"Error fetching{url}:{result}")else:processed=awaitprocess_data(result)print(f"Processed{url}:{processed}")# 运行异步程序if__name__=="__main__":# 执行协程(coroutine)并获得结果asyncio.run(main())

七、Java 开发者常见陷阱

1、可变默认参数

Python 方法中默认参数值是可变的 => Default argument value is mutable。

也就意味着,如果你在参数默认值中定义一个列表,那么这个列表其实就是共享的!

# ❌ 错误做法:可变对象作为默认参数defbad_function(items=[]):# 默认列表在函数定义时创建,所有调用共享!items.append(1)returnitemsprint(bad_function())# [1]print(bad_function())# [1, 1] 不是预期的[1]!# ✅ 正确做法:使用None作为默认值defgood_function(items=None):ifitemsisNone:items=[]# 每次调用创建新列表items.append(1)returnitemsprint(good_function())# [1]print(good_function())# [1] 正确!

在 IDEA 中编写代码时,也会给出提示及修改后的代码。

2、相等性比较

Java 中 equals 判断内容是否相同,==判断是否是同一个对象。

Python 中 == 判断值是否相同,is 判断是不是同一个对象。【需注意,别弄反了】

# Python 陷阱2:相等比较## Python的 == 和 is 区别## ==判断值是否相等,is判断是否是同一对象## Java中equals判断是否相等,==判断是否是同一对象!a=[1,2,3]b=[1,2,3]c=aprint(a==b)# True - 值相等print(aisb)# False - 不是同一对象print(aisc)# True - 同一对象## 小整数缓存(类似Java Integer缓存)## CPython的小整数缓存范围[-5, 256]x=256y=256print(xisy)# True - Python缓存小整数x=257y=257print(xisy)# True - (编译器优化:同一代码块内的常量折叠)print(x==y)# True - 值相等# 绕过编译器优化,查看真实的内存行为x=257y=int("257")# 运行时生成,不被缓存print(xisy)# False - 这证明了257确实不在小整数缓存[-5, 256]范围内

3、循环变量作用域

Python 中没有块级作用域,编写代码时需注意。

# Python陷阱3:没有块级作用域funcs=[]foriinrange(3):# lambda捕获的是变量i,不是i的值funcs.append(lambda:print(f"value:{i}"))forfinfuncs:f()# 全部打印,value: 2# 解决方案1:使用默认参数funcs=[]foriinrange(3):funcs.append(lambdae=i:print(f"value:{e}"))forfinfuncs:f()# 解决方案2:创建闭包funcs=[]foriinrange(3):defmake_func(x):returnlambda:print(f"value:{x}")funcs.append(make_func(i))forfinfuncs:f()

4、浅拷贝与深拷贝

Python 中的浅拷贝、深拷贝与 Java 中的概念及含义类似。浅拷贝复制的是引用,深拷贝是完全复制对象。

特性浅拷贝 (copy)深拷贝 (deepcopy)
外层对象创建新对象创建新对象
内部元素引用原对象的元素递归复制原对象的元素
速度慢(需要递归)
内存占用
适用场景对象只有一层,或希望共享内部状态对象有多层嵌套,需要完全独立的数据副本

Python 示例代码:

importcopy# 浅拷贝original=[[1,2],[3,4]]shallow_copy=original.copy()original[0][0]=100print(original)# [[100, 2], [3, 4]]print(shallow_copy)# [[100, 2], [3, 4]] 也被修改了# 深拷贝deep_copy=copy.deepcopy(original)original[1][1]=100print(original)# [[100, 2], [3, 100]]print(deep_copy)# [[100, 2], [3, 4]]

八、实用工具对比

下面是 Java 与 Python 中常用的工具/框架的对比:

Java工具/概念Python对应说明/差异
构建工具Mavenpip + pyproject.tomlPython使用pyproject.toml定义项目
GradlePoetryPoetry是现代化的Python包管理工具
测试框架JUnitpytestpytest功能更丰富,语法更简洁
Mockitounittest.mockPython内置mock模块
日志记录Log4j/SLF4Jlogging模块Python标准库提供
Web框架Spring BootFastAPI/Django/FlaskFastAPI适合API,Django全功能
JAX-RSFastAPI/Flask
ORM框架HibernateSQLAlchemySQLAlchemy是Python的ORM标准
JPADjango ORM/SQLAlchemy
序列化Jackson/Gsonjson模块Python内置JSON支持
函数式编程Stream API生成器/列表推导式Python使用yield创建生成器
Optionaltyping.Optional类型提示,非运行时检查
文档生成Javadocdocstring + SphinxPython使用reStructuredText或Google风格
代码检查Checkstyle/PMDpylint/flake8Python有多种代码检查工具
打包部署JAR/WARWheel/DockerPython使用wheel包分发

九、Pythonic 编程风格

Pythonic 指的是遵循 Python 哲学和习惯的编程风格,强调简介清晰优雅高效

直接在 python 命令中输入import this即可看到 Python 哲学。

The Zen of Python, by Tim Peters 《Python 语言的核心哲学指南》 Beautiful is better than ugly. 代码美观性优先,强调清晰、简介和一致性,使代码易于理解和维护。 Explicit is better than implicit. 代码意图要明确表达,以免晦涩的逻辑或魔法操作。比如明确引用模块而非通配符引入。 Simple is better than complex. 优选直接、简单的方案,避免不必要的复杂性。比如使用列表推导式替代冗长的循环。 Complex is better than complicated. 如果问题本身很复杂,代码应该有组织的处理复杂性,而非杂乱无章。比如通过职责分离提升维护性。 Flat is better than nested. 减少代码嵌套,越扁平越好,使逻辑更清晰。比如提前返回简化条件嵌套。 Sparse is better than dense. 适当的代码间隔,避免紧凑拥挤。比如合理使用空行和空格。 Readability counts. 可读性至关重要。比如使用描述性命名和文档字符串。 Special cases aren't special enough to break the rules. 不要为特殊情况破坏代码一致性,应在规则内统一处理。比如使用异常捕获而非特殊返回值。 Although practicality beats purity. 实用性优于纯粹性,鼓励使用标准库避免重复造轮子。 Errors should never pass silently. 错误应该被明确处理,避免静默忽略。比如精准捕获异常而非使用空的except块。 Unless explicitly silenced. 仅在明确需要时忽略错误或警告,并指定作用范围和类型。 In the face of ambiguity, refuse the temptation to guess. 遇到不确定情况时,应明确处理而非猜测。比如要求调用者指定数据格式。 There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. 应该有一种且最好只有一种明显的方式来做这件事。不过,除非你是荷兰人(Python创始人),否则一开始可能不那么明显。 Now is better than never. Although never is often better than *right* now. 现在开始比永远不做好。尽管“永远不做”常常比“立马匆忙去做”更好。 If the implementation is hard to explain, it's a bad idea.If the implementation is easy to explain, it may be a good idea. 如果某个实现很难解释,那它很可能是个坏主意。如果某个实现易于解释,那它或许是个好主意。 Namespaces are one honking great idea -- let's do more of those! 命名空间是个绝妙的想法,让我们多多使用它吧!

简单来说,就是写出让人一眼就能看懂的代码充分利用 Python 的特性遵循社区约定和最佳实践保持代码简介而不失去表达力

1. 列表推导式替代循环

使用 Pythonic 的列表推导式替代传统的 Java 风格的循环。

# Java风格(非Pythonic)list=[]foriinrange(10):ifi%2==0:list.append(i*2)print(list)# Pythonic风格list=[i*2foriinrange(10)ifi%2==0]print(list)# 嵌套推导式matrix=[[1,2,3],[4,5,6],[7,8,9]]flattened=[numforrowinmatrixfornuminrow]print(flattened)

2. 使用生成器节省内存

生成器是惰性计算,更加节省内存。可以计算一部分,使用一部分,有点像流式调用。

# 1、列表推导式(立即计算,占用内容)squares_list=[x**2forxinrange(100000)]# 占用大量内存print(squares_list)# 2、生成器表达式(惰性计算,节省内存)squares_gen=(x**2forxinrange(100000))# 此时几乎不占内存,只保存了计算规则## ⚠️ 注意:调用 list() 会立即触发所有计算,并将结果全部加载到内存中!## 这会失去生成器节省内存的优势。## print(list(squares_gen))## ✅ 正确用法:直接遍历,用一个算一个,内存占用极低,类似于流式调用forvalinsquares_gen:# 这里演示只打印前几个,避免刷屏ifval>100:breakprint(val)# 3、生成器函数,def定义的函数中包含yield关键字defread_large_file(file_path:str):"""逐行读取大文件"""# 只要函数里有 yield,调用它就不会立刻执行,而是返回一个生成器对象!withopen(file_path,'r',encoding='utf-8')asfile:forlineinfile:# yield 相当于 "return and pause" (返回并暂停)# 1. 把值交出去# 2. 暂停函数执行,记住当前状态(比如读到第几行了)# 3. 等待下一次被唤醒(next()调用)yieldline.strip()# 使用生成器函数# 调用 read_large_file 时,并没有开始读文件,只是拿到了一个生成器forlineinread_large_file(file_path="large_file.txt"):# 每次循环,生成器恢复执行,直到遇到下一个 yieldprint(line)

3. 上下文管理器(替代try-finally)

Java 中有 try-with-resource 实现资源的自动关闭。Python 中也有上下文管理器,支持对资源进行获取及关闭。

# Java风格资源管理 try-with-resources# try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {# // 使用资源# }# Python上下文管理器(自动初始化和关闭资源)# with open("large_file.txt", "r", encoding="utf-8") as file:# content = file.read()# print(content)# 自定义上下文管理器fromcontextlibimportcontextmanager# 模拟资源获取函数defacquire_resource(name):print(f"资源 '{name}' 已获取")returnname# 模拟资源释放函数defrelease_resource(resource):print(f"资源 '{resource}' 已释放")@contextmanagerdefmanaged_resource(*args,**kwargs):# 初始化资源resource=acquire_resource(*args,**kwargs)try:# yield 前面是 __enter__ 逻辑yieldresourcefinally:# yield 后面是 __exit__ 逻辑(finally 确保即使报错也会执行)release_resource(resource)# 测试代码if__name__=='__main__':print("\n--- 自定义上下文管理器演示 ---")withmanaged_resource("TestDB")asdb:print(f"正在使用:{db}")print("Doing work...")

4. 使用枚举(Enum)

Java 中有枚举类。Python 同样支持枚举类。

# 从 enum 模块中导入 Enum 类,auto是一个辅助函数,用于自动分配枚举值fromenumimportEnum,auto# 定义枚举classColor(Enum):# auto() 会自动分配值,默认从 1 开始递增 (1, 2, 3...)# 当你不关心具体的值,只关心唯一性时非常有用RED=auto()GREEN=auto()YELLOW=auto()# 使用枚举defprocess_color(color:Color):ifcolor==Color.RED:print("Stop")elifcolor==Color.GREEN:print("Go")elifcolor==Color.YELLOW:print("Caution")else:raiseValueError(f"Invalid color:{color}")process_color(Color.GREEN)# 遍历枚举forcolorinColor:print(f"{color.name}:{color.value}")

十、wheel + pyproject.toml 案例

工具概述

🚀 pyproject.toml 是 Python 社区为了统一构建配置而推出的标准配置文件。用于替代散乱的setup.pyrequirements.txtsetup.cfgMANIFEST.ini等文件。

🚀 wheel 是 Python 的二进制分发格式包含预编译的扩展模块(如 C/C++扩展),编码用户安装时需要本地编辑器(如 gcc 或 Visual Studio)。

1️⃣ 设计目标:快速、可靠的安装,避免在目标机器上编译代码。

2️⃣ 支持跨平台兼容(Win、MacOS、Linux),每个 wheel 包都会有一个标签,说明是哪一个平台的。pip 安装时会自动选择与当前环境匹配的 wheel 安装,无需源码编译。

  • 示例:numpy-1.24.0-cp39-cp39-win_amd64.whl
  • 解读:cp39-cp39 表示适用于 CPython 3.9;win_amd64 表示适用的平台。

3️⃣ 为什么 wheel 比源码包更好?

特性源码包(**<font style="color:rgb(15, 17, 21);">.tar.gz</font>**Wheel 包(**<font style="color:rgb(15, 17, 21);">.whl</font>**
安装速度较慢(可能需要编译)极快(直接解压文件到 site-packages)
依赖编译器是(如果有 C 扩展)
跨平台可靠性依赖本地环境高(预编译针对特定平台)
元数据需执行<font style="color:rgb(15, 17, 21);">setup.py</font>读取包含在<font style="color:rgb(15, 17, 21);">.dist-info/</font>中,可直接读取

4️⃣ 如何使用?pip 安装是会自动选择 wheel

  • 方式 1(从 PyPI 安装):pip install 包名
  • 方式 2(本地 wheel 文件):pip install 路径/xxx.whl
  • 方式 3(强制使用源码包):pip install --no-binary 包名

案例

下面,创建一个非常简单 wheel + pyproject.toml 的案例。

目录结构如下:

编写 pyproject.toml 文件

# 定义构建工具 [build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta" # 定义项目元数据 [project] name = "my-math-lib" version = "0.1.0" description = "一个极简的数学计算包示例" readme = "README.md" requires-python = ">=3.8" authors = [ {name = "DemoUser", email = "demo@example.com"} ]

编写 my_math.py

defadd(a,b):returna+bdefsub(a,b):returna-bif__name__=="__main__":print(f"1 + 1 ={add(1,1)}")

编写 README.md

pyproject.toml中使用readme = "README.md"指定了 readme 文件。

# My Math Lib 这是一个用于演示 Wheel 打包的示例项目。

构建 Wheel 包

wheel_demo目录下运行以下命令。

1、安装构建工具

pipinstallbuild# Collecting build# Downloading build-1.3.0-py3-none-any.whl.metadata (5.6 kB)# Collecting packaging>=19.1 (from build)# Downloading packaging-25.0-py3-none-any.whl.metadata (3.3 kB)# Collecting pyproject_hooks (from build)# Downloading pyproject_hooks-1.2.0-py3-none-any.whl.metadata (1.3 kB)# Requirement already satisfied: colorama in d:\idea-workspace-python\helloworld\.venv\lib\site-packages (from build) (0.4.6)# Downloading build-1.3.0-py3-none-any.whl (23 kB)# Downloading packaging-25.0-py3-none-any.whl (66 kB)# Downloading pyproject_hooks-1.2.0-py3-none-any.whl (10 kB)# Installing collected packages: pyproject_hooks, packaging, build# Successfully installed build-1.3.0 packaging-25.0 pyproject_hooks-1.2.

2、开始构建

python -m build

3、查看结果

构建后,会在当前目录下产生一个 dist 目录,里面就是打好的包。

至此,Java 转换 Python 介绍完毕!🚀 只有一步一步代码敲过来,才能领会 Python 语言的魅力。

参考

1.https://docs.python.org/zh-cn/3.13/tutorial/index.html

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/29 12:35:18

FastDepth深度估计算法:从入门到实战的完整指南

FastDepth深度估计算法&#xff1a;从入门到实战的完整指南 【免费下载链接】fast-depth ICRA 2019 "FastDepth: Fast Monocular Depth Estimation on Embedded Systems" 项目地址: https://gitcode.com/gh_mirrors/fa/fast-depth FastDepth是一个专为嵌入式系…

作者头像 李华
网站建设 2026/1/29 14:53:41

揭秘腾讯混元3D-Part:从零掌握3D文件格式的实战指南

在3D内容创作的世界里&#xff0c;文件格式就像是不同语言之间的翻译器&#xff0c;而腾讯混元3D-Part正是那个精通多种"语言"的顶级翻译官。想要驾驭这个强大的3D部件生成与分割工具&#xff0c;首先需要理解它的文件格式支持体系&#xff0c;这是开启高效3D创作之旅…

作者头像 李华
网站建设 2026/2/3 11:19:57

Blender资源宝库:一站式掌握3D创作完整指南

Blender资源宝库&#xff1a;一站式掌握3D创作完整指南 【免费下载链接】awesome-blender &#x1fa90; A curated list of awesome Blender addons, tools, tutorials; and 3D resources for everyone. 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-blender …

作者头像 李华
网站建设 2026/2/2 16:33:42

Rust全栈开发新篇章:Loco框架与Tauri桌面应用实战指南

Rust全栈开发新篇章&#xff1a;Loco框架与Tauri桌面应用实战指南 【免费下载链接】loco &#x1f682; &#x1f980; The one-person framework for Rust for side-projects and startups 项目地址: https://gitcode.com/GitHub_Trending/lo/loco 在当今桌面应用开发领…

作者头像 李华
网站建设 2026/2/1 8:15:13

Granite Docling 258M:轻量化文档智能处理的技术突破

Granite Docling 258M&#xff1a;轻量化文档智能处理的技术突破 【免费下载链接】granite-docling-258M 项目地址: https://ai.gitcode.com/hf_mirrors/ibm-granite/granite-docling-258M 在数字化办公需求激增的当下&#xff0c;IBM Research推出的Granite Docling 2…

作者头像 李华
网站建设 2026/2/3 7:41:18

Ursa.Avalonia样式系统完整教程:构建专业级跨平台界面

Ursa.Avalonia样式系统完整教程&#xff1a;构建专业级跨平台界面 【免费下载链接】Ursa.Avalonia Ursa是一个用于开发Avalonia程序的控件库 项目地址: https://gitcode.com/IRIHI_Technology/Ursa.Avalonia 在现代企业级应用开发中&#xff0c;一套强大而灵活的样式系统…

作者头像 李华