当前位置:首页>python>Python 函数进阶:property、/ * 分隔符、any/all...你都会吗?

Python 函数进阶:property、/ * 分隔符、any/all...你都会吗?

  • 2026-10-11 07:48:13
Python 函数进阶:property、/ * 分隔符、any/all...你都会吗?
函数写得好不好,是区分新手和老手的重要标志。这 5 个函数技巧,每个都来自真实项目的实战经验。

1. 用 property 装饰器实现属性访问控制

看起来没问题,但其实有更好的方式:

class Circle:    def __init__(self, radius):        self._radius = radius    def get_radius(self):        return self._radius    def set_radius(self, value):        if value < 0:            raise ValueError        self._radius = value

换个思路,问题迎刃而解:

import mathclass Circle:    def __init__(self, radius):        self.radius = radius  # 触发 setter    @property    def radius(self):        return self._radius    @radius.setter    def radius(self, value):        if value < 0:            raise ValueError('Radius must be non-negative')        self._radius = value    @property    def area(self):        return math.pi * self._radius ** 2c = Circle(5)print(c.area)  # 78.54 (像属性一样访问)

property 装饰器让方法像属性一样访问,在赋值时自动校验,在读取时计算派生值。Pythonic 的方式不是写 get/set 方法,而是用 property。


2. 函数参数中的 / 和 * 分隔符

搜一下 Stack Overflow,排第一的答案通常长这样:

def greet(name, greeting='Hello'):    # 调用者可能写 greet(greeting='Hi', name='Bob')    # 但你想强制 name 只能按位置传    print(f'{greeting}, {name}!')

其实标准库早就有答案了:

def greet(name, /, *, greeting='Hello'):    print(f'{greeting}, {name}!')greet('Alice')              # OKgreet('Bob', greeting='Hi') # OK# greet(name='Alice')       # TypeError! name 只能按位置传# greet('Alice', 'Hi')      # TypeError! greeting 只能用关键字

/ 之前的参数只能按位置传,* 之后的只能用关键字传。这样可以防止调用者依赖参数名(方便以后重命名),同时强制某些参数必须显式命名。


3. 用 lambda 创建匿名函数

看起来没问题,但其实有更好的方式:

def square(x):    return x ** 2numbers = [1, 2, 3, 4, 5]result = list(map(square, numbers))

换个思路,问题迎刃而解:

numbers = [1, 2, 3, 4, 5]result = list(map(lambda x: x ** 2, numbers))print(result)  # [1, 4, 9, 16, 25]# 更 Pythonic: 用列表推导式result = [x ** 2 for x in numbers]

lambda 适合简单的一行函数,常与 map/filter/sorted 配合。但如果逻辑复杂或需要复用,应该定义具名函数。列表推导式通常比 map+lambda 更清晰。


4. 用 any/all 简化条件判断

包括我自己,一开始也是这么干的:

numbers = [2, 4, 6, 8, 10]all_even = Truefor n in numbers:    if n % 2 != 0:        all_even = False        break

换个思路,问题迎刃而解:

numbers = [2, 4, 6, 8, 10]print(all(n % 2 == 0 for n in numbers))  # True - 全部为偶数print(any(n > 8 for n in numbers))       # True - 存在大于8的print(any(n < 0 for n in numbers))       # False - 不存在负数

all() 检查所有元素是否为真,any() 检查是否存在真元素。配合生成器表达式,一行代码替代循环+标志变量,而且支持短路求值。


5. 用 *args 和 **kwargs 接收可变参数

刚学 Python 的时候我这么写过:

def log(level, msg, user=None, action=None):    # 每增加一个字段就要改函数签名    print(f'[{level}] {msg} user={user} action={action}')

其实标准库早就有答案了:

def log(level, msg, **context):    details = ' '.join(f'{k}={v}' for k, v in context.items())    print(f'[{level}] {msg}{details}')log('INFO', 'User login', user='Alice', ip='1.2.3.4')

*args 收集位置参数为元组,**kwargs 收集关键字参数为字典。让函数签名更灵活,新增字段无需修改函数定义,常用于日志、装饰器等场景。


速查表

场景别这样写试试这样
属性访问控制get_radius() / set_radius()@property 装饰器
强制位置/关键字参数参数顺序靠约定/ 和 * 分隔符
匿名函数def square(x): return x**2lambda x: x**2
全部/任一判断for 循环 + 标志变量all() / any()
可变参数逐个写 param=None**kwargs

以上就是函数技巧的 5 个实用技巧,每个都是我在实际项目中踩过坑才总结出来的。挑一个今天就用上,慢慢积累,你的代码质量会肉眼可见地提升。

评论区聊聊:这 5 个技巧里哪个你之前不知道?

下期预告:内置模块专场


关于作者

写了 10 年 Python,赶上了机器学习的热潮,又撞上了大模型的浪头,每次以为学明白了,行业又变了一次。把自己踩过的坑、走过的弯路、看过的热闹,说给还在路上的人听。

关注「鲁叶的Python」,一起穿越迷茫期。

最新文章

随机文章