Python 条件,循环以及其他语句

本文深入探讨了Python中的print和import特性,介绍了多个参数打印、导入时重命名等实用技巧。此外,文章还讲解了序列解包、增强赋值、条件语句、循环控制、列表推导等高级主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

再谈print和import

  随着你对Python的认识越来越深入,可能发现有些你自以为很熟悉的方面隐藏着让人惊喜的
  特性。下面就来看看printimport隐藏的几个特性。虽然print现在实际上是一个函数,但以前
  却是一种语句 。

打印多个参数
        你知道, print可用于打印一个表达式,这个表达式要么是字符串,要么将自动转换为字符
        串。但实际上,你可同时打印多个表达式,条件是用逗号分隔它们:
        >>> print('Age:', 42)
        Age: 42
        如你所见,在参数之间插入了一个空格字符。在你要合并文本和变量值,而又不想使用字符
        串格式设置功能时,这种行为很有帮助。
        >>> name = 'Gumby'
        >>> salutation = 'Mr.'
        >>> greeting = 'Hello,'
        >>> print(greeting, salutation, name)
        Hello, Mr. Gumby
        如果字符串变量greeting不包含逗号,如何在结果中添加呢?你不能像下面这样做:
        print(greeting, ',', salutation, name)
        因为这将在逗号前添加一个空格。下面是一种可行的解决方案:
        print(greeting + ',', salutation, name)
        它将逗号和变量greeting相加。如果需要,可自定义分隔符:
        >>> print("I", "wish", "to", "register", "a", "complaint", sep="_")
        I_wish_to_register_a_complaint
        你还可自定义结束字符串,以替换默认的换行符。例如,如果将结束字符串指定为空字符串,
        以后就可继续打印到当前行。
        print('Hello,', end='123')
        上述代码打印Hello123
    导入时重命名
        从模块导入时,通常使用
        import somemodule
        或使用
        from somemodule import somefunction
        或
        from somemodule import somefunction, anotherfunction, yetanotherfunction
        或
        from somemodule import *
        仅当你确定要导入模块中的一切时,采用使用最后一种方式。但如果有两个模块,它们都包
        含函数open,该如何办呢?你可使用第一种方式导入这两个模块,并像下面这样调用函数:
        module1.open(...)
        module2.open(...)
        但还有一种办法:在语句末尾添加as子句并指定别名。下面是一个导入整个模块并给它指定
        别名的例子:
        >>> import math as foobar
        >>> foobar.sqrt(4)
        2.0
        下面是一个导入特定函数并给它指定别名的例子:
        >>> from math import sqrt as foobar
        >>> foobar(4)
        2.0
        对于前面的函数open,可像下面这样导入它们:
        from module1 import open as open1
        from module2 import open as open2
View Code

赋值魔法

  序列解包 

赋值语句你见过很多,有的给变量赋值,还有的给数据结构的一部分(如列表中的元素和切
        片,或者字典项)赋值,但还有其他类型的赋值语句。例如,可同时(并行)给多个变量赋值:
        >>> x, y, z = 1, 2, 3
        >>> print(x, y, z)
        1 2 3
        看似用处不大?看好了,使用这种方式还可交换多个变量的值。
        >>> x, y = y, x
        >>> print(x, y, z)
        2 1 3
        实际上,这里执行的操作称为序列解包(或可迭代对象解包):将一个序列(或任何可迭代
        对象)解包,并将得到的值存储到一系列变量中。下面用例子进行解释。
        >>> values = 1, 2, 3
        >>> values
        (1, 2, 3)
        >>> x, y, z = values
        >>> x
        1
        这在使用返回元组(或其他序列或可迭代对象)的函数或方法时很有用。假设要从字典中随
        便获取(或删除)一个键值对,可使用方法popitem,它随便获取一个键值对并以元组的方式
        返回。接下来,可直接将返回的元组解包到两个变量中。
        >>> scoundrel = {'name': 'Robin', 'girlfriend': 'Marion'}
        >>> key, value = scoundrel.popitem()
        >>> key
        'girlfriend'
        >>> value
        'Marion'
        这让函数能够返回被打包成元组的多个值,然后通过一条赋值语句轻松地访问这些值。要解
        包的序列包含的元素个数必须与你在等号左边列出的目标个数相同,否则Python将引发异常。
        >>> x, y, z = 1, 2
        Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        ValueError: need more than 2 values to unpack
        >>> x, y, z = 1, 2, 3, 4
        Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        ValueError: too many values to unpack
        可使用星号运算符(*)来收集多余的值,这样无需确保值和变量的个数相同,如下例所示:
        >>> a, b, *rest = [1, 2, 3, 4]
        >>> rest
        [3, 4]
        还可将带星号的变量放在其他位置。
        >>> name = "Albus Percival Wulfric Brian Dumbledore"
        >>> first, *middle, last = name.split()
        >>> middle
        ['Percival', 'Wulfric', 'Brian']
        赋值语句的右边可以是任何类型的序列,但带星号的变量最终包含的总是一个列表。在变量
        和值的个数相同时亦如此。
        >>> a, *b, c = "abc"
        >>> a, b, c
        ('a', ['b'], 'c')
        这种收集方式也可用于函数参数列表中
