美文网首页
导入模块的两种写法的区别

导入模块的两种写法的区别

作者: Python_Camp | 来源:发表于2022-05-10 11:00 被阅读0次

    Built-in Functions — Python 3.10.4 documentationhttps://docs.python.org/3/library/functions.html#float访问以上链接学习内置函数 1、内置函数

    image.png

    例如常见的索引 a 中的两个内置函数 all(), any(),如何运用官方文档学习它们的用法?**

    all(iterable)
    如果iterable的所有元素都是真的,返回True(或者iterable为空)。
    相当于:

    def all(iterable):
        for element in iterable:
            if not element:
                return False
        return True
    

    any(iterable)
    如果iterable的任何元素为真,返回True。如果iterable是空的,返回False。相当于:

    def any(iterable):
        for element in iterable:
            if element:
                return True
        return False
    

    注意:Python的逐位运算符只对整数起作用。
    Bitwise AND operator: Returns 1 if both the bits are 1 else 0.
    位与运算符。如果两个位都是1,则返回1,否则返回0。
    a = 10 = 1010 (Binary)
    b = 4 = 0100 (Binary)

    a & b = 1010 &
    0100
    = 0000
    = 0 (Decimal)

    位或运算符 |
    如果其中一个位是1,则返回1,否则返回0。
    a = 10 = 1010 (Binary)
    b = 4 = 0100 (Binary)

    a | b = 1010 | 0100
    = 1110
    = 14 (Decimal)

    Bitwise not运算符。
    a = 10 = 1010 (Binary)

    ~a = ~1010
    = -(1010 + 1)
    = -(1011)
    = -11 (Decimal)

    Bitwise xor运算符:
    如果其中一个比特是1,另一个是0,则返回1,否则返回false。
    a = 10 = 1010 (Binary)
    b = 4 = 0100 (Binary)

    a ^ b = 1010
    ^
    0100
    = 1110
    = 14 (Decimal)

    # Python program to show
    # bitwise operators
     
    a = 10
    b = 4
     
    # Print bitwise AND operation
    print("a & b =", a & b)
     
    # Print bitwise OR operation
    print("a | b =", a | b)
     
    # Print bitwise NOT operation
    print("~a =", ~a)
     
    # print bitwise XOR operation
    print("a ^ b =", a ^ b)
    

    Output:

    a & b = 0
    a | b = 14
    ~a = -11
    a ^ b = 14

    移位运算符
    这些运算符用于将一个数字的位向左或向右移动,从而使该数字分别乘以或除以2。当我们需要将一个数字乘以或除以2时,就可以使用这些操作。
    位向右移。将数字的位向右移动,并在左边的空位上填上0(在负数的情况下填上1),作为结果。与数字除以2的某个幂的效果类似。
    例子。

    例1:
    a = 10 = 0000 1010 (二进制)
    a >> 1 = 0000 0101 = 5

    例2:
    A = -10 = 1111 0110 (二进制)
    a >> 1 = 1111 1011 = -5
    位向左移。将数字的位向左移动,并将0填在右边的空位上。与数字乘以2的某个幂的效果类似。
    例子。

    例1:
    a = 5 = 0000 0101 (二进制)
    a << 1 = 0000 1010 = 10
    a << 2 = 0001 0100 = 20

    例2:
    B = -10 = 1111 0110 (二进制)
    b << 1 = 1110 1100 = -20
    b << 2 = 1101 1000 = -40

    # Python program to show
    # shift operators
     
    a = 10
    b = -10
     
    # print bitwise right shift operator
    print("a >> 1 =", a >> 1)
    print("b >> 1 =", b >> 1)
     
    a = 5
    b = -10
     
    # print bitwise left shift operator
    print("a << 1 =", a << 1)
    print("b << 1 =", b << 1)
    

    Output:

    a >> 1 = 5
    b >> 1 = -5
    a << 1 = 10
    b << 1 = -20

    比特运算符重载
    操作符重载是指在其预定的操作意义之外赋予扩展的意义。例如,操作符+用于添加两个整数,以及连接两个字符串和合并两个列表。这是可以实现的,因为'+'运算符被int类和str类所重载。你可能已经注意到,同样的内置运算符或函数对不同类的对象显示出不同的行为,这就叫运算符重载。
    下面是一个简单的Bitwise运算符重载的例子。

    # Python program to demonstrate
    # operator overloading
     
     
    class Geek():
        def __init__(self, value):
            self.value = value
     
        def __and__(self, obj):
            print("And operator overloaded")
            if isinstance(obj, Geek):
                return self.value & obj.value
            else:
                raise ValueError("Must be a object of class Geek")
     
        def __or__(self, obj):
            print("Or operator overloaded")
            if isinstance(obj, Geek):
                return self.value | obj.value
            else:
                raise ValueError("Must be a object of class Geek")
     
        def __xor__(self, obj):
            print("Xor operator overloaded")
            if isinstance(obj, Geek):
                return self.value ^ obj.value
            else:
                raise ValueError("Must be a object of class Geek")
     
        def __lshift__(self, obj):
            print("lshift operator overloaded")
            if isinstance(obj, Geek):
                return self.value << obj.value
            else:
                raise ValueError("Must be a object of class Geek")
     
        def __rshift__(self, obj):
            print("rshift operator overloaded")
            if isinstance(obj, Geek):
                return self.value & obj.value
            else:
                raise ValueError("Must be a object of class Geek")
     
        def __invert__(self):
            print("Invert operator overloaded")
            return ~self.value
     
     
    # Driver's code
    if __name__ == "__main__":
        a = Geek(10)
        b = Geek(12)
        print(a & b)
        print(a | b)
        print(a ^ b)
        print(a << b)
        print(a >> b)
        print(~a)
    

    Output:

    And operator overloaded
    8
    Or operator overloaded
    14
    Xor operator overloaded
    8
    lshift operator overloaded
    40960
    rshift operator overloaded
    8
    Invert operator overloaded
    -11

    页面底部给出了更多重载的用法链接
    [Operator Overloading in Python - GeeksforGeeks]
    https://www.geeksforgeeks.org/operator-overloading-in-python/

    官方文档

    [PEP 492 – Coroutines with async and await syntax | peps.python.org]
    https://peps.python.org/pep-0492/

    摘要
    互联网和一般连接的增长引发了对响应性和可扩展代码的相应需求。本建议旨在满足这一需求,使编写明确的异步、并发的Python代码变得更容易、更Pythonic。

    我们建议在Python中使轮子成为一个适当的独立概念,并引入新的支持语法。最终的目标是帮助建立一个通用的、容易接近的、在Python中的异步编程的心理模型,并使其尽可能地接近同步编程。

    这个PEP假设异步任务是由一个类似于stdlib模块asyncio.events.AbstractEventLoop的事件循环来安排和协调的。虽然该PEP并不与任何特定的事件循环实现相联系,但它只与那种使用产量作为调度器信号的冠词有关,表明该冠词将一直等待,直到一个事件(如IO)完成。

    我们相信这里提出的修改将有助于保持 Python 在快速增长的异步编程领域的相关性和竞争力,因为许多其它语言已经采用或正计划采用类似的特性。[2], [5], [6], [7], [8], [10].

    API设计和实现的修订
    对Python 3.5最初的测试版的反馈导致了对支持本PEP的对象模型的重新设计,以更清楚地将本机程序与生成器分开--本机程序现在不是一种新的生成器,而是自己完全不同的类型(在 [17] 中实现)。
    这一改变主要是由于在尝试将对本地程序的支持整合到Tornado网络服务器中时遇到的问题(在[18]中报告)。

    在CPython 3.5.2中,aiter协议被更新。
    在3.5.2之前,aiter被期望返回一个可等待的解析到一个异步迭代器。从 3.5.2 开始,aiter 应该直接返回异步的迭代器。

    如果在3.5.2中使用旧的协议,Python将引发一个PendingDeprecationWarning。

    在 CPython 3.6 中,旧的 aiter 协议仍将被支持,并引发一个 DeprecationWarning。

    在CPython 3.7中,旧的aiter协议将不再被支持:如果aiter除了返回一个异步的迭代器之外,还返回一个RuntimeError。

    更多细节见 [19] 和 [20]。

    理论基础和目标
    当前的 Python 支持通过生成器 (PEP 342) 实现 coroutines,并通过 PEP 380 中引入的 yield from 语法进一步加强。这种方法有很多缺点。

    很容易将程序与普通生成器混淆,因为它们的语法相同;这对于新的开发者来说尤其如此。
    一个函数是否是coroutine是由其主体中是否存在yield或yield from语句决定的,当这些语句在重构过程中出现或从函数主体中消失时,会导致不明显的错误。
    对异步调用的支持仅限于语法上允许产生的表达式,从而限制了语法特性的实用性,例如with和for语句。
    这个建议使 COROUTINE 成为 Python 语言的原生特性,并将其与生成器明确分开。这消除了生成器/程序的模糊性,并使可靠地定义程序成为可能,而无需依赖特定的库。这也使得linters和IDE能够改善静态代码分析和重构。

    原生的coroutines和相关的新语法特征使得用异步术语定义上下文管理和迭代协议成为可能。如本提案后面所示,新的async with语句让Python程序在进入和退出运行时上下文时执行异步调用,而新的async for语句使在迭代器中执行异步调用成为可能。

    规范
    这个提议引入了新的语法和语义,以增强 Python 中的 coroutine 支持。

    本规范假定对Python中的轮回线的实现有一定了解 (PEP 342 和 PEP 380)。这里提出的语法变化的动机来自于asyncio框架(PEP 3156)和 "Cofunctions "提案(PEP 3152,现在被拒绝,而支持本规范)。

    从本文开始,我们使用native coroutine这个词来指代使用新语法声明的函数。必要时使用generator-based coroutine来指代基于generator语法的coroutine。coroutine在两种定义都适用的情况下被使用。

    新的 Coroutine 声明语法

    import sys
    import time
    
    def binary(n):
        if n <= 0:
            return 1
        l = yield from binary(n - 1)
        r = yield from binary(n - 1)
        return l + 1 + r
    
    async def abinary(n):
        if n <= 0:
            return 1
        l = await abinary(n - 1)
        r = await abinary(n - 1)
        return l + 1 + r
    
    def timeit(func, depth, repeat):
        t0 = time.time()
        for _ in range(repeat):
            o = func(depth)
            try:
                while True:
                    o.send(None)
            except StopIteration:
                pass
        t1 = time.time()
        print('{}({}) * {}: total {:.3f}s'.format(
            func.__name__, depth, repeat, t1-t0))
    

    导入模块并不浪费任何东西;模块总是被完全导入(到sys.modules映射中),所以无论你使用import sys还是from sys import argv都没有什么区别。

    这两种说法的唯一区别是绑定的名字;import sys将sys这个名字绑定到模块上(所以sys -> sys.modules['sys']),而from sys import argv绑定了一个不同的名字,argv,直接指向模块内包含的属性(所以argv -> sys.modules['sys'].argv)。sys模块的其他部分仍然存在,无论你是否使用该模块的其他东西。

    这两种方法在性能上也没有区别。是的,sys.argv需要查找两样东西;它需要在你的全局命名空间中查找sys(找到模块),然后查找argv这个属性。是的,通过使用 from sys import argv 你可以跳过属性查询,因为你已经有了对该属性的直接引用。但是import语句仍然要做这些工作,它在导入时查找同一个属性,而你只需要使用一次argv。如果你不得不在一个循环中使用argv数千次,这也许会有区别,但在这个特定的案例中,它确实没有区别。

    因此,选择一个或另一个应该完全基于编码风格。

    在一个大模块中,我当然会使用import sys;代码文档很重要,在一个大模块中的某个地方使用sys.argv,比仅仅使用argv更清楚地表明你所指的是什么。

    如果你唯一使用argv的地方是在'main'块中调用main()函数,如果你觉得这样做比较好,可以使用从sys导入argv。

    if __name__ == '__main__':
        from sys import argv
        main(argv)
    

    我自己还是会在那里使用 import sys。在所有事情都相同的情况下(确切地说,在性能和用于编写的字符数方面,它们是相同的),这对我来说更容易看懂。

    如果你导入的是其他东西,那么性能可能会有影响。但只有当你在一个模块中多次使用一个特定的名字,例如在一个关键的循环中。但是,创建一个本地名称(在一个函数中)会更快。

     import somemodule
    
     def somefunction():
          localname = somemodule.somefunctionorother
          while test:
              # huge, critical loop
              foo = localname(bar)
    

    还有一种情况是,你有一个带有子包或模块的包,在顶层包中暴露了这些子包/模块中的一个属性。使用from...import允许你做package.attribute而不是package.subpackage_or_module.attribute,如果你在包内有逻辑或概念上的分组,但想让你的包的用户更方便一些,这可能很有用。(numpy做了类似的事情,我相信)

    你正在加入一个属性查询。为了正确比较import module和from module的导入名称,请在import module的案例中添加该名称的查询。例如,在ar测试中加入sys.argv这一行,等等。仍然会有差异,因为所做的工作略有不同,因为生成的字节码不同,执行的代码路径也不同。

    请注意,我在回答中直接谈到了这个区别;使用import sys然后在一个循环中使用sys.argv数千次与from sys import argv然后只使用argv之间会有区别。但你不会。对于你在模块的全局层面上只做一次的事情,你真的应该优化可读性,而不是时间上的微小差异。

    相关文章

      网友评论

          本文标题:导入模块的两种写法的区别

          本文链接:https://www.haomeiwen.com/subject/wkhlurtx.html