当前位置: 代码网 > it编程>前端脚本>Python > Python函数与面向对象详解

Python函数与面向对象详解

2026年09月22日 Python 我要评论
python的函数比java灵活得多——默认参数、关键字参数、lambda表达式,这些在java里需要各种重载和接口才能实现的功能,python几行就搞定。面向对象部分更有趣,

python的函数比java灵活得多——默认参数、关键字参数、lambda表达式,这些在java里需要各种重载和接口才能实现的功能,python几行就搞定。面向对象部分更有趣,python的多继承、魔术方法、动态属性,和java的设计哲学差异巨大,面试也经常拿来对比考察。

一、函数定义与调用

1.1 基本语法

python用def关键字定义函数,不需要声明返回类型和参数类型(但支持类型注解)。

# python 定义函数
def add(a: int, b: int) -> int:
    """两数相加(文档字符串,类似java的javadoc)"""
    return a + b
result = add(1, 2)  # 调用
print(result)  # 3
// java 对比
public static int add(int a, int b) {
    return a + b;
}
int result = add(1, 2);

核心差异:

  • python函数是一等公民,可以赋值给变量、作为参数传递、作为返回值
  • 不需要声明在类里,python有独立的函数概念(java的方法必须属于类)
  • 类型注解是可选的,运行时不强制检查

1.2 函数的返回值

python函数可以返回多个值(本质是返回元组),这在java里需要封装对象才能实现。

# python:返回多个值
def divide(a, b):
    quotient = a // b
    remainder = a % b
    return quotient, remainder  # 实际返回的是元组 (quotient, remainder)
q, r = divide(10, 3)  # 解包
print(f"商: {q}, 余: {r}")  # 商: 3, 余: 1
// java:需要封装返回类型
public class divresult {
    int quotient;
    int remainder;
    // 构造器、getter 省略...
}
public divresult divide(int a, int b) {
    return new divresult(a / b, a % b);
}

1.3 常见坑点

坑1:默认参数不要用可变对象

# 错误示范!
def append_to(item, lst=[]):  # 默认参数在函数定义时只创建一次!
    lst.append(item)
    return lst
print(append_to(1))      # [1]
print(append_to(2))      # [1, 2]  而不是 [2]!
print(append_to(3))      # [1, 2, 3]
# 正确写法:用 none 作为哨兵
def append_to(item, lst=none):
    if lst is none:
        lst = []
    lst.append(item)
    return lst

面试常考:python的默认参数在函数定义时求值一次,不是每次调用时求值。这和java不同(java每次调用都重新计算默认值)。

二、默认参数与关键字参数

2.1 默认参数(≈ java方法重载的简化版)

java里想实现"可选参数",需要写多个重载方法。python直接用默认参数搞定。

# python:默认参数
def greet(name: str, greeting: str = "hello", punctuation: str = "!") -> str:
    return f"{greeting}, {name}{punctuation}"
print(greet("alice"))                     # "hello, alice!"
print(greet("bob", "hi"))                 # "hi, bob!"
print(greet("charlie", "hey", "."))       # "hey, charlie."
// java:需要3个重载方法
public string greet(string name) {
    return greet(name, "hello");
}
public string greet(string name, string greeting) {
    return greet(name, greeting, "!");
}
public string greet(string name, string greeting, string punctuation) {
    return greeting + ", " + name + punctuation;
}

面试提醒:java的@overload在python里用默认参数就替代了,这也是python"简洁"哲学的体现。

2.2 位置参数 vs 关键字参数

def create_user(name, age, city="unknown"):
    print(f"{name}, {age}岁, 来自{city}")
# 位置参数:按顺序传
create_user("alice", 25, "beijing")
# 关键字参数:按名字传,顺序随意
create_user("bob", city="shanghai", age=30)
# 混合使用:位置参数在前,关键字参数在后
create_user("charlie", 28, city="shenzhen")
# python 3.8+ 还支持:强制位置参数 / 强制关键字参数
def func(a, b, /, c, d, *, e, f):
    pass