View Code

  链式赋值

    链式赋值是一种快捷方式,用于将多个变量关联到同一个值。这有点像前一节介绍的并行赋
    值,但只涉及一个值:
    x = y = somefunction()
    上述代码与下面的代码等价:
    y = somefunction()
    x = y
    请注意,这两条语句可能与下面的语句不等价:
    x = somefunction()
    y = somefunction()
    有关这方面的详细信息,请参阅5.4.6节介绍相同运算符(is)的部分。
View Code

  增强赋值  

可以不编写代码x = x + 1,而将右边表达式中的运算符(这里是+)移到赋值运算符(=)
    的前面,从而写成x += 1。这称为增强赋值,适用于所有标准运算符,如*、 /、 %等。
    >>> x = 2
    >>> x += 1
    >>> x *= 2
    >>> x
    6
    增强赋值也可用于其他数据类型(只要使用的双目运算符可用于这些数据类型)。
    >>> fnord = 'foo'
    >>> fnord += 'bar'
    >>> fnord *= 2
    >>> fnord
    'foobarfoobar'
    通过使用增强赋值,可让代码更紧凑、更简洁,同时在很多情况下的可读性更强。
View Code    

代码块
  代码块是一组语句,可在满足条件时执行(if语句),可执行多次(循环),等等。代码块是
  通过缩进代码(即在前面加空格)来创建的。
  注意:也可使用制表符来缩进代码块。 Python将制表符解释为移到下一个制表位(相邻制表位
  相距8个空格),但标准(也是更佳的)做法是只使用空格(而不使用制表符)来缩进,
  且每级缩进4个空格。
  在很多语言中,都使用一个特殊的单词或字符(如begin或{)来标识代码块的起始位置,并
  使用另一个特殊的单词或字符(如end或})来标识结束位置。在Python中,使用冒号(:)指出
  接下来是一个代码块,并将该代码块中的每行代码都缩进相同的程度。发现缩进量与之前相同时,
  你就知道当前代码块到此结束了。(很多用于编程的编辑器和IDE知道如何缩进代码块,可帮助你
  轻松地正确缩进。)
条件和条件语句
  布尔值 

