python面试题大全(一)

文件操作

1. 大文件读取问题

有一个jsonline格式的文件file.txt大小约为10K,如何读取内容?

#! -*-conding=: UTF-8 -*-
# 2024/1/19 16:46

def get_lines():
    with open('file.txt', 'rb') as f:
        return f.readlines()


if __name__ == '__main__':
    for line in get_lines():
        print(line)  # 处理每一行数据

现在要处理一个大小为10G的文件,但是内存只有4G,如果在只修改get_lines函数而其他代码保持不变的情况下,应该如何实现?需要考虑的问题都有那些?

#! -*-conding=: UTF-8 -*-
# 2024/1/19 16:46

def get_lines():
    with open('file.txt', 'rb') as f:
        for i in f:
            yield i


if __name__ == '__main__':
    for line in get_lines():
        print(line)  # 处理每一行数据

个人认为:还是设置下每次返回的内容较好,否则读取次数太多。

#! -*-conding=: UTF-8 -*-
# 2024/1/19 16:46


def get_lines():
    with open('file.txt', 'r', encoding='utf-8') as f:
        _lines = []
        for line in f:
            _lines.append(line.strip())
            if len(_lines) == 2:
                yield _lines
                _lines = []
        if _lines:
            yield _lines


if __name__ == '__main__':
    for lines in get_lines():
        print(lines)  # 处理每两行数据

使用itertools

import itertools


def get_lines(line):
    with open('file.txt', 'r', encoding='utf-8') as f:
        while True:
            _lines = list(itertools.islice(f, line))
            if len(_lines) < line:
                yield [line.strip() for line in _lines]
                break
            yield [line.strip() for line in _lines]


if __name__ == '__main__':
    for lines in get_lines(2):
        print(lines)  # 处理每两行数据

使用mmap库

from mmap import mmap


def get_lines(fp):
    with open(fp, "r+") as f:
        m = mmap(f.fileno(), 0)
        start = 0
        while True:
            pos = m.find(b"\n", start)
            if pos == -1:
                break
            yield m[start:pos + 1].decode()
            start = pos + 1


if __name__ == '__main__':
    for lines in get_lines('file.txt'):
        print(lines)  # 处理每两行数据

要考虑的问题有:

  • 内存只有4G无法一次性读入10G文件,需要分批读入分批读入数据要记录每次读入数据的位置。
  • 分批每次读取数据的大小,太小会在读取操作花费过多时间。

https://stackoverflow.com/questions/30294146/fastest-way-to-process-a-large-file

2. 目录遍历

请打印指定目录的目录树

#! -*-conding=: UTF-8 -*-
# 2024/1/19 16:46
import os


def print_directory_contents(s_path):
    """
    这个函数接收文件夹的名称作为输入参数
    返回该文件夹中文件的路径
    以及其包含文件夹中文件的路径
    """

    for s_child in os.listdir(s_path):
        s_child_path = os.path.join(s_path, s_child)
        if os.path.isdir(s_child_path):
            print_directory_contents(s_child_path)
        else:
            print(s_child_path)


if __name__ == '__main__':
    print_directory_contents('.')

模块与包

3.输入日期, 判断这一天是这一年的第几天?

#! -*-conding=: UTF-8 -*-
# 2024/1/19 16:46
import datetime


def day_of_year():
    year = input("请输入年份: ")
    month = input("请输入月份: ")
    day = input("请输入天: ")
    date1 = datetime.date(year=int(year), month=int(month), day=int(day))
    date2 = datetime.date(year=int(year), month=1, day=1)
    return (date1 - date2).days + 1


if __name__ == '__main__':
    print(day_of_year())

4.打乱一个排好序的list对象alist?

import random

alist = [1, 2, 3, 4, 5]
random.shuffle(alist)
print(alist)

数据类型

5.现有字典 d= {‘a’:24,‘g’:52,‘i’:12,‘k’:33}请按value值进行排序?

d = {'a': 24, 'g': 52, 'i': 12, 'k': 33}

# 升序
d_set = sorted(d.items(), key=lambda x: x[1], reverse=False)
print(d_set)  # [('i', 12), ('a', 24), ('k', 33), ('g', 52)]

# 降序
print(sorted(d.items(), key=lambda x: x[1], reverse=True))
# [('g', 52), ('k', 33), ('a', 24), ('i', 12)]

x[0]代表用key进行排序;x[1]代表用value进行排序。

6.字典推导式

创建一个字典,将列表中的元素作为键,元素的平方作为值

my_list = [1, 2, 3, 4, 5]
my_dict = {x: x**2 for x in my_list}
print(my_dict)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

7.请反转字符串 “aStr”?

print("aStr"[::-1])  # rtSa

8.将字符串 “k:1 |k1:2|k2:3|k3:4”,处理成字典 {k:1,k1:2,…}

def process_string_to_dict(input_string):
    # 去除字符串中的空格
    input_string = input_string.replace(" ", "")

    # 拆分字符串成键值对列表
    pairs = input_string.split("|")

    # 创建字典
    my_dict = {}
    for pair in pairs:
        key, value = pair.split(":")
        my_dict[key] = int(value)

    return my_dict


# 调用函数并打印结果
my_string = "k:1 |k1:2|k2:3|k3:4"
result_dict = process_string_to_dict(my_string)
print(result_dict)  # {'k': 1, 'k1': 2, 'k2': 3, 'k3': 4}

