1
0

Python:整理入门笔记

This commit is contained in:
周中平 2022-12-03 18:18:23 +08:00
parent 1a67dfaa88
commit 41051fa1b3
No known key found for this signature in database
GPG Key ID: B1DF9DD42D8E00DC
7 changed files with 302 additions and 430 deletions

View File

@ -1,8 +1,14 @@
--- ---
id: 函数方法
title: 函数方法 title: 函数方法
sidebar_position: 5 description: Python 的函数方法
data: 2022年2月10日 keywords:
- Python
- 函数方法
tags:
- Python
sidebar_position: 4
author: 7Wate
date: 2022-12-03
--- ---
## 函数 ## 函数
@ -190,144 +196,6 @@ lambda [arg1 [,arg2,.....argn]]:expression
43 43
``` ```
## 迭代器
迭代器的使用非常普遍并使得 Python 成为一个统一的整体。 在幕后for 语句会在容器对象上调用 `iter()`。 该函数返回一个定义了 `__next__()` 方法的迭代器对象,此方法将逐一访问容器中的元素。 当元素用尽时,`__next__()` 将引发 `StopIteration` 异常来通知终止 `for` 循环。 可以使用 `next()` 内置函数来调用 __next__() 方法;
- **iter()**:创建迭代器。
- **next()**:输出迭代器的下一个元素。
```python
s = 'abc'
it = iter(s)
print(it) # <str_iterator object at 0x10c90e650>
next(it) # 'a'
next(it) # 'b'
next(it) # 'c'
next(it)
# 抛出异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration
```
```python
# 为类添加迭代器
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
```
## yield 生成器
Python 中还有另外一种定义生成器的方式,就是通过`yield`关键字将一个普通函数改造成生成器函数。它们的写法类似于标准的函数,但当它们要返回数据时会使用 `yield` 语句。
```python
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
for i in fibonacci(10):
print(i,end=" ")
```
## 推导生成式
Python 推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个新的数据序列的结构体。
### 列表
```python
# 语法
[out_exp_res for out_exp in input_list]
[out_exp_res for out_exp in input_list if condition]
# 实例
multiples = [i for i in range(30) if i % 3 == 0]
print(multiples) # [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
```
### 字典
```python
# 语法
{ key_expr: value_expr for value in collection }
{ key_expr: value_expr for value in collection if condition }
# 实例
dic = {x: x**2 for x in (2, 4, 6)}
print(dic) # {2: 4, 4: 16, 6: 36}
```
### 集合
```python
# 语法
{ expression for item in Sequence }
{ expression for item in Sequence if conditional }
# 实例
a = {x for x in 'abracadabra' if x not in 'abc'}
print(a) # {'d', 'r'}
```
### 元组
```python
# 语法
(expression for item in Sequence )
(expression for item in Sequence if conditional )
# 实例
a = (x for x in range(1,10))
print(a) # 返回的是生成器对象
tuple(a) # 使用 tuple() 函数,可以直接将生成器对象转换成元组
```
### 其他
```python
f = [x for x in range(1, 10)]
print(f)
f = [x + y for x in 'ABCDE' for y in '1234567']
print(f)
# 用列表的生成表达式语法创建列表容器
# 用这种语法创建列表之后元素已经准备就绪所以需要耗费较多的内存空间
f = [x ** 2 for x in range(1, 1000)]
print(sys.getsizeof(f)) # 查看对象占用内存的字节数
print(f)
# 请注意下面的代码创建的不是一个列表而是一个生成器对象
# 通过生成器可以获取到数据但它不占用额外的空间存储数据
# 每次需要数据的时候就通过内部的运算得到数据(需要花费额外的时间)
f = (x ** 2 for x in range(1, 1000))
print(sys.getsizeof(f)) # 相比生成式生成器不占用存储数据的空间
print(f)
for val in f:
print(val)
```
## 全局、局部变量 ## 全局、局部变量
**定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。** **定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。**

View File

