两天上手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
命名规则
- 变量名只能包含字母、数字和下划线。它们不能以数字开头。
- 有效示例:
var_name
,_myVar
,thisIsAVariable
- 无效示例:
2ndVariable
,this-is-a-variable
- 有效示例:
- 变量名区分大小写。这意味着
variable
,Variable
和VARIABLE
是三个不同的变量。- 有效示例:
variable
,Variable
,VARIABLE
- 有效示例:
- 不能使用Python的保留关键字作为变量名。Python有一些内置的关键字,如
if
,else
,for
,while
,class
,def
, 等等,这些都不能作为变量名使用。- 无效示例:
if = 1
,class = "example"
- 无效示例:
- 变量名不能包含空格。如果需要多个单词来描述一个变量,通常使用下划线
_
分隔单词。- 有效示例:
my_variable
,this_is_a_long_variable_name
- 有效示例:
命名约定
除了上述规则外,还有一些普遍接受的约定来帮助提高代码的可读性和一致性:
- 小写字母和下划线:对于普通变量和函数名,通常使用小写字母,并用下划线分隔单词。
- 示例:
my_variable
,get_user_info
- 示例:
- 大写字母和下划线:对于常量(其值在整个程序运行过程中不应该改变),使用全大写字母,并用下划线分隔单词。
- 示例:
MAX_ATTEMPTS
,PI
- 示例:
- CamelCase:对于类名,通常使用首字母大写的驼峰命名法(CamelCase)。
- 示例:
MyClass
,HTTPRequest
- 示例:
- PascalCase:有时在某些上下文中,尤其是当涉及到类的方法或属性时,也可能会使用PascalCase(每个单词首字母大写)。
- 示例:
GetUserInformation
,CreateNewFile
- 示例:
- 单下划线前缀:单下划线前缀 (
_
) 通常用来表示一个变量或方法是“私有的”,即不建议外部代码直接访问。- 示例:
_private_variable
,_internal_method
- 示例:
- 双下划线前缀:双下划线前缀 (
__
) 通常用于实现命名空间的私有化。- 示例:
__private_variable
,__init__
- 示例:
- 双下划线后缀:双下划线后缀 (
__
) 用于特殊方法,如构造函数或比较运算符。- 示例:
__init__
,__str__
,__eq__
- 示例:
- 避免使用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
break 和 continue 控制循环的流程
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))
区别
- 可读性:
- 使用
import
通常会让代码更具可读性,因为它明确指出了成员来自哪个模块。 - 使用
from ... import ...
可能会让读者不清楚成员是从哪个模块导入的,特别是在导入多个成员时。
- 使用
- 命名冲突:
- 使用
from ... import ...
可能会导致命名冲突,尤其是在导入多个模块中的同名成员时。 - 使用
import
则较少发生此类问题,因为成员都属于特定的模块。
- 使用
- 性能:
- 使用
from ... import ...
通常比使用import
稍微快一点,因为它不需要在每次调用时查找模块名称。 - 但在大多数情况下,这种差异可以忽略不计。
- 使用
- 导入所有成员:
- 可以使用
from module import *
来导入模块中的所有公共成员。但这种做法通常不被推荐,因为它可能导致命名冲突,并降低了代码的可读性。
- 可以使用
推荐使用
- 推荐使用
import
: 对于大型项目或需要维护的代码,推荐使用import
语句来导入模块。这种方式提高了代码的可读性和可维护性。 - 使用
from ... import ...
: 当你只需要从一个模块中导入一两个成员,并且确信不会产生命名冲突时,可以使用from ... import ...
。这种方式可以让代码更简洁。
异常处理
使用 try
和 except
来捕获异常
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero.")
进阶语法
__main__
的作用
在 Python 中,__main__
是一个特殊的模块名称,它表示当前正在运行的脚本。当一个 Python 脚本被直接运行时,__name__
内置变量会被设置为 "__main__"
。这在 Python 中经常被用来判断脚本是直接运行还是被导入到另一个脚本中。
- 区分直接运行和导入:
- 当一个脚本被直接运行时,它的
__name__
属性会被设置为"__main__"
。 - 当一个脚本被另一个脚本导入时,它的
__name__
属性会保持为脚本文件的文件名(不包括.py
后缀)。
- 当一个脚本被直接运行时,它的
- 封装主程序逻辑:
- 通常,在 Python 脚本中,
if __name__ == "__main__":
语句用于封装脚本的主入口点逻辑。 - 这样做可以确保这部分代码仅在脚本直接运行时才会执行。
- 通常,在 Python 脚本中,
使用技巧
独立运行脚本
使用 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)是一种特殊类型的函数,它能够记住并访问其定义时所在的作用域中的变量,即使在其外部作用域已经关闭的情况下也是如此。简单来说,闭包就是能够访问其自身范围以外变量的函数。
要形成一个闭包,需要满足以下三个条件:
- 函数里面嵌套函数。
- 内部函数引用了外部函数的局部变量。
- 外部函数返回了内部函数的引用。
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
, withdraw
和 get_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!
关键点解释
- super(): 在子类的构造函数中使用
super()
函数来调用父类的构造函数。这确保了父类的初始化逻辑也会被执行。 - 覆盖方法: 子类可以通过重新定义父类的方法来覆盖它们。例如,在上面的例子中,
Dog
和Cat
类都覆盖了speak
方法。 - 抽象方法: 在父类中可以定义一个没有具体实现的方法(通常抛出异常),这样强制所有子类必须实现这个方法。这可以通过
NotImplementedError
或者使用第三方库如abc
来实现。 - 添加新方法: 子类可以添加自己的方法,这些方法只存在于子类中。
- 多重继承: Python 也支持多重继承,即一个子类可以从多个父类继承。只需在括号内列出所有的父类即可。
多继承
class ChildClass(ParentClass1, ParentClass2):
pass
总结
格式:
class 类名(需要继承的类名1、类名2...):
pass
多态
Python中的多态可以通过以下几种方式实现:
- 鸭子类型:对象之间不需要共享继承关系,只要它们具有相同的方法签名,就可以互换使用。
- 方法重写:子类可以重写父类的方法,以实现不同的行为。
- 抽象基类:使用模块
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
区别总结
- 参数:
- 类方法的第一个参数通常为
cls
,代表类本身。 - 实例方法的第一个参数通常为
self
,代表实例对象。
- 类方法的第一个参数通常为
- 调用方式:
- 类方法可以直接通过类名调用,不需要创建类的实例。
- 实例方法需要通过类的实例来调用。
- 用途:
- 类方法通常用于操作类级别的属性或执行与类相关的任务。
- 实例方法用于操作实例级别的属性或执行与特定实例相关的任务。
- 装饰器:
- 类方法使用
@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
静态方法的特点
- 不需要传递
self
或cls
参数:- 静态方法不依赖于类的状态或实例的状态,因此不需要传递
self
或cls
参数。
- 静态方法不依赖于类的状态或实例的状态,因此不需要传递
- 可以直接通过类名调用:
- 与类方法类似,静态方法可以直接通过类名来调用,不需要创建类的实例。
- 无法访问类的状态或实例的状态:
- 静态方法无法直接访问类的属性或实例的属性,除非通过参数传递。
- 装饰器:
- 静态方法使用
@staticmethod
装饰器来定义。
- 静态方法使用
静态方法的应用场景
- 工具方法
- 实现一些通用的、与类无关的工具方法。
- 计算或转
- 执行一些简单的计算或数据转换任务。
- 工厂方法
- 在某些情况下,静态方法可以用作工厂方法来创建类的实例。