Python中的语法糖介绍


语法糖(syntactic sugar)是指一种语法形式,它并不影响语言的功能,但使得代码更加易读、简洁和优雅。在Python编程中使用Python语法糖,可提高代码可读性和编写效率,使得代码更加精炼清晰,减少冗余和复杂性。

1. 魔法方法(magic methods)

python中的魔法方法是以双下划线开头和结尾的特殊方法,例如 initstr。这些方法在对象生命周期的不同阶段或特定操作中被自动调用,从而允许编程时自定义对象的行为。

基础魔法方法

  • __init__(self, ...): 初始化对象,在创建实例时调用。
  • __del__(self): 对象销毁时调用,用于释放资源。
  • __call__(self):允许一个类的实例像函数一样被调用。

属性相关的魔法方法

属性相关的魔法方法主要用于定义对象的属性访问行为。这些魔法方法可以让你定制属性的读取、赋值、删除等操作。

  • __getattribute__(self, name): 当访问对象的属性时调用, 用于定制所有属性的访问行为。
  • __getattr__(self, name): 在访问不存在的属性时调用。通常用于提供默认值或触发特定的行为。
  • __setattr__(self, name, value): 在给对象的属性赋值时调用。用于定制属性赋值的行为。
  • __delattr__(self, name): 在删除对象的属性时调用。用于定制属性删除的行为。
  • __dir__(self):在调用 dir(obj) 时调用。用于定制对象的属性列表,返回实例所拥有的属性和方法。

2. 装饰器(decorators)

装饰器是一种通过包装目标函数来修改器其行为的特殊高阶函数,输入的参数是被装饰的函数。
装饰器可能对输入的函数做某些处理,返回的结果可能是1)被装饰的函数;2)另一函数;3)可调用对象。大部分装饰器是利用函数的闭包原理实现的。

内置装饰器

@property:让方法变为虚拟属性

@property属性装饰器提供了一种让类方法变为虚拟属性的实现方式,利用属性装饰器,可实现基于方法定义类属性,控制属性的读取、赋值、删除等行为。

定义一个鸭子类:

class Duck:
    def __init__(self,color):
        self.color = color
    def quack(self):
        print(f"hi,this is a {self.color} duck")

调用quack方法时,需要实例化对象.方法名()的形式:

d = Duck('red')
d.quack() # hi,this is a red duck

@property则可让被装饰的类方法通过属性的方式调用:

class Duck:
    def __init__(self,color):
        self.color = color
    @property
    def quack(self):
        print(f"hi,this is a {self.color} duck")
# 用类属性的方式访问
d.quack # hi,this is a red duck

@property还支持自定义属性赋值(setter)和删除(deleter):

class Duck:
    def __init__(self,color):
        self.color = color
    @property
    def quack(self):
        print(f"hi,this is a {self.color} duck")
    @quack.setter
    def quack(self,new_color):
        self.color = self.color + "&" + new_color
    @quack.deleter
    def quack(self):
        raise RuntimeError("can not this cute duck!")

@quack.setter这段代码的作用是,设置给quack赋值时,改变Duck的color属性:

d = Duck('red')
d.color # 'red'
d.quack = 'blue' # 把quack当做属性赋值,相当于quack(new_color='blue')
d.color # 'red&blue'

@quack.deleter这段代码则设置了在删除quack方法时,抛出错误:

d = Duck('red')
del d.quack # RuntimeError: can not this cute duck!
@classmenthod:定义类方法

装饰器 @classmenthod用于定义类方法。类方法是绑定到类而不是实例的方法,可以通过类名或实例名调用。在类方法中,第一个参数通常被命名为 cls,表示类本身。使用 @classmethod 装饰器来定义类方法,可以使得在调用该方法时,类会被作为第一个参数传递给方法。这对于在方法中访问类级别的属性或执行与类相关的操作非常有用。
@classmenthod装饰的类方法可以通过类名直接调用:

class Duck:
    def __init__(self,color):
        self.color = color
    def quack(self):
        print(f"hi,this is a {self.color} duck")
    @classmethod
    def create_random(cls):
        import random
        color = random.choice(['yellow','white','green'])
        cls.color=color # 给类的color属性赋值
        print(f"Class variable: {cls.color}")
        return cls(color=color)
# 通过类名直接调用类方法
Duck.create_random() # Class variable: yellow
# <__main__.Duck at 0x2856afd2a58>

类方法也可以通过实例调用:

d = Duck('red')
d.create_random()
# Class variable: yellow
# <__main__.Duck at 0x28508003cc0>
@staticmethod: 定义静态方法

若类中某个方法不需要使用当前实例里的任何内容,可以用@staticmethod将该方法装饰为静态方法。
静态方法不接受当前实例作为第一个位置参数,即方法的输入可以没有self参数。
如下面的例子中定义get_name为静态方法,随机生成鸭子的名字:

class Duck:
    def __init__(self,color):
        self.color = color
    def quack(self):
        print(f"hi,this is a {self.color} duck")
    @staticmethod
    def get_name(): # get_name设为静态方法,不需要self参数
        import random
        repeats = random.randrange(1,10)
        return ' '.join(['keda']*repeats)

输出结果为:

d = Duck('red')

# @staticmethod装饰后
d.get_name() # 'keda keda keda keda keda keda keda keda'

若get_name不使用@staticmethod装饰,则会抛出类型错误:

# 缺少self
d.get_name() # TypeError: get_name() takes 0 positional arguments but 1 was given

functools中的装饰器

