Python八股文

python return 和yield区别

在Python中,returnyield 是用于从函数中返回值的两种关键字,但它们之间有着很大的区别。

  1. return:return 语句用于从函数中返回一个值,并终止函数的执行。当函数执行到 return 语句时,它会立即返回指定的值,并且不再执行函数的其他部分。一个函数可以包含多个 return 语句,但只有其中一个会被执行,因为执行到一个 return 语句后函数就会退出。
  2. yield:yield 关键字用于定义生成器函数,它允许函数暂停执行,并返回一个中间值。每次调用生成器函数时,它会从上次暂停的地方继续执行,直到遇到下一个 yield 语句。yield 语句可以多次出现在一个生成器函数中,每次调用生成器函数时,它会执行到下一个 yield 语句,然后暂停,直到再次被调用。生成器函数的执行状态会被保存,这使得它可以生成一个序列而不需要一次性将所有值存储在内存中。
def generate_numbers():
    for i in range(5):
        yield i

numbers = generate_numbers()
for num in numbers:
    print(num)
#输出: 0 1 2 3 4

生成器函数:生成器函数是一种特殊的函数,它可以通过 yield 关键字来生成一系列值,而不是一次性返回所有结果。生成器函数可以在需要时生成值,这样可以节省内存,并允许以一种惰性的方式产生数据。在上文中numbers = generate_numbers() 只运行了一次,但它创建了一个生成器对象 numbers。当你使用 for num in numbers: 循环迭代生成器对象时,每次迭代都会触发生成器函数的执行,从上次暂停的地方继续执行,直到遇到下一个 yield 语句暂停。这样就会产生多个值,每次迭代都会生成一个新的值。

什么是闭包closure

闭包(Closure)是一种编程语言的特性,指的是一个函数(或者称为内部函数)能够访问其外部函数中的变量,并将该函数及其相关的环境打包成一个整体,形成一个闭包。闭包允许函数在定义时捕获其所在作用域的状态,即使在其定义作用域外被调用时也可以访问和修改这些状态。

下面是一个简单的实例:

def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

closure = outer_function(5)
result = closure(3)
print(result)  # 输出: 8

在这个示例中,outer_function 是外部函数,它接受一个参数 x,并返回了一个内部函数 inner_functioninner_function 中引用了 outer_function 中的变量 x,形成了闭包。当 outer_function(5) 调用时,会返回 inner_function,此时 x 被绑定为 5。然后通过 closure(3) 调用返回的闭包,此时 x 保持为 5,然后与 y 相加得到结果 8

闭包的优点和应用包括:

  1. 保持状态:闭包可以在函数调用之间保持状态,而不需要使用全局变量。
  2. 封装性:闭包可以封装私有数据和操作,并将其作为单个单元暴露给外部。
  3. 代码复用:可以利用闭包来封装通用的功能,并在不同的上下文中复用。
  4. 回调函数:闭包常用于创建回调函数,在事件发生时执行特定的逻辑。

需要注意的是,闭包可能导致内存泄漏,因为闭包中包含了对外部作用域的引用,使得外部作用域中的变量无法被垃圾回收。因此,当不再需要闭包时,最好手动解除对其的引用,以释放资源。

类方法、实例方法和静态方法

1. 类方法 (Class Methods):

类方法是与类相关联的方法,而不是与实例相关联。通过装饰器 @classmethod 来声明,第一个参数通常是 cls,代表类本身。类方法可以访问类的属性和方法,但不能直接访问实例的属性和方法。类方法通常用于创建、操作或者是在类级别上进行操作,而不涉及特定的实例。

class MyClass:
    class_variable = 0
    
    @classmethod
    def increment_class_variable(cls):
        cls.class_variable += 1
        
    @classmethod
    def get_class_variable(cls):
        return cls.class_variable

# 调用类方法
MyClass.increment_class_variable()
print(MyClass.get_class_variable())  # 输出: 1

2. 实例方法 (Instance Methods):

实例方法是与类的实例相关联的方法。在方法定义中,第一个参数通常是 self,代表实例本身。实例方法可以访问实例的属性和方法,也可以访问类的属性和方法。实例方法通常用于实例的初始化、操作和处理实例的状态。

class MyClass:
    def __init__(self, value):
        self.value = value
    
    def add_value(self, num):
        self.value += num
        
    def get_value(self):
        return self.value

# 创建实例
obj = MyClass(5)
# 调用实例方法
obj.add_value(3)
print(obj.get_value())  # 输出: 8

3. 静态方法 (Static Methods):

静态方法与类或实例无关,与普通函数类似,但是定义在类的内部。通过装饰器 @staticmethod 来声明,没有默认的第一个参数。静态方法不能访问类的属性和方法,也不能访问实例的属性和方法。静态方法通常用于在类的范围内提供一些功能,这些功能与特定的实例或类无关。