用作布尔表达式(如用作if语句中的条件)时,下面的值都将被解释器视为假:
        False None 0 "" () [] {}
        换而言之,标准值False和None、各种类型(包括浮点数、复数等)的数值0、空序列(如空
        字符串、空元组和空列表)以及空映射(如空字典)都被视为假,而其他各种值都被视为真①,
        包括特殊值True②。
        明白了吗?这意味着任何Python值都可解释为真值。乍一看这有点令人迷惑,但也很有用。
        虽然可供选择的真值非常多,但标准真值为True和False。在有些语言(如C语言和2.3之前的Python
        版本)中,标准真值为0(表示假)和1(表示真)。实际上, True和False不过是0和1的别名,虽
        然看起来不同,但作用是相同的。
        >>> True
        True
        >>> False
        False
        >>> True == 1
        True
        >>> False == 0
        True
        >>> True + False + 42
        43
        因此,如果你看到一个返回1或0的表达式(可能是使用较旧的Python版本编写的),就知道
        这实际上意味着True或False。
        布尔值True和False属于类型bool,而bool与list、 str和tuple一样,可用来转换其他的值。
        >>> bool('I think, therefore I am')
        True
        >>> bool(42)
        True
        >>> bool('')
        False
        >>> bool(0)
        False
        鉴于任何值都可用作布尔值,因此你几乎不需要显式地进行转换(Python会自动转换)
        注意:虽然[]和""都为假(即bool([]) == bool("") == False),但它们并不相等(即[] != "")。
            对其他各种为假的对象来说,情况亦如此(一个更显而易见的例子是() != False)。
View Code

三目运算
  status = "friend" if name.endswith("Gumby") else "stranger"
  如果条件(紧跟在if后面)为真,表达式的结果为提供的第一个值(这里为"friend"),否
  则为第二个值(这里为"stranger")。
is相同运算符  

这个运算符很有趣,其作用看似与==一样,但实际上并非如此。
        >>> x = y = [1, 2, 3]
        >>> z = [1, 2, 3]
        >>> x == y
        True
        >>> x == z
        True
        >>> x is y
        True
        >>> x is z
        False
        在前几个示例中,看不出什么问题,但最后一个示例的结果很奇怪: x和z相等,但x is z的
        结果却为False。为何会这样呢?因为is检查两个对象是否相同(而不是相等)。变量x和y指向同
        一个列表,而z指向另一个列表(其中包含的值以及这些值的排列顺序都与前一个列表相同)。这
        两个列表虽然相等,但并非同一个对象。
        这好像不可理喻?请看下面的示例:
        >>> x = [1, 2, 3]
        >>> y = [2, 4]
        >>> x is not y
        True
        >>> del x[2]
        >>> y[1] = 1
        >>> y.reverse()
        在这个示例中,我首先创建了两个不同的列表x和y。如你所见, x is not y(与x is y相反)
        的结果为True,这一点你早已知道。接下来,我稍微修改了这两个列表,现在它们虽然相等,但
        依然是两个不同的列表。
        >>> x == y
        True
        >>> x is y
        False
        显然,这两个列表相等但不相同。
        总之, ==用来检查两个对象是否相等,而is用来检查两个对象是否相同(是同一个对象)。
        警告:不要将is用于数和字符串等不可变的基本值。鉴于Python在内部处理这些对象的方式,
            这样做的结果是不可预测的。
View Code

assert断言

if语句有一个很有用的“亲戚”,其工作原理类似于下面的伪代码:
        if not condition:
        crash program
        问题是,为何要编写类似于这样的代码呢?因为让程序在错误条件出现时立即崩溃胜过以后
        再崩溃。基本上,你可要求某些条件得到满足(如核实函数参数满足要求或为初始测试和调试提
        供帮助),为此可在语句中使用关键字assert。
        >>> age = 10
        >>> assert 0 < age < 100
        >>> age = -1
        >>> assert 0 < age < 100
        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        AssertionError
        如果知道必须满足特定条件,程序才能正确地运行,可在程序中添加assert语句充当检查点,
        这很有帮助。
        还可在条件后面添加一个字符串,对断言做出说明。
        >>> age = -1
        >>> assert 0 < age < 100, 'The age must be realistic'
        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        AssertionError: The age must be realistic
View Code 

循环
  while循环
 

