python is cool

2025-12-11 0 578

python-is-cool

我不知道存在或太害怕使用的Python功能的温和指南。随着我学到的更多信息和变得不那么懒惰,这将被更新。

这使用python> = 3.6。

GitHub在渲染Jupyter笔记本上有问题,因此我在此处复制了内容。我仍然保留笔记本,以防您要克隆并在计算机上运行它,但是也可以单击下面活页夹徽章并将其运行在浏览器中。

1。lambda,地图,过滤,减少

Lambda关键字用于创建内联函数。下面的functionsSquare_fnsquare_ld是相同的。

 def square_fn ( x ):
    return x * x

square_ld = lambda x : x * x

for i in range ( 10 ):
    assert square_fn ( i ) == square_ld ( i )

它的快速声明使lambda函数非常适合在回调中使用,并且何时将功能作为参数传递给其他函数。与MAP,过滤和减少等功能结合使用时,它们特别有用。

MAP(FN,ITOBLE)将FN应用于峰值的所有元素(例如,set,set,dictionary,tuple,string),并返回映射对象。

 nums = [ 1 / 3 , 333 / 7 , 2323 / 2230 , 40 / 34 , 2 / 3 ]
nums_squared = [ num * num for num in nums ]
print ( nums_squared )

== > [ 0.1111111 , 2263.04081632 , 1.085147 , 1.384083 , 0.44444444 ]

这与使用带有回调函数的MAP调用相同。

 nums_squared_1 = map ( square_fn , nums )
nums_squared_2 = map ( lambda x : x * x , nums )
print ( list ( nums_squared_1 ))

== > [ 0.1111111 , 2263.04081632 , 1.085147 , 1.384083 , 0.44444444 ]

您还可以使用多个峰值的地图。例如,如果要计算带有真正标签标签的简单线性函数f(x)= ax + b的平方平方误差,这两种方法是等效的:

 a , b = 3 , - 0.5
xs = [ 2 , 3 , 4 , 5 ]
labels = [ 6.4 , 8.9 , 10.9 , 15.3 ]

# Method 1: using a loop
errors = []
for i , x in enumerate ( xs ):
    errors . append (( a * x + b - labels [ i ]) ** 2 )
result1 = sum ( errors ) ** 0.5 / len ( xs )

# Method 2: using map
diffs = map ( lambda x , y : ( a * x + b - y ) ** 2 , xs , labels )
result2 = sum ( diffs ) ** 0.5 / len ( xs )

print ( result1 , result2 )

== > 0.35089172119045514 0.35089172119045514

请注意,映射和过滤器返回的对象是迭代器,这意味着其值未存储,而是根据需要生成。打电话给sum(差异)后,差异变为空。如果要将所有元素保留在差异中,请使用列表(diffs)将其转换为列表。

滤波器(fn,iToble)的工作方式与映射相同,只是fn返回布尔值和滤波器返回FN返回true的所有元素的所有元素。

 bad_preds = filter ( lambda x : x > 0.5 , errors )
print ( list ( bad_preds ))

== > [ 0.8100000000000006 , 0.6400000000000011 ]

当我们想迭代操作员将操作员应用于列表中的所有元素时,将使用redair(fn,iTable,Initializer)。例如,如果我们要计算列表中所有元素的产品:

 product = 1
for num in nums :
    product *= num
print ( product )

== > 12.95564683272412

这相当于:

 from functools import reduce
product = reduce ( lambda x , y : x * y , nums )
print ( product )

== > 12.95564683272412

注意Lambda功能的性能

Lambda功能是一次使用。每次调用lambda X:dosomething(x)时,必须创建函数,如果您多次调用lambda x:dosomething(x)多次(例如,当您将其传递到Replay中时)。

当您将名称分配到lambda函数中,如fn = lambda x:dosomething(x)时,其性能比使用def定义的同一函数稍慢,但是差异可以忽略不计。请参阅此处。

即使我觉得Lambdas很酷,我个人建议您在为清晰起见时使用命名功能。

2。列表操纵

Python列表非常酷。

2.1解箱

我们可以通过这样的每个元素解开列表:

 elems = [ 1 , 2 , 3 , 4 ]
a , b , c , d = elems
print ( a , b , c , d )

== > 1 2 3 4

我们还可以打开这样的清单:

 a , * new_elems , d = elems
print ( a )
print ( new_elems )
print ( d )

== > 1
    [ 2 , 3 ]
    4

2.2切片

我们知道我们可以使用[:: – 1]扭转列表。

 elems = list ( range ( 10 ))
print ( elems )

== > [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]

print ( elems [:: - 1 ])