@ -13,7 +13,7 @@ date: 2022-11-20
## 简介 ## 简介
Python 是一门易于学习、功能强大的编程语言。同时是一种**解释型语言,不需要编译和链接**,可以节省大量开发时间。 Python 是一门易于学习、功能强大的编程语言。同时是一种**解释型语言,不需要编译和链接**,可以节省大量开发时间。Python 入门相对其它程序设计语言简单,但是熟练掌握需要一定学习时间,尤其是丰富的魔术方法。
Python 程序**简洁、易读,通常**比实现同种功能的 C、C++、Java 代码短很多,原因如下: Python 程序**简洁、易读,通常**比实现同种功能的 C、C++、Java 代码短很多,原因如下:
@ -28,13 +28,13 @@ Python 官网上免费提供了 Python 解释器和扩展的标准库,包括
Python 官网还包含许多**免费丰富的第三方 Python 模块**、程序和工具发布包及文档链接。 Python 官网还包含许多**免费丰富的第三方 Python 模块**、程序和工具发布包及文档链接。
## 运行 ## 使用
### 安装 ### 安装
Python 官网:<https://www.python.org/>,可以在[官方文档](https://docs.python.org/)帮助下选择合适版本安装。 Python 官网:<https://www.python.org/>,可以在[官方文档](https://docs.python.org/)帮助下选择合适版本安装。
### 使用 ### 运行
Python 安装后在 Shell 中输入 Python 既可运行交互解释器,在解释器内编写 Python 脚本既可以运行。如果需要退出,输入`quit()`。 Python 安装后在 Shell 中输入 Python 既可运行交互解释器,在解释器内编写 Python 脚本既可以运行。如果需要退出,输入`quit()`。
@ -84,7 +84,7 @@ else:
## 行语句 ## 行语句
如果语句很长,我们可以使用反斜杠 **\\** 来实现多行语句;如果在同一行中使用多条语句,语句之间使用分号 **;** 分割。**在 [], {}, 或 () 中的多行语句,不需要使用反斜杠 \\。** 如果语句很长,我们可以使用反斜杠 **\\** 来实现多行语句;如果在同一行中使用多条语句,语句之间使用分号 **;** 分割。**在 [], {}, 或 () 中的多行语句,不需要使用反斜杠 \\。** 字符串之间不换行则会自动拼接。
```python ```python
# 反斜杠 \ 用法 # 反斜杠 \ 用法
@ -98,6 +98,9 @@ import sys; x = 'runoob'; sys.stdout.write(x + '\n')
# 特殊多行语句 # 特殊多行语句
total = ['item_one', 'item_two', 'item_three', total = ['item_one', 'item_two', 'item_three',
'item_four', 'item_five'] 'item_four', 'item_five']
# 字符串
str = "hello" "world" "!"
``` ```
## 复合语句 ## 复合语句

View File