# a, b 只能按位置传
# c, d 按位置或关键字都行
# e, f 必须用关键字传
// java 没有关键字参数的概念,全靠顺序
createuser("alice", 25, "beijing");
// 想跳过参数?只能传 null 或者用 builder 模式

2.3 *args 和 **kwargs

# *args:接收任意数量的位置参数(打包成元组)
# **kwargs:接收任意数量的关键字参数(打包成字典)
def print_info(name, *args, **kwargs):
    print(f"name: {name}")
    print(f"args: {args}")          # 元组
    print(f"kwargs: {kwargs}")      # 字典
print_info("alice", 25, "beijing", hobby="coding", level="senior")
# name: alice
# args: (25, 'beijing')
# kwargs: {'hobby': 'coding', 'level': 'senior'}

对比java:java的可变参数用string... args,但只支持一种类型。python的*args/**kwargs可以混合接收任意类型、任意数量的参数,灵活得多。

2.4 常见坑点

坑2:关键字参数传了位置参数

def func(a, b):
    pass
func(1, a=2)  # typeerror: func() got multiple values for argument 'a'
# 1 已经赋给了 a,a=2 又给 a 赋值,冲突了

坑3:*args 后面跟的关键字参数会被吞进 **kwargs

def func(a, *args, **kwargs):
    print(a, args, kwargs)
func(1, 2, 3, b=4)  # 1 (2, 3) {'b': 4}
# 注意 b=4 进了 kwargs,不是报"未知参数"的错误

三、lambda匿名函数

3.1 基本语法

lambda是匿名函数的简写,只能写一个表达式,不能写复杂逻辑。

# lambda 语法:lambda 参数: 表达式
double = lambda x: x * 2
print(double(5))  # 10
# 等价于
def double_def(x):
    return x * 2
# 多参数
add = lambda a, b: a + b
print(add(3, 4))  # 7
# 带条件
abs_val = lambda x: x if x >= 0 else -x
print(abs_val(-5))  # 5
// java 对比
// java lambda 需要函数式接口
function<integer, integer> doublefn = x -> x * 2;
bifunction<integer, integer, integer> add = (a, b) -> a + b;
// java 可以写多行(用花括号)
function<integer, integer> complex = x -> {
    system.out.println("计算中...");
    return x * 2;
};
// python lambda 只能写一行表达式!

3.2 最常见的用法:排序的key

这是lambda在python里最高频的使用场景,面试必会。

# 按年龄排序
students = [
    {"name": "alice", "age": 25},
    {"name": "bob", "age": 20},
    {"name": "charlie", "age": 23}
]
# 用 lambda 指定排序依据
students.sort(key=lambda s: s["age"])
print(students)
# [{'name': 'bob', 'age': 20}, {'name': 'charlie', 'age': 23}, {'name': 'alice', 'age': 25}]
# 按字符串长度排序
words = ["banana", "pie", "washington", "book"]
words.sort(key=lambda w: len(w))
print(words)  # ['pie', 'book', 'banana', 'washington']
# 多条件排序:先按年龄,年龄相同按名字
students.sort(key=lambda s: (s["age"], s["name"]))
// java 对比
students.sort(comparator.comparingint(s -> s.getage()));
// 多条件
students.sort(comparator.comparingint(student::getage)
                        .thencomparing(student::getname));

3.3 lambda vs def 怎么选

场景推荐原因
排序key、map/filter的回调lambda简洁,意图明确
逻辑超过一行deflambda只能写表达式
需要复用def有名字,可调用、可测试
需要文档说明deflambda没法写docstring
需要异常处理deflambda里try-except很丑

3.4 常见坑点

坑4:lambda中的闭包陷阱

# 想创建 [f(0)=0, f(1)=1, f(2)=2, ...]
funcs = [lambda: i for i in range(5)]
print([f() for f in funcs])  # [4, 4, 4, 4, 4] 全是4!
# 原因:lambda 捕获的是变量 i 的引用,不是值
# 循环结束后 i=4,所有 lambda 都返回 4
# 修复:用默认参数绑定当前值
funcs = [lambda i=i: i for i in range(5)]
print([f() for f in funcs])  # [0, 1, 2, 3, 4] ✓

java对比:java的lambda要求捕获的变量是effectively final,所以java不会出现这个问题。这也是java更"安全"的地方。

四、类的基本定义

4.1 构造函数与self

class student:
    """学生类(类似java的student类)"""
    # 类属性(所有实例共享,≈ java的static字段)
    school = "清华大学"
    # 构造方法(≈ java的构造器)
    def __init__(self, name: str, age: int):
        # 实例属性(每个实例独有)
        self.name = name       # self ≈ java的this,但必须显式写!
        self.age = age
        self._score = 0        # 约定私有(单下划线)
    # 实例方法(第一个参数必须是self)
    def introduce(self) -> str:
        return f"{self.name}, {self.age}岁, 来自{student.school}"
    # 另一个方法
    def study(self, course: str):
        print(f"{self.name}正在学习{course}")
# 创建对象(不用new!)
stu = student("alice", 20)
print(stu.introduce())   # alice, 20岁, 来自清华大学
stu.study("python")       # alice正在学习python
// java 对比
public class student {
    // 类属性
    static string school = "清华大学";
    // 实例属性
    private string name;
    private int age;
    // 构造器
    public student(string name, int age) {
        this.name = name;   // this可以省略(不推荐),python的self不能省略
        this.age = age;
    }
    // 方法
    public string introduce() {
        return name + ", " + age + "岁, 来自" + school;
        // java中可以省略this,python必须写self.name
    }
}
student stu = new student("alice", 20);  // java需要new

4.2 实例属性 vs 类属性

class counter:
    count = 0  # 类属性:所有实例共享
    def __init__(self, name):
        self.name = name   # 实例属性:每个实例独有
        counter.count += 1  # 通过类名修改类属性
c1 = counter("a")
c2 = counter("b")
print(counter.count)   # 2(类属性被修改了)
print(c1.count)        # 2(通过实例也能访问类属性)
print(c2.count)        # 2
# ⚠️ 危险操作:通过实例赋值会创建同名的实例属性,遮蔽类属性
c1.count = 100         # 这是创建了实例属性,不是修改类属性!
print(c1.count)        # 100(实例属性)
print(c2.count)        # 2(类属性没变)
print(counter.count)   # 2(类属性没变)

面试必知:通过实例c1.count = 100是在实例上创建了一个新的实例属性,不会修改类属性。要修改类属性,必须用counter.count = 100

4.3 常见坑点

坑5:忘记写self

class myclass:
    def method(self):
        pass
    def wrong_method():  # 忘记self!
        pass
obj = myclass()
obj.method()       # ok
obj.wrong_method() # typeerror: wrong_method() takes 0 positional arguments but 1 was given
# python自动把obj作为第一个参数传给wrong_method,但函数没接收

坑6:类属性的"遮蔽"问题

上面4.2已经讲了。记住:读属性时先找实例、再找类;写属性时只在实例上创建,不会改到类属性。

五、静态方法、类方法与属性访问

5.1@staticmethod(≈ java的static方法)

不需要访问实例(self)也不需要访问类(cls),纯粹是工具方法。

class mathutil:
    @staticmethod
    def add(a: int, b: int) -> int:
        return a + b
    @staticmethod
    def is_even(n: int) -> bool:
        return n % 2 == 0
# 不需要创建实例就能调用(和java一样)
print(mathutil.add(1, 2))       # 3
print(mathutil.is_even(4))      # true
# 也可以通过实例调用(但不推荐)
util = mathutil()
print(util.add(3, 4))           # 7
// java 对比
public class mathutil {
    public static int add(int a, int b) {
        return a + b;
    }
    // java里static方法属于类,python的@staticmethod也属于类
}

5.2@classmethod(java没有直接对应)

第一个参数是cls(类本身),可以访问和修改类属性,常用于工厂方法。

class date:
    def __init__(self, year: int, month: int, day: int):
        self.year = year
        self.month = month
        self.day = day
    @classmethod
    def from_string(cls, date_str: str) -> 'date':
        """工厂方法:从字符串创建date对象"""
        year, month, day = map(int, date_str.split("-"))
        return cls(year, month, day)  # cls 就是 date
    @classmethod
    def tomorrow(cls):
        """工厂方法:创建明天的日期"""
        from datetime import date, timedelta
        t = date.today() + timedelta(days=1)
        return cls(t.year, t.month, t.day)
    def __str__(self):
        return f"{self.year}-{self.month:02d}-{self.day:02d}"
# 使用工厂方法
d1 = date.from_string("2026-09-18")
d2 = date.tomorrow()
print(d1)  # 2026-09-18
print(d2)  # 2026-09-19

面试对比@classmethod 在继承时,cls会自动变成子类,所以子类调用工厂方法创建的是子类实例。java要实现类似效果需要额外处理。

5.3 三种方法对比

实例方法@classmethod@staticmethod
第一个参数self(实例)cls(类)无强制要求
能访问实例属性+类属性类属性都不能直接访问
java对应普通方法无直接对应static方法
典型用途操作实例数据工厂方法、修改类状态纯工具函数

六、@property(getter/setter)

java的getter/setter冗长,python用@property装饰器优雅解决。

class student:
    def __init__(self, name: str, score: int):
        self.name = name
        self._score = score  # 约定私有,外部不要直接访问
    @property
    def score(self) -> int:
        """getter:像属性一样访问,实际调的是方法"""
        print("  [调用getter]")
        return self._score
    @score.setter
    def score(self, value: int):
        """setter:赋值时自动调用,可以加校验逻辑"""
        if not 0 <= value <= 100:
            raise valueerror("分数必须在0-100之间")
        self._score = value
    @property
    def grade(self) -> str:
        """只读属性(只有getter,没有setter)"""
        if self._score >= 90:
            return "a"
        elif self._score >= 80:
            return "b"
        elif self._score >= 60:
            return "c"
        else:
            return "d"
stu = student("alice", 85)
print(stu.score)       # 85(像属性一样访问,不用加括号)
stu.score = 92         # 自动调用setter,有校验
print(stu.grade)       # a(只读属性,自动计算)
# stu.grade = "a"      # attributeerror: can't set attribute(只读!)
// java 对比:需要手写getter/setter
public class student {
    private int score;
    public int getscore() { return score; }
    public void setscore(int score) {
        if (score < 0 || score > 100) {
            throw new illegalargumentexception("分数必须在0-100之间");
        }
        this.score = score;
    }
    // 调用:stu.getscore()、stu.setscore(92)
    // python:stu.score、stu.score = 92(更自然!)
}

面试加分@property实现了"像访问属性一样调用方法",后续想加校验、缓存、日志等逻辑时,不需要改调用方代码。这是python"渐进式增强"设计的典型例子。

七、继承

7.1 基本继承

class animal:
    def __init__(self, name: str):
        self.name = name
    def speak(self) -> str:
        return f"{self.name} makes a sound"
    def __str__(self):
        return f"animal({self.name})"
class dog(animal):  # 继承animal
    def __init__(self, name: str, breed: str):
        super().__init__(name)  # 调用父类构造方法(≈ java的super())
        self.breed = breed
    def speak(self) -> str:  # 方法覆盖(override)
        return f"{self.name} barks: woof!"
    def fetch(self, item: str):
        return f"{self.name} fetches {item}"
dog = dog("buddy", "golden retriever")
print(dog.speak())     # buddy barks: woof!
print(dog.fetch("ball"))  # buddy fetches ball
print(dog)             # animal(buddy)(继承的__str__)
// java 对比
public class animal {
    protected string name;
    public animal(string name) { this.name = name; }
    public string speak() { return name + " makes a sound"; }
}
public class dog extends animal {
    private string breed;
    public dog(string name, string breed) {
        super(name);          // 和python的super().__init__()一样
        this.breed = breed;
    }
    @override
    public string speak() {   // 方法覆盖
        return name + " barks: woof!";
    }
}

7.2 多继承(java只支持单继承!)

python支持多继承,这是面试的高频考点。

class flyable:
    def fly(self):
        return f"{self.__class__.__name__} is flying"
class swimmable:
    def swim(self):
        return f"{self.__class__.__name__} is swimming"
class duck(flyable, swimmable):  # 多继承
    def quack(self):
        return "quack! quack!"
duck = duck()
print(duck.fly())     # duck is flying
print(duck.swim())    # duck is swimming
print(duck.quack())   # quack! quack!
// java:只能实现多个接口(接口没有实现逻辑,java 8+有default方法)
public class duck implements flyable, swimmable {
    // 如果flyable和swimmable有同名方法,java会要求你显式解决
}

7.3 mro(方法解析顺序)

多继承时,如果多个父类有同名方法,python按什么顺序查找?答案是c3线性化算法。

class a:
    def who(self): return "a"
class b(a):
    def who(self): return "b"
class c(a):
    def who(self): return "c"
class d(b, c):
    pass
d = d()
print(d.who())      # b(按mro顺序:d -> b -> c -> a)
print(d.__mro__)     # 查看mro顺序
# (<class 'd'>, <class 'b'>, <class 'c'>, <class 'a'>, <class 'object'>)

面试提醒:不需要记住c3算法的细节,但要知道:

  1. python使用c3线性化算法确定mro
  2. 可以通过classname.__mro__classname.mro()查看
  3. 菱形继承时,子类方法优先,然后按继承列表从左到右

7.4 常见坑点

坑7:多继承的方法覆盖陷阱

class base:
    def method(self):
        print("base.method")
class left(base):
    def method(self):
        print("left.method")
class right(base):
    def method(self):
        print("right.method")
class child(left, right):
    pass
child().method()  # "left.method"
# 因为mro是 child -> left -> right -> base
# 先找到left就停了,不会到right

坑8:super().__init__() 在多继承中的行为

super()不是调用父类,而是按mro顺序调用下一个类。多继承时要确保每个父类的__init__都被调用,且只调用一次。

八、私有属性与名称改写

8.1 python的"私有"机制

python没有java那样的private/protected/public关键字,靠的是约定名称改写

class person:
    def __init__(self, name, age, ssn):
        self.name = name          # public:任何人都能访问
        self._age = age           # protected(约定):外部不该直接访问
        self.__ssn = ssn          # "private":会触发名称改写
    def get_ssn(self):
        return self.__ssn
p = person("alice", 25, "123-45-6789")
print(p.name)       # alice(直接访问)
print(p._age)       # 25(可以访问,但约定不该这么做)
# print(p.__ssn)    # attributeerror!
print(p._person__ssn)  # 123-45-6789(名称改写后还是可以访问!)

核心区别

  • java的private强制的,编译期检查,外部无法访问
  • python的__开头是名称改写(name mangling),只是把__ssn改成了_person__ssn,是一种"防君子不防小人"的机制
  • python哲学:“we are all consenting adults here”——大家都是成年人,应该知道什么该做什么不该做

8.2 单下划线 vs 双下划线

写法含义强制程度java对应
namepublicpublic
_nameprotected(约定)约定,不强制protected
__name名称改写改写名称,仍可绕过private(但弱得多)
__name__魔术方法特殊用途,不要自定义无对应

8.3 常见坑点

坑9:子类和父类"私有属性"同名

class parent:
    def __init__(self):
        self.__value = "parent"  # 改写为 _parent__value
class child(parent):
    def __init__(self):
        super().__init__()
        self.__value = "child"   # 改写为 _child__value,不是同一个属性!
c = child()
print(c._parent__value)  # "parent"
print(c._child__value)   # "child"
# 两个不同的属性!不会互相覆盖

九、魔术方法(dunder methods)

魔术方法是python面向对象的精髓,让你的类可以像内置类型一样工作。

9.1 字符串表示:__str__和__repr__

class point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __str__(self):
        """面向用户:print()、str()时调用 ≈ java的tostring()"""
        return f"point({self.x}, {self.y})"
    def __repr__(self):
        """面向开发者:交互式环境、调试时显示"""
        return f"point(x={self.x!r}, y={self.y!r})"
p = point(1, 2)
print(p)       # point(1, 2)(调用__str__)
print(repr(p)) # point(x=1, y=2)(调用__repr__)
// java 对比
@override
public string tostring() {
    return "point(" + x + ", " + y + ")";
}
// python 分了两个:__str__(用户友好)+ __repr__(开发调试)

9.2 比较运算

class student:
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def __eq__(self, other):   # ==
        return self.score == other.score
    def __lt__(self, other):   # <
        return self.score < other.score
    def __le__(self, other):   # <=
        return self.score <= other.score
    def __gt__(self, other):   # >
        return self.score > other.score
s1 = student("alice", 90)
s2 = student("bob", 85)
print(s1 > s2)     # true
print(s1 == s2)    # false
# 更简洁的方式:用functools.total_ordering
from functools import total_ordering
@total_ordering
class student2:
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def __eq__(self, other):
        return self.score == other.score
    def __lt__(self, other):
        return self.score < other.score
    # 只需要定义 __eq__ 和 __lt__,其他会自动推导!
// java 对比:实现comparable接口
public class student implements comparable<student> {
    @override
    public int compareto(student other) {
        return integer.compare(this.score, other.score);
    }
}

9.3 容器协议:__len__、__getitem__

class todolist:
    def __init__(self):
        self._items = []
    def add(self, item):
        self._items.append(item)
    def __len__(self):             # 支持 len(obj)
        return len(self._items)
    def __getitem__(self, index):  # 支持 obj[index]
        return self._items[index]
    def __contains__(self, item):  # 支持 item in obj
        return item in self._items
    def __iter__(self):            # 支持 for item in obj
        return iter(self._items)
todo = todolist()
todo.add("学python")
todo.add("准备面试")
todo.add("刷算法题")
print(len(todo))          # 3(__len__)
print(todo[1])            # 准备面试(__getitem__)
print("学python" in todo)  # true(__contains__)
for item in todo:         # __iter__
    print(f"  - {item}")

面试加分:实现了这些魔术方法,你的自定义类就能像list一样使用len()[]infor循环。这就是python的"鸭子类型"——走起来像鸭子、叫起来像鸭子,那就是鸭子。

9.4 其他常用魔术方法速查

方法触发方式java近似
__init__(self)创建对象时构造器
__str__(self)print(obj)tostring()
__repr__(self)交互式环境显示tostring()
__eq__(self, other)obj1 == obj2equals()
__hash__(self)放入set/dict时hashcode()
__len__(self)len(obj)size() (collection)
__getitem__(self, key)obj[key]get() (map/list)
__call__(self)obj()无对应(java对象不可调用)
__enter__/__exit__with语句try-with-resources

🗺️ 思维导图速览

python函数与面向对象
├── 函数
│   ├── 定义与调用:def func(params):
│   ├── 参数类型
│   │   ├── 位置参数
│   │   ├── 关键字参数
│   │   ├── 默认参数(≈ java重载简化版)
│   │   ├── *args(可变位置参数)
│   │   └── **kwargs(可变关键字参数)
│   ├── lambda
│   │   ├── 语法:lambda x: 表达式
│   │   ├── 常见用法:sorted(key=lambda...)
│   │   ├── 局限性:只能写一行表达式
│   │   └── 闭包陷阱:变量捕获是引用不是值
│   └── 返回值:支持多值返回(元组解包)
├── 面向对象基础
│   ├── 类定义:class classname:
│   ├── __init__ 构造方法(≈ java构造器)
│   ├── self(≈ java的this,但必须显式写)
│   ├── 实例属性 vs 类属性
│   └── 方法定义(第一个参数必须self)
├── 三种特殊方法
│   ├── 实例方法:def method(self)
│   ├── @classmethod:def method(cls)  → 工厂方法
│   └── @staticmethod:def method()    → 工具方法
├── @property
│   ├── getter:@property
│   ├── setter:@xxx.setter
│   └── 优势:像属性一样访问,保留方法逻辑
├── 继承
│   ├── 单继承:class child(parent)
│   ├── super().__init__()(≈ java的super())
│   ├── 方法覆盖(override)
│   ├── 多继承(vs java单继承)
│   └── mro:c3线性化算法
├── 私有属性
│   ├── _name:约定私有(protected)
│   ├── __name:名称改写(name mangling)
│   └── 哲学:"we are all consenting adults"
└── 魔术方法
    ├── __str__ / __repr__(≈ tostring)
    ├── __eq__ / __hash__(≈ equals/hashcode)
    ├── __len__ / __getitem__(容器协议)
    └── __enter__ / __exit__(≈ try-with-resources)

📝 写在最后

学习建议

  1. 函数部分重点掌握:默认参数的陷阱(可变对象默认值)、*args/**kwargs的用法、lambda的适用场景和闭包问题——这些面试出现频率极高。
  2. 面向对象要对标java学:每个概念都想想"这在java里是怎么做的",对比记忆效率高。尤其是self必须显式写、多继承、私有属性的差异。
  3. 魔术方法不用全背:先掌握__init____str____repr____eq__这四个,其他的用到的时候再查。面试时能说出"实现了__len____getitem__就能当容器用"就是加分项。
  4. @property@classmethod:这两个java里没有对应的概念,需要单独理解。工厂模式用@classmethod实现非常优雅,面试手写代码时可以用。

面试高频问答

q:python的self和java的this有什么区别?

功能相同,都指向当前实例。区别:python的self必须在方法定义中显式声明为第一个参数,java的this是隐式的;python调用实例方法时也要传self(obj.method()本质是class.method(obj)),java不需要。

q:python多继承有什么问题?怎么解决?

主要是菱形继承问题——两个父类继承自同一个基类,子类会继承两份基类的方法/属性。python用c3线性化算法(mro)来解决,确保每个类只被访问一次。可以通过classname.__mro__查看解析顺序。实际开发中推荐用mixin模式(每个父类只提供一个功能),避免复杂的继承关系。

q:@staticmethod@classmethod的区别?

@staticmethod不需要类或实例参数,就是个普通函数放在类的命名空间里,适合放工具方法。@classmethod第一个参数是cls(类本身),可以访问类属性、创建类实例,适合做工厂方法。关键区别:@classmethod在继承时cls会变成子类,所以子类调用时创建的是子类实例;@staticmethod没有这个能力。

q:python的"私有"和java的private有什么不同?

java的private是编译期强制的,外部代码无法访问。python没有真正的私有,__双下划线开头会触发名称改写(__name变成_classname__name),但这只是"防误触",通过改写后的名字仍然可以访问。python的设计哲学是"we are all consenting adults here",靠约定而不是强制来约束行为。

到此这篇关于python函数与面向对象详解的文章就介绍到这了,更多相关python函数与面向对象内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com