Python常见的基础概念问题

  1. 说一说Python中的新式类和旧式类有什么区别。

    新式类与旧式类的区别主要在于它们的继承类的搜索顺序,

    新式类:广度优先查找,需要的属性现在自己本身查找,如果没有就从继承的第一个父类中查找,如果没有就从继承的第二个父类中查找,还是没有的话就从第一个父类的父类中查找该属性,依此类推,广度优先其实就是找新的父类的属性,不去往父类的深度去查找。
    继承通过:super(子类名, self).__init(属性1,属性2…)

    旧式类(经典类):深度优先查找,需要的属性先在自己本身查找,如果没有就从继承的第一个父类中找,如果没有就从该父类的父类中查找,没有就再去继承的第二个父类中查该属性,依此类推,深度优先就是从继承父类的深度去查找,就相当于往经典的方面去查找。
    继承通过:父类名.init(self,属性1…)

  2. Python中is运算符和==运算符有什么区别?

    is 同一性运算符:比较两个对象的地址是否相等,id做为判断因素

    == 比较运算符:比较两个对象的值是否相等,value做为判断因素

  3. Python中如何动态设置和获取对象属性?

    python中有几个内建的方法,可以用来检查和设置和访问对象的属性,

    dir(obj):返回的obj大多数的属性列表,

    hasattr(obj, attr):检查对象是否有指定属性,返回布尔值

    getattr(obj, attr):获取对象的指定属性

    setattr(obj, attr, value):给对象添加属性attr属性名,value属性值

    class Person:
    
        def __init__(self, name='Tom'):
            self.name = name
    
        def say_hi(self):
            print(f'Hello, {self.name}')
    
    p = Person()
    p.say_hi()      # Hello, Tom
    print(hasattr(p, 'name'))  # True
    print(hasattr(p, 'age'))   # False
    print(p.name)               # Tom
    print(getattr(p, 'name'))   # Tom
    print(getattr(p, 'age'))   # AttributeError: 'Person' object has no attribute 'age'
    setattr(p, 'name', 'Bob')
    print(p.name)           # Bom
    print(getattr(p, 'name'))   # Bob
    getattr(p, 'say_hi')()   # Hello, Bob
    print(dir(p))
    # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'say_hi']
    
  4. Python如何实现内存管理?有没有可能出现内存泄露的问题?

    1. 引用计数,查看引用计数sys.getrefcount()

      python内部使用了引用计数来追踪内存中的对象,当该对象的引用计数为0的时候,将被垃圾回收

    2. 垃圾回收

      当内存中有不在使用的部分时,垃圾收集器将会把它们清理掉,也就是清理引用计数为0的对象,垃圾回收机制还有一个循环垃圾收集器,确保循环引用的对象也会被清理(a引用b,b引用a)

    3. 内存池机制

      python引用了一个内存池(memory pool)机制,即Pymalloc机制(malloc:n.分配内存),用于管理小块内存的申请和释放,pymalloc的实现就是
      当对象大小小于256bits时会在pymalloc中申请内存,
      如果大于256bits时会直接执行malloc的行为来申请内存空间

      内存池的概念:
      当创建大量消耗小内存的对象时,频繁调用malloc会导致大量的内存碎片,失效率降低。内存池就是预先在内存中申请一定数量的,大小相等的内存块作为备用,当有需求时直接从内存池中分配内存给这个需求,不够再重新申请。

      python内存机制以金字塔形式,

      -1,-2层主要由操作系统进行;

      第0层是C中的malloc,free等内存分配和释放函数进行,当对象的小于256k时;

      第1,2层是内存池,由python的接口函数Pymalloc进行,当对象的大于256k时该层直接分配内存

      第3层就是python直接对对象的操作

      内存泄露指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。导致程序运行速度减慢甚至系统崩溃等严重后果。有 del() 函数的对象间的循环引用是导致内存泄漏的主凶。不使用一个对象时使用:del object 来删除一个对象的引用计数就可以有效防止内存泄漏问题。通过Python 扩展模块 gc 来查看不能回收的对象的详细信息。

      可以通过 sys.getrefcount(obj) 来获取对象的引用计数,并根据返回值是否为 0 来判断是否内存泄漏

  5. 阐述列表和集合的底层实现原理。

    • 列表
      • 创建一个列表的时候,调用了底层的C语言编写的函数,为该列表分配了大于列表长度的插槽。
      • 执行append()的过程中列表大小大于插槽数量调用底层list_resize函数对列表分配更大的插槽数量,增长速度为0、4、8、16、25、35…
      • 执行insert()的过程中调用内部的ins1()函数,insert()的平均复杂度为O(n)
      • 执行pop()的过程中调用内部的listpop()函数,在调用listpop()函数的时候会自动调用list_resize(),当列表的大小小于插槽数量一半的时候,则重新分配列表插槽。pop()操作的平均复杂度为O(1)
      • 执行remove()的过程中调用内部的listremove(),remove()操作的平均复杂度为O(n)
    • 集合
      • 集合和列表都是可变容器,但实现为哈希表,在执行增加元素查找元素的时候都是仍然是调用了底层的C语言对应的函数实现。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值