当前位置: 首页 > news >正文

学习日志37 python

1 Python 和 Java 在类属性(静态属性)和实例属性的处理

题目

执行以下程序,输出结果为()
class Base(object):count = 0def __init__(self):pass
b1 = Base()
b2 = Base()
b1.count = b1.count + 1
print(b1.count,end=" ")
print(Base.count,end=" ")
print(b2.count)A 1 1 1
B 1 0 0
C 1 0 1
D 抛出异常正确答案:B

解析

在这个程序中,我们需要理解类属性和实例属性的区别:

  1. count = 0 是 Base 类的类属性,所有实例共享这个属性
  2. 当我们创建 b1 = Base() 和 b2 = Base() 时,它们最初都没有自己的 count 实例属性,会共享类的 count 属性

关键操作是 b1.count = b1.count + 1

  • 这行代码首先读取 b1.count,由于 b1 没有自己的 count 属性,会读取类属性 Base.count(值为 0)
  • 然后创建一个 b1 的实例属性 count,并赋值为 0 + 1 = 1

此时:

  • b1.count 访问的是 b1 自己的实例属性,值为 1
  • Base.count 访问的是类属性,仍然保持初始值 0
  • b2.count 访问的是类属性(因为 b2 没有自己的实例属性),值为 0

所以输出结果是 1 0 0,正确答案是 B。

【base不用先创造实例吗?】

在 Python 中,类属性(如 Base.count)属于类本身不需要先创建实例就可以直接访问。

