编程细节总结

一、列表

1.删除列表中的元素:

  • 用 del 删除元素会导致列表的剩余元素(从删除元素的后面元素开始)的索引发生变化,一般不建议使用。

  • 用 remove 或 pop 方法移除可不会发生溢出列表长度的错误,remove只会移除首先遍历到的元素,pop() 括号内不写入值时,默认删除最后一个元素,加入就按索引删除元素

  • 列表切片,取到==最后==一个元素

    lis=[3::]  #取索引为3到最后的元素,注意冒号之间没有数字
    lis=[len(lis)-1::-1] #倒着取所有元素,包含最后元素,只要倒着取,一定要加负数的步长
  • range() 倒着遍历列表到==最后==一个元素

    for i in range(len(lis)-1,-1,-1)
    #注意各个数字

2.输出列表中元素的索引:

  • 当列表中有重复的元素时,使用for i in lis_1: 循环时,当要输出i的索引时,若此时i为列表中的重复的元素,则重复的元素的索引会一样即相等,因为系统默认lis_1.index(i)这里的i是一个列表中值,只会输出列表中的最先遍历到的i的索引。

二、字符串

1.切割字符串:

  • 切割字符串时,会生成新的列表,原字符串不变化。

  • 字符串的内置方法中,凡是对字符串做修改的操作,字符串本身不会发生变化,想要得到变化后的结果,就要新赋值给一个变量。

    也可当做当对不可变的数据类型做修改操作时,这个不可变的数据类型本身不会发生变化,想要得到变化的结果,需要把变化的东西赋值给一个变量

  • 字符串转换成列表,不用再遍历字符串了。 如:

    s='abcd ef ,g'
    lis=list(s)
    print(lis)
    #打印结果:
    #['a', 'b', 'c', 'd', ' ', 'e', 'f', ' ', ',', 'g']

2. 字符串也可以进行比较,先按首字母比较,相同就比较第二位字母。

三、BUG

  • debug:定位bug,不一定是定位的那一行出错了

四、 读取文本文件

txt文档按行读取时(f.readline()),利用字符串的strip方法切割,把换行符切掉,再利用split方法切割,就可以生成新列表,这样就可以处理按行存储的信息

  • 修改文本文件的原理

    with open('test.txt', 'r', encoding='utf8') as fr,open('test_swap.txt', 'w', encoding='utf8') as fw:
        # 再大的文件都能修改
        data = fr.read()
        fw.write(data)   
    
    import os
    
    os.remove('test.txt')
    os.rename('test_swap.txt', 'test.txt')#先是要修改的文件名字,后是修改后的文件名字,replace 也是如此。

五、一些小的技巧

1. 字符串

  • 把字符串的字母都变大写

    s='ab cd,f'
    s=s.upper() #注意,一定一定一定要重新赋值一下,或者直接打印print(s.upper()),否则打印print(s),还是小写的
    
  • 把字符串的字母都变小写

    用 lower() 方法

2. 运算

  • print(1.2 - 1.0 == 0.2)  # False
    #010101010 01010101010# # # 010101010 - 01010101010  # 一些差错# # print(round(1.2 - 1.0))  # 浮点数运算时造成的不确定尾数
    小数不比整数,小数的二进制非常复杂,所有当两个小数进行算术运算的时候,会出现错误,这个计算的结果无限接近0.2,但是不等于0.2,因此打印返回的是 Fales
    而且小数保留两位的时候,不会四舍五入,只有整数有四舍五入。
    
    但是我们可以用下面的方法得到0.2
    就是先把两个运算的浮点数变成整数之后在进行运算。最后再除以10的倍数
    n = (1.2*10 - 1.0*10)/10
    print(n)

3.Python自带的一些东西

  • Python中只要定义变量就会创建新的内存空间,以下为两种特例

    Python里的小整数池,在Python启动时就自动为[-5,256]分配内存空间,也就是说,在这个区间内的整数,它们的内存地址被写死,不会改变。

    而Pycharm中,把这个小整数池扩大了,在很短的一段时间内定义一个变量值相同的变量,他们的内存地址相同。

  • Python中每个数据类型的数据都有对应的布尔值,

    0 / None / 空(空字符、空列表、空字典、空元组) /Falese这些对应的布尔值都为False,其他的为True

  • 存不是目的,取才是目的

  • 深浅拷贝:

    ==列表,字典等数据类型的内置方法中的 .copy方法都是浅拷贝==

    lt2 是 lt1的浅/深复制对象  :  就是lt2 复制了lt1 
    lt2 = copy.copy(lt1)  
    lt2 = copy.deepcopy(lt1) 

4. 散列表(哈希表)

字典的key 和集合的元素 都是基于散列表来存储的。索引字典和集合无序,不重复。

六、 集合

乱序:当集合中只有正整数的时候,按升序排序。有正负整数时,正整数升序排序,负数乱序排序,且,且负数在正数后面开始排序。当集合中有正浮点数和符浮点数时,都是按乱序排列,正的排在负的前,正浮点数会乱序在正整数中。

七、 re模块