class MyClass:
    @staticmethod
    def multiply(x, y):
        return x * y

# 调用静态方法
result = MyClass.multiply(3, 4)
print(result)  # 输出: 12

这些不同类型的方法可以根据需要在类中混合使用。调用这些方法的方式也不同:类方法通过类名调用,实例方法通过实例调用,而静态方法可以通过类名或实例名调用。

多线程和多进程区别

  1. 多线程 (Multithreading):多线程是在同一进程内执行的多个线程,每个线程共享相同的地址空间和其他资源。多线程适合于I/O密集型任务和轻量级的并发操作,因为线程之间的切换开销较小。多线程的优势在于线程之间可以共享内存,因此数据共享和通信相对容易实现。线程之间的同步和互斥操作通常需要额外的锁机制,以防止竞态条件和数据不一致的问题。
  2. 多进程 (Multiprocessing):多进程是在不同的进程中执行的多个进程,每个进程有自己独立的地址空间和资源。多进程适合于CPU密集型任务和需要更高级别的并行性的应用程序,因为进程之间的切换开销较大。多进程的优势在于进程之间的隔离性,每个进程有自己独立的内存空间,因此数据共享和通信相对复杂。进程之间的通信通常使用消息传递机制,如队列、管道等,或者使用共享内存来实现数据共享。

总的来说,多线程适用于轻量级的并发任务,而多进程更适用于需要更高级别并行性和更好隔离性的任务。选择使用哪种方式取决于具体的应用场景和需求。

*arg 和**karg的区别是什么

*args**kwargs 是 Python 中用于处理函数参数的特殊语法,它们用于接收不定数量的参数,其中 *args 用于接收位置参数,而 **kwargs 用于接收关键字参数。

*args:*args 是一个元组(tuple),用于接收不定数量的位置参数。

  • 当你不确定函数会接收多少个位置参数时,可以使用 *args 来接收。
  • 在函数定义时,将 *args 放在参数列表中,表示该函数可以接收任意数量的位置参数。
  • 在函数调用时,可以传递任意数量的位置参数给 *args,它们会被自动打包成一个元组传递给函数。

**kwargs:**kwargs 是一个字典(dictionary),用于接收不定数量的关键字参数。

  • 当你不确定函数会接收多少个关键字参数时,可以使用 **kwargs 来接收。
  • 在函数定义时,将 **kwargs 放在参数列表中,表示该函数可以接收任意数量的关键字参数。
  • 在函数调用时,可以传递任意数量的关键字参数给 **kwargs,它们会被自动打包成一个字典传递给函数,其中键是参数名,值是对应的参数值。
def example_function(*args, **kwargs):
    print("Positional arguments (args):", args)
    print("Keyword arguments (kwargs):", kwargs)

# 测试
example_function(1, 2, 3, name="Alice", age=30)

在这个示例中,example_function() 函数接收了三个位置参数和两个关键字参数。*args 接收了位置参数 1, 2, 3,它们被打包成一个元组;**kwargs 接收了关键字参数 name="Alice"age=30,它们被打包成一个字典。

python的内存管理方式

Python的内存管理机制涉及多个方面,包括对象的分配和释放、垃圾回收机制、内存池管理等。以下是对这些方面的详细介绍:

1. 内存分配和释放

Python使用动态内存分配来管理对象的内存,这意味着内存的分配和释放都是在运行时进行的。Python通过一个名为PyObject的结构体来管理对象的引用计数,以此来追踪对象的使用情况。

2. 引用计数

Python使用引用计数(Reference Counting)作为其主要的内存管理机制。每个对象都有一个引用计数器,记录有多少个引用指向该对象。当一个新的引用指向对象时,引用计数器加1;当引用被删除时,引用计数器减1。引用计数器为0时,表示该对象不再被使用,其占用的内存可以被回收。

import sys
a = []
print(sys.getrefcount(a))  # 初始引用计数
b = a
print(sys.getrefcount(a))  # 引用计数增加
del b
print(sys.getrefcount(a))  # 引用计数减少

3. 垃圾回收机制

除了引用计数,Python还实现了一个垃圾回收(Garbage Collection, GC)机制来处理循环引用的问题。Python的垃圾回收机制使用了分代回收算法,将对象分为三代(generation),新创建的对象属于第0代,存活时间较长的对象会逐渐移动到第1代和第2代。垃圾回收器会优先检查第0代对象,逐渐向更高代次推进。

垃圾回收器的工作流程包括以下几步:

  1. 标记:标记所有活动的对象。
  2. 清除:清除未被标记的对象。
  3. 整理:有时会整理内存以减少碎片。
import gc
gc.collect()  # 手动触发垃圾回收

4. 内存池管理

为了提高内存分配和释放的效率,Python使用了一种称为内存池(Memory Pool)的技术。内存池将小对象(小于256字节)的内存分配委托给一个名为pymalloc的专用分配器,而不是直接使用操作系统提供的内存分配函数(如malloc)。这种方式减少了内存碎片,提高了内存分配和释放的效率。

