Python入门笔记

python变量

  • 没有类型声明
  • 必须要赋初值

python中的可变(mutable)和不可变(immutable)对象

  • 可变对象:list,dict,set,user-defined classes(unless specifically made immutable)

    a = {}
    b = a 
    print('id(a) = {}, id(b) = {}'.format(id(a),id(b)))
    a['yzc'] = 'nb'
    print('id(a) = {}, id(b) = {}'.format(id(a),id(b)))
    print(b['yzc'])

    其输出为:
    id(a) = 1789662989624, id(b) = 1789662989624
    id(a) = 1789662989624, id(b) = 1789662989624
    nb
    从输出结果可知,a的值发生变化,a,b的地址相同且没有发生变化,并且a发生变化b也会相应的发生变化。

  • 不可变对象:int,string,float,tuple

    i = 1
    j = 1
    print('id(i) = {},id(j) = {},id(1) = {}'.format(id(i), id(j), id(1)))
    i = i + 2
    print('id(i) = {},id(j) = {},id(1) = {}'.format(id(i), id(j), id(1)))

    其运行结果为:
    id(i) = 1541696576,id(j) = 1541696576,id(1) = 1541696576
    id(i) = 1541696640,id(j) = 1541696576,id(1) = 1541696576
    可以看出由于i的值发生变化,导致地址发生了变化

    i = 1
    j = i
    print('id(i) = {},id(j) = {},id(1) = {}'.format(id(i), id(j), id(1)))
    i = i + 2
    print('id(i) = {},id(j) = {},id(1) = {}'.format(id(i), id(j), id(1)))

    通过以上两个程序发现,当内存存储了一个数之后,就变得不可改变了,如果改变变量的值,相当于另开辟一块新的内存存储新的值。

Python中的字符串

  1. +操作符重载->字符串的拼接
  2. 字符串之前加‘r’可以表示原始字符串,而不是转义字符
  3. 多行字符串用三个引号包括,可以省去每行的换行符

python中的字符串格式化

  1. %-formatting
'%s %s' % ('one', 'two')

要注意,字符串和%之间没有逗号分隔,要写在一起
2. str.format()
3. f-strings

name = 'Tom'
age = 3
f'His name is {name},he is {age} yeas old'

python中的类型

  1. 整型
    没有short,int,long之分,统一集成为整形
  2. 浮点型
    可以用e计法来表示 15e8<=>15108 15 e 8 <=> 15 ∗ 10 8
  3. bool类型
    bool类型支持数值运算,但是不建议使用

python中的类型转换

这里写图片描述
注:如果声明的对象名与python中内置的函数名一样,对象名会覆盖掉python内置的函数,导致其无法正常调用。

  1. type():查询变量类型,返回字符串
  2. isinstance():比较类型值是否一致,返回bool类型

python中的is vs ==

最近一直被 is 和==所困扰之前一直有一种错觉觉得is 就等价于==,但是在实际应用的时候总是会出现问题,用is程序莫名其妙的不对,也查不出错误,但是换成==,程序就会正常执行,因此特地查了查is vs ==,他们到底有什么区别

  • is
    is的功能是检查两个变量是不是引用了同一个对象
  • ==
    ==的本质是检查两个对象是不是值相同
    这里写图片描述
    python解释器为1和True分别分配了不同的空间(通过打印id地址可以看出)1和True在取值上是相等的,但是地址不同。故当使用is的时候,打印结果为False,因为True和1并没有引用同一个对象。当使用==的时候,结果为True,因为==就是单纯的判断两个变量的值是否相等

python操作符

  • +,+=
  • -, -=
  • *, *=
  • **
    **代表幂操作符,其优先级是比左侧操作符高,比右侧操作符低。
  • /, /=
    在python中除法会得自动得到一个浮点数,而不是像C语言那样确定类型。
  • //
  • 两个除号的除法的结果是整数(向下取整)
  • and–对应&&
  • or–对应||
  • not–对应!
    注:
  • python中比较运算符支持连续比较操作,eg:a<b<c其等价于(a<b)and(b<c)
  • 操作符优先级 not>and>or

    python条件操作符

  • 三元操作符(x if condition else y)