== > [ 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ]

语法[x:y:z]的意思是“从索引x到索引y,将列表的每个zth元素删除”。当z为负时,它表示向后移动。当未指定X时,它将默认为列表的第一个元素,以您遍历列表的方向。当未指定Y时,它将默认为列表的最后一个元素。因此,如果我们想获取列表的每个第2个要素,我们使用[:: 2]。

 evens = elems [:: 2 ]
print ( evens )

reversed_evens = elems [ - 2 :: - 2 ]
print ( reversed_evens )

== > [ 0 , 2 , 4 , 6 , 8 ]
    [ 8 , 6 , 4 , 2 , 0 ]

我们还可以使用切片来删除列表中的所有均匀数字。

 del elems [:: 2 ]
print ( elems )

== > [ 1 , 3 , 5 , 7 , 9 ]

2.3插入

我们可以将列表中元素的值更改为另一个值。

 elems = list ( range ( 10 ))
elems [ 1 ] = 10
print ( elems )

== > [ 0 , 10 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]

如果我们想用多个元素以索引替换元素,例如,将值1替换为3个值20、30、40:

 elems = list ( range ( 10 ))
elems [ 1 : 2 ] = [ 20 , 30 , 40 ]
print ( elems )

== > [ 0 , 20 , 30 , 40 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]

如果我们想在索引0处的元素0和索引1的元素之间插入3个值0.2、0.3、0.5:

 elems = list ( range ( 10 ))
elems [ 1 : 1 ] = [ 0.2 , 0.3 , 0.5 ]
print ( elems )

== > [ 0 , 0.2 , 0.3 , 0.5 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]

2.4扁平

我们可以使用sum弄平列表的列表。

 list_of_lists = [[ 1 ], [ 2 , 3 ], [ 4 , 5 , 6 ]]
sum ( list_of_lists , [])

== > [ 1 , 2 , 3 , 4 , 5 , 6 ]

如果我们有嵌套列表,我们可以递归将其弄平。这是Lambda功能的另一个美 – 我们可以在与其创建的同一行中使用它。

 nested_lists = [[ 1 , 2 ], [[ 3 , 4 ], [ 5 , 6 ], [[ 7 , 8 ], [ 9 , 10 ], [[ 11 , [ 12 , 13 ]]]]]]
flatten = lambda x : [ y for l in x for y in flatten ( l )] if type ( x ) is list else [ x ]
flatten ( nested_lists )

# This line of code is from
# https://gith*ub.**com/sahands/python-by-example/blob/master/python-by-example.rst#flattening-lists

2.5列表与生成器

为了说明列表和生成器之间的区别,让我们看一个从令牌列表中创建n-grams的示例。