functools 模块提供了一些用于创建和操作装饰器的函数,常用的包括wrap、lru_cache等。

functools wraps: 保留元数据

wraps 装饰器位于 functools 模块中,用于修饰其他装饰器函数。它的作用是将原始函数的元信息(如文档字符串、函数名)复制到装饰器函数,从而保留原函数的特性。
在装饰器包装目标函数的过程中,常会出现一些副作用,如丢失函数元数据:


from functools import wraps
def my_decorator(func):
    """this is my_decorator __doc__"""
    def wrapper(*args,**kwargs):
        """this is wrapper __doc__"""
        print(f"this is wrapper method")
        print(f"Calling {func.__name__}")
        res = func(*args,**kwargs)
        print(f"{func.__name__} returned {res}")
        return func(*args,**kwargs)
    return wrapper

@my_decorator
def example_func():
    """this is example_func __doc__"""
    print(f"Executing the example function")
    return 1

result = example_func()
print(f"func name:{example_func.__name__}") # func name:wrapper
print(f"docstring:{example_func.__doc__}") # docstring:this is wrapper __doc__

使用@wraps装饰器则可解决元数据丢失的问题:


from functools import wraps
def my_decorator(func):
    """this is my_decorator __doc__"""
    @wraps(func)
    def wrapper(*args,**kwargs):
        """this is wrapper __doc__"""
        print(f"this is wrapper method")
        print(f"Calling {func.__name__}")
        res = func(*args,**kwargs)
        print(f"{func.__name__} returned {res}")
        return func(*args,**kwargs)
    return wrapper

@my_decorator
def example_func():
    """this is example_func __doc__"""
    print(f"Executing the example function")
    return 1

result = example_func()
print(f"func name:{example_func.__name__}") # func name:example_func
print(f"docstring:{example_func.__doc__}") # docstring:this is example_func __doc__


functools lru_cache: 缓存计算结果

functools 模块中的 lru_cache 装饰器用于实现缓存,可以有效地提高函数的执行速度,特别是对于需要消耗较多计算资源的函数。
使用lru_cache 装饰器时可传入可选的maxsize参数(默认值为128),表示当前函数最多保存的缓存结果的数量。当缓存结果数超过maxsize后,程序会基于最近最少使用算法丢弃旧缓存,释放内存。
下面给出一个在计算斐波那契数列中使用LRU缓存机制的例子:

from functools import lru_cache
@lru_cache(maxsize=3)
def fibonacci(n):
    if n<=1:
        return n
    return fibonacci(n-1)+fibonacci(n-2)
fibonacci(6)

3. 推导式(comprehension)

列表推导式(list comprehension)

[x for x in range(8)] # [0, 1, 2, 3, 4, 5, 6, 7]

字典推导式(dict comprehension)

d={'a':1,'b':2,'c':3}
{k:v for k,v in d.items()} # {'a': 1, 'b': 2, 'c': 3}

生成器推导式(generator comprehension)

gen = (x**2 for x in range(8))
gen # <generator object <genexpr> at 0x00000285082342B0>
print(next(gen)) # 0
print(gen.__next__()) # 1

4. 上下文管理器

使用类来定义上下文管理器,只需在类中实现__enter____exit__魔法方法。__exit__接收三个参数,exc_type表示异常的类型,exc_value表示异常对象,traceback表示错误的堆栈对象。

class MyContextManager:
    def __enter__(self):
        print("Entering the context")
        return 'Resource'

    def __exit__(self,exc_type,exc_value,traceback):
        print("Exiting the context")

with MyContextManager() as resource:
    print("Inside the context, using resource: {resource}")
# Entering the context
# Inside the context, using resource: {resource}
# Exiting the context

其中__enter__方法返回被管理的资源,而__exit__方法在退出代码块时被调用。

5. 海象运算符

海象运算符(walrus operator)在python3,8版本中引入,赋值表达式使用海象运算符(:=)在单个表达式中同时对变量名进行赋值和计算,从而减少重复。当赋值表达式是一个较大表达式的子表达式时,必须用圆括号括起来。
海象表达式的语法形式是:

variable_name := expression

使用海象表达式可简化if-else、while语句等写法。

a = 6
if a>5:
    print("do something")
# 使用海象表达式可简化代码为:
if a := 6 > 5:
    print("do something")

6. 比较运算符

在其他语言中,小于和大于比较运算需要分开来表示,但在python中可以连写:

x,a,b = 4,3,6
if a<x<b:
    print(x)

7. 数字的下划线写法

python中数字的下划线写法(Underscores in Numeric Literals)即使用下划线 _ 来分割大数字,是一种数字字面量的可读性改进,这个特性的引入旨在使长数字更易读,可以帮助人们更容易地理解数字的大小,而不会影响数字的实际值。

big_number = 6_666_000_000 # 大数用_分隔符表示更直观易读
print(big_number+1) # 等于6666000001

8. 匿名函数

使用lambda关键字可以定义匿名函数;

multi = lambda x,y : x*y
multi(3,4) # 调用匿名函数

函数在Python中是一等对象,因此函数自身也可以作为函数参数来使用,如内置排序函数sorted函数的用法:

l = [2,4,6,9,1,3]
sorted(l,key=lambda i:i % 3)

参考资料

《Python工匠:案例、技巧与工程实践》
《Python Cookbook》
《Fluent Python》
《The-Kaggle-Book》:https://github.com/PacktPublishing/The-Kaggle-Book
Syntactic Sugar in Python:https://medium.com/analytics-vidhya/syntactic-sugar-in-python-3e61d1ef2bbf

  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值