你应该知道的 9 个高级 Python 概念

Python 是一种通用编程语言,因其可读性、面向对象的特性和强大的社区支持而广受欢迎。除了用于 Web 应用程序之外,Python 还用于数据科学、人工智能、科学计算等各个领域。

因此,如果你一直在考虑进入编程领域并寻找一种通用语言,那么 Python 可能适合你。在本文中将分享一些高级 Python 概念,这些概念将帮助您在扎根的同时取得成功。阅读本文可以不必是经验丰富的 Python 程序员;它只会帮助你更好地理解语言并使你成为更好的Python开发人员。

推导式

推导式分为三种类型:列表推导、字典推导和集合推导。如果您想从现有的可迭代对象中创建新的列表、字典或集合,请使用推导式。以下代码片段展示了这些用法

# 创建一个用于推导式的列表
numbers = [1, 2, 3, -3, -2, -1]
# 创建一个包含这些数字的方格的新列表
mylist = [x*x for x in numbers][1, 4, 9, 9, 4, 1]
# 为这些数字的幂创建一个新字典
mydict = {x: pow(10, x) for x in numbers} 
# 输出 {1: 10, 2: 100, 3: 1000, -3: 0.001, -2: 0.01, -1: 0.1}
# 创建一组这些数字的绝对值
myset = {abs(x) for x in numbers} 
# 输出 {1, 2, 3}

这些推导具有相似的语法。以下是对不同形式的简要概述。值得注意的是可以设置条件以确保保留所需的元素

列表推导: [expr for x in iterable]
字典推导: {key_expr: value_expr for x in iterable}
集合推导: {expr for x in iterable}
可选条件:
[expr for x in iterable if condition] 
{key_expr: value_expr for x in iterable if condition} 
{expr for x in iterable if condition}

异常处理

异常是在程序执行期间出现并导致程序中断的情况。它可能由各种原因而发生。假设正在构建一个除法程序,并且分母包含 0,从而导致 ZeroDivisionError。导入不存在的库或访问不在列表索引中的元素是另外两个实例。Python 带有大约 30 个内置异常。

tryexcept块用于处理python中的异常。except当我们需要同时处理多个异常时,我们可以使用多个块。

try块是要执行的指令。except块包含执行try失败时执行的代码。还有elsefinally块。else块仅在try成功执行块时执行。finally无论前一个块的结果如何,finally块将始终执行。