# 字典推导式
print({k: int(v) for t in my_string.split("|") for k, v in (t.split(":"),)})
# {'k': 1, 'k1': 2, 'k2': 3, 'k3': 4}

9.请按alist中元素的age由大到小排序

alist = [{'name': 'a', 'age': 20}, {'name': 'b', 'age': 30}, {'name': 'c', 'age': 25}]


def sort_by_age(list1):
    return sorted(list1, key=lambda x: x['age'], reverse=True)


print(sort_by_age(alist))
# [{'name': 'b', 'age': 30}, {'name': 'c', 'age': 25}, {'name': 'a', 'age': 20}]

10.下面代码的输出结果将是什么?

alist = ['a', 'b', 'c', 'd', 'e']
print(alist[10:])  # []

11.写一个列表生成式,产生一个公差为11的等差数列

print([x*11 for x in range(10)])  # [0, 11, 22, 33, 44, 55, 66, 77, 88, 99]

12.给定两个列表,怎么找出他们相同的元素和不同的元素?

list1 = [1, 2, 3]
list2 = [3, 4, 5]

set1 = set(list1)
set2 = set(list2)

print(set1 & set2)  # {3}
print(set1 ^ set2)  # {1, 2, 4, 5}

13.请写出一段python代码实现删除list里面的重复元素?

def duplicate_removal1(a):
    """使用集合去重"""
    a = list(set(a))
    print(a)


def duplicate_removal2(a):
    """将一个列表的数据取出放到另一个列表中,中间作判断"""
    alist = []
    for i in a:
        if i not in alist:
            alist.append(i)
    # 如果需要排序的话用sort
    alist.sort()
    print(alist)


def duplicate_removal3(a):
    """使用字典"""
    b = {}
    b = b.fromkeys(a)
    c = list(b.keys())
    print(c)


al = [1, 2, 4, 2, 4, 5, 7, 10, 5, 5, 7, 8, 9, 0, 3]
duplicate_removal1(a=al)  # [0, 1, 2, 3, 4, 5, 7, 8, 9, 10]
duplicate_removal2(a=al)  # [0, 1, 2, 3, 4, 5, 7, 8, 9, 10]
duplicate_removal3(a=al)  # [1, 2, 4, 5, 7, 10, 8, 9, 0, 3]

14.python如何实现单例模式?请写出两种实现方式?

  1. 使用装饰器实现单例模式:
import threading


def singleton(cls):
    instances = {}
    lock = threading.Lock()

    def get_instance(*args, **kwargs):
        if cls not in instances:
            with lock:
                if cls not in instances:
                    instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return get_instance


@singleton
class IdGenerator:
    def __init__(self):
        self.id = 0

    def get_id(self):
        with threading.Lock():
            self.id += 1
            return self.id


if __name__ == '__main__':
    singleton1 = IdGenerator()
    singleton2 = IdGenerator()

    print(singleton1 is singleton2)  # 输出 True,表示是同一个实例

    # 使用 __call__ 方法获取单例
    singleton3 = IdGenerator()
    print(singleton1 is singleton3)  # 输出 True,表示是同一个实例

import threading


class SingletonDecorator:
    def __init__(self, cls):
        self._cls = cls
        self._instances = {}
        self._lock = threading.Lock()

    def __call__(self, *args, **kwargs):
        if self._cls not in self._instances:
            with self._lock:
                if self._cls not in self._instances:
                    instance = self._cls(*args, **kwargs)
                    self._instances[self._cls] = instance
        return self._instances[self._cls]


@SingletonDecorator
class IdGenerator:
    def init_generator(self):
        self.id = 0

    def get_id(self):
        with threading.Lock():
            self.id += 1
            return self.id


if __name__ == '__main__':
    singleton1 = IdGenerator()
    singleton2 = IdGenerator()

    print(singleton1 is singleton2)  # 输出 True,表示是同一个实例

    # 使用装饰器获取单例
    singleton3 = IdGenerator()
    print(singleton1 is singleton3)  # 输出 True,表示是同一个实例

  1. 通过__new__方法实现单例
#! -*-conding=: UTF-8 -*-
# 2023/9/13 18:21


import threading


class LazySingleton:
    _instance = None
    _lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super(LazySingleton, cls).__new__(cls, *args, **kwargs)
                cls._instance.init_generator()
        return cls._instance

    def init_generator(self):
        self.id = 0

    def get_id(self):
        with self._lock:
            self.id += 1
            return self.id


# 使用示例
singleton1 = LazySingleton()
singleton2 = LazySingleton()

print(singleton1 is singleton2)  # 输出 True,表示是同一个实例

  1. 使用类方法实现单例
import threading


