两天上手python

python语言学习

软件使用pycharm

安装python解释器,类似于java的jdk

基础语法

注释

单行注释使用 # 开头:

# 这是一个注释

多行注释可以使用三引号 """ 或者 ''' 包围:

"""
这是多行注释
可以跨多行
"""
'''

变量和数据类型

Python 使用动态类型,变量不需要显式声明类型:

-----------------------数值类型
# 整数
a = 42

# 浮点数
b = 3.14

# 复数
c = 3 + 4j

# 操作
print(a + b)  # 45.14
print(c.real)  # 3.0
print(c.imag)  # 4.0
------------------------序列类型
# 字符串
s = "hello"

# 列表
l = [1, 2, 3]

# 元组
t = (1, 2, 3)

# 操作
print(s[0])  # h
print(l[1:])  # [2, 3]
print(t.count(1))  # 1

------------------------映射类型
# 字典
d = {'name': 'Alice', 'age': 30}

# 操作
print(d['name'])  # Alice
print(d.get('age'))  # 30
---------------------------集合类型
# 集合
s1 = {1, 2, 3}
s2 = {3, 4, 5}

# 操作
print(s1.union(s2))  # {1, 2, 3, 4, 5}
print(s1.intersection(s2))  # {3}
----------------------------------布尔类型
# 布尔值
b1 = True
b2 = False

# 操作
print(b1 and b2)  # False
print(b1 or b2)  # True
print(not b1)  # False
---------------------------------二进制类型
# 字节
b = b'hello'

# 字节数组
ba = bytearray(b)

# 操作
print(b.decode())  # hello
print(ba[0])  # 104
-----------------------------------None 类型
# None
n = None

# 操作
print(n is None)  # True
命名规则
  1. 变量名只能包含字母、数字和下划线。它们不能以数字开头。
    • 有效示例:var_name, _myVar, thisIsAVariable
    • 无效示例:2ndVariable, this-is-a-variable
  2. 变量名区分大小写。这意味着 variable, VariableVARIABLE 是三个不同的变量。
    • 有效示例:variable, Variable, VARIABLE
  3. 不能使用Python的保留关键字作为变量名。Python有一些内置的关键字,如 if, else, for, while, class, def, 等等,这些都不能作为变量名使用。
    • 无效示例:if = 1, class = "example"
  4. 变量名不能包含空格。如果需要多个单词来描述一个变量,通常使用下划线 _ 分隔单词。
    • 有效示例:my_variable, this_is_a_long_variable_name
命名约定

除了上述规则外,还有一些普遍接受的约定来帮助提高代码的可读性和一致性:

  1. 小写字母和下划线:对于普通变量和函数名,通常使用小写字母,并用下划线分隔单词。
    • 示例:my_variable, get_user_info
  2. 大写字母和下划线:对于常量(其值在整个程序运行过程中不应该改变),使用全大写字母,并用下划线分隔单词。
    • 示例:MAX_ATTEMPTS, PI
  3. CamelCase:对于类名,通常使用首字母大写的驼峰命名法(CamelCase)。
    • 示例:MyClass, HTTPRequest
  4. PascalCase:有时在某些上下文中,尤其是当涉及到类的方法或属性时,也可能会使用PascalCase(每个单词首字母大写)。
    • 示例:GetUserInformation, CreateNewFile
  5. 单下划线前缀:单下划线前缀 (_) 通常用来表示一个变量或方法是“私有的”,即不建议外部代码直接访问。
    • 示例:_private_variable, _internal_method
  6. 双下划线前缀:双下划线前缀 (__) 通常用于实现命名空间的私有化。
    • 示例:__private_variable, __init__
  7. 双下划线后缀:双下划线后缀 (__) 用于特殊方法,如构造函数或比较运算符。
    • 示例:__init__, __str__, __eq__
  8. 避免使用Python内置的函数名:虽然这不是一个规则,但最好避免使用像 list, dict, str 等内置函数的名字作为变量名,以防止意外覆盖这些重要的内置功能。

控制结构

条件语句

if x > 0:
    print("x is positive")
elif x == 0:
    print("x is zero")
else:
    print("x is negative")

循环语句

for 循环用于遍历序列(如列表、字符串等):

for i in range(5):
    print(i)

while 循环重复执行直到条件为假:

while x < 10:
    print(x)
    x += 1

breakcontinue 控制循环的流程

for i in range(10):
    if i == 5:
        break
    print(i)

函数

定义函数使用 def 关键字

def greet(name):
    return f"Hello, {name}!"

print(greet("Alice"))

列表和元组

列表 (可变)

numbers = [1, 2, 3]
numbers.append(4)
print(numbers)

元组 (不可变)

point = (1, 2)
print(point)

字典

键值对的集合

person = {"name": "Alice", "age": 30}
print(person["name"])

模块和包

导入模块使用 import 关键字,也可以使用from...import

import math
print(math.sqrt(16))
import 语句

import 语句用于导入整个模块到当前命名空间中。当你使用 import 语句时,你必须通过模块名来引用其中的成员。

import math
print(math.sqrt(16))

from ... import ... 语句

from ... import ... 语句允许你从一个模块中导入一个或多个特定的成员(如函数、类或变量)到当前命名空间中。这样你就可以直接使用这些成员的名字,而无需指定模块名。

from math import sqrt

print(sqrt(16))
区别
  1. 可读性:
    • 使用 import 通常会让代码更具可读性,因为它明确指出了成员来自哪个模块。
    • 使用 from ... import ... 可能会让读者不清楚成员是从哪个模块导入的,特别是在导入多个成员时。
  2. 命名冲突:
    • 使用 from ... import ... 可能会导致命名冲突,尤其是在导入多个模块中的同名成员时。
    • 使用 import 则较少发生此类问题,因为成员都属于特定的模块。
  3. 性能:
    • 使用 from ... import ... 通常比使用 import 稍微快一点,因为它不需要在每次调用时查找模块名称。
    • 但在大多数情况下,这种差异可以忽略不计。
  4. 导入所有成员:
    • 可以使用 from module import * 来导入模块中的所有公共成员。但这种做法通常不被推荐,因为它可能导致命名冲突,并降低了代码的可读性。
推荐使用
  • 推荐使用 import: 对于大型项目或需要维护的代码,推荐使用 import 语句来导入模块。这种方式提高了代码的可读性和可维护性。
  • 使用 from ... import ...: 当你只需要从一个模块中导入一两个成员,并且确信不会产生命名冲突时,可以使用 from ... import ...。这种方式可以让代码更简洁。

异常处理

使用 tryexcept 来捕获异常

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero.")

进阶语法

__main__ 的作用

在 Python 中,__main__ 是一个特殊的模块名称,它表示当前正在运行的脚本。当一个 Python 脚本被直接运行时,__name__ 内置变量会被设置为 "__main__"。这在 Python 中经常被用来判断脚本是直接运行还是被导入到另一个脚本中。

  1. 区分直接运行和导入:
    • 当一个脚本被直接运行时,它的 __name__ 属性会被设置为 "__main__"
    • 当一个脚本被另一个脚本导入时,它的 __name__ 属性会保持为脚本文件的文件名(不包括 .py 后缀)。
  2. 封装主程序逻辑:
    • 通常,在 Python 脚本中,if __name__ == "__main__": 语句用于封装脚本的主入口点逻辑。
    • 这样做可以确保这部分代码仅在脚本直接运行时才会执行。
使用技巧

独立运行脚本

使用 if __name__ == "__main__": 来保护脚本的主要逻辑,确保这部分逻辑仅在直接运行脚本时执行。

def main():
    print("This script is running directly.")

if __name__ == "__main__":
    main()

可导入性

如果你希望脚本中的某些函数或类可以被其他脚本导入和使用,同时又希望脚本本身也可以独立运行,那么使用 if __name__ == "__main__": 是非常有用的。

def useful_function():
    print("This function can be imported.")

if __name__ == "__main__":
    useful_function()

参数处理

当脚本直接运行时,通常会处理命令行参数。可以在 if __name__ == "__main__": 块中解析这些参数。

import sys

def main(args):
    print(f"Arguments: {args}")

if __name__ == "__main__":
    main(sys.argv[1:])

单元测试

如果你使用 Python 的标准库 unittest 来编写单元测试,通常会在脚本的最后使用 if __name__ == "__main__": unittest.main() 来运行测试。

import unittest

class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

if __name__ == '__main__':
    unittest.main()

避免污染全局命名空间

当一个脚本被导入时,如果不使用 if __name__ == "__main__":,那么脚本中的所有顶层代码都会被执行,可能会无意间修改全局命名空间。使用 if __name__ == "__main__": 可以避免这种情况。

def say_hello(name):
    print(f"Hello, {name}!")

def main():
    name = input("Enter your name: ")
    say_hello(name)

if __name__ == "__main__":
    main()

总结

使用 if __name__ == "__main__": 是一个很好的编程习惯,它可以帮助你编写更灵活、更易于维护的代码。无论是在开发独立的脚本还是构建更大的应用程序时,这种方法都是非常有用的。如果你有任何更具体的问题或需要进一步的指导,请随时告诉我!

闭包

在Python中,闭包(Closure)是一种特殊类型的函数,它能够记住并访问其定义时所在的作用域中的变量,即使在其外部作用域已经关闭的情况下也是如此。简单来说,闭包就是能够访问其自身范围以外变量的函数。

要形成一个闭包,需要满足以下三个条件:

  1. 函数里面嵌套函数。
  2. 内部函数引用了外部函数的局部变量。
  3. 外部函数返回了内部函数的引用。
def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

closure = outer_function(10)
print(closure(5))  # 输出 15
  • outer_function 是一个外部函数,它接受一个参数 x
  • inner_function 是一个内部函数,它接受一个参数 y 并使用外部函数 outer_function 的局部变量 x
  • 当调用 outer_function(10) 时,它返回 inner_function 的引用,并且 x 被绑定为 10。
  • 最后,closure(5) 调用返回 15,这是因为内部函数记得 x 的值是 10。
闭包的应用场景

封装:闭包可以用来创建私有变量和函数,实现信息隐藏和封装。这有助于避免全局变量污染,并允许函数拥有持久化的状态

def counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

c = counter()
print(c())  # 输出 1
print(c())  # 输出 2

函数式编程:闭包可以用来创建高阶函数、延迟执行函数、柯里化(Currying)等功能。

def make_adder(n):
    def add(x):
        return n + x
    return add

add_five = make_adder(5)
print(add_five(10))  # 输出 15

定时器和事件处理:在JavaScript中,闭包经常用于定时器和事件处理器中,以保持函数执行时的状态。

function createClickHandler(id) {
    return function() {
        console.log('Clicked on element with id:', id);
    };
}

const buttonHandler = createClickHandler('button1');
document.getElementById('button1').addEventListener('click', buttonHandler);

模块模式:在JavaScript中,通过立即执行函数表达式(IIFE)结合闭包可以创建模块模式,实现私有成员和公共接口。

const myModule = (function() {
    const privateVar = 'private data';

    function privateFunction() {
        console.log(privateVar);
    }

    return {
        publicMethod: function() {
            privateFunction();
        }
    };
})();

myModule.publicMethod();  // 输出 "private data"

回调函数:在异步编程中,闭包可以确保回调函数访问到正确的上下文和参数。

function processAsyncData(data, callback) {
    setTimeout(function() {
        callback(data);
    }, 1000);
}

processAsyncData('some data', function(data) {
    console.log('Received:', data);
});

循环中的异步操作:在循环中处理异步操作时,闭包可以确保每个操作引用的是正确的迭代变量。

const items = [1, 2, 3];
items.forEach(function(item, index) {
    setTimeout(function() {
        console.log('Item:', item, 'Index:', index);
    }, 1000 * index);
});

缓存:闭包可以用来实现函数结果的缓存,以提高性能。

def memoize(func):
    cache = {}
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@memoize
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))  # 输出 55

装饰器

在Python中,装饰器是一种非常强大的工具,用于修改或增强现有函数或类的功能。装饰器本质上是一个接收函数作为参数的函数,并返回一个新的函数。这个新的函数通常会对原始函数的行为进行扩展或者完全替换。

基本语法

装饰器的基本语法是在函数定义之前加上一个“@”符号,后跟装饰器的名称。

@decorator
def some_function():
    pass
    
----------------相当于
def some_function():
    pass

some_function = decorator(some_function)
简单装饰器示例
def simple_decorator(func):
    def wrapper():
        print("Before the function is called.")
        func()
        print("After the function is called.")
    return wrapper

@simple_decorator
def say_hello():
    print("Hello!")

say_hello()
---------------------------
输出结果
Before the function is called.
Hello!
After the function is called.
使用闭包来保留状态

​ 装饰器还可以利用闭包来保存状态。例如,我们可以创建一个装饰器来记录函数被调用的次数。

def count_calls(func):
    def wrapper():
        wrapper.calls += 1
        print(f"Function {func.__name__} was called {wrapper.calls} times")
        func()
    
    wrapper.calls = 0
    return wrapper

@count_calls
def greet():
    print("Greetings!")

greet()
greet()
greet()
参数传递

如果要装饰的函数带有参数,装饰器也需要相应地处理这些参数。

def params_decorator(func):
    def wrapper(*args, **kwargs):
        print("Arguments were: ", args, kwargs)
        return func(*args, **kwargs)
    return wrapper

@params_decorator
def add(a, b):
    return a + b

result = add(1, 2)
print("Result:", result)
---------------------------输出结果
Arguments were:  (1, 2) {}
Result: 3
使用多个装饰器

你可以将多个装饰器应用到同一个函数上。装饰器的执行顺序是从下往上。

def uppercase_decorator(func):
    def wrapper():
        original_result = func()
        modified_result = original_result.upper()
        return modified_result
    return wrapper

def split_words_decorator(func):
    def wrapper():
        original_result = func()
        modified_result = original_result.split()
        return modified_result
    return wrapper

@uppercase_decorator
@split_words_decorator
def greet():
    return "hello world"

print(greet())
------------输出结果
['HELLO', 'WORLD']
使用装饰器类

装饰器也可以定义为类,这允许你使用更多的功能,例如初始化状态等。

class TimeThis:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        import time
        start_time = time.time()
        result = self.func(*args, **kwargs)
        end_time = time.time()
        print(f"{self.func.__name__} took {end_time - start_time:.2f} seconds to run")
        return result

@TimeThis
def heavy_computation(n):
    sum(range(n))

heavy_computation(1000000)
装饰器与functools.wraps

为了保持被装饰函数的元数据(如函数名、文档字符串等),可以使用 functools.wraps

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Before the function is called.")
        result = func(*args, **kwargs)
        print("After the function is called.")
        return result
    return wrapper

@my_decorator
def example_function():
    """This is an example function."""
    print("Inside the function.")

print(example_function.__name__)
print(example_function.__doc__)
——————————————————————————————————————输出结果
example_function
This is an example function.

面向对象

在 Python 中,类是面向对象编程的基础。类允许你定义对象的蓝图,这些对象可以拥有属性(数据成员)和方法(函数)。下面我将详细介绍 Python 中类的基本概念、语法以及如何使用它们。

创建类

在 Python 中,类定义通常以关键字 class 开始,后面跟着类的名字,通常采用大写字母开头的驼峰式命名法。类体包含类的属性和方法。

class MyClass:
    # 类的构造方法
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

    # 类的方法
    def method_name(self):
        # 方法的实现
        pass
构造方法 __init__

类的构造方法是一个特殊的方法,它会在创建类的实例时自动调用。构造方法的名称是 __init__,它总是接收至少一个参数 self,表示类的实例。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
实例化类

要创建一个类的实例,只需调用类,就像调用一个普通的函数一样,但不需要括号如果类没有定义任何参数。

person1 = Person("Alice", 30)
person2 = Person("Bob", 25)
访问属性和方法

一旦创建了类的实例,就可以通过点操作符来访问其属性和方法。

print(person1.name)  # 输出: Alice
print(person1.age)   # 输出: 30

person1.say_hello()  # 假设 Person 类有一个 say_hello 方法
方法
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_hello(self):
        print(f"Hello, my name is {self.name} and I am {self.age} years old.")
继承

Python 支持单继承和多继承。子类可以继承父类的属性和方法。

class Employee(Person):
    def __init__(self, name, age, position):
        super().__init__(name, age)
        self.position = position

    def introduce(self):
        self.say_hello()  # 调用父类的方法
        print(f"I work as a {self.position}.")
多态

Python 支持多态,即子类可以重写父类的方法,并且可以根据对象的类型自动选择合适的方法

class Manager(Employee):
    def introduce(self):
        super().introduce()
        print("I manage the team.")

emp1 = Employee("Charlie", 35, "Engineer")
mgr1 = Manager("David", 40, "Manager")

emp1.introduce()
mgr1.introduce()
小结

Python 中的类提供了一种组织代码的强大方式,可以帮助你更好地管理复杂的应用程序。通过使用类,你可以创建具有共同特性的对象,并通过方法来封装行为。此外,通过继承和多态,你可以扩展和定制类的行为,使代码更加灵活和可重用。

常用的魔术方法

Python的魔术方法(也称作特殊方法或dunder方法)是Python中非常强大的特性之一,它们允许你定义类的行为,使得类的对象可以像内置类型一样工作。

初始化方法

__init__(self, ...)这个方法在对象创建之后立即被调用,用来初始化对象的状态。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person('Alice', 30)
print(p.name)  # 输出: Alice
字符串表示方法

__str__(self)当使用print()函数或str()函数转换对象时,这个方法会被调用。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"{self.name} is {self.age} years old."

p = Person('Bob', 25)
print(p)  # 输出: Bob is 25 years old.

__repr__(self)这个方法返回一个字符串,表示对象的官方字符串表示形式,通常用于调试。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __repr__(self):
        return f"Person({self.name}, {self.age})"

p = Person('Eve', 35)
print(repr(p))  # 输出: Person(Eve, 35)
比较方法

__eq__(self, other)定义了两个对象是否相等的逻辑。

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __eq__(self, other):
        if isinstance(other, Point):
            return self.x == other.x and self.y == other.y
        return False

p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2)  # 输出: True
数学运算方法

__add__(self, other)定义了加法运算。

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2
print(v3.x, v3.y)  # 输出: 4 6
容器协议

__getitem__(self, key)定义了通过索引获取对象元素的行为。

class MyList:
    def __init__(self, lst):
        self.lst = lst
    
    def __getitem__(self, index):
        return self.lst[index]

ml = MyList([1, 2, 3, 4])
print(ml[2])  # 输出: 3

__len__(self)定义了len()函数的行为。

class MyList:
    def __init__(self, lst):
        self.lst = lst
    
    def __len__(self):
        return len(self.lst)

ml = MyList([1, 2, 3, 4])
print(len(ml))  # 输出: 4
上下文管理器

__enter__(self)** 和 **__exit__(self, exc_type, exc_value, traceback)这两个方法允许你在with语句中使用自定义的上下文管理器。

class File:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
    
    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()

with File('example.txt', 'w') as f:
    f.write('Hello, world!')

高级语法

私有属性和方法的命名约定:

单下划线前缀 (_)

当一个属性或者方法名以单下划线开头时 (_), 它表示这是一个内部使用的成员,虽然可以被外部访问,但不建议这么做。

这种命名方式更多是一种约定,用来提示其他开发者不要直接访问或修改这些成员。

class MyClass:
    def __init__(self):
        self._private_attribute = 42

    def _private_method(self):
        print("This is a private method.")

# 创建一个对象
obj = MyClass()

# 访问私有属性
print(obj._private_attribute)  # 输出: 42

# 调用私有方法
obj._private_method()  # 输出: This is a private method.
双下划线前缀 (__)

当一个属性或方法名以双下划线开头 (__) 时,Python会对其进行名称改写(也称为名称改编或名称重整)。

名称改写是指将成员的名称从 __private_attribute 改为 _ClassName__private_attribute,这里的 ClassName 是类的名字。

这种方式可以有效地阻止从类的外部直接访问这些成员,除非你知道确切的名称。

class MyClass:
    def __init__(self):
        self.__private_attribute = 42

    def __private_method(self):
        print("This is a private method.")

# 创建一个对象
obj = MyClass()

# 尝试访问私有属性
print(obj.__private_attribute)  # 抛出 AttributeError

# 尝试调用私有方法
obj.__private_method()  # 抛出 AttributeError

# 访问经过名称改编后的私有属性
print(obj._MyClass__private_attribute)  # 输出: 42

# 调用经过名称改编后的私有方法
obj._MyClass__private_method()  # 输出: This is a private method.
总结:
  • 单下划线: 表示这是内部使用的成员,不建议外部直接访问。
  • 双下划线: 表示这是严格私有的成员,外部无法直接访问,除非使用名称改编的形式。
  • 强行获取私有属性:如果想强行获取私有属性的值,可以使用 _ + 类名 + 属性名
  • 合法的使用私有属性: 使用类中方法是否私有属性,getter、setter
注意事项:
  • 名称改编不是真正的私有性: 尽管名称改编提供了一定程度的保护,但它并不是完全私有的,因为可以通过名称改编的方式访问这些成员。
  • 封装与接口: 即使成员不是私有的,也应该通过公共的方法来操作这些成员,以保证良好的封装性和易于维护。
示例: 使用私有属性和方法
class BankAccount:
    def __init__(self, initial_balance):
        self.__balance = initial_balance

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
        else:
            raise ValueError("Deposit amount must be positive.")

    def withdraw(self, amount):
        if amount > 0 and amount <= self.__balance:
            self.__balance -= amount
        else:
            raise ValueError("Withdrawal amount is invalid or exceeds balance.")

    def get_balance(self):
        return self.__balance

# 创建一个银行账户
account = BankAccount(1000)

# 存款
account.deposit(500)

# 取款
account.withdraw(200)

# 获取余额
print(account.get_balance())  # 输出: 1300

在这个例子中,__balance 是一个私有属性,而 deposit, withdrawget_balance 方法提供了与该属性交互的方式。通过这种方式,我们可以确保数据的安全性和一致性。

类的继承

直接代码演示

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        raise NotImplementedError("Subclass must implement this abstract method")

class Dog(Animal):
    def speak(self):
        return self.name + ' says Woof!'
    
    def fetch_stick(self):
        print(self.name + " runs to fetch the stick!")

class Cat(Animal):
    def speak(self):
        return self.name + ' says Meow!'
    
    def chase_laser(self):
        print(self.name + " chases the laser pointer!")

# 创建对象
fido = Dog('Fido')
isis = Cat('Isis')

print(fido.speak())  # 输出: Fido says Woof!
fido.fetch_stick()   # 输出: Fido runs to fetch the stick!

print(isis.speak())  # 输出: Isis says Meow!
isis.chase_laser()   # 输出: Isis chases the laser pointer!
关键点解释
  1. super(): 在子类的构造函数中使用 super() 函数来调用父类的构造函数。这确保了父类的初始化逻辑也会被执行。
  2. 覆盖方法: 子类可以通过重新定义父类的方法来覆盖它们。例如,在上面的例子中,DogCat 类都覆盖了 speak 方法。
  3. 抽象方法: 在父类中可以定义一个没有具体实现的方法(通常抛出异常),这样强制所有子类必须实现这个方法。这可以通过 NotImplementedError 或者使用第三方库如 abc 来实现。
  4. 添加新方法: 子类可以添加自己的方法,这些方法只存在于子类中。
  5. 多重继承: Python 也支持多重继承,即一个子类可以从多个父类继承。只需在括号内列出所有的父类即可。
多继承
class ChildClass(ParentClass1, ParentClass2):
    pass
总结
格式:
class 类名(需要继承的类名1、类名2...):
    pass

多态

Python中的多态可以通过以下几种方式实现:

  1. 鸭子类型:对象之间不需要共享继承关系,只要它们具有相同的方法签名,就可以互换使用。
  2. 方法重写:子类可以重写父类的方法,以实现不同的行为。
  3. 抽象基类:使用模块 abc 来定义抽象基类和抽象方法,强制子类必须实现这些方法。
鸭子类型
class Duck:
    def quack(self):
        print("Quack quack!")

    def fly(self):
        print("Flap flap!")


class Person:
    def quack(self):
        print("The person imitates a duck: Quack quack!")

    def fly(self):
        print("The person flaps their arms and jumps.")


def in_the_forest(creature):
    creature.quack()
    creature.fly()


# 创建对象
duck = Duck()
person = Person()

# 调用函数
in_the_forest(duck)  # 输出: Quack quack! Flap flap!
in_the_forest(person)  # 输出: The person imitates a duck: Quack quack! The person flaps their arms and jumps.
方法重写
class Animal:
    def speak(self):
        raise NotImplementedError("Subclass must implement this abstract method")


class Dog(Animal):
    def speak(self):
        return "Woof woof!"


class Cat(Animal):
    def speak(self):
        return "Meow meow!"


def animal_speaks(animal):
    print(animal.speak())


# 创建对象
fido = Dog()
isis = Cat()

# 调用函数
animal_speaks(fido)  # 输出: Woof woof!
animal_speaks(isis)  # 输出: Meow meow!

类方法

实例方法和类方法,理解:类方法类似于静态方法

@classmethod
--------------------------------------
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        """计算矩形的面积"""
        return self.width * self.height

    @classmethod
    def square(cls, side_length):
        """创建一个正方形(特殊的矩形)"""
        return cls(side_length, side_length)

# 创建一个矩形实例
rect = Rectangle(4, 6)
print(rect.area())  # 输出: 24

# 使用类方法创建一个正方形
square = Rectangle.square(5)
print(square.area())  # 输出: 25
区别总结
  1. 参数:
    • 类方法的第一个参数通常为 cls,代表类本身。
    • 实例方法的第一个参数通常为 self,代表实例对象。
  2. 调用方式:
    • 类方法可以直接通过类名调用,不需要创建类的实例。
    • 实例方法需要通过类的实例来调用。
  3. 用途:
    • 类方法通常用于操作类级别的属性或执行与类相关的任务。
    • 实例方法用于操作实例级别的属性或执行与特定实例相关的任务。
  4. 装饰器:
    • 类方法使用 @classmethod 装饰器定义。
    • 实例方法没有特殊的装饰器,直接定义。
应用场景
  • 类方法常用于:
    • 创建工厂方法,用于替代构造函数创建实例。
    • 执行与类相关的操作,比如读取配置信息等。
    • 提供一些工具性的方法,这些方法不需要实例就能完成。
  • 实例方法常用于:
    • 处理实例级别的状态和行为。
    • 实现对象之间的交互。

静态方法

import math

class MathUtils:
    @staticmethod
    def calculate_area(radius):
        """计算圆的面积"""
        return math.pi * radius ** 2

    @staticmethod
    def add_numbers(a, b):
        """添加两个数字"""
        return a + b

# 调用静态方法
area = MathUtils.calculate_area(5)
print(area)  # 输出: 78.53981633974483

sum_result = MathUtils.add_numbers(10, 20)
print(sum_result)  # 输出: 30
静态方法的特点
  1. 不需要传递 selfcls 参数
    • 静态方法不依赖于类的状态或实例的状态,因此不需要传递 selfcls 参数。
  2. 可以直接通过类名调用
    • 与类方法类似,静态方法可以直接通过类名来调用,不需要创建类的实例。
  3. 无法访问类的状态或实例的状态
    • 静态方法无法直接访问类的属性或实例的属性,除非通过参数传递。
  4. 装饰器
    • 静态方法使用 @staticmethod 装饰器来定义。
静态方法的应用场景
  • 工具方法
    • 实现一些通用的、与类无关的工具方法。
  • 计算或转
    • 执行一些简单的计算或数据转换任务。
  • 工厂方法
    • 在某些情况下,静态方法可以用作工厂方法来创建类的实例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

学习路上的bug

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

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

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

打赏作者

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

抵扣说明:

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

余额充值