f x < y:
  small = x
else:
  small = y

等价于

small = x if x < y else y

python 循环

  • while
while 条件:
    循环体
  • for
for 目标 in 表达式/列表:
    循环体

python中的list

python中直接用=赋值,是将引用赋值给新的变量,相当于两个变量指向同一片内存空间。如果想重新赋值到一片新的存储空间当中需要在列表后边加上:。因为slice会生成一个新的列表。
配合如下程序:

list1 = [1, 2, 3, 4];
list2 = list1
list3 = list1[:]
list1[3] = 6
print("List2 = ",list2)
print("List3 = ",list3)

其运行结果为:
这里写图片描述
由于list2是list1的引用,所以list1的值改变了,list2的值也会相应改变。list3是通过slice重新生成的序列,并不于list1共用一片内存,所以其值不改变
注:在list中[a:b]的取值范围是左开右闭,即list中[a,b)范围内所对应的值

python元组(tuple)

  • List的内置函数
  • 列表将数据放到中括号里,元组将数据放到小括号里,没有括号的一串数值默认缺省为元组
  • 如果只有一个数,编译器不会将其视为元组。如果想要一个元素的元组,需要在数值后边加逗号
    这里给出一个程序示例:
print(8*(8)
print(8*(8,))

其结果为:
这里写图片描述
如果在后边不加逗号,编译器理解为8*8的运算操作。加上逗号,编译器理解为8次的拷贝操作

  • 元组的赋值方法
    在元组中无法像列表那样直接赋值,因此元组需要利用slice重新开辟一片内存空间,将新的值写入到另一片内存空间中。并将元组的名字指向该内存。python解释器会自动将老的元组片段自动回收,防止内存泄漏。
    示例程序如下:
tuple1 = 1,2,3,4,5,6
print(tuple1)
tuple1 = tuple1[0:3]+(7,)+tuple1[4:6]
print(tuple1)

其结果为:
这里写图片描述

python字符串

python中字符串中的方法参考小甲鱼的字符串方法及注释

python格式化

  • format函数
  • 位置 eg:{0},{1},{2}
  • 关键字 eg:{a},{b},{c}
    format中,可以位置参数和关键字混用,但是位置参数要在关键字之前

  • python字符串中格式化符号的含义及转移字符含义
    这里写图片描述
    这里写图片描述
    这里写图片描述

python函数

  • def关键字定义函数
  • return返回
  • 函数的文档(doc
  • python函数支持关键字参数,防止参数过多,形参匹配发生错误
  • python函数支持默认参数
  • python支持变参
    需要在形参前加入*,形似C语言指针。这样python是将输入参数打包到一个元组里,作为可变参数使用。
    如果有可变参数,那么其可变参数后边的形参需要用关键字赋值,否则会出现二义性(报错)。为了避免错误,在定义函数的时候,通常给第默认参数后边的参数设置缺省值(默认参数)。
    例如python中的print函数
print(*object,sep = '', end = '\n', file = sys.stdout,f lish = False)

在*object之后,每一个参数都有默认参数。
另外:
如果想将一个列表里边的每个变量当作一个可变参数,需要在列表名前加*

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

nums = [1, 2, 3]
calc(*nums)
  • 关键字参数
    关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict
def person(name, age, **kw):
    print('name', name,'age:', age, 'other',kw)

person('Bob', 35, city = 'Beijing', gender = 'M', job = 'Engineer')

当然也可以在外部生成一个字典传递给函数,但是要在实参前加**

def person(name, age, **kw):
    print('name', name,'age:', age, 'other',kw)
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra)
  • 命名关键字参数
    如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:
def person(name, age, *, city, job):
    print(name, age, city, job)

和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符,后面的参数被视为命名关键字参数。
命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错(TypeError):

  • 在python中只有函数,没有过程,任何对象都是有返回值的,如果没有返回值,返回的是None
  • 函数可以返回多个值,通过list或者tuple打包返回。
  • 全局变量在函数中可以访问
  • 在函数中不能修改全局变量的值,因为一旦修改全局变量的值,python解释器会在栈上重新创建一个新的同名变量,对全局变量的操作会施加到新的变量上,并不会改变全局变量的值,并且导致全局变量无法访问。
  • golbal 关键字修饰,可以避免函数覆盖全局变量
  • 闭包:

    • 定义:

      1. 在函数内部嵌套函数
      2. 在嵌套的函数内部使用外层函数的局部变量
    • 作用:

      1. 提高代码可复用性

        def Func(a, b):
        def Line(x):
        return a*x + b
        return Line
        
        line1 = Func(2, 4)
        line2 = Func(3, 5)
        
        print(line1(1),line2(2))
      2. 提高并行性(流水并行),闭包可以封装函数,让函数只有一个参数输入,让流水线跑得更加顺畅

    • 关于无法使用外部局部变量进行运算的解决方案(可以赋值)

      1. 通过容器来赋值(list)

        def Func():
          z = [2]
          def Line(x):
            z[0] += 1
            return z
          return Line
        
        print (Func()(4))
      2. 通过nonlocal关键字修饰,告知编译器

        def Func():
          z = 2
          def Line(x):
            nonlocal z 
            z += 1
            return z
          return Line
        
        print (Func()(4))

    闭包的注意事项:
    返回的函数并没有立刻执行,而是直到调用了闭包才执行:

    def count():
        fs = []
        for i in range(1, 4):
            def f():
                 return i*i
            fs.append(f)
        return fs
    
    f1, f2, f3 = count()

    其f1, f2, f3的值都是9,因为只有三个函数都迭代完成才会返回i的值,此时i的值为3.

    • lambda函数
      定义方式:
    g = lambda x: x+1; #lambda 变量: 返回值
    print(g(1))
    • Python 中一些关键函数
      • filter
      • map

python 递归:

  • Fibonacci数列:

    
    #Fibonacci,F(1) = 1; F(2) = 1; F(N) = F(N-1) + F(N-2)
    
    def Fibonacci(length):
      if length<1:
        print("Exception: out of range of Fibonacci")
      elif (length == 1) or (length == 2)  :
        return 1
      else:
        return Fibonacci(length-1) + Fibonacci(length-2)
    
    for i in range(10):
      print(Fibonacci(i))
    
  • 汉诺塔:

    def hanoi(lay_num, a, b, c):#a柱子上的盘子借助b柱子到达C柱子
      if(lay_num < 1):
        print('Exception: out of the range')
      elif(lay_num == 1):
        print(a, '->', c)
      else:
        hanoi(lay_num-1, a, c, b )#a柱子上的盘子借助c柱子到达b柱子
        print(a, '->', c)
        hanoi(lay_num-1, b, a, c)#b柱子上的盘子借助a柱子到达c柱子
    
    hanoi(3, 'a', 'b', 'c')

python 字典

  • python字典初始化三种方式(value必须是字符串)
    1. dict1 = {'1':'one', '2': 'two'}
    2. dict2 = dict(((1,'one'),(2,'two')))
      前两种key可以是数字或者字符串,不能是未定义的变量名。
    3. dict3 = dict(a = 'one',b = 'two' )
      第三种方式,不能用数字或者字符串作为左值,即dict3 = dict(1 = 'one',2 = 'two' )dict3 = dict('a' = 'one','b' = 'two' )都是错误的
  • 字典中的内置函数
  • python的删除操作
    在python中等于空,并不等价于对象被删除,需要调用clear函数,才能彻底删除

    a = {'yzc': 'father'}
    print(a)
    b=a
    
    print('id(a) = ', id(a), 'id(a) = ', id(b))
    a = {}
    print(a, b)
    print('id(a) = ', id(a), 'id(a) = ', id(b))

    其结果为:
    这里写图片描述
    从结果中可以看出,当a赋值为空的时候,a的id发生变化,也就意味着,编译器重新让a指向了一个新的空字典对象,而之前的字典对象并没有被释放掉。

python中的,赋值,shallow copy 和 deep copy

  • 赋值( 直接用= )
    对于类的直接赋值的话相当于赋值引用,其对象的id是相同的
  • shallow copy
    在python中,shallow copy处理方式是:如果拷贝的是一个复杂的类型(有嵌套关系),被嵌套的部分将会被共用,没有嵌套的部分会在内存中重新拷贝一份。
    1. copy 函数
      copy函数在list,dict,tuple类被创建的时候会自动创建,也可以improt copy模块
    2. slice 赋值:copied_list = original_list[:]
  • deep copy(deepcopy 函数)
    变量内所有的内容都会被重新拷贝一份放到内存里。

python 中的集合(set)

  • 用大括号包含的元素,没有映射关系的话,就会视为集合
  • 集合中所有元素的值都是唯一的(不可重复)
  • 不支持索引
  • 没有顺序
  • frozenset无法对集合内的元素做更改

文件操作

  • open函数打开文件
    其中路径要用两个斜杠(//)进行转义
  • 文件的打开模式和文件对象方法
    文件对象用完,一定要用close函数关闭,因为文件被读取到内存进行操作,掉电丢失,只有在关闭文件的时候才会被写回硬盘中。如果不及时close文件,很有可能文件在内存中,并没有保存到磁盘里,进而导致文件内容的丢失。

  • 支持用for循环直接读取文档内容,无需转换成列表

    OS模块(系统模块)/os.path模块

    os模块中关于文件/目录常用的函数使用方法

  • 要想rmdir(删除路径,先用remove删除路径下的文件)

    pickle模块

    pickle模块的主要目的是将文本文件和一种pickle的二进制文件之间的转换。
    pickle的优势:

    • 占用更少的空间
    • pickle是一种python内嵌的二进制文件编码方式,因此通过使用pickle可以解决可移植性的问题。

python中的exception

Python中异常的种类
异常检测:

  • try-except-finally语句

        try:
            异常检测
        except Exception[as reason]:
            出现异常(Exception)后的处理代码
        finally:
            无论如何都会执行的代码

    伪代码中的Exception可以是一个tuple(Exception1, Exception2….)。

    try:
        sum = 1+'1'
    except (OSError, TypeError) as reason:
        print('Exception'+str(reason))

    运行结果为:

    Exception unsupported operand type(s) for +: ‘int’ and ‘str’

    try:
        f = open('abc123.txt','w')
        print('document has existed')
    except OSError as reason:
        print('Exception'+str(reason))
    finally:
        f.close()

    另外一个值得注意的是,当try语句中有异常与except语句匹配,finally部分的代码仍会在except语句执行之后执行。其好处就是能够防止异常发生后,某些操作没来的及做,或者被打断。(例如打开一个文件,发生异常后,文件没有及时关闭,可能造成文件内容丢失)

  • with语句对上述问题的优化,在with open语句代码块内对文件操作,出代码块,文件会被自动关闭

    with open() as object
  • raise语句可以引入一个异常

python中的else语句:

  • if…else…
  • while…else…

    def ShowMaxFactor(num):
      count = num // 2
      while count > 1:
        if num % count == 0:
          print("%d is the maximum factor of %d" %(num, count))
        count -= 1
      else:
        print('%d is a prime' %num)
    
    num = int(input (" input a number please: "))
    
    ShowMaxFactor(num)

    该程序目的是寻找最大约数,while语句循环执行结束会执行else语句,如果while语句被break中断,则else语句部分不会被执行。

  • try…else…
    当except类型没有明确被指出时,为了代码健壮性,使用else语句,应对位置异常。类似于C++中的catch(…)

python中的对象

对象的概念
  • 对象 = 属性 + 方法
  • 对象的特点:封装,继承 和 多态
面对对象编程
  • self:等价于C++中this指针,类的内部调用self来调用自身
  • __init__(self, param1, param2 ….): 构造方法
    param1,2这些参数最好设置默认值,防止出现构造的时候参数不匹配而报错。
    该魔法方法返回值必须是None

  • 私有和共有:
    python通过name mangling技术来划分private和public属性,即通过特殊的命名方式赋予私有属性。
    python默认属性和方法都是公有的
    在方法或属性命名中,最前方加双下划线,将其变为私有属性

  • 继承class DerivedClassName(BaseClassName):
    子类会覆盖父类同名的方法和属性。

    • 子类初始化父类方法:
      1. 调用未绑定的父类方法
        在子类的构造方法中BaseClassName.__init__(self)
      2. 使用super函数
        super().__init__()
        super函数可以避免菱形多继承导致的多次初始化问题
  • 类,类对象,实例对象

    class C:
        x = 1
    
    a = C()
    b = C()
    c = C()
    
    c.x = 10
    C.x = 100
    
    print(f'a.x = {a.x},\nb.x = {b.x},\nc.x = {c.x}')

    其结果为:
    a.x = 100,
    b.x = 100,
    c.x = 10
    在类定义的同时,会生成一个类对象,当类对象被实例化后会生成一个实例化对象,改变实例化对象的属性,会生成一个新的x属性,并且覆盖掉类对象的属性。

  • 类的属性和对象重名的时候,属性会覆盖方法,导致方法无法调用,因此:

    1. 不要试图在一个类里边定义出所有能想到的情况和方法,应该利用继承和组合机制来进行扩展
    2. 用不同词性命名:属性->名词,方法->动词
  • 绑定:python严格要求方法需要有实例才能被调用
    因为类对象没有self,只有实例化之后的对象才有self,因此在类的方法中调用需要使用self的方法,会报错,同时如果类中的函数第一个变量没有写self,实例化对象调用该方法时会出错。

  • 魔法方法合集

  • __new__():实例化的时候被调用,唯一一个在__init__之前被调用的方法。
    作用:customize the instance creation,大部分不需要重写,主要是需要修改不可变对象的时候需要重写
  • __del__(self):析构方法,由于采用copy-on-write技术,所以只有当所有引用都被删除的时候,才会调用析构方法
  • 用魔法方法要注意防止出现无限递归的现象

    class A(int):
        def __add__(self, other):
            return self + other
    
    a = A(1)
    b = A(2)
    a+b

    因为return self + other相当于再次调用加法函数将self和other相加。
    正确方法是:return int(self) + int(other)

  • python会根据从左向右的顺序匹配操作符运算,例如:a + b,编译器会先查询a是否支持加法运算,然后再对b进行查询。

  • 反运算:注意反运算传入的self值是右侧的操作数,因此在运算时需要注意顺序问题
class A(int):
    def __rsub__(self,other):
        return self - other
a = A(3)
5-a

其结果为-2,因为用self-other,self传入的是a的值,所以运算方向反了。

  • 属性访问

    1. __getattr__(self, name)
      定义当用户试图获取一个不存在的属性时的行为
    2. __getattribute__(self, name)
      定义当该类的属性被访问的定位
    3. __setattr__(self, name, value)
      定义当一个属性被设置时的行为
    4. __delattr__(self, name)
      定义当一个属性被删除时的行为

    属性访问容易进入死循环的陷阱

    class Rectangle:
        def __init__(self, width = 0, height = 0):
            self.width = width
            self.height = height
    
        def __setattr__(self, name, value):
            if name == 'square':
                self.width = width
                self.height = height
            else:
                self.name = value
    
        def getArea(self):
            return self.width * self.height
    
    Rectangle(4, 5)

    由于每次self.name = value的时候都要调用__setattr__(),所以构成了一个没有出口的递归。
    解决方法:

    1. 使用super函数调用基类的__setattr__()
    2. 调用ClassName.__dict__[name]的方式来赋值.
  • 描述符:将某种特殊类型的类的实例指派给另一个类的属性

    • __get__(self, instance ,ower)
      用于访问属性,它返回属性的值
    • __set__(self, instance, value)
      将在属性分配操作调用,不返回任何内容
    • __delete__(self, instance)
      控制删除操作,不返回任何内容

迭代和迭代器

注意:python迭代器中的变量不能在迭代结束之前不能随意改动,改动迭代器需要的变量会影响迭代器的运行结果(因为迭代器是用一步算一步的)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值