为避免前述示例所示的繁琐代码,能够像下面这样做很有帮助:
        x = 1
        while x <= 100:
        print(x)
        x += 1
        那么如何使用Python来实现的?你猜对了,就像上面那样做。不太复杂,不是吗?你还可以
        使用循环来确保用户输入名字,如下所示:
        name = ''
        while not name:
        name = input('Please enter your name: ')
        print('Hello, {}!'.format(name))
        请尝试运行这些代码,并在要求你输入名字时直接按回车键。你会看到提示信息再次出现,
        因为name还是为空字符串,这相当于假。
        提示:如果你只是输入一个空格字符(将其作为你的名字),结果将如何呢?试试看。程序将
            接受这个名字,因为包含一个空格字符的字符串不是空的,因此不会将name视为假。这
            无疑是这个小程序的一个瑕疵,但很容易修复:只需将while not name改为while not name
            or name.isspace()或while not name.strip()即可。
View Code

   迭代字典 

        要遍历字典的所有关键字,可像遍历序列那样使用普通的for语句。
        d = {'x': 1, 'y': 2, 'z': 3}
        for key in d:
            print(key, 'corresponds to', d[key])
        也可使用keys等字典方法来获取所有的键。如果只对值感兴趣,可使用d.values。你可能还
        记得, d.items以元组的方式返回键值对。 for循环的优点之一是,可在其中使用序列解包。
        for key, value in d.items():
            print(key, 'corresponds to', value)
        注意:字典元素的排列顺序是不确定的。换而言之,迭代字典的键或值时,一定会处理所有的
            键或值,但不知道处理的顺序。如果顺序很重要,可将键或值存储在一个列表中并对列
            表排序,再进行迭代。要让映射记住其项的插入顺序,可使用模块collections中的
            OrderedDict类。
View Code

  一些迭代工具 

 1 并行迭代
 2             有时候,你可能想同时迭代两个序列。假设有下面两个列表:
 3             names = ['anne', 'beth', 'george', 'damon']
 4             ages = [12, 45, 32, 102]
 5             如果要打印名字和对应的年龄,可以像下面这样做:
 6             for i in range(len(names)):
 7             print(names[i], 'is', ages[i], 'years old')
 8             i是用作循环索引的变量的标准名称。一个很有用的并行迭代工具是内置函数zip,它将两个
 9             序列“缝合”起来,并返回一个由元组组成的序列。返回值是一个适合迭代的对象,要查看其内