类属性的特点:

  • 它是类级别的属性,不属于任何特定实例
  • 可以通过 类名.属性名 直接访问(如 Base.count
  • 所有实例在没有自己的同名实例属性时,都会共享这个类属性

在你提供的代码中:

  • count = 0 是 Base 类的类属性,定义后就存在了
  • 即使不创建 b1 和 b2 实例,也可以直接访问 Base.count(值为 0)

当创建实例后:

  • b1 和 b2 初始时没有自己的 count 属性,所以 b1.count 和 b2.count 会指向类属性 Base.count
  • 直到执行 b1.count = ... 时,才会给 b1 创建一个独立的实例属性 count,此时 b1.count 不再指向类属性

这就是为什么代码中可以直接访问 Base.count 而不需要先创建实例的原因。

【这个py和java的语法规则一样吗?】

不仅学混了还学忘了。

Python 和 Java 在类属性(静态属性)和实例属性的处理上有相似之处,但语法和细节实现细节存在差异,主要区别如下:

1. 类属性的定义与访问

  • Python
    直接在类中定义的变量就是类属性,无需特殊关键字,可通过 类名.属性名 或 实例.属性名(无同名实例属性时)访问。
    例:

    python

    运行

    class Base:count = 0  # 类属性print(Base.count)  # 直接通过类访问,无需实例化
    
  • Java
    类属性需要用 static 关键字声明,称为 “静态属性”,必须通过 类名.属性名 或 实例.属性名 访问(推荐用类名)。
    例:

    java

    运行

    class Base {static int count = 0;  // 静态属性(类属性)
    }public class Main {public static void main(String[] args) {System.out.println(Base.count);  // 直接通过类访问}
    }
    

2. 实例属性对类属性的遮蔽(Shadowing)

  • Python
    当实例定义与类属性同名的实例属性时,会自动 “遮蔽” 类属性(实例访问时优先用自己的属性,类访问仍用类属性)。
    例:

    python

    运行

    b1 = Base()
    b1.count = 1  # 给b1创建实例属性,遮蔽类属性
    print(b1.count)  # 1(实例属性)
    print(Base.count)  # 0(类属性不受影响)
    
  • Java
    实例不能定义与静态属性同名的实例属性(编译报错),避免混淆。
    若尝试定义:

    java

    运行

    class Base {static int count = 0;int count;  // 编译错误:与静态属性重名
    }
    

3. 核心区别总结

场景PythonJava
类属性声明直接定义(无关键字)必须用 static 关键字
类属性访问类名。属性 或 实例。属性(无同名实例属性)类名。属性 或 实例。属性(推荐类名访问)
实例与类属性重名允许(实例属性遮蔽类属性)不允许(编译报错)
类属性是否依赖实例化不依赖(类加载时就存在)不依赖(类加载时就存在)

回到原题

如果用 Java 实现类似逻辑,由于不允许实例属性与静态属性重名,b1.count = ... 这样的代码会直接编译报错。

但 Python 允许这种操作,因此两者行为不同。

简单说:语法规则不完全相同,核心差异体现在类属性的声明方式和实例属性与类属性的重名处理上

2 Python中or运算符的一个重要特性:它返回的是操作数本身,而不是布尔值。

Python 中的 or 运算符有一个重要特性:它返回的是第一个为 “真” 的操作数,而不是单纯的布尔值 True 或 False。如果所有操作数都为 “假”,则返回最后一个操作数。

这与许多其他编程语言中 or 仅返回布尔值的行为不同,在 Python 中,or 更像是 "返回第一个真值" 的运算符。

示例:

python

运行

# 返回第一个真值(非空字符串是真值)
print("hello" or 0)  # 输出: hello# 0是假值,返回第二个操作数
print(0 or "world")  # 输出: world# 所有都是假值,返回最后一个
print(0 or "" or None)  # 输出: None# 数字0是假值,非0数字是真值
print(0 or 42)  # 输出: 42# 空列表是假值,非空列表是真值
print([] or [1, 2, 3])  # 输出: [1, 2, 3]

这个特性在 Python 中非常实用,可以用来简洁地设置默认值,例如:

python

运行

def greet(name=None):# 如果name为None(假值),则使用"Guest"作为默认值name = name or "Guest"print(f"Hello, {name}!")greet()  # 输出: Hello, Guest!
greet("Alice")  # 输出: Hello, Alice!

理解这个特性有助于写出更简洁、更 Pythonic 的代码。

【和java一样吗?不一样!】

在 Java 中,|| 运算符(逻辑或)的行为与 Python 的 or 有本质区别:

Java 的 || 严格返回布尔值(true 或 false),不会返回操作数本身。它仅判断操作数的真假性,最终结果只能是布尔类型。

示例对比:

java

运行

// Java 中 || 返回布尔值
System.out.println("hello" || 0);  // 编译错误(操作数类型不兼容)
System.out.println(0 || 42);      // 编译错误(操作数必须是布尔类型)// 正确用法:操作数为布尔值,结果为布尔值
System.out.println(1 > 0 || 2 > 5);  // 输出 true
System.out.println(1 < 0 || 2 > 5);  // 输出 false

而 Python 的 or 如前所述,返回的是第一个为 "真" 的操作数本身(非布尔值),这是两种语言在设计上的明显差异。

简单说:

  • Java 的 || 是 "逻辑或判断",结果只能是 true/false
  • Python 的 or 是 "取第一个真值",结果是操作数本身

题目

下列Python3代码运行结果是( )
a = 'a'
print(a > 'b' or 'c')
A a
B b
C c
D True
E False正确答案:C

这道题考查的是 Python 中 or 运算符的特性 —— 它返回的是操作数本身,而不是布尔值,这与许多其他语言不同。

分析代码 print(a > 'b' or 'c')

  1. 首先计算 a > 'b',其中 a = 'a'。在 Python 中,字符串比较是基于字符的 Unicode 编码值,'a' 的编码值小于 'b',所以 a > 'b' 的结果为 False(假值)。
  2. 然后执行 or 运算。or 运算符的逻辑是:如果第一个操作数是真值,则返回第一个操作数;如果第一个操作数是假值,则返回第二个操作数。
  3. 由于 a > 'b' 的结果是 False(假值),所以 or 运算返回第二个操作数 'c'

因此,代码的输出结果是 c,正确答案是 C。

3 Python 中可以直接修改原字典的方法

  1. 直接赋值
    通过 dict[key] = value 为已有键设置新值,或添加新的键值对:

    python

    运行

    d = {"a": 1}
    d["a"] = 100  # 修改已有键
    d["b"] = 2    # 添加新键值对
    
  2. update()
    合并其他字典或键值对到原字典,重复键会被覆盖:

    python

    运行

    d = {"a": 1}
    d.update({"b": 2, "a": 10})  # 原字典变为 {"a": 10, "b": 2}
    
  3. pop(key[, default])
    删除指定键并返回其值,原字典尺寸减小:

    python

    运行

    d = {"a": 1, "b": 2}
    d.pop("a")  # 返回 1,原字典变为 {"b": 2}
    
  4. popitem()
    删除并返回字典中最后插入的键值对(Python 3.7+ 有序):

    python

    运行

    d = {"a": 1, "b": 2}
    d.popitem()  # 返回 ("b", 2),原字典变为 {"a": 1}
    
  5. clear()
    清空字典中所有键值对,原字典变为空:

    python

    运行

    d = {"a": 1}
    d.clear()  # 原字典变为 {}
    
  6. setdefault(key[, default])
    若键不存在,则添加键值对(key: default),原字典被修改:

    python

    运行

    d = {"a": 1}
    d.setdefault("b", 2)  # 原字典变为 {"a": 1, "b": 2}
    

  7. del 语句
    通过 del dict[key] 直接删除指定键:

    python

    运行

    d = {"a": 1}
    del d["a"]  # 原字典变为 {}
    

这些操作都会直接修改原字典本身,而非返回新字典。如果需要保持原字典不变,可先使用 copy() 方法创建副本后再操作。

4 正则表达式中字符集([])的用法

下面字符串中匹配正则的有?mstr = r"red hed ced ped"
regex = r"[^c|p]ed"
pattern = re.compile(regex)
print pattern.findall(mstr)A red
B hed
C ced
D ped正确答案:AB

首先看正则表达式:r"[^c|p]ed"

这里的关键是 [^c|p] 这个部分,我们拆开来理解:

  1. [] 表示 “字符集”,匹配其中任意一个字符
  2. ^ 放在字符集开头,表示 “取反”,即 “不匹配后面的字符”
  3. 所以 [^c|p] 的意思是:匹配一个 “既不是 c、也不是 |、也不是 p” 的字符
    (注意:| 在这里只是一个普通字符,不是 “或” 的意思,因为在字符集里|没有特殊含义)

再看被匹配的字符串:"red hed ced ped"

里面有 4 个以 ed 结尾的子串,我们逐个检查:

  1. red:前面的字符是 r
    r 既不是 c、也不是 |、也不是 p,符合 [^c|p],所以会被匹配。

  2. hed:前面的字符是 h
    h 既不是 c、也不是 |、也不是 p,符合 [^c|p],所以会被匹配。

  3. ced:前面的字符是 c
    c 是 [^c|p] 中明确排除的字符,不符合,所以不会被匹配。

  4. ped:前面的字符是 p
    p 也是 [^c|p] 中明确排除的字符,不符合,所以不会被匹配。

结论

符合正则表达式 r"[^c|p]ed" 的只有 red 和 hed,对应选项 A、B

补充说明

如果想表达 “不是 c 也不是 p”,正确的写法应该是 [^cp](去掉 |),因为 | 在字符集里是普通字符,会被当成 “需要排除的字符” 之一。原正则 [^c|p] 多排除了一个 |,但不影响这道题的结果(因为字符串里没有 |)。(看来是起到迷惑作用的)

理解字符集的 “取反” 逻辑是关键,多练习几个例子就会熟悉啦~

http://www.lryc.cn/news/624727.html

相关文章:

  • [优选算法专题二滑动窗口——水果成篮]
  • PyTorch数据处理工具箱(数据处理工具箱概述)
  • 【JavaEE】(16) Spring Boot 日志
  • C语言关于函数传参和返回值的一些想法
  • 《亚矩阵云手机重构出租接单:KVM 虚拟化与边缘计算驱动的设备替代技术路径》
  • Highcharts for Flutter 正式发布
  • SQL语法大全指南
  • 【Day 29 】Linux-数据库
  • 设计模式(四)——责任链模式
  • 福彩双色球第2025095期篮球号码分析
  • 19.8 《3步实现OPT-6.7B无损量化:用自定义数据集省70%显存,精度仅跌2.3%》
  • 终极方案!lightRag/graphRag离线使用tiktoken持续报错SSLError,不改源码,彻底解决!
  • 海洋牧场邂逅海洋旅游:碰撞出新业态的璀璨火花
  • 北斗安心联车辆管理系统优势分析
  • 飞机起落架轮轴深孔中间段电解扩孔内轮廓检测 - 激光频率梳 3D 轮廓检测
  • Conda技巧:修改Conda环境目录,节省系统盘空间
  • 【每天学点‘音视频’】前向纠错 和 漏包重传
  • vue从入门到精通:搭建第一个vue项目
  • 表格内容对比及标记
  • PLC无线组网实现多台RGV搬运机器人输送系统通讯案例
  • SSM从入门到实战:1.4 Spring Bean的生命周期管理
  • 【STM32】STM32H750 CubeMX 配置 USB CDC 虚拟串口笔记
  • ThinkPHP的安装运行和调试
  • MCP协议演进:从SSE到Streamable HTTP的技术革命
  • SAP ABAP IS SUPPLIED
  • 【语法糖】什么是语法糖
  • Java+Vue构建资产设备管理系统,适配移动端与后台管理,实现全生命周期管理,涵盖采购、入库、使用、维护、报废等环节,提供完整源码,便于二次开发
  • 快速搭建项目(若依)
  • CentOS 7 LAMP快速部署WordPress指南
  • linux中的hostpath卷、nfs卷以及静态持久卷的区别