• Python的语言特性


    1、Python的函数传参

      Python中所有的变量都可以理解为内存中一个对象的“引用”,或者,也可以看似C中的void *的感觉。这里记住的是类型是属于对象的,而不是变量。对象分为两种:

      可更改的:list,dict;

      不可更改的:strings,tuples,numbers;

      当向函数传递一个参数,即引用的时候:

       1)如果该参数是函数外一个不可变的对象的引用,则函数执行完之后,在函数外打印的是原来的值,与函数对该引用做什么事情无关。

       2)如果该函数是函数外一个可变的对象的引用,则函数执行完之后,在函数外打印的是该函数多该引用所执行的内存空间改变的结果。

    2、普通方法、实例方法、类方法和静态方法

      普通方法:在一个Python环境中,独立于类或者对象的函数,可直接导入文件中的方法直接使用。

      实例方法:实例定义来类中,使用之前先通过类实例化一个对象,然后在通过对象调用实例方法。与c++类似。实例方法的第一个参数默认传入一个self,这个self会与实例绑定。

      类方法:与实例方法的调用方式类似,不同的是类方法第一个参数默认传入一个类cls,而不是对象。

      静态方法:对于静态方法其实和普通的方法一样,不需要对谁进行绑定,唯一的区别是调用的时候需要使用a.static_foo(x)或者A.static_foo(x)来调用.

      

      静态方法修饰:@staticmethod

      类方法修饰:@classmethod

     1 #普通方法
     2 def foo(x):
     3     pass
     4 
     5 class A(object):
     6     #实例方法
     7     def foo(self,x):
     8         pass
     9     
    10     #类方法
    11     @classmethod
    12     def class_foo(cls,x):
    13         pass
    14     
    15     #静态方法
    16     @staticmethod
    17     def static_foo(x):
    18         pass

    3、类属性和实例属性

      类属性就是供类使用的属性,实例属性就是供实例使用的属性。

      由于Python是动态语言,根据类创建的实例可以任意绑定属性。

      给实例绑定属性的方法是通过实例变量,或者通过self变量:

    1 class Student(object):
    2     def __init__(self, name):
    3         self.name = name
    4 
    5 s = Student('Bob')
    6 s.score = 90

      但是,如果Student类本身需要绑定一个属性呢?可以直接在class中定义属性,这种属性是类属性,归Student类所有

    1 class Student(object):
    2     name = 'Student'

      当我们定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到。来测试一下:

    >>> class Student(object):
    ...     name = 'Student'
    ...
    >>> s = Student() # 创建实例s
    >>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
    Student
    >>> print(Student.name) # 打印类的name属性
    Student
    >>> s.name = 'Michael' # 给实例绑定name属性
    >>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
    Michael
    >>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
    Student
    >>> del s.name # 如果删除实例的name属性
    >>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
    Student

      从上面的例子可以看出,在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性

    4、Python自省

      自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时能够获得对象的类型.比如type(),dir(),getattr(),hasattr(),isinstance()

    5、python的各种推导式(列表推导式、字典推导式、集合推导式) 

      推导式comprehensions(又称解析式),是Python的一种独有特性。推导式是可以从一个数据序列构建另一个新的数据序列的结构体。 共有三种推导,在Python2和3中都有支持:

    • 列表(list)推导式
    • 字典(dict)推导式
    • 集合(set)推导式

      使用[]生成list

      基本格式

    variable = [out_exp_res for out_exp in input_list if out_exp == 2]
      out_exp_res:  列表生成元素表达式,可以是有返回值的函数。
      for out_exp in input_list:  迭代input_list将out_exp传入out_exp_res表达式中。
      if out_exp == 2:  根据条件过滤哪些值可以。

    注意:表达式是用方括号扩起来,说明生成的是一个列表。

    实例一:
    multiples = [i for i in range(30) if i % 3 is 0]
    print(multiples)
    # Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
    实例二:
    
    def squared(x):
        return x*x
    multiples = [squared(i) for i in range(30) if i % 3 is 0]
    print multiples
    #  Output: [0, 9, 36, 81, 144, 225, 324, 441, 576, 729]

      使用()生成generator

      将列表推导式的 [] 改成 () 即可得到生成器。以下会介绍生成器。

    multiples = (i for i in range(30) if i % 3 is 0)
    print(type(multiples))
    #  Output: <type 'generator'>

      

      字典推导式

       字典推导和列表推导的使用方法是类似的,只不中括号该改成大括号。

      基本格式

    variable = {out_exp_res for out_exp in input_list if out_exp == 2}
      out_exp_res:  列表生成元素表达式,可以是有返回值的函数。
      for out_exp in input_list:  可迭代的input_list将out_exp传入out_exp_res表达式中。
      if out_exp == 2:  根据条件过滤哪些值可以。

    例子一:大小写key合并

    mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
    mcase_frequency = {
        k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0)
        for k in mcase.keys()
        if k.lower() in ['a','b']
    }
    print mcase_frequency
    #  Output: {'a': 17, 'b': 34}

    例子二:快速更换key和value

    mcase = {'a': 10, 'b': 34}
    mcase_frequency = {v: k for k, v in mcase.items()}
    print mcase_frequency
    #  Output: {10: 'a', 34: 'b'}

      集合推导式

      它们跟列表推导式也是类似的。 唯一的区别在于它使用大括号{}。

    squared = {x**2 for x in [1, 1, 2]}
    print(squared)
    # Output: set([1, 4])

    6、生成器generator

      通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

      所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

      要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:在第五点中有陈述

      如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值

    >>> next(g)
    0
    >>> next(g)
    1
    >>> next(g)
    4
    >>> next(g)
    9
    >>> next(g)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration

      不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象

    >>> g = (x * x for x in range(10))
    >>> for n in g:
    ...     print(n)
    ... 
    0
    1
    4
    9

     第二种generator的获取方法:

      比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

      1, 1, 2, 3, 5, 8, 13, 21, 34, ...

      斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            print(b)
            a, b = b, a + b
            n = n + 1
        return 'done'

      仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

     也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            a, b = b, a + b
            n = n + 1
        return 'done'

      如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。

      这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

      同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

      >>> for n in fib(6):
      ...     print(n)

     但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中:
     
      >>> g = fib(6)
      >>> while True:
      ...     try:
      ...         x = next(g)
      ...         print('g:', x)
      ...     except StopIteration as e:
      ...         print('Generator return value:', e.value)
      ...         break
      ...
      g: 1
      g: 1
      g: 2
      g: 3
      g: 5
      g: 8
      Generator return value: done

    7、Python中单下划线和双下划线  

      __foo__:一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突.

      _foo:一种约定,用来指定变量私有.程序员用来指定私有变量的一种方式.

      __foo:这个有真正的意义:解析器用_classname__foo来代替这个名字,以区别和其他类相同的命名.

    8、字符串格式化:%和format函数格式化的用法

     .format在许多方面看起来更便利.对于%最烦人的是它无法同时传递一个变量和元组.你可能会想下面的代码不会有什么问题:

     

     但是,如果name恰好是(1,2,3),它将会抛出一个TypeError异常.为了保证它总是正确的,你必须这样做:

     

     但是有点丑..format就没有这些问题.你给的第二个问题也是这样,.format好看多了.

      

      自python2.6开始,新增了一种格式化字符串的函数str.format(),可谓威力十足。那么,他跟之前的%型格式化字符串相比,有什么优越的存在呢?让我们来揭开它羞答答的面纱。
     详见如下文章:http://www.jb51.net/article/63672.htm

     

    9、迭代器和生成器

       看廖雪峰的Python教程:

       迭代器:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143178254193589df9c612d2449618ea460e7a672a366000

        凡是可作用于for循环的对象都是Iterable类型;

        凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

        集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

        Python的for循环本质上就是通过不断调用next()函数实现的,例如:

       生成器:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317799226173f45ce40636141b6abc8424e12b5fb27000  

        generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。

        要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

        请注意区分普通函数和generator函数,普通函数调用直接返回结果:

        >>> r = abs(6)
        >>> r
        6

        generator函数的“调用”实际返回一个generator对象:

        >>> g = fib(6)
        >>> g
        <generator object fib at 0x1022ef948>

    10、*args and **kwargs(可变参数)

      用*args**kwargs只是为了方便并没有强制使用它们.

      当你不确定你的函数里将要传递多少参数时你可以用*args.例如,它可以传递任意数量的参数:

    def print_everything(*args):
        for count,thing int enumerate(args):
            print '{0},{1}'.format(count,thing);
    print_everything('apple','banana','cabbage');
    
    output:
    0,apple
    1,banana
    2,cabbage

      相似的,**kwargs允许你使用没有事先定义的参数名:

  • 相关阅读:
    部署webapp到web容器的三种方式(这里的web容器Tomcat)
    jquery1.8.3文档的一些问题(可能是我理解错了,不喜勿喷)
    JQuery异步请求之省略dataType的设置
    Tomcat启动一闪而过的问题(我是windows系统,所以查看的是.bat的文件)
    tomcat控制台乱码问题
    IDEA常用的快捷键和代码模板
    ajax返回问题
    php大文件下载问题
    微信企业付款到银行卡
    支付宝单笔转账支付功能
  • 原文地址:https://www.cnblogs.com/houjun/p/8671689.html
Copyright © 2020-2023  润新知