# findall match  search 的区别:
s = 'abcd abcddd abc'

print(re.findall('abcd*', s))
# ## match:  从开头找一个,找得到就不找了 ;找不到报错 --》
# s = 'ab abcddd abc'
# res = re.match('abcd*', s)
# print(res.group())

## search: 从字符串找一个,就不找了
s = 'ab abcddd abc'
res = re.search('abcd*', s)

print(1115555,res)
print(res.group())

八 、迭代器与生成器

#除了数字类型,所有数据类型都是可迭代对象
#为什么要有迭代器对象:提供了 不依赖索引取值的 手段

生成器都是可以用迭代进行取值的,如__next__() ,for循环,还可以使用强制类型转换,转换成列表就可以直接打印出来生成器中的元素。

#for循环原理,本质是可控的while循环
dic = {'a':1,'b':2,'c':3}
dic_iter = dic.__iter__()
while True:
    try:
        print(dic_iter.__next__())
    except StopIteration:
        break
# 生成器 自定义range方法
def re_range(start,stop,step):
    while start < stop:
        yield start
        start += step

for i in re_range(0,10,2):
    print(i)

九、 循环导入问题和解决办法

  • 导模块,模块永远只会开辟一次内存空间,所以当发生循环导入的情况时,不会出现内存满了了的错误,只会发生死循环的错误。
    
    循环导入原理:模块永远只会开辟一次 ; from m1 import 必须得执行m1.py中所有代码,当两个模块互相导入时,就有可能会发生死循环。
    1. 在m1中运行m2模块
    2. 在m2中运行m1模块
    1. 在m1中运行m2模块
    2. 在m2中运行m1模块
    ...
  • 解决方法

    # 第一种解决方法:
     # m1.py下:
    
    x = 10
    from m2 import y
    
    print('m1:', x, y)
    
    # 第一种解决方法:
     # m2.py下:
    
     y = 20
    from m1 import x
    
    print('m2:',x,y)
    
    
    
    # 第二种: 定义函数阶段只检测语法,不执行代码
    
     # m1.py下:
    def f1():
        from m2 import y
    
        print('m1:', x, y)
    
    
    x = 10
    f1()
    
    # 第二种解决方法:
     # m2.py 下:
    def f2():
        from m1 import x
    
        print('m2:', x, y)
    
    y = 20

十、 函数和类

  • 函数在调用的时候才开辟名称空间,执行函数内部的代码

  • 类是在定义的时候就会开辟名称空间(把类内部的名称全部丢进类的名称空间里),执行类内部的代码。

  • 名称空间的执行(生成)顺序:

    内置——》全局——》局部

  • 名称空间的搜索顺序:

    先当前位置 局部——》全局——》内置——》报错 (不可逆)

  • 模块的搜索顺序:

    内存中的模块——》内置模块——》自定义模块

  • 对象中名称的搜索顺序:

    • 先对象自己的名称空间——》实例化产生对象的类的名称空间——》父类的名称空间(有多个父类时,按照继承父类的顺序查找)

    • 当类中有self.func()时,还会重新开始从对象开始按上面的顺序搜索

  • 在类中的定义的函数,类自己调用它是它就是普通的函数(function)。当对象调用它时,它是绑定方法 (bound method),且类和不同的对象调用同一个函数时,他们(如Student.func stu1.func stu2.func)的内存地址都不同

十一、 装饰器的特性

对于二层装饰器,多次使用这个装饰器时,装饰器中 两个函数之间的代码,只会在第一次调用装饰器时执行一次,仅这一次,只会调用这个装饰器,会直接从第二个函数运行。

十二、 面向对象之 反射

对象.__dict__ 只返回对象自己的属性(即通过self.属性的这些属性),就是不包过继承的类中类自己的属性

类.__dict__只返回类自己的属性

hasattrgetattr,判断对象时,会查找对象自己的,对象自己没有就去找类的。

十三、 面向对象之 魔法方法(类的内置方法)

    __getattr__: 会在执行程序时遇到 对象.属性 或者 getattr 方法时,并且 “属性没有” 的情况下才会触发,对象.属性 或者 getattr 的返回值永远是None。
        
    __getattribute__ : 会在执行程序时遇到 对象.属性 或者 getattr 方法 时,无论 “属性有或者没有” 的情况下都会触发。无论属性有没有,对象.属性 或者 getattr 的返回值永远是None,使用这两个方法,对象.属性永远不会报错。
    当 __getattr__ 和 __getattribute__ 同时存在,只会触发                 __getattribute__ 。
    
    __delattr__ : 会在执行程序时遇到删除对象属性(即 del 对象.属性 【属性是对象自己的或者类的】 )时触发
    而且 del 对象.属性  并没有删除该属性
    del  类名.属性  会删除该属性 ,删除类的属性不会触发 __delattr__
    
    __del__ : 会在要销毁对象时触发 。如:(1) del 对象名 。
            (2)程序执行结束,因此这种情况会在最后执行该方法的代码    
    

猜你喜欢

转载自www.cnblogs.com/Mcoming/p/11670584.html