@ -11,7 +11,12 @@ author: 7Wate
date: 2022-11-19 date: 2022-11-19
--- ---
## 判断 ## 条件
在 Python 中,判断的值可以分为:
- 假值 None、空列表、空集合、空字典空元组、空字符串、0、False 等。
- 真值 :非空列表、非空集合、非空字典,非空元组、非空字符串、非 0 数值、True 等。
### if ### if
@ -69,9 +74,6 @@ Python 的 for 语句与 C 或 Pascal 中的不同。**Python 的 for 语句不
```python ```python
""" """
用for循环实现1~100求和 用for循环实现1~100求和
Version: 0.1
Author: 骆昊
""" """
sum = 0 sum = 0
@ -96,9 +98,6 @@ print(sum)
```python ```python
""" """
猜数字游戏 猜数字游戏
Version: 0.1
Author: 骆昊
""" """
import random import random
@ -213,7 +212,7 @@ except:
### with ### with
Python 的 [`with`](https://docs.python.org/zh-cn/3/reference/compound_stmts.html#with) 语句支持通过上下文管理器所定义的运行时上下文这一概念。 此对象的实现使用了一对专门方法,**允许用户自定义类来定义运行时上下文**,在语句体被执行前进入该上下文,并在语句执行完毕时退出该上下文。 Python 的 with 语句支持通过上下文管理器所定义的运行时上下文这一概念。 此对象的实现使用了一对专门方法,**允许用户自定义类来定义运行时上下文**,在语句体被执行前进入该上下文,并在语句执行完毕时退出该上下文。
通过上下文管理器,我们可以更好的控制对象在不同区间的特性,并且**可以使用 with 语句替代 try...except** 方法,使得代码更加的简洁,主要的**使用场景是访问资源,可以保证不管过程中是否发生错误或者异常都会执行相应的清理操作,释放出访问的资源。** 通过上下文管理器,我们可以更好的控制对象在不同区间的特性,并且**可以使用 with 语句替代 try...except** 方法,使得代码更加的简洁,主要的**使用场景是访问资源,可以保证不管过程中是否发生错误或者异常都会执行相应的清理操作,释放出访问的资源。**
@ -263,7 +262,7 @@ NameError: HiThere
### assert ### assert
Python assert(断言)用于判断一个表达式,在表达式条件为 false 的时候触发异常。 Python 断言(assert用于判断一个表达式在表达式条件为 false 的时候触发异常。
简单形式 `assert expression` 等价于: 简单形式 `assert expression` 等价于:
@ -290,6 +289,10 @@ while True:
# 最小的类 # 最小的类
class MyEmptyClass: class MyEmptyClass:
pass pass
# 三个点 等同于 pass
class MyEmptyClass:
...
``` ```
### del ### del
@ -331,37 +334,3 @@ starting...
9 9
10 10
``` ```
### import
基本的 import 语句(不带 from 子句)会分两步执行:
1. 查找一个模块,如果有必要还会加载并初始化模块。
2. 在局部命名空间中为 import 语句发生位置所处的作用域定义一个或多个名称。
```python
import foo # foo imported and bound locally
import foo.bar.baz # foo.bar.baz imported, foo bound locally
import foo.bar.baz as fbb # foo.bar.baz imported and bound as fbb
from foo.bar import baz # foo.bar.baz imported and bound as baz
from foo import attr # foo imported and foo.attr bound as attr
```
from 形式使用的过程略微繁复一些:
1. 查找 from 子句中指定的模块,如有必要还会加载并初始化模块;
2. 对于 import 子句中指定的每个标识符:
1. 检查被导入模块是否有该名称的属性
2. 如果没有,尝试导入具有该名称的子模块,然后再次检查被导入模块是否有该属性
3. 如果未找到该属性,则引发 ImportError。
4. 否则的话,将对该值的引用存入局部命名空间,如果有 as 子句则使用其指定的名称,否则使用该属性的名称
### global
global 语句是作用于整个当前代码块的声明。 它意味着所列出的标识符将被解读为全局变量。
### nonlocal
nonlocal 语句会使得所列出的名称指向之前在最近的包含作用域中绑定的除全局变量以外的变量。

View File

@ -5,7 +5,7 @@ keywords:
- Python - Python
- 数据类型 - 数据类型
tags: tags:
- 标签 - Python
sidebar_position: 2 sidebar_position: 2
author: 7Wate author: 7Wate
date: 2022-11-19 date: 2022-11-19
@ -13,6 +13,8 @@ date: 2022-11-19
## 内置类型 ## 内置类型
**Python中的一切都是对象变量是对象的引用同时 Python 的动态语言特性变量和常量不需要事先声明类型。**
**Python 3 内置类型**如下除了各种数据类型Python 解释器内建了还有很多其他类型,比如上下文管理器类型,模块、方法、代码对象、类型对象、内部对象等类型。 **Python 3 内置类型**如下除了各种数据类型Python 解释器内建了还有很多其他类型,比如上下文管理器类型,模块、方法、代码对象、类型对象、内部对象等类型。
| 类型 | 可变性 | 描述 | 语法例子 | | 类型 | 可变性 | 描述 | 语法例子 |
@ -100,4 +102,5 @@ $ print(keyword.kwlist)
- 受保护的实例属性用单个下划线开头(后面会讲到)。 - 受保护的实例属性用单个下划线开头(后面会讲到)。
- 私有的实例属性用两个下划线开头(后面会讲到)。 - 私有的实例属性用两个下划线开头(后面会讲到)。
使用 type() 检查变量的类型。 Python 使用 `type() 检查变量的类型。
Python 使用 `id() 查看变量的内存地址。

View File

@ -6,14 +6,14 @@ keywords:
- 数据结构 - 数据结构
tags: tags:
- Python - Python
sidebar_position: 4 sidebar_position: 5
author: 7Wate author: 7Wate
date: 2022-11-20 date: 2022-11-20
--- ---
## 数 ## 数
Python 数数据类型用于存储数值。数据类型是不允许改变的,这就意味着如果改变数字数据类型的值将重新分配内存空间。Python 支持三种不同的数值类型: Python 数数据类型用于存储数值。数据类型是不允许改变的,这就意味着如果改变数字数据类型的值将重新分配内存空间。Python 支持三种不同的数值类型:
- **整型(int)** - 通常被称为是整型或整数是正或负整数不带小数点。Python3 整型是没有限制大小的,可以当作 Long 类型使用,所以 Python3 没有 Python2 的 Long 类型。布尔bool是整型的子类型。 - **整型(int)** - 通常被称为是整型或整数是正或负整数不带小数点。Python3 整型是没有限制大小的,可以当作 Long 类型使用,所以 Python3 没有 Python2 的 Long 类型。布尔bool是整型的子类型。
- **浮点型(float)** - 浮点型由整数部分与小数部分组成浮点型也可以使用科学计数法表示2.5e2 = 2.5 x 102 = 250 - **浮点型(float)** - 浮点型由整数部分与小数部分组成浮点型也可以使用科学计数法表示2.5e2 = 2.5 x 102 = 250
@ -526,3 +526,151 @@ for q, a in zip(questions, answers):
# What is your favorite color? It is blue. # What is your favorite color? It is blue.
``` ```
## 推导式
Python 推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个新的数据序列的结构体。
### 列表
```python
# 语法
[out_exp_res for out_exp in input_list]
[out_exp_res for out_exp in input_list if condition]
# 实例
multiples = [i for i in range(30) if i % 3 == 0]
print(multiples) # [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
```
### 字典
```python
# 语法
{ key_expr: value_expr for value in collection }
{ key_expr: value_expr for value in collection if condition }
# 实例
dic = {x: x**2 for x in (2, 4, 6)}
print(dic) # {2: 4, 4: 16, 6: 36}
```
### 集合
```python
# 语法
{ expression for item in Sequence }
{ expression for item in Sequence if conditional }
# 实例
a = {x for x in 'abracadabra' if x not in 'abc'}
print(a) # {'d', 'r'}
```
### 元组
```python
# 语法
(expression for item in Sequence )
(expression for item in Sequence if conditional )
# 实例
a = (x for x in range(1,10))
print(a) # 返回的是生成器对象
tuple(a) # 使用 tuple() 函数,可以直接将生成器对象转换成元组
```
### 其他
```python
f = [x for x in range(1, 10)]
print(f)
f = [x + y for x in 'ABCDE' for y in '1234567']
print(f)
# 用列表的生成表达式语法创建列表容器
# 用这种语法创建列表之后元素已经准备就绪所以需要耗费较多的内存空间
f = [x ** 2 for x in range(1, 1000)]
print(sys.getsizeof(f)) # 查看对象占用内存的字节数
print(f)
# 请注意下面的代码创建的不是一个列表而是一个生成器对象
# 通过生成器可以获取到数据但它不占用额外的空间存储数据
# 每次需要数据的时候就通过内部的运算得到数据(需要花费额外的时间)
f = (x ** 2 for x in range(1, 1000))
print(sys.getsizeof(f)) # 相比生成式生成器不占用存储数据的空间
print(f)
for val in f:
print(val)
```
## 迭代器
可以利用 for 循环的对象,都叫可迭代对象。列表、元组、字典、字符串等都是可迭代对象。
迭代器非常普遍的使用并使得 Python 成为一个统一的整体。 在幕后for 语句会在容器对象上调用 `iter()`。 该函数返回一个定义了 `__next__()` 方法的迭代器对象,此方法将逐一访问容器中的元素。 当元素用尽时,`__next__()` 将引发 `StopIteration` 异常来通知终止 `for` 循环。 可以使用 `next()` 内置函数来调用 __next__() 方法;
- **iter()**:创建迭代器。
- **next()**:输出迭代器的下一个元素。
```python
s = 'abc'
it = iter(s)
print(it) # <str_iterator object at 0x10c90e650>
next(it) # 'a'
next(it) # 'b'
next(it) # 'c'
next(it)
# 抛出异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration
```
```python
# 为类添加迭代器
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
```
## 生成器
生成器Generator是一个可以像迭代器那样使用 for 循环来获取元素的函数。
Python 中还有另外一种定义生成器的方式,就是通过 yield 关键字将一个普通函数改造成生成器函数。yield 相当于 return 但有所不同yield 虽然返回了但是函数并没有结束。当函数运行到 yield 后,函数暂停运行并把 yield 后表达式的值返回出去。若 yield 没有接任何值,则返回 None。
生成器在其生命周期中,会有如下四个状态:
- GEN_CREATED生成器已创建还未被激活。
- GEN_RUNNING解释器正在执行只有在多线程应用中才能看到这个状态
- GEN_SUSPENDED在 yield 表达式处暂停。
- GEN_CLOSED生成器执行结束。
```python
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
for i in fibonacci(10):
print(i,end=" ")
```

View File

@ -87,6 +87,22 @@ runoob2()
Python 中,模块(包、类、函数)的导入方式有以下四种: Python 中,模块(包、类、函数)的导入方式有以下四种:
import 语句(不带 from 子句)会分两步执行:
1. 查找一个模块,如果有必要还会加载并初始化模块。
2. 在局部命名空间中为 import 语句发生位置所处的作用域定义一个或多个名称。
from 形式使用的过程略微繁复一些:
1. 查找 from 子句中指定的模块,如有必要还会加载并初始化模块;
2. 对于 import 子句中指定的每个标识符:
1. 检查被导入模块是否有该名称的属性
2. 如果没有,尝试导入具有该名称的子模块,然后再次检查被导入模块是否有该属性
3. 如果未找到该属性,则引发 ImportError。
4. 否则的话,将对该值的引用存入局部命名空间,如果有 as 子句则使用其指定的名称,否则使用该属性的名称
```python ```python
import xx.xx import xx.xx
from xx.xx import xx from xx.xx import xx

View File

@ -13,11 +13,11 @@ date: 2022-11-20
面对对象把一组数据结构和处理它们的方法组成对象object把相同行为的对象归纳为类class通过类的封装encapsulation隐藏内部细节通过继承inheritance实现类的特化specialization和泛化generalization通过多态polymorphism实现基于对象类型的动态分派 面对对象把一组数据结构和处理它们的方法组成对象object把相同行为的对象归纳为类class通过类的封装encapsulation隐藏内部细节通过继承inheritance实现类的特化specialization和泛化generalization通过多态polymorphism实现基于对象类型的动态分派
## 类和对象 ## 类
是对象的蓝图和模板,而对象是类的实例。类是抽象的概念,而对象是具体的东西 class是具有相同特性属性和行为方法的对象实例的抽象模板
在面向对象编程的世界中,一切皆为对象,对象都有属性和行为,每个对象都是独一无二的,而且对象一定属于某个类(型)。当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定义出一个叫做的东西。 在面向对象编程的世界中,一切皆为对象,对象都有属性和行为,每个对象都是独一无二的,而且对象一定属于某个类(型)。当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定义出一个叫做类的东西。
- **类(Class)** 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。 - **类(Class)** 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- **方法:**类中定义的函数。 - **方法:**类中定义的函数。
@ -26,11 +26,11 @@ date: 2022-11-20
- **方法重写:**如果从父类继承的方法不能满足子类的需求可以对其进行改写这个过程叫方法的覆盖override也称为方法的重写。 - **方法重写:**如果从父类继承的方法不能满足子类的需求可以对其进行改写这个过程叫方法的覆盖override也称为方法的重写。
- **局部变量:**定义在方法中的变量,只作用于当前实例的类。 - **局部变量:**定义在方法中的变量,只作用于当前实例的类。
- **实例变量:**在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。 - **实例变量:**在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
- **继承:**即一个派生类derived class继承基类base class的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如有这样一个设计一个Dog类型的对象派生自Animal类这是模拟"是一个is-a"关系(例Dog是一个Animal - **继承:**即一个派生类derived class继承基类base class的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如有这样一个设计一个 Dog 类型的对象派生自 Animal 类,这是模拟"是一个is-a"关系(例 Dog 是一个 Animal
- **实例化:**创建一个类的实例,类的具体对象。 - **实例化:**创建一个类的实例,类的具体对象。
- **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。 - **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
### 定义 ### 定义
Python中可以使用`class`关键字定义类,然后在类中通过之前学习过的函数来定义方法,这样就可以将对象的动态特征描述出来,代码如下所示。 Python中可以使用`class`关键字定义类,然后在类中通过之前学习过的函数来定义方法,这样就可以将对象的动态特征描述出来,代码如下所示。
@ -58,52 +58,92 @@ print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的方法 f 输出为:", x.f()) print("MyClass 类的方法 f 输出为:", x.f())
``` ```
### 属性 ### 属性
属性引用使用和 Python 中所有的属性引用一样的标准语法:**obj.name**。类对象创建后,类命名空间中所有的命名都是有效属性名。 属性引用使用和 Python 中所有的属性引用一样的标准语法:**obj.name**。类对象创建后,类命名空间中所有的命名都是有效属性名。
### 方法 ### 方法
在类的内部,使用 **def** 关键字来定义一个方法,与一般函数定义不同,**类方法必须包含参数 self,** 且为第一个参数self 代表的是类的实例。 在类的内部,使用 **def** 关键字来定义一个方法,与一般函数定义不同,**类方法必须包含参数 self,** 且为第一个参数self 代表的是类的实例方法
```python ```python
#类定义 class Animal:
class people: def __init__(self, name):
#定义基本属性 self.name = name
name = ''
age = 0 def run(self):
#定义私有属性,私有属性在类外部无法直接进行访问 print(f"{self.name}跑起来啦")
__weight = 0
#定义构造方法 >>> dog=Animal(name="小黑")
def __init__(self,n,a,w): >>> dog.run()
self.name = n 小黑跑起来啦
self.age = a >>> Animal.run(dog)
self.__weight = w 小黑跑起来啦
def speak(self): ```
print("%s 说: 我 %d 岁。" %(self.name,self.age))
### 类方法
# 实例化类
p = people('runoob',10,30) 类方法在定义时,第一个参数固定是 cls为 class 的简写,代表类本身。不管是通过实例还是类调用类方法,都不需要传入 cls 的参数。
p.speak() # runoob 说: 我 10 岁。
```python
class Animal:
def __init__(self, name):
self.name = name
def run(self):
print(f"{self.name}跑起来啦")
@classmethod
def jump(cls, name):
print(f"{name}跳起来啦")
>>> dog=Animal(name="小黑")
>>> dog.eat()
正在吃饭...
>>> Animal.eat()
正在吃饭...
```
### 静态方法
Python 类的静态方法在定义时,不需要 self 参数。 @staticmethod 装饰的函数就是静态方法,静态方法不需要实例化就可以调用。
```python
class Animal:
def __init__(self, name):
self.name = name
def run(self):
print(f"{self.name}跑起来啦")
@staticmethod
def eat():
print("正在吃饭...")
>>> dog=Animal(name="小黑")
>>> dog.jump("小黑")
小黑跳起来啦
>>> Animal.jump("小黑")
小黑跳起来啦
``` ```
### 访问可见性 ### 访问可见性
因为在很多面向对象编程语言中我们通常会将对象的属性设置为私有的private或受保护的protected简单的说就是不允许外界访问而对象的方法通常都是公开的public因为公开的方法就是对象能够接受的消息。 在Python中属性和方法的访问权限只有两种也就是公开的和私有的。如果希望属性是私有的在给属性命名时可以参考以下方法
在Python中属性和方法的访问权限只有两种也就是公开的和私有的如果希望属性是私有的在给属性命名时可以用两个下划线作为开头。 #### 私有属性、方法
#### 私有属性 ##### 单下划线
**__private_attrs**:以两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 **self.__private_attrs** Python 以单个下划线开头的变量或方法仅供内部使用,但是不做强制约束,依旧可以正常访问
#### 私有方法 ##### 双下划线
**__private_method**:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。在类内部的方法中使用时**self.__private_methods**。 Python 以两个下划线开头会导致 Python解释器重写属性名称以避免子类中的命名冲突
#### 强制访问 #### 强制访问
但是Python并没有从语法上严格保证私有属性或方法的私密性它只是给私有的属性和方法换了一个名字来妨碍对它们的访问事实上如果你知道更换名字的规则仍然可以访问到它们下面的代码就可以验证这一点。 但是Python 并没有从语法上严格保证私有属性或方法的私密性,它只是给私有的属性和方法换了一个名字来妨碍对它们的访问,事实上如果你知道更换名字的规则仍然可以访问到它们,下面的代码就可以验证这一点。
```python ```python
class Test: class Test:
@ -126,30 +166,41 @@ if __name__ == "__main__":
main() main()
``` ```
### 专有方法 ### 封装
封装是指将数据与具体操作的实现代码放在某个对象内部,使这些代码的实现细节不被外界发现,外界只能通过接口使用该对象,而不能通过任何形式修改对象内部实现。
```python ```python
__init__ : 构造函数,在生成对象时调用 ############ 未封装
__del__ : 析构函数,释放对象时使用 class Person:
__repr__ : 打印,转换 def __init__(self, name, age):
__setitem__ : 按照索引赋值 self.name = name
__getitem__ : 按照索引获取值 self.age = age
__len__ : 获得长度
__cmp__ : 比较运算 xh = Person(name="小红", age=27)
__call__ : 函数调用 if xh.age >= 18:
__add__ : 加运算 print(f"{xh.name}已经是成年人了")
__sub__ : 减运算 else:
__mul__ : 乘运算 print(f"{xh.name}还是未年人")
__truediv__ : 除运算
__mod__ : 求余运算 ############ 封装后
__pow__ : 乘方 class Person:
def __init__(self, name, age):
self.name = name
self.__age = age
def is_adult(self):
return self.__age >= 18
xh = Person(name="小红", age=27)
xh.is_adult()
``` ```
### 继承 ### 继承
面对对象的三大特征其一继承:可以在已有类的基础上创建新类,这其中的一种做法就是让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。 继承可以在已有类的基础上创建新类,这其中的一种做法就是让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。
子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力,在实际开发中,我们经常会用子类对象去替换掉一个父类对象,这是面向对象编程中一个常见的行为,对应的原则称之为[里氏替换原则](https://zh.wikipedia.org/wiki/里氏替换原则)。下面我们先看一个继承的例子。 子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力,在实际开发中,我们经常会用子类对象去替换掉一个父类对象,这是面向对象编程中一个常见的行为,对应的原则称之为里氏替换原则。下面我们先看一个继承的例子。
```python ```python
# 语法 # 语法
@ -260,196 +311,10 @@ c.myMethod() # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法 super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
``` ```
### 类的关系 ### 关系
简单的说类和类之间的关系有三种is-a、has-a和use-a关系。 简单的说类和类之间的关系有三种is-a、has-a和use-a关系。
- is-a关系也叫继承或泛化比如学生和人的关系、手机和电子产品的关系都属于继承关系。 - is-a关系也叫继承或泛化比如学生和人的关系、手机和电子产品的关系都属于继承关系。
- has-a关系通常称之为关联比如部门和员工的关系汽车和引擎的关系都属于关联关系关联关系如果是整体和部分的关联那么我们称之为聚合关系如果整体进一步负责了部分的生命周期整体和部分是不可分割的同时同在也同时消亡那么这种就是最强的关联关系我们称之为合成关系。 - has-a关系通常称之为关联比如部门和员工的关系汽车和引擎的关系都属于关联关系关联关系如果是整体和部分的关联那么我们称之为聚合关系如果整体进一步负责了部分的生命周期整体和部分是不可分割的同时同在也同时消亡那么这种就是最强的关联关系我们称之为合成关系。
- use-a关系通常称之为依赖比如司机有一个驾驶的行为方法其中的参数使用到了汽车那么司机和汽车的关系就是依赖关系。 - use-a关系通常称之为依赖比如司机有一个驾驶的行为方法其中的参数使用到了汽车那么司机和汽车的关系就是依赖关系。
## 面向对象进阶
### **slots** 魔法
如果我们需要限定自定义类型的对象只能绑定某些属性可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效对子类并不起任何作用。
```python
class Person(object):
# 限定Person对象只能绑定_name, _age和_gender属性
__slots__ = ('_name', '_age', '_gender')
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
self._age = age
def play(self):
if self._age <= 16:
print('%s正在玩飞行棋.' % self._name)
else:
print('%s正在玩斗地主.' % self._name)
def main():
person = Person('王大锤', 22)
person.play()
person._gender = '男'
# AttributeError: 'Person' object has no attribute '_is_gay'
# person._is_gay = True
```
### @property 装饰器
如果想访问属性可以通过属性的 getter访问器和 setter修改器方法进行对应的操作。要做到这点就可以考虑使用@property包装器来包装getter和setter方法使得对属性的访问既安全又方便代码如下所示。
```python
class Person(object):
def __init__(self, name, age):
self._name = name
self._age = age
# 访问器 - getter方法
@property
def name(self):
return self._name
# 访问器 - getter方法
@property
def age(self):
return self._age
# 修改器 - setter方法
@age.setter
def age(self, age):
self._age = age
def play(self):
if self._age <= 16:
print('%s正在玩飞行棋.' % self._name)
else:
print('%s正在玩斗地主.' % self._name)
def main():
person = Person('王大锤', 12)
person.play()
person.age = 22
person.play()
# person.name = '白元芳' # AttributeError: can't set attribute
if __name__ == '__main__':
main()
```
### @staticmethod 静态方法
可以使用`@staticmethod`注解定义静态方法,通过直接调用类使用方法。
```python
from math import sqrt
class Triangle(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
@staticmethod
def is_valid(a, b, c):
return a + b > c and b + c > a and a + c > b
def perimeter(self):
return self._a + self._b + self._c
def area(self):
half = self.perimeter() / 2
return sqrt(half * (half - self._a) *
(half - self._b) * (half - self._c))
def main():
a, b, c = 3, 4, 5
# 静态方法和类方法都是通过给类发消息来调用的
if Triangle.is_valid(a, b, c):
t = Triangle(a, b, c)
print(t.perimeter())
# 也可以通过给类发消息来调用对象方法但是要传入接收消息的对象作为参数
# print(Triangle.perimeter(t))
print(t.area())
# print(Triangle.area(t))
else:
print('无法构成三角形.')
if __name__ == '__main__':
main()
```
### @classmethod 类方法
Python 还可以在类中定义类方法,类方法的第一个参数约定名为 cls它代表的是当前类相关的信息的对象类本身也是一个对象有的地方也称之为类的元数据对象通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象代码如下所示。
```python
from time import time, localtime, sleep
class Clock(object):
"""数字时钟"""
def __init__(self, hour=0, minute=0, second=0):
self._hour = hour
self._minute = minute
self._second = second
@classmethod
def now(cls):
ctime = localtime(time())
return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec)
def run(self):
"""走字"""
self._second += 1
if self._second == 60:
self._second = 0
self._minute += 1
if self._minute == 60:
self._minute = 0
self._hour += 1
if self._hour == 24:
self._hour = 0
def show(self):
"""显示时间"""
return '%02d:%02d:%02d' % \
(self._hour, self._minute, self._second)
def main():
# 通过类方法创建对象并获取系统时间
clock = Clock.now()
while True:
print(clock.show())
sleep(1)
clock.run()
if __name__ == '__main__':
main()
```