创建n-grams的一种方法是使用滑动窗口。

 tokens = [ \'i\' , \'want\' , \'to\' , \'go\' , \'to\' , \'school\' ]

def ngrams ( tokens , n ):
    length = len ( tokens )
    grams = []
    for i in range ( length - n + 1 ):
        grams . append ( tokens [ i : i + n ])
    return grams

print ( ngrams ( tokens , 3 ))

== > [[ \'i\' , \'want\' , \'to\' ],
     [ \'want\' , \'to\' , \'go\' ],
     [ \'to\' , \'go\' , \'to\' ],
     [ \'go\' , \'to\' , \'school\' ]]

在上面的示例中,我们必须同时存储所有n-gram。如果文本具有m令牌,则内存的要求为O(nm),当m大时,这可能会出现问题。

与其使用列表存储所有n-gram,我们可以使用在需要时生成下一个n-gram的生成器。这被称为懒惰评估。我们可以使用关键字收益率使函数ngrams返回生成器。然后,内存要求为O(M+N)。

 def ngrams ( tokens , n ):
    length = len ( tokens )
    for i in range ( length - n + 1 ):
        yield tokens [ i : i + n ]

ngrams_generator = ngrams ( tokens , 3 )
print ( ngrams_generator )

== > < generator object ngrams at 0x1069b26d0 >

for ngram in ngrams_generator :
    print ( ngram )

== > [ \'i\' , \'want\' , \'to\' ]
    [ \'want\' , \'to\' , \'go\' ]
    [ \'to\' , \'go\' , \'to\' ]
    [ \'go\' , \'to\' , \'school\' ]

生成n -grams的另一种方法是使用切片来创建列表:[0,1,…,…,-n],[1,2,…,…,-n+1],…,[n -1,n,…,…,-1],然后将它们一起sip。

 def ngrams ( tokens , n ):
    length = len ( tokens )
    slices = ( tokens [ i : length - n + i + 1 ] for i in range ( n ))
    return zip ( * slices )

ngrams_generator = ngrams ( tokens , 3 )
print ( ngrams_generator )

== > < zip object at 0x1069a7dc8 > # zip objects are generators

for ngram in ngrams_generator :
    print ( ngram )

== > ( \'i\' , \'want\' , \'to\' )
    ( \'want\' , \'to\' , \'go\' )
    ( \'to\' , \'go\' , \'to\' )
    ( \'go\' , \'to\' , \'school\' )

请注意,要创建切片,我们在范围(n)中使用(tokens […]),而不是[tokens […]在范围(n)中的i]。 []是返回列表的普通列表理解。 ()返回发电机。

3。课程和魔术方法

在Python中,魔术方法前缀并用双重下划线__(也称为Dunder)后缀。最著名的魔术方法可能是__init__。

 class Node :
    \"\"\" A struct to denote the node of a binary tree.
    It contains a value and pointers to left and right children.
    \"\"\"
    def __init__ ( self , value , left = None , right = None ):
        self . value = value
        self . left = left
        self . right = right

但是,当我们尝试打印一个节点对象时,它不是很容易解释的。

 root = Node ( 5 )
print ( root ) # <__main__.Node object at 0x1069c4518>

理想情况下,当用户打印出节点时,我们希望打印出节点的值及其孩子的值。为此,我们使用魔法方法__repr__,该方法必须返回可打印对象,例如字符串。

 class Node :
    \"\"\" A struct to denote the node of a binary tree.
    It contains a value and pointers to left and right children.
    \"\"\"
    def __init__ ( self , value , left = None , right = None ):
        self . value = value
        self . left = left
        self . right = right

    def __repr__ ( self ):
        strings = [ f\'value: { self . value } \' ]
        strings . append ( f\'left: { self . left . value } \' if self . left else \'left: None\' )
        strings . append ( f\'right: { self . right . value } \' if self . right else \'right: None\' )
        return \', \' . join ( strings )

left = Node ( 4 )
root = Node ( 5 , left )
print ( root ) # value: 5, left: 4, right: None

我们还想通过比较它们的值来比较两个节点。为此,我们用__eq__,<with __lt__和> = = __ge ____________________________________________。

 class Node :
    \"\"\" A struct to denote the node of a binary tree.
    It contains a value and pointers to left and right children.
    \"\"\"
    def __init__ ( self , value , left = None , right = None ):
        self . value = value
        self . left = left
        self . right = right

    def __eq__ ( self , other ):
        return self . value == other . value

    def __lt__ ( self , other ):
        return self . value < other . value

    def __ge__ ( self , other ):
        return self . value >= other . value


left = Node ( 4 )
root = Node ( 5 , left )
print ( left == root ) # False
print ( left < root ) # True
print ( left >= root ) # False

有关此处支持的魔术方法的全面列表,或在此处查看官方的Python文档(更难阅读)。

我强烈建议使用的一些方法:

  • __len __:要超载len()函数。
  • __STR__:要超载str()函数。
  • __ITER__:如果您想成为迭代器。这也使您可以在对象上调用Next()。

对于Node之类的类,我们可以确保它们可以支持的所有属性(对于节点,它们是值,左和右),我们可能想使用__slots__代表这些值的性能增强和存储器保存。要全面了解__slots__的优缺点,请参见Aron Hall在Stackoverflow上的绝对惊人答案。

 class Node :
    \"\"\" A struct to denote the node of a binary tree.
    It contains a value and pointers to left and right children.
    \"\"\"
    __slots__ = ( \'value\' , \'left\' , \'right\' )
    def __init__ ( self , value , left = None , right = None ):
        self . value = value
        self . left = left
        self . right = right 

4。本地名称空间,对象的属性

Locals()函数返回包含本地名称空间中定义的变量的字典。

 class Model1 :
    def __init__ ( self , hidden_size = 100 , num_layers = 3 , learning_rate = 3e-4 ):
        print ( locals ())
        self . hidden_size = hidden_size
        self . num_layers = num_layers
        self . learning_rate = learning_rate

model1 = Model1 ()

== > { \'learning_rate\' : 0.0003 , \'num_layers\' : 3 , \'hidden_size\' : 100 , \'self\' : < __main__ . Model1 object at 0x1069b1470 > }

对象的所有属性都存储在其__ -dict__中。

 print ( model1 . __dict__ )

== > { \'hidden_size\' : 100 , \'num_layers\' : 3 , \'learning_rate\' : 0.0003 }

请注意,当参数列表很大时,将每个参数手动分配给属性可能会很累。为了避免这种情况,我们可以将参数列表直接分配给对象的__ -dict__。

 class Model2 :
    def __init__ ( self , hidden_size = 100 , num_layers = 3 , learning_rate = 3e-4 ):
        params = locals ()
        del params [ \'self\' ]
        self . __dict__ = params

model2 = Model2 ()
print ( model2 . __dict__ )

== > { \'learning_rate\' : 0.0003 , \'num_layers\' : 3 , \'hidden_size\' : 100 }

当使用All ** kwargs启动对象时,这可能特别方便,尽管应将** kwargs的使用降低到最小值。

 class Model3 :
    def __init__ ( self , ** kwargs ):
        self . __dict__ = kwargs

model3 = Model3 ( hidden_size = 100 , num_layers = 3 , learning_rate = 3e-4 )
print ( model3 . __dict__ )

== > { \'hidden_size\' : 100 , \'num_layers\' : 3 , \'learning_rate\' : 0.0003 }

5。野外进口

通常,您会遇到这种看起来像这样的野外进口 *:

file.py

    from parts import *

这是不负责任的,因为它将导入模块中的所有内容,即使是该模块的导入。例如,如果parts.py看起来像这样:

parts.py

 import numpy
import tensorflow

class Encoder :
    ...

class Decoder :
    ...

class Loss :
    ...

def helper ( * args , ** kwargs ):
    ...

def utils ( * args , ** kwargs ):
    ...

由于parts.py没有指定__________py将导入编码器,解码器,损失,UTILS,助手,以及numpy和tensorflow。

如果我们打算只能在另一个模块中导入和使用编码器,解码器和损失,则应在parts.py中使用__________的关键字来指定。

parts.py

 __all__ = [ \'Encoder\' , \'Decoder\' , \'Loss\' ]
import numpy
import tensorflow

class Encoder :
    ...

现在,如果某些用户不负责任地用零件导入了狂野的导入,他们只能导入编码器,解码器,损失。就个人而言,我也发现__ All __有帮助,因为它为我提供了模块的概述。

6。装饰器时间来计时您的功能

知道运行需要多长时间,例如,当您需要比较两种执行同一操作的算法的性能时,通常会很有用。一种幼稚的方法是在每个功能的开始和结束时打电话时间()并打印出差异。

例如:比较两种算法来计算第n-fibonacci编号,一个人使用回忆,一个不使用。

 def fib_helper ( n ):
    if n < 2 :
        return n
    return fib_helper ( n - 1 ) + fib_helper ( n - 2 )

def fib ( n ):
    \"\"\" fib is a wrapper function so that later we can change its behavior
    at the top level without affecting the behavior at every recursion step.
    \"\"\"
    return fib_helper ( n )

def fib_m_helper ( n , computed ):
    if n in computed :
        return computed [ n ]
    computed [ n ] = fib_m_helper ( n - 1 , computed ) + fib_m_helper ( n - 2 , computed )
    return computed [ n ]

def fib_m ( n ):
    return fib_m_helper ( n , { 0 : 0 , 1 : 1 })

让我们确保FIB和FIB_M在功能上是等效的。

 for n in range ( 20 ):
    assert fib ( n ) == fib_m ( n )
 import time

start = time . time ()
fib ( 30 )
print ( f\'Without memoization, it takes { time . time () - start :7f } seconds.\' )

== > Without memoization , it takes 0.267569 seconds .

start = time . time ()
fib_m ( 30 )
print ( f\'With memoization, it takes { time . time () - start :.7f } seconds.\' )

== > With memoization , it takes 0.0000713 seconds .

如果要计时多个功能,则必须一遍又一遍地编写相同的代码。很高兴有一种方法来指定如何以相同的方式更改任何功能。在这种情况下,将在每个函数的开头和结束时致电Time(Time(),并打印出时间差。

这正是装饰者所做的。它们允许程序员更改功能或类的行为。这是创建装饰时间时间的示例。

 def timeit ( fn ): 
    # *args and **kwargs are to support positional and named arguments of fn
    def get_time ( * args , ** kwargs ): 
        start = time . time () 
        output = fn ( * args , ** kwargs )
        print ( f\"Time taken in { fn . __name__ } : { time . time () - start :.7f } \" )
        return output  # make sure that the decorator returns the output of fn
    return get_time 

将Decorator @TimeIT添加到您的功能中。

 @ timeit
def fib ( <span class=\"pl

下载源码

通过命令行克隆项目:

git clone https://github.com/chiphuyen/python-is-cool.git

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 python is cool https://www.zuozi.net/34377.html

flake8
上一篇: flake8
pampy
下一篇: pampy
常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务