try:
    a = int(input("Enter numerator:")
    b = int(input("Enter denominator:")
    c = a / b
    print(c)
except ZeroDivisionError as e:
    print(e, " please provide a non zero denominator")
import sys
try:
   f = open('myfile.txt') 
   s = f.readline()
   i = int(s.strip())
except OSError as err:
   print("OS error: {0}".format(err))
except ValueError:
   print("Could not convert data to an integer.")
except:
   print("Unexpected error:", sys.exc_info()[0])
   raise
finally:
   print("Operation Successfully Done!!")(Example Taken From Official Python Docs)


集合库

将可迭代对象作为输入并返回一个字典,其中键是可迭代元素,值是它们各自在原始可迭代对象中出现的次数。

from collections import Counter
data = [1,1,1,1,2,3,4,3,3,5,6,7,7]
count = Counter(data)
print(count)

## Counter({1: 4, 3: 3, 7: 2, 2: 1, 4: 1, 5: 1, 6: 1})

生成可以使用名字来访问元素内容的tuple子类,命名元组赋予每个位置一个含义,提供可读性和自文档性。

from collections import namedtuple
Direction = namedtuple('Direction','N,S,E,W')
dt = Direction(4,74,0,0)
print(dt)

# Direction(N=4, S=74, E=0, W=0)

这是一个记忆键插入顺序的字典结构。最新版本的 python 中字典已经包含了这个特性。

from collections import OrderedDict
dictt = OrderedDict()
dictt['a'] = 5
dictt['d'] = 2
dictt['c'] = 1
dictt['b'] = 3
print(dictt)

# OrderedDict([('a', 5), ('d', 2), ('c', 1), ('b', 3)])

这是一个字典结构,当访问结构中不存在的键时将返回默认值,而不是引发错误。

from collections import defaultdict 
dictt = defaultdict(int) 
dictt['a'] = 2 
print(dictt['a']) ##返回值
print(dictt['b']) ##返回默认值

# 2 
# 0

双端队列,可以快速的从另外一侧追加和推出对象,deque是一个双向链表,针对list连续的数据结构插入和删除进行优化。它提供了两端都可以操作的序列,这表示在序列的前后你都可以执行添加或删除操作。

from collections import deque
d = deque('abc')  
d.append('d') 
print(d)
# deque(['a', 'b', 'c', 'd'])

# appendleft 添加元素到左端
d.appendleft('e')
print(d)
# deque(['e','a', 'b', 'c', 'd'])

# clear 清除所有元素
d.clear()
print(d)
# deque([])

还有一些经常用的方法比如pop,copy,count,extend,index,insert,popleft,remove,reverse,maxlen

迭代工具

Python itertools 模块提供了适用于迭代器的各种函数

装饰器

装饰器是 Python 中修改函数和类行为的一种方式。它们允许您通过添加方法或更改参数来更改功能,或通过添加属性来更改类。装饰器函数@在函数名之前有一个,具体我有文章详细说明了装饰器感兴趣可以看一下:

例如,如果想在每次调用“my_function”函数时记录日志,可以这样编写代码:

def logging_func(original_func):
    def wrapper(*args, **kwargs):
        print(f"Called {original_func.__name__} with", args, kwargs)
        return original_func(*args, **kwargs)
    return wrapper
@logging_func
def add(a, b):
    return a + b
result = add(5, 6)
print(result)

让我们解释上面的装饰器的例子——首先,我们有一个函数名add,它的工作是获取两个变量并返回它们的总和。现在经过一段时间的工作,我们意识到需要将功能记录到相同的函数中。现在我们有两个选择,第一个是在同一个add函数中添加函数调用日志代码,或者我们可以使用装饰器添加功能而不显式更改函数。为了使用装饰器,我们首先定义了一个装饰器函数。该函数original_func作为输入。然后,我们有另一个功能。它是一个具有*args, **kwargs函数参数的包装函数。有了这些,现在都定义为参数,我们可以在函数内传递任意数量的参数。在包装函数的主体中,我们有日志功能的逻辑。当我们add使用一些参数调用函数时add(5,6),输出将是:

生成器

生成器是一个返回可迭代值序列的函数。与一次返回所有元素并消耗整个列表长度的内存的列表不同,生成器会一个一个地生成项目。它至少包含一个yield声明。yield是python中的一个关键字,用于从函数返回值而不破坏其当前状态或对局部变量的引用。带有yield关键字的函数称为生成器,比如最经典的面试题斐波那契数列

def fibon(limit):
  a,b = 0,1
  while a < limit:
      yield a
      a, b = b, a + bfor x in fibon(10):
   print (x)

魔术方法

Magic方法,__方法名前后有两个下划线。在某个动作上,这些方法直接从类中调用。当使用*a 符号将两个数字相乘时,将__mul__调用内部过程。

num =  5
num*6
>> 30
num.__mul__(6)
>>30

通常,这些方法用于重载预定义的运算符。例如,数字运算符+,-,*,/必须在数字对象周围使用,但+也可以用于连接两个字符串。因此,我们可能会争辩说,+操作符在执行字符串连接消耗的内存大。

5+6
>>11
"python"+"programming"
>> 'pythonprogramming'

哈希性

在学习 Python 字典时,我们了解到键必须是可散列的。可哈希是什么意思?Hashable 基本上表示一个 Python 对象可以被散列,也就是散列的行为。下图描述了散列的工作流程。

散列是使用散列函数(也称为散列器)(在图中称为散列)将 Python 对象(在图中称为键)转换为数字散列值的过程。使用内置的 hash() 方法来获取 Python 对象的哈希值是一种判断它是否存在的简单方法。如果对象不可散列,Python 将抛出 TypeError 异常。

# Get an string object’s hash value
hash("This is me")
5361907397716593195
 
# Get a tuple object’s hash value
hash((1,2))
-3550055125485641917
 
# Get a list object’s hash value
hash([1, 2, 3])
Traceback (most recent call last):
 File “”, line 1, in 
TypeError: unhashable type: ‘list’
 
# Get a dict object’s hash value
hash({“a”: 1, “b”: 2})
Traceback (most recent call last):
 File “”, line 1, in 
TypeError: unhashable type: ‘dict’

特别是散列需要时间,并且比构造列表和元组要慢。那么,为什么我们首先要费心使用散列创建字典呢?在类似的问题上,你可能听说过设置项也必须是可散列的。字典和集合都需要在底层创建哈希表。以下代码片段演示了特定对象的哈希性如何影响它们作为字典键的适用性。哈希最显着的好处是它们在检索字典元素时提供即时查找时间(即 O(1) 时间复杂度)。检查特定项目是否在集合中需要相同的时间。换句话说,使用散列作为实现机制减少了在后台使用散列表的开销,同时提高了一些常见操作(如项目检索、项目插入和项目验证)的效率。

import random
import timeit
# Create a function to check the look up time
def dict_look_up_time(n):
    numbers = list(range(n))
    random.shuffle(numbers)
    d0 = {x: str(x) for x in numbers}
    random_int = random.randint(0, n — 1)
    t0 = timeit.timeit(lambda: d0[random_int], number=10000)
    return t0
for n in (10, 100, 1000, 10000, 100000):
    elapse_time = dict_look_up_time(n)
    print(f”*** N = {n:<8}: {elapse_time:.5f}”)
*** N = 10 : 0.00114
*** N = 100 : 0.00256
*** N = 1000 : 0.00291
*** N = 10000 : 0.00207
*** N = 100000 : 0.00286

上面的代码生成一些随机整数来确定项目获取的平均查找时间,来模拟真实情况。如你所见,即使字典中有 100,000 个条目,查找时间也几乎相同,这证明了使用哈希表作为字典存储机制的好处。

线程和多处理

线程和多处理是同时运行多个脚本的两种方法。线程是进程中的一个实体,进程是程序的一个实例。

多处理是一种技术,其中许多进程同时在不同的 CPU 上运行。线程是一种技术,其中许多线程同时运行以完成不同的任务。让我们看一个线程可能派上用场的例子。假设你有一个需要时间才能完成的函数,并且需要使用不同的参数一次又一次地执行它。你可以使用线程通过使用不同参数并行执行函数来加快此过程。当你想将相同类型的代码用于重复性任务(例如,处理多个图像)时,多处理可能会派上用场。你可以使用多处理,以便同时使用所有处理器,而不是在单个处理器上运行此任务。具体我有文章详细的说明了Python多线程的使用方法及一些案例,如果感兴趣请阅读:

希望给你带来帮助,Happy Code!

展开阅读全文

页面更新:2024-03-27

标签:线程   字典   函数   元素   异常   对象   概念   参数   高级   代码   时间   列表

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top