class IdGenerator:
    _instance = None
    _lock = threading.Lock()

    def __init__(self):
        self.init_generator()

    def init_generator(self):
        self.id = 0

    def get_id(self):
        with self._lock:
            self.id += 1
            return self.id

    @classmethod
    def get_instance(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = cls()
        return cls._instance


if __name__ == '__main__':
    singleton1 = IdGenerator.get_instance()
    singleton2 = IdGenerator.get_instance()

    print(singleton1 is singleton2)  # 输出 True,表示是同一个实例
  1. 使用元类metaclass实现单例模式
import threading


class SingletonMeta(type):
    _instances = {}
    _lock = threading.Lock()

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            with cls._lock:
                if cls not in cls._instances:
                    instance = super(SingletonMeta, cls).__call__(*args, **kwargs)
                    cls._instances[cls] = instance
        return cls._instances[cls]


class IdGenerator(metaclass=SingletonMeta):
    def init_generator(self):
        self.id = 0

    def get_id(self):
        with threading.Lock():
            self.id += 1
            return self.id


if __name__ == '__main__':
    singleton1 = IdGenerator()
    singleton2 = IdGenerator()

    print(singleton1 is singleton2)  # 输出 True,表示是同一个实例

15.反转一个整数,例如-123 --> -321

要反转一个整数,可以使用数学运算和字符串操作来实现。

def reverse_integer(n):
    # 将整数转换为字符串
    num_str = str(n)

    # 判断是否有负号
    if num_str[0] == '-':
        # 如果有负号,保留负号并反转剩余部分
        reversed_str = '-' + num_str[:0:-1]
    else:
        # 如果没有负号,直接反转整个字符串
        reversed_str = num_str[::-1]

    # 将反转后的字符串转换为整数
    _reversed_num = int(reversed_str)

    return _reversed_num


# 测试
num = -123
reversed_num = reverse_integer(num)
print(reversed_num)  # -321

16.设计实现遍历目录与子目录,抓取.pyc文件

第一种方法

import os


def get_files(_dir, suffix):
    res = []
    for root, dirs, files in os.walk(_dir):
        for filename in files:
            name, suf = os.path.splitext(filename)
            if suf == suffix:
                res.append(os.path.join(root, filename))
    print(res)


get_files("./", '.pyc')

第二种方法

import os


def pick(obj):
    if obj.endswith(".pyc"):
        print(obj)


def scan_path(ph):
    file_list = os.listdir(ph)
    for obj in file_list:
        if os.path.isfile(obj):
            pick(obj)
        elif os.path.isdir(obj):
            scan_path(obj)


if __name__ == '__main__':
    scan_path("./")

17.一行代码实现1-100之和

print(sum(range(0, 101)))

18.遍历列表时删除元素的正确做法

复制一份列表操作

a = [1, 2, 3, 4, 5, 6, 7, 8]
print(id(a))
print(id(a[:]))
for i in a[:]:
    if i > 5:
        pass
    else:
        a.remove(i)
print(a)

使用倒序遍历
在循环过程中,从列表末尾开始倒序遍历,然后使用 del 语句删除需要删除的元素。这样做可以避免由于删除元素而导致的索引错位或跳过元素的问题。

my_list = [1, 2, 3, 4, 5]

for i in range(len(my_list) - 1, -1, -1):
    if my_list[i] > 3:
        del my_list[i]

print(my_list)  # [1, 2, 3]

创建新列表

my_list = [1, 2, 3, 4, 5]
new_list = []

for item in my_list:
    if item > 3:
        new_list.append(item)

print(new_list)  # [4, 5]

18.字符串操作

全字母短句 PANGRAM 是包含所有英文字母的句子,比如:A QUICK BROWN FOX JUMPS OVER THE LAZY DOG

定义并实现一个方法get_missing_letter, 传入一个字符串采纳数,返回参数字符串变成一个PANGRAM中所缺失的字符。应该忽略传入字符串参数中的大小写,返回应该都是小写字符并按字母顺序排序(请忽略所有非 ACSII 字符)。

下面示例是用来解释,双引号不需要考虑:

下面示例是用来解释,双引号不需要考虑:
输入: "A quick brown for jumps over the lazy dog"
返回: ""
    
输入: "A slow yellow fox crawls under the proactive dog"
返回: "bjkmqz"

输入: "Lions, and tigers, and bears, oh my!"
返回: "cfjkpquvwxz" 

输入: ""
返回:"abcdefghijklmnopqrstuvwxyz"

使用set求解

import string

print(string.ascii_lowercase)  # abcdefghijklmnopqrstuvwxyz

print("".join(map(chr, range(ord('a'), ord('z') + 1))))  # abcdefghijklmnopqrstuvwxyz


def get_missing_letter(a):
    s1 = set(string.ascii_lowercase)
    s2 = set(a.lower())
    ret = "".join(sorted(s1 - s2))
    return ret


print(get_missing_letter("xyz"))  # abcdefghijklmnopqrstuvw

19. 可变类型和不可变类型

1,可变类型有list,dict.不可变类型有string,number,tuple.

2,当进行修改操作时,可变类型传递的是内存中的地址,也就是说,直接修改内存中的值,并没有开辟新的内存。

3,不可变类型被改变时,并没有改变原内存地址中的值,而是开辟一块新的内存,将原地址中的值复制过去,对这块新开辟的内存中的值进行操作。

20. is和==有什么区别?

  • is:比较的是两个对象的id值是否相等,也就是比较俩对象是否为同一个实例对象。是否指向同一个内存地址
  • == : 比较的两个对象的内容/值是否相等,默认会调用对象的eq()方法

21. 求出列表所有奇数并构造新列表

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
res = [i for i in a if i % 2 == 1]
print(res)

22. 用一行python代码写出1+2+3+10248

from functools import reduce

# 1.使用sum内置求和函数
num = sum([1, 2, 3, 10248])
print(num)
# 2.reduce 函数
num1 = reduce(lambda x, y: x + y, [1, 2, 3, 10248])
print(num1)

23. 字符串 “123” 转换成 123 ,不使用内置api,例如int()

方法一:利用 str 函数

def atoi(s):
    num = 0
    for v in s:
        for j in range(10):
            if v == str(j):
                num = num * 10 + j

    return num


print(atoi("123"))  # 123

方法二:利用 ord 函数

def atoi(s):
    num = 0
    for v in s:
        num = num * 10 + ord(v) - ord('0')
    return num


print(atoi("123"))  # 123

方法三: 利用 eval 函数

def atoi(s):
    num = 0
    for v in s:
        t = "%s * 1" % v
        n = eval(t)
        num = num * 10 + n
    return num


print(atoi("123"))  # 123

方法四: 结合方法二,使用 reduce ,一行解决

from functools import reduce


def atoi(s):
    return reduce(lambda num, v: num * 10 + ord(v) - ord('0'), s, 0)


print(atoi("123"))  # 123

24. 两数和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用

示例:

给定nums = [2,7,11,15],target=9;因为 nums[0]+nums[1] = 2+7 =9,所以返回[0,1]。

class Solution:
    @staticmethod
    def two_sum(nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        d = {}
        size = 0
        while size < len(nums):
            if target - nums[size] in d:
                if d[target - nums[size]] < size:
                    return [d[target - nums[size]], size]
            else:
                d[nums[size]] = size
                size = size + 1


solution = Solution()

print(solution.two_sum(nums=[2, 7, 11, 15], target=18))  # [1, 2]

方法二:

class Solution(object):
    @staticmethod
    def two_sum(nums, target):
        for i in range(len(nums)):
            num = target - nums[i]
            if num in nums[i + 1:]:
                return [i, nums.index(num, i + 1)]


solution = Solution()

print(solution.two_sum(nums=[2, 7, 11, 15], target=18))  # [1, 2]

25. 统计一个文本中单词频次最高的10个单词?

import re


def test(filepath):
    distone = {}
    with open(filepath) as f:
        for line in f:
            line = re.sub("\W+", " ", line)
            lineone = line.split()
            for keyone in lineone:
                if not distone.get(keyone):
                    distone[keyone] = 1
                else:
                    distone[keyone] += 1
    num_ten = sorted(distone.items(), key=lambda x: x[1], reverse=True)[:10]
    print(num_ten)  # [('aaaa', 1), ('dsds', 1), ('sdsdsds', 1)]
    num_ten = [x[0] for x in num_ten]
    return num_ten


print(test("./file.txt"))  # ['aaaa', 'dsds', 'sdsdsds']

方法二:

import re
from collections import Counter


def test2(filepath):
    with open(filepath) as f:
        return list(map(lambda c: (c[0], c[1]), Counter(re.sub("\W+", " ", f.read()).split()).most_common(10)))


print(test2("./file.txt"))

26. 请写出一个函数满足以下条件

该函数的输入是一个仅包含数字的list,输出一个新的list,其中每一个元素要满足以下条件:

  • 1、该元素是偶数
  • 2、该元素在原list中是在偶数的位置(index是偶数)
def num_list(num):
    return [i for i in num if i % 2 == 0 and num.index(i) % 2 == 0]


result = num_list(num=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(result)  # [0, 2, 4, 6, 8, 10]

27. 使用单一的列表生成式来产生一个新的列表

该列表只包含满足以下条件的值,元素为原始列表中偶数切片:

list_data = [1, 2, 5, 8, 10, 3, 18, 6, 20]
res = [x for x in list_data[::2] if x % 2 == 0]
print(res)  # [10, 18, 20]

28. 用一行代码生成[1,4,9,16,25,36,49,64,81,100]

result = [x * x for x in range(1, 11)]

29. 两个有序列表,l1,l2,对这两个列表进行合并不可使用extend

方法一:

merged_list = sorted(l1 + l2)

方法二:使用循环

def loop_merge_sort(l1, l2):
    tmp = []
    while len(l1) > 0 and len(l2) > 0:
        if l1[0] < l2[0]:
            tmp.append(l1[0])
            del l1[0]
        else:
            tmp.append(l2[0])
            del l2[0]
    while len(l1) > 0:
        tmp.append(l1[0])
        del l1[0]
    while len(l2) > 0:
        tmp.append(l2[0])
        del l2[0]
    return tmp


l1 = [1, 3, 5, 7]
l2 = [2, 4, 6, 8, 9]
result = loop_merge_sort(l1, l2)
print(result)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

30. 让所有奇数都在偶数前面,而且奇数升序排列,偶数降序排序

方法一:

def func1(l):
    if isinstance(l, str):
        l = [int(i) for i in l]
    if isinstance(l, list):
        l.sort(reverse=True)
    for i in range(len(l)):
        if l[i] % 2 > 0:
            l.insert(0, l.pop(i))
    print(''.join(str(e) for e in l))


l1 = [3, 5, 2, 7, 1, 4]
func1(l1)  # 135742

l2 = "568731"
func1(l2)  # 135786

方法二:

def func2(l):
    if isinstance(l, str):
        l = list(l)
    l = sorted(l, key=lambda x: int(x) % 2 == 0 and 20 - int(x) or int(x))
    print("".join(str(e) for e in l))


l1 = [3, 5, 2, 7, 1, 4]
func2(l1)  # 135742

l2 = "568731"
func2(l2)  # 135786

31. 写一个函数找出一个整数数组中,第二大的数

def find_second_large_num(num_list):
    # 方法一:直接排序,输出倒数第二个数即可
    tmp_list = sorted(num_list)
    print("方法一\nSecond_large_num is:", tmp_list[-2])

    # 方法二:设置两个标志位,一个存储最大数,一个存储次大数
    one = num_list[0]
    two = num_list[0]
    for i in range(1, len(num_list)):
        if num_list[i] > one:
            two = one
            one = num_list[i]
        elif num_list[i] > two:
            two = num_list[i]
    print("方法二\nSecond_large_num is:", two)

    # 方法三:使用 reduce 与逻辑符号 (and, or)
    # 基本思路与方法二一样,但是不需要用 if 进行判断。
    from functools import reduce
    num = reduce(lambda ot, x: ot[1] < x and (ot[1], x) or ot[0] < x and (x, ot[1]) or ot, num_list, (0, 0))[0]
    print("方法三\nSecond_large_num is:", num)


num_list = [34, 11, 23, 56, 78, 0, 9, 12, 3, 7, 5]
find_second_large_num(num_list)

"""
方法一
Second_large_num is: 56
方法二
Second_large_num is: 56
方法三
Second_large_num is: 56
"""

32. 阅读一下代码他们的输出结果是什么?

def multi():
    return [lambda x: i * x for i in range(4)]


print([m(3) for m in multi()])  # [9, 9, 9, 9]

这段代码创建了一个包含四个 lambda 函数的列表,并尝试通过列表推导式对这些 lambda 函数进行调用。然而,由于在 lambda 函数中使用了变量 i,而 i 是在循环结束后的值,这导致 lambda 函数在被调用时都引用了相同的最终值。

因此,代码的输出结果将是 [9, 9, 9, 9],而不是 [0, 3, 6, 9]

这是因为在循环结束后,变量 i 的值为 3,而所有的 lambda 函数都引用了这个最终值。所以,当你调用这些 lambda 函数时,它们实际上是使用值为 3 的 i 来计算结果。

如果你想要得到 [0, 3, 6, 9] 的输出结果,可以在 lambda 函数中使用默认参数来捕获循环变量 i 的值。以下是修改后的代码:

def multi():
    return [lambda x, i=i: i * x for i in range(4)]

print([m(3) for m in multi()])

通过在 lambda 函数定义中添加 i=i,我们在创建 lambda 函数时捕获了循环变量 i 的当前值,并将其作为默认参数。这样,在每次调用 lambda 函数时,它将使用捕获的默认参数值来计算结果,而不是引用最终值。

这样修改后的代码将输出 [0, 3, 6, 9],符合预期的结果。

33. 统计一段字符串中字符出现的次数

方法一:

def count_str(str_data):
    """定义一个字符出现次数的函数"""
    dict_str = {}
    for i in str_data:
        dict_str[i] = dict_str.get(i, 0) + 1
    return dict_str


dict_str = count_str("AAABBCCAC")
str_count_data = ""

for k, v in dict_str.items():
    str_count_data += k + str(v)
print(dict_str)  # {'A': 4, 'B': 2, 'C': 3}
print(str_count_data)  # A4B2C3

方法二:

from collections import Counter

print(list(map(lambda x: (x[0], x[1]), Counter("AAABBCCAC").most_common())))  # [('A', 4), ('C', 3), ('B', 2)]

34. super函数的具体用法和场景

在Python中,super()函数用于调用父类的方法。它主要用于子类重写父类方法时,在子类中调用父类的相同方法,以实现方法的继承和扩展。

super()函数的常见用法是在子类的方法中调用父类的同名方法。通过使用super()函数,子类可以直接调用父类的方法,并在该方法的基础上进行扩展。这种方式可以保持代码的重用性和结构的一致性。

super()函数的语法如下:

super().父类方法名(参数列表)

在使用super()函数时,不需要显式地指定父类的名称,Python会自动根据当前类的继承关系来确定要调用的父类方法。

下面是一个简单的示例,演示了super()函数的用法:

class ParentClass:
    def __init__(self):
        self.parent_attr = "Parent Attribute"
    
    def some_method(self):
        print("Parent Method")

class ChildClass(ParentClass):
    def __init__(self):
        super().__init__()  # 调用父类的 __init__ 方法
        self.child_attr = "Child Attribute"
    
    def some_method(self):
        super().some_method()  # 调用父类的 some_method 方法
        print("Child Method")

child = ChildClass()
print(child.parent_attr)  # 输出: Parent Attribute
print(child.child_attr)  # 输出: Child Attribute
child.some_method()  # 输出: Parent Method
                     #      Child Method

在上面的示例中,ChildClass继承自ParentClass。子类ChildClass中的构造函数__init__使用super()函数调用了父类ParentClass的构造函数,以便子类能够继承父类的属性。另外,子类ChildClass重写了父类的some_method方法,并在方法中通过super()函数调用了父类的同名方法,以实现方法的扩展。

总结来说,super()函数在子类中调用父类方法的场景包括但不限于以下情况:

  1. 子类需要继承父类的属性或方法。
  2. 子类需要在重写父类方法时,在子类方法中调用父类的同名方法以实现方法的继承和扩展。
  3. 子类需要在多重继承的情况下,调用指定父类的方法。

35. Python中类方法、类实例方法、静态方法有何区别?

在Python中,类方法(class method)、类实例方法(instance method)和静态方法(static method)是三种不同类型的方法,它们在使用方式和功能上有一些区别。

  1. 类方法(Class Method):

    • 使用@classmethod装饰器进行修饰。
    • 第一个参数为类本身,通常被命名为cls
    • 类方法可以通过类或实例进行调用。
    • 类方法可以访问类属性,并且可以修改类属性的值。
    • 类方法常用于对类属性进行操作、创建类的备用构造函数等。
  2. 类实例方法(Instance Method):

    • 在类中定义的普通方法,默认为实例方法。
    • 第一个参数为实例对象本身,通常被命名为self
    • 实例方法只能通过类的实例进行调用。
    • 实例方法可以访问和修改实例属性和类属性。
    • 实例方法常用于操作和访问实例的状态和属性。
  3. 静态方法(Static Method):

    • 使用@staticmethod装饰器进行修饰。
    • 静态方法不需要传递类或实例作为参数。
    • 静态方法可以通过类或实例进行调用,但不会自动传递类或实例参数。
    • 静态方法不能访问或修改实例属性和类属性。
    • 静态方法通常用于与类相关的功能,但不依赖于实例状态或属性的操作。

下面是一个示例,演示了类方法、类实例方法和静态方法的使用:

class MyClass:
    class_attr = "Class Attribute"

    @classmethod
    def class_method(cls):
        print("This is a class method")
        print("Accessing class attribute:", cls.class_attr)

    def instance_method(self):
        print("This is an instance method")
        print("Accessing class attribute:", self.class_attr)
        print("Accessing instance attribute:", self.instance_attr)

    @staticmethod
    def static_method():
        print("This is a static method")

# 调用类方法
MyClass.class_method()  # 输出: This is a class method
                        #      Accessing class attribute: Class Attribute

# 创建实例对象
my_obj = MyClass()
my_obj.instance_attr = "Instance Attribute"

# 调用实例方法
my_obj.instance_method()  # 输出: This is an instance method
                          #      Accessing class attribute: Class Attribute
                          #      Accessing instance attribute: Instance Attribute

# 调用静态方法
MyClass.static_method()  # 输出: This is a static method

总结:

  • 类方法使用@classmethod修饰,第一个参数为cls,可以通过类或实例调用,可以访问和修改类属性。
  • 类实例方法是普通的实例方法,默认以self作为第一个参数,只能通过实例调用,可以访问和修改实例属性和类属性。
  • 静态方法使用@staticmethod修饰,不需要类或实例作为参数,可以通过类或实例调用,但不能访问或修改实例属性和类属性。

36. 遍历一个object的所有属性,并print每一个属性名?

要遍历一个对象的所有属性并打印每个属性名,你可以使用内置的dir()函数获取对象的所有属性名称列表。然后,你可以使用getattr()函数获取每个属性的值,并打印属性名。

下面是一个示例代码,展示了如何遍历对象的所有属性并打印属性名:

class MyClass:
    def __init__(self):
        self.attribute1 = "Value 1"
        self.attribute2 = "Value 2"
        self.attribute3 = "Value 3"

my_obj = MyClass()

# 获取对象的属性列表
attribute_list = dir(my_obj)

# 遍历属性列表并打印属性名
for attribute_name in attribute_list:
    attribute_value = getattr(my_obj, attribute_name)
    print(attribute_name)

在上面的示例中,我们定义了一个名为MyClass的类,并创建了一个my_obj的实例。然后,我们使用dir()函数获取my_obj的所有属性名称列表,并将其存储在attribute_list中。接下来,我们使用for循环遍历attribute_list,对于每个属性名attribute_name,我们使用getattr()函数获取该属性的值,并打印属性名。

请注意,dir()函数返回的属性列表包括对象的所有属性,包括类定义的属性、继承的属性和一些内置属性。因此,遍历属性时可能会包含一些你不感兴趣的属性。你可以根据自己的需求进行过滤或处理。

37.写一个类,并让它尽可能多的支持操作符?

自定义int类

class MyNumber:
    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        if isinstance(other, MyNumber):
            return MyNumber(self.value + other.value)
        elif isinstance(other, int):
            return MyNumber(self.value + other)
        else:
            raise TypeError("Unsupported operand type for +")

    def __sub__(self, other):
        if isinstance(other, MyNumber):
            return MyNumber(self.value - other.value)
        elif isinstance(other, int):
            return MyNumber(self.value - other)
        else:
            raise TypeError("Unsupported operand type for -")

    def __mul__(self, other):
        if isinstance(other, MyNumber):
            return MyNumber(self.value * other.value)
        elif isinstance(other, int):
            return MyNumber(self.value * other)
        else:
            raise TypeError("Unsupported operand type for *")

    def __str__(self):
        return str(self.value)

    def __eq__(self, other):
        if isinstance(other, MyNumber):
            return self.value == other.value
        elif isinstance(other, int):
            return self.value == other
        else:
            raise TypeError("Unsupported operand type for ==")

    def __lt__(self, other):
        if isinstance(other, MyNumber):
            return self.value < other.value
        elif isinstance(other, int):
            return self.value < other
        else:
            raise TypeError("Unsupported operand type for <")


# 创建 MyNumber 对象
num1 = MyNumber(5)
num2 = MyNumber(3)

# 加法
result_add = num1 + num2
print(result_add)  # 输出: 8

# 减法
result_sub = num1 - num2
print(result_sub)  # 输出: 2

# 乘法
result_mul = num1 * num2
print(result_mul)  # 输出: 15

# 字符串表示
print(str(num1))  # 输出: 5

# 相等性比较
print(num1 == num2)  # 输出: False

# 小于比较
print(num1 < num2)  # 输出: False

自定义list类

class MyList:
    def __init__(self):
        self.items = []

    def __del__(self):
        del self.items

    def __str__(self):
        return str(self.items)

    def __add__(self, other):
        if isinstance(other, MyList):
            new_list = MyList()
            new_list.items = self.items + other.items
            return new_list
        else:
            raise TypeError("Unsupported operand type for +")

    def __sub__(self, other):
        if isinstance(other, MyList):
            new_list = MyList()
            new_list.items = [item for item in self.items if item not in other.items]
            return new_list
        else:
            raise TypeError("Unsupported operand type for -")

    def __mul__(self, other):
        if isinstance(other, int):
            new_list = MyList()
            new_list.items = self.items * other
            return new_list
        else:
            raise TypeError("Unsupported operand type for *")

    def __eq__(self, other):
        if isinstance(other, MyList):
            return self.items == other.items
        else:
            return False

    def __lt__(self, other):
        if isinstance(other, MyList):
            return len(self.items) < len(other.items)
        else:
            raise TypeError("Unsupported operand type for <")

    def __getitem__(self, index):
        return self.items[index]

    def __len__(self):
        return len(self.items)

    def remove(self, item):
        self.items.remove(item)

    def display_items(self):
        for item in self.items:
            print(item)


# 创建 MyList 对象
my_list1 = MyList()
my_list2 = MyList()

# 添加元素
my_list1.items.append('Apple')
my_list1.items.append('Banana')
my_list1.items.append('Orange')

my_list2.items.append('Apple')
my_list2.items.append('Grapes')

# 加法
result_add = my_list1 + my_list2
print(result_add)  # 输出: ['Apple', 'Banana', 'Orange', 'Apple', 'Grapes']

# 减法
result_sub = my_list1 - my_list2
print(result_sub)  # 输出: ['Banana', 'Orange']

# 乘法
result_mul = my_list1 * 2
print(result_mul)  # 输出: ['Apple', 'Banana', 'Orange', 'Apple', 'Banana', 'Orange']

# 字符串表示
print(str(my_list1))  # 输出: ['Apple', 'Banana', 'Orange']

# 相等性比较
print(my_list1 == my_list2)  # 输出: False

# 小于比较
print(my_list1 < my_list2)  # 输出: False

# 获取元素
print(my_list1[1])  # 输出: Banana

# 删除元素
my_list1.remove('Banana')
print(my_list1)  # 输出: ['Apple', 'Orange']

# 显示所有元素
my_list1.display_items()
# 输出:
# Apple
# Orange

# 获取列表长度
print(len(my_list1))  # 输出: 2

# 删除 MyList 对象
del my_list1

38. 介绍Cython,Pypy Cpython Numba各有什么优缺点?

Cython、PyPy、CPython和Numba是针对Python代码进行优化的工具和实现方式。它们各自具有不同的优点和缺点,下面是对它们的简要介绍:

  1. Cython:

    • 优点:
      • 提供了静态类型声明和编译扩展的能力,可以将Python代码转换为C语言并编译成高效的机器码。
      • 可以直接调用C/C++代码,并且与Python语法兼容。
      • 支持使用Python标准库和第三方库。
      • 可以获得接近C语言的性能。
    • 缺点:
      • 编写和调试Cython代码可能相对复杂,需要对C语言有一定的了解。
      • 需要编译过程,增加了开发和部署的复杂性。
  2. PyPy:

    • 优点:
      • 使用即时编译(Just-in-Time Compilation)技术,可以在运行时动态地将Python代码转换为机器码,提高执行速度。
      • 支持大部分Python语法和标准库。
      • 对于某些特定类型的Python代码,PyPy的性能可能比CPython更好。
    • 缺点:
      • PyPy并不是完全兼容CPython,有些第三方库可能无法正常工作。
      • 在某些情况下,PyPy的内存占用可能比CPython更高。
      • 对于某些特定类型的Python代码,PyPy的性能可能比CPython差。
  3. CPython:

    • 优点:
      • 官方和最常用的Python解释器。
      • 拥有广泛的第三方库和生态系统支持。
      • 可以与C扩展无缝集成。
      • 相对稳定,支持性良好。
    • 缺点:
      • 在某些情况下,CPython的执行速度可能较慢。
      • 由于全局解释器锁(Global Interpreter Lock,GIL)的存在,无法充分利用多核处理器。
  4. Numba:

    • 优点:
      • 使用即时编译技术,可以将Python代码转换为高效的机器码。
      • 通过提供装饰器和函数修饰符,可以轻松地将Python函数转换为高性能的机器码。
      • 相对于使用NumPy进行数值计算,Numba可以提供更快的执行速度。
    • 缺点:
      • 对于某些类型的Python代码,Numba的性能优势可能不明显。
      • 不支持所有的Python语法和标准库。
      • 对于大型、复杂的代码,Numba的编译时间可能较长。

需要注意的是,每种工具和实现方式都有其适用的场景。选择合适的工具取决于你的具体需求,如性能要求、代码复杂性、对第三方库的依赖等因素。在实际使用时,可以根据具体情况进行评估和测试,以选择最适合的工具和实现方式。

39. 请描述python中抽象类和接口类的区别和联系?

  • 1.抽象类: 规定了一系列的方法,并规定了必须由继承类实现的方法。由于有抽象方法的存在,所以抽象类不能实例化。可以将抽象类理解为毛坯房,门窗,墙面的样式由你自己来定,所以抽象类与作为基 类的普通类的区别在于约束性更强。

  • 2.接口类:与抽象类很相似,表现在接口中定义的方法,必须由引用类实现,但他与抽象类的根本区别在于用途:与不同个体间沟通的规则,你要进宿舍需要有钥匙,这个钥匙就是你与宿舍的接口,你的舍 友也有这个接口,所以他也能进入宿舍,你用手机通话,那么手机就是你与他人交流的接口。

  • 3.区别和关联:

    • 1.接口是抽象类的变体,接口中所有的方法都是抽象的,而抽象类中可以有非抽象方法,抽象类是声明 方法的存在而不去实现它的类
    • 2.接口可以继承,抽象类不行
    • 3.接口定义方法,没有实现的代码,而抽象类可以实现部分方法
    • 4.接口中基本数据类型为static而抽象类不是

举个栗子:

首先,我们使用抽象类来表示一个动物,并定义一个抽象方法 make_sound,表示动物发出声音的行为。

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        pass

接下来,我们定义两个具体的动物类:狗和猫,它们都继承自抽象类 Animal,并实现了 make_sound 方法。

class Dog(Animal):
    def make_sound(self):
        print("Dog barks")

class Cat(Animal):
    def make_sound(self):
        print("Cat meows")

现在,我们可以创建 DogCat 的实例,并调用它们的 make_sound 方法。

dog = Dog()
dog.make_sound()  # 输出: Dog barks

cat = Cat()
cat.make_sound()  # 输出: Cat meows

在这个例子中,Animal 是一个抽象类,它定义了一个抽象方法 make_soundDogCat 是具体的动物类,它们继承了抽象类 Animal 并实现了 make_sound 方法。通过这种方式,我们可以使用抽象类 Animal 来表示一类动物,并要求每个具体的动物类都必须实现 make_sound 方法。

接下来,我们使用接口类来定义一个 Runnable 接口,表示可运行的对象,并定义一个抽象方法 run,表示对象运行的行为。

class Runnable:
    @abstractmethod
    def run(self):
        pass

然后,我们定义一个具体的类 Car,它实现了 Runnable 接口,并实现了 run 方法。

class Car(Runnable):
    def run(self):
        print("Car is running")

现在,我们可以创建 Car 的实例,并调用它的 run 方法。

car = Car()
car.run()  # 输出: Car is running

在这个例子中,Runnable 是一个接口类(在Python中没有明确的语法支持),它定义了一个抽象方法 runCar 是一个具体的类,它实现了 Runnable 接口并提供了 run 方法的具体实现。通过这种方式,我们可以使用接口类 Runnable 来表示一类可运行的对象,并要求每个具体的类都必须实现 run 方法。

这就是一个简单的例子,展示了如何使用抽象类和接口类来表示抽象概念并要求子类提供具体的实现。抽象类和接口类在软件设计中起到了规范和约束的作用,帮助我们构建可扩展、灵活的代码架构。

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

在Python中,可以使用以下方式动态获取和设置对象的属性:

  1. 获取属性

    • 使用点号运算符(.):通过对象的名称和属性名称,可以使用点号运算符直接访问对象的属性。
    obj.attribute  # 获取对象obj的attribute属性的值
    
    • 使用getattr()函数:getattr()函数可以接收一个对象和属性名称作为参数,并返回对象的属性值。如果属性不存在,可以提供一个默认值作为第三个参数。
    getattr(obj, 'attribute')  # 获取对象obj的attribute属性的值
    
  2. 设置属性

    • 使用点号运算符(.):通过对象的名称和属性名称,可以使用点号运算符直接设置对象的属性值。
    obj.attribute = value  # 设置对象obj的attribute属性的值为value
    
    • 使用setattr()函数:setattr()函数可以接收一个对象、属性名称和属性值作为参数,并将对象的属性设置为指定的值。
    setattr(obj, 'attribute', value)  # 设置对象obj的attribute属性的值为value
    

需要注意的是,使用动态获取和设置属性的方式可以方便地在运行时根据需要访问和修改对象的属性。但是,如果属性不存在,直接使用点号运算符会引发AttributeError异常;而使用getattr()函数可以通过提供默认值来避免异常的抛出。类似地,如果设置属性时,使用点号运算符设置一个不存在的属性会创建一个新的属性,而使用setattr()函数可以更严格地控制属性的设置行为。

另外,还可以使用hasattr()函数来检查对象是否具有特定的属性,以及使用delattr()函数来删除对象的属性。这些函数提供了更多操作对象属性的灵活性和控制性。

  • 29
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海哥python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值