专业编程基础技术教程

网站首页 > 基础教程 正文

5个Python 隐藏的功能,你知道吗

ccvgpt 2024-08-09 12:03:01 基础教程 10 ℃

1. 函数对象

python 中的所有内容都是从某个类实例化的对象。这也包括函数,但接受这个事实一开始往往会让人觉得有悖常理。

def add_subject(name, subject, subjects=[]):
    subjects.append(subject)
    return {'name': name, 'subjects': subjects}

add_subject('person1', 'subject1')
add_subject('person2', 'subject2')
add_subject('person3', 'subject3')


output - 
{'name': 'person1', 'subjects': ['subject1']}
{'name': 'person2', 'subjects': ['subject1', 'subject2']}
{'name': 'person3', 'subjects': ['subject1', 'subject2', 'subject3']}

Python 中的可变性可能是最容易被误解和忽视的概念之一。

5个Python 隐藏的功能,你知道吗

函数的默认参数在定义函数时立即计算。因此,一旦定义了函数,函数对象就会将默认参数存储在其 __defaults__ 属性中。

可以在下面验证这一点——

def my_functions(a=1, b=2, c=3):
    pass

print(my_functions.__defaults__)

output - (1, 2, 3)

因此,如果在函数中指定可变默认参数并对其进行更改,则会在不知不觉中无意中修改该参数,以便将来对该函数进行所有调用。

这在下面的演示中显示。Python 不会在每次函数调用时创建一个新列表,而是将元素附加到同一个副本中。

def add_subject(name, subject, subjects=[]):
    subjects.append(subject)
    return {'name': name, 'subjects': subjects}


print(add_subject.__defaults__)

add_subject('person1', 'subject1')
print(add_subject.__defaults__)

add_subject('person2', 'subject2')
print(add_subject.__defaults__)

add_subject('person3', 'subject3'))
print(add_subject.__defaults__)


Output - 
([],)
(['subject1'],)
(['subject1', 'subject2'],)
(['subject1', 'subject2', 'subject3'],)

如何避免

与其在函数的定义中指定可变的默认参数,不如将其替换为 None .如果函数在函数调用过程中未收到相应的值,请在函数内创建可变对象。

def add_subject(name, subject, subjects=None):
    if subjects is None:
        subjects = []

    subjects.append(subject)
    return {'name': name, 'subjects': subjects}

print(add_subject.__defaults__)
print(add_subject('person1', 'subject1'))
print(add_subject('person2', 'subject1'))
print(add_subject('person3', 'subject1'))


## Output - 
(None,)
{'name': 'person1', 'subjects': ['subject1']}
{'name': 'person2', 'subjects': ['subject1']}
{'name': 'person3', 'subjects': ['subject1']}

如上所示,如果函数在调用时未收到任何值,将创建一个新列表。这样可以避免发生更改同一对象的意外行为。

2. 使类对象的行为像一个函数

如果要使类对象可调用,即行为类似于函数,可以通过定义 __call__ 方法来实现。此方法允许定义对象在像函数一样被调用时的行为。

class Multiplier:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    def __call__(self, x):
        return (self.a * x**2) + (self.b * x**2) + (self.c * x**2)


func = Multiplier(2, 4, 6)
print(func(2))    # 48
print(func(4))    # 192
print(callable(func))    # True

这可能有很多优点。例如,它允许我们实现可以灵活直观地使用的对象。更重要的是,熟悉的函数调用语法有时可以使代码更具可读性。

它允许在需要可调用对象的上下文中使用类对象。例如,使用类作为装饰器。

3. 字符串法

在 Python 中, startswithendswith string 方法通常用于匹配字符串开头和结尾的子字符串。

places = ["India", "London", "Poland", "Netherlands"]
for place in places:
    if place.startswith('Lo') or place.startswith('Po'):
        print(place)

但是,是否知道也可以将多个子字符串作为元组传递给这些方法?

places = ["India", "London", "Poland", "Netherlands"]
for place in places:
    if place.startswith(('Lo', 'Po')):
        print(place)

这样可以防止在保留相同功能的同时编写多个条件。

4. 使用 Frozenset

Python 中的字典要求其键不可变。因此,集合不能用作键,因为它是可变的。

set_ex = {1, 2, 3}
dict_obj = {set_ex: "This is a Set"}

## Error - TypeError: unhashable type: 'set'

如果要使用集合,请考虑将其声明为 FrozenSet。

set_ex = frozenset({1, 2, 3})
dict_obj = {set_ex: "This is a Set"}

print(dict_obj[set_ex])

## Output - This is a Set

它是一个不可变的集合,这意味着它的元素在创建后无法更改。因此,它们可以安全地用作字典的键。

5. pickle文件

pickle广泛用于将数据对象转储到磁盘。但是人们通常只将单个对象转储到pickle文件中。此外,一个人创建多个pickle来存储多个对象。但是,可以在单个pickle文件中存储任意数量的对象?更重要的是,重新加载时,没有必要加载所有对象。

只需确保将对象转储到同一上下文管理器中(与一起使用)。

import pickle

a, b, c = 1, 2, 3

with open("data.pkl", "wb") as f:
    pickle.dump(a, f)
    pickle.dump(b, f)
    pickle.dump(c, f)
import pickle

with open("data.pkl", "rb") as f:
    a = pickle.load(f)
    b = pickle.load(f)

print(f"{a = } {b = }")

当然,一种解决方案是将对象存储为元组。但是在重新加载时,将加载整个元组。在某些情况下,这可能不是需要的。

最近发表
标签列表