10             容,可使用list将其转换为列表。
11             >>> list(zip(names, ages))
12             [('anne', 12), ('beth', 45), ('george', 32), ('damon', 102)]
13             “缝合”后,可在循环中将元组解包。
14             for name, age in zip(names, ages):
15             print(name, 'is', age, 'years old')
16             函数zip可用于“缝合”任意数量的序列。需要指出的是,当序列的长度不同时,函数zip将
17             在最短的序列用完后停止“缝合”。
18             >>> list(zip(range(5), range(100000000)))
19             [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
20         迭代时获取数据
21             在有些情况下,你需要在迭代对象序列的同时获取当前对象的索引。例如,你可能想替换一
22             个字符串列表中所有包含子串'xxx'的字符串。当然,完成这种任务的方法有很多,但这里假设
23             你要像下面这样做:
24             for string in strings:
25             if 'xxx' in string:
26             index = strings.index(string) # 在字符串列表中查找字符串
27             strings[index] = '[censored]'
28             这可行,但替换前的搜索好像没有必要。另外,如果没有替换,搜索返回的索引可能不对(即
29             返回的是该字符串首次出现处的索引)。下面是一种更佳的解决方案:
30             index = 0
31             for string in strings:
32             if 'xxx' in string:
33             strings[index] = '[censored]'
34             index += 1
35             这个解决方案虽然可以接受,但看起来也有点笨拙。另一种解决方案是使用内置函数
36             enumerate。
37             for index, string in enumerate(strings):
38             if 'xxx' in string:
39             strings[index] = '[censored]'
40             这个函数让你能够迭代索引值对,其中的索引是自动提供的。    
41         反向迭代和排序后再迭代
42             来看另外两个很有用的函数: reversed和sorted。它们类似于列表方法reverse和sort(sorted
43             接受的参数也与sort类似),但可用于任何序列或可迭代的对象,且不就地修改对象,而是返回
44             反转和排序后的版本。
45             >>> sorted([4, 3, 6, 8, 3])
46             [3, 3, 4, 6, 8]
47             >>> sorted('Hello, world!')
48             [' ', '!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
49             >>> list(reversed('Hello, world!'))
50             ['!', 'd', 'l', 'r', 'o', 'w', ' ', ',', 'o', 'l', 'l', 'e', 'H']
51             >>> ''.join(reversed('Hello, world!'))
52             '!dlrow ,olleH'
53             请注意, sorted返回一个列表,而reversed像zip那样返回一个更神秘的可迭代对象。你无需
54             关心这到底意味着什么,只管在for循环或join等方法中使用它,不会有任何问题。只是你不能
55             对它执行索引或切片操作,也不能直接对它调用列表的方法。要执行这些操作,可先使用list对
56             返回的对象进行转换。
57             提示:要按字母表排序,可先转换为小写。为此,可将sort或sorted的key参数设置为str.lower。
58                 例如, sorted("aBc", key=str.lower)返回['a', 'B', 'c']。
View Code

  跳出循环

通常,循环会不断地执行代码块,直到条件为假或使用完序列中的所有元素。但在有些情况
        下,你可能想中断循环、开始新迭代(进入“下一轮”代码块执行流程)或直接结束循环。
        1. break
        要结束(跳出)循环,可使用break。假设你要找出小于100的最大平方值(整数与自己相乘
        的结果),可从100开始向下迭代。找到一个平方值后,无需再迭代,因此直接跳出循环。
        from math import sqrt
        for n in range(99, 0, -1):
        root = sqrt(n)
        if root == int(root):
        print(n)
        break
        如果你运行这个程序,它将打印81并结束。注意到我向range传递了第三个参数——步长,
        即序列中相邻数的差。通过将步长设置为负数,可让range向下迭代,如上面的示例所示;还可
        让它跳过一些数:
        >>> range(0, 10, 2)
        [0, 2, 4, 6, 8]
        2. continue
        语句continue没有break用得多。它结束当前迭代,并跳到下一次迭代开头。这基本上意味
        着跳过循环体中余下的语句,但不结束循环。这在循环体庞大而复杂,且存在多个要跳过它的原
        因时很有用。在这种情况下,可使用continue,如下所示:
        for x in seq:
        if condition1: continue
        if condition2: continue
        if condition3: continue
        do_something()
        do_something_else()
        do_another_thing()
        etc()
        然而,在很多情况下,使用一条if语句就足够了。
        for x in seq:
        if not (condition1 or condition2 or condition3):
        do_something()
        do_something_else()
        do_another_thing()
        etc()
        continue虽然是一个很有用的工具,但并非不可或缺的。然而,你必须熟悉break语句,因为
        在while True循环中经常用到它.
View Code

  简单推导

列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导。列表推导的工作原
        理非常简单,有点类似于for循环。
        >>> [x * x for x in range(10)]
        [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
        这个列表由range(10)内每个值的平方组成,非常简单吧?如果只想打印那些能被3整除的平
        方值,该如何办呢?可使用求模运算符:如果y能被3整除, y 3 % 将返回0(请注意,仅当x能被3
        整除时, x*x才能被3整除)。为实现这种功能,可在列表推导中添加一条if语句。
        >>> [x*x for x in range(10) if x 3 == 0] %
        [0, 9, 36, 81]
        还可添加更多的for部分。
        >>> [(x, y) for x in range(3) for y in range(3)]
        [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
        作为对比,下面的两个for循环创建同样的列表:
        result = []
        for x in range(3):
        for y in range(3)
        result.append((x, y))
        与以前一样,使用多个for部分时,也可添加if子句。
        >>> girls = ['alice', 'bernice', 'clarice']
        >>> boys = ['chris', 'arnold', 'bob']
        >>> [b+'+'+g for b in boys for g in girls if b[0] == g[0]]
        ['chris+clarice', 'arnold+alice', 'bob+bernice']
        这些代码将名字的首字母相同的男孩和女孩配对。
        最佳解决方案
        前述男孩/女孩配对示例的效率不太高,因为它要检查每种可能的配对。使用Python解决
        这个问题的方法有很多,下面是Alex Martelli推荐的解决方案:
        girls = ['alice', 'bernice', 'clarice']
        boys = ['chris', 'arnold', 'bob']
        letterGirls = {}
        for girl in girls:
        letterGirls.setdefault(girl[0], []).append(girl)
        print([b+'+'+g for b in boys for g in letterGirls[b[0]]])
        这个程序创建一个名为letterGirls的字典,其中每项的键都是一个字母,而值为以这个
        字母打头的女孩名字组成的列表(字典方法setdefault在前一章介绍过)。创建这个字典后,
        列表推导遍历所有的男孩,并查找名字首字母与当前男孩相同的所有女孩。这样,这个列表
        推导就无需尝试所有的男孩和女孩组合并检查他们的名字首字母是否相同了。
        使用圆括号代替方括号并不能实现元组推导,而是将创建生成器,详细信息请参阅第9章的
        旁注“简单生成器”。然而,可使用花括号来执行字典推导。
        >>> squares = {i:"{} squared is {}".format(i, i**2) for i in range(10)}
        >>> squares[8]
        '8 squared is 64'
        在列表推导中, for前面只有一个表达式,而在字典推导中, for前面有两个用冒号分隔的表
        达式。这两个表达式分别为键及其对应的值。
View Code

  pass,del和exec

使用del
        对于你不再使用的对象, Python通常会将其删除(因为没有任何变量或数据结构成员指向它)。
        >>> scoundrel = {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
        >>> robin = scoundrel
        >>> scoundrel
        {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
        >>> robin
        {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
        >>> scoundrel = None
        >>> robin
        {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
        >>> robin = None
        最初, robin和scoundrel指向同一个字典,因此将None赋给scoundrel后,依然可以通过robin
        来访问这个字典。但将robin也设置为None之后,这个字典就漂浮在计算机内存中,没有任何名
        称与之相关联,再也无法获取或使用它了。因此,智慧无穷的Python解释器直接将其删除。这被
        称为垃圾收集。请注意,在前面的代码中,也可将其他任何值(而不是None)赋给两个变量,这
        样字典也将消失。
        另一种办法是使用del语句。(第2章和第4章使用这条语句来删除序列和字典,还记得吗?)
        这不仅会删除到对象的引用,还会删除名称本身。
        >>> x = 1
        >>> del x
        >>> x
        Traceback (most recent call last):
        File "<pyshell#255>", line 1, in ?
        x
        NameError: name 'x' is not defined
        这看似简单,但有时不太好理解。例如,在下面的示例中, x和y指向同一个列表:
        >>> x = ["Hello", "world"]
        >>> y = x
        >>> y[1] = "Python"
        >>> x
        ['Hello', 'Python']
        你可能认为通过删除x,也将删除y,但情况并非如此。
        >>> del x
        >>> y
        ['Hello', 'Python']
        这是为什么呢? x和y指向同一个列表,但删除x对y没有任何影响,因为你只删除名称x,而
        没有删除列表本身(值)。事实上,在Python中,根本就没有办法删除值,而且你也不需要这样
        做,因为对于你不再使用的值, Python解释器会立即将其删除。
    使用 exec 和 eval 执行字符串及计算其结果
        有时候,你可能想动态地编写Python代码,并将其作为语句进行执行或作为表达式进行计算。
        这可能犹如黑暗魔法,一定要小心。 exec和eval现在都是函数,但exec以前是一种语句,而eval
        与它紧密相关。这就是我在这里讨论它们的原因所在。
        警告 本节介绍如何执行存储在字符串中的Python代码,这样做可能带来严重的安全隐患。如
            果将部分内容由用户提供的字符串作为代码执行,将无法控制代码的行为。在网络应用
            程序,通用网关接口(CGI)脚本中,这样做尤其危险。
        1. exec
            函数exec将字符串作为代码执行。
            >>> exec("print('Hello, world!')")
            Hello, world!
            然而,调用函数exec时只给它提供一个参数绝非好事。在大多数情况下,还应向它传递一个
            命名空间——用于放置变量的地方;否则代码将污染你的命名空间,即修改你的变量。例如,假
            设代码使用了名称sqrt,结果将如何呢?
            >>> from math import sqrt
            >>> exec("sqrt = 1")
            >>> sqrt(4)
            Traceback (most recent call last):
            File "<pyshell#18>", line 1, in ?
            sqrt(4)
            TypeError: object is not callable: 1
            既然如此,为何要将字符串作为代码执行呢?函数exec主要用于动态地创建代码字符串。如
            果这种字符串来自其他地方(可能是用户),就几乎无法确定它将包含什么内容。因此为了安全
            起见,要提供一个字典以充当命名空间。
                注意:命名空间(作用域)是个重要的概念,但就目前而言,你可将命
                    名空间视为放置变量的地方,类似于一个看不见的字典。因此,当你执行赋值语句x = 1
                    时,将在当前命名空间存储键x和值1。当前命名空间通常是全局命名空间(到目前为止,
                    我们使用的大都是全局命名空间),但并非必然如此。
                    实际上,可向exec提供两个命名空间:一个全局的和一个局部的。提供的全局命名空间必须是字典,而提供的局
                    部命名空间可以是任何映射。这一点也适用于eval。
            为此,你添加第二个参数——字典,用作代码字符串的命名空间
            >>> from math import sqrt
            >>> scope = {}
            >>> exec('sqrt = 1', scope)
            >>> sqrt(4)
            2.0
            >>> scope['sqrt']
            1
            如你所见,可能带来破坏的代码并非覆盖函数sqrt。函数sqrt该怎样还怎样,而通过exec执
            行赋值语句创建的变量位于scope中。
            请注意,如果你尝试将scope打印出来,将发现它包含很多内容,这是因为自动在其中添加
            了包含所有内置函数和值的字典__builtins__。
            >>> len(scope)
            2
            >>> scope.keys()
            ['sqrt', '__builtins__']
        2. eval
            eval是一个类似于exec的内置函数。 exec执行一系列Python语句,而eval计算用字符串表示
            的Python表达式的值,并返回结果(exec什么都不返回,因为它本身是条语句)。例如,你可使
            用如下代码来创建一个Python计算器:
            >>> eval(input("Enter an arithmetic expression: "))
            Enter an arithmetic expression: 6 + 18 * 2
            42
            与exec一样,也可向eval提供一个命名空间,虽然表达式通常不会像语句那样给变量重新
            赋值。
            警告 虽然表达式通常不会给变量重新赋值,但绝对能够这样做,如调用给全局变量重新赋值
                的函数。因此,将eval用于不可信任的代码并不比使用exec安全。当前,在Python中执行
                不可信任的代码时,没有安全的办法。一种替代解决方案是使用Jython(参见第17章)等
                Python实现,以使用Java沙箱等原生机制。
View Code

chr(n) 返回一个字符串,其中只包含一个字符,这个字符对应于传入的顺序值n(0 ≤n < 256)
eval(source[,globals[,locals]]) 计算并返回字符串表示的表达式的结果
exec(source[, globals[, locals]]) 将字符串作为语句执行
enumerate(seq) 生成可迭代的索引值对
ord(c) 接受一个只包含一个字符的字符串,并返回这个字符的顺序值(一个整数)
range([start,] stop[, step]) 创建一个由整数组成的列表
reversed(seq) 按相反的顺序返回seq中的值,以便用于迭代
sorted(seq[,cmp][,key][,reverse]) 返回一个列表,其中包含seq中的所有值且这些值是经过排序的
xrange([start,] stop[, step]) 创建一个用于迭代的xrange对象
zip(seq1, seq2,...) 创建一个适合用于并行迭代的新序列

 

  

 

转载于:https://www.cnblogs.com/daidechong/p/9519424.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值