5. 内存泄漏检测

尽管Python的内存管理机制较为完善,但在某些情况下仍可能发生内存泄漏,特别是在使用外部扩展模块时。为了检测内存泄漏,可以使用Python标准库中的gc模块和tracemalloc模块。

import tracemalloc
tracemalloc.start()
# 代码运行
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')
for stat in top_stats[:10]:
    print(stat)

6. 使用工具监控内存

开发过程中,可以使用一些第三方工具来监控和分析Python程序的内存使用情况。例如:

  • objgraph:可以生成对象引用图,帮助分析对象间的引用关系。
  • memory_profiler:可以按行监控内存使用情况。
  • guppy3:可以提供详细的内存使用报告。
from memory_profiler import profile
@profile
def my_func():
    a = [1] * (10 ** 6)
    b = [2] * (2 * 10 ** 7)
    del b
    return a
my_func()

Python通过引用计数和垃圾回收机制实现了自动内存管理,并通过内存池技术优化了小对象的内存分配和释放。这些机制共同作用,使得开发者能够专注于业务逻辑,而不必过多担心内存管理的细节

python的继承机制是什么样的

  1. 单继承与多继承:单继承:一个子类只能继承一个父类。多继承:一个子类可以继承多个父类。
  2. 继承的层次结构:继承关系可以形成多层次的继承结构,即一个类可以继承另一个类,而这个类又可以继承另一个类。
  3. 方法重载与重写:方法重载(Overloading):Python不直接支持方法重载,即不能定义同名的多个方法,只能通过默认参数等方式实现类似效果。方法重写(Overriding):子类可以重写父类的方法。通过调用super()函数,子类可以调用被重写的父类方法。
  4. 继承内置类:Python允许自定义类继承内置类,如list、dict等,从而扩展其功能。

下面是一些具体的例子来说明如何实现继承及其相关特点:

单继承

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name} makes a sound")

class Dog(Animal):
    def speak(self):
        print(f"{self.name} barks")

# 使用子类
dog = Dog("Buddy")
dog.speak()  # 输出: Buddy barks

多继承

class Flyer:
    def fly(self):
        print("Flying")

class Swimmer:
    def swim(self):
        print("Swimming")

class Duck(Flyer, Swimmer):
    pass

# 使用子类
duck = Duck()
duck.fly()   # 输出: Flying
duck.swim()  # 输出: Swimming

方法重写与super()

class Parent:
    def greet(self):
        print("Hello from Parent")

class Child(Parent):
    def greet(self):
        super().greet()  # 调用父类的方法
        print("Hello from Child")

# 使用子类
child = Child()
child.greet()  # 输出: Hello from Parent
               #      Hello from Child

继承内置类

class MyList(list):
    def append(self, item):
        print(f"Adding {item} to the list")
        super().append(item)

# 使用自定义类
my_list = MyList()
my_list.append(1)  # 输出: Adding 1 to the list
print(my_list)     # 输出: [1]

#八股#
全部评论
您就是我的救星
点赞 回复 分享
发布于 2024-07-17 10:15 美国

相关推荐

1. 请先做个简单的自我介绍?重点介绍一下自己的相关经历,最好能提及与产品相关方面。2. 你最近5年的职业规划是什么,能否详细的谈一下,尤其是针对产品经理实习生阶段?3. 你应聘这个岗位的优势是什么?劣势是什么?(各说三点)请具体结合岗位要求说明。4. 为什么选择应聘我们公司?请阐述下对美图公司产品及企业文化的认知。5. 能不能谈谈对我们公司产品和所在行业的了解?比如美图相关影像修图产品情况。6. 你期望的薪酬是多少? 说明下期望薪资的考量因素及与自身能力的匹配度。7. 大学期间最喜欢哪一门专业课程?为什么喜欢这一门?讲讲对该课程的独特见解。8. 用三个词,总结一下这几年自己大学的经历?并分别展开说说为何选这三个词9. 大学期间都参加过哪些社团或者学生组织?可否谈一谈?说说在其中承担的角色。10. 平时有什么兴趣爱好?有什么特长吗?阐述下兴趣爱好与特长对该岗位的潜在助力11. 若协助产品经理落地产品需求,输出产品原型时遇到难题,你会如何解决?12. 当与各部门沟通协调推动产品上线环节出现分歧,你有什么应对策略?13. 关注数据和用户反馈后,怎样基于此分析出准确的用户需求?14. 请说明如何有效分析行业竞品,为产品创新提供思路?15. 对于持续创新优化产品体验,你有哪些自己的想法和途径?16. 怎样跟踪优化产品体验后的效果,并以数据呈现给团队
查看16道真题和解析
点赞 评论 收藏
分享
评论
86
557
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务