python进阶01
在前面的python入门中我们知道python是面向对象的,今天就来详细解释一下面向对象这个事情,在游戏中我们会发现各个人物都有自己的属性,如攻击力,防御力,在游戏的底层代码逻辑中,他们就是一个个对象之间的交互,相同的对象抽象出了”类“的概念,而对象就是类的具象,我们这里引入了类的概念,类也是python中非常重要的部分,同时python中也内置了非常多的类,类与函数类似,但又有些许不同,例如,函数可以被调用,而类可以被继承,在官方版本的python中所有的类都来自一个超级父类---------Object
那我们接下来就来学习类的写法,类的特性,类的使用方法,以及类的功能
类的写法
下面是最简单的一个类,这个类只有两个属性
class Student:#类名的首字母一定要大写 def __init__(self, name, score):#数据的定义 self.name = name self.score = score def print_score(self): print(f"姓名:{self.name},得分:{self.score}")#定义操作数据的方式 if __name__ == '__main__': A = Student("小米", 90)#引入实例A A.print_score()
一个类中需要有两种东西,一种是数据,另外一种是对数据的操作
类的特性
类是面向对象编程的基础,它具有以下特性:
-
封装:封装是将数据(属性)和操作数据的函数(方法)捆绑在一起的概念。通过封装,类可以隐藏其内部实现细节,只提供公共接口供外部使用,这样可以降低代码的耦合度,提高代码的可维护性和可复用性。
-
继承:继承是指一个类(子类)可以从另一个类(父类)继承属性和方法的能力。子类可以重用父类的代码,并可以在此基础上进行扩展或修改。继承可以建立类之间的层次关系,提高代码的可扩展性和可维护性。
-
多态:多态是指同一个方法名可以在不同的类中具有不同的实现方式。这意味着可以使用统一的接口来调用不同类的方法,而不需要考虑具体的实现细节。多态可以提高代码的灵活性和可扩展性,使代码更易于理解和维护。
-
抽象:抽象:抽象是指将类的通用特征提取出来形成抽象类或接口,从而隐藏对象的复杂性,只展示对象的关键特征和行为。通过抽象,可以简化问题的复杂度,提高代码的可读性和可维护性。
类的隐藏和强制访问
在Python中,类中的属性和方法可以使用下划线进行隐藏或者强制访问。这是通过命名约定来实现的,而不是通过严格的访问控制关键字(如public、private、protected)。
-
隐藏属性和方法:
在Python中,通过在属性名或方法名前面加一个下划线
_
来表示该属性或方法是私有的,即隐藏起来不希望外部直接访问。但这只是一种命名约定,实际上仍然可以通过对象名来访问这些属性和方法。class MyClass: def __init__(self): self._hidden_attr = "hidden attribute" def _hidden_method(self): return "hidden method" obj = MyClass() print(obj._hidden_attr) # 可以访问隐藏属性 print(obj._hidden_method()) # 可以访问隐藏方法
-
强制访问:
如果希望将属性或方法设置为完全私有的,即在外部无法直接访问,可以在属性或方法名前面加两个下划线
__
。这样会触发Python的名称修饰(Name Mangling)机制,Python会在名字前加上类名,以此防止子类中的命名冲突。class MyClass: def __init__(self): self.__private_attr = "private attribute" def __private_method(self): return "private method" obj = MyClass() # print(obj.__private_attr) # 无法直接访问,会抛出AttributeError # print(obj.__private_method()) # 无法直接访问,会抛出AttributeError print(obj._MyClass__private_attr) # 可以通过名字修饰来强制访问隐藏属性 print(obj._MyClass__private_method()) # 可以通过名字修饰来强制访问隐藏方法
需要注意的是,虽然可以通过名字修饰来强制访问隐藏属性和方法,但这不是Python官方鼓励的做法。通常情况下,应该尽量遵循命名约定,而不是使用名称修饰来访问私有属性和方法。
-
文件的读写
首先介绍两个基本概念:绝对路径和相对路径
-
绝对路径: 绝对路径是从文件系统的根目录(通常是硬盘的根目录)开始指定文件或目录的路径。这种路径独立于当前工作目录。在Windows系统中,绝对路径通常以驱动器名和冒号开始,例如
C:\Users\User\file.txt
。绝对路径可以准确地定位文件或目录,不受当前工作目录的影响。 -
相对路径: 相对路径是相对于当前工作目录的文件或目录的路径。相对路径不包含根目录的信息,而是从当前工作目录开始指定文件或目录的位置。因此,相对路径的有效性取决于当前工作目录。在相对路径中,常见的标识符是
.
(当前目录)和..
(上一级目录)。例如,假设当前工作目录是/home/user/
,则文件file.txt
的相对路径可以简单表示为file.txt
。
相对路径和绝对路径各有优势:
-
绝对路径: 确保了对文件或目录的准确定位,不受当前工作目录的影响。在某些情况下,特别是当你需要在不同的环境中运行程序时,使用绝对路径更为安全。
-
相对路径: 更为简洁和灵活,因为它们不需要包含完整的目录结构,而是相对于当前工作目录。这使得代码更易于移植和维护,尤其是在涉及多个操作系统或不同目录结构的情况下。
read函数中的参数在不同类型中表示的含义不同
读
-
内置
open()
函数中的read(size)
:size:可选参数,表示要读取的字节数。如果未指定则默认读取整个文件。如果指定了
则只读取指定字节数的数据。例如:
with open('file.txt', 'r') as f: data = f.read(100) # 读取前100个字节的数据
-
Pandas DataFrame 对象中的
read(nrows)
:nrows:可选参数,表示要读取的行数。默认情况下,Pandas 会尝试读取整个文件。如果指定了 则只读取指定数量的行。例如:
pythonCopy codeimport pandas as pd df = pd.read_csv('data.csv', nrows=10) # 仅读取前10行数据
-
SQLite 中
fetchmany(size)
:size:可选参数,表示要获取的记录数量。如果未指定则默认为 cursor.arraysize的值。例如:
import sqlite3 conn = sqlite3.connect('example.db') cursor = conn.cursor() cursor.execute('SELECT * FROM table_name') data = cursor.fetchmany(5) # 获取前5条记录
写
1:使用内置的 open()
函数:
with open('filename.txt', 'w') as f: f.write('Hello, world!')
2:使用文件对象的 write()
方法:
f = open('filename.txt', 'w') f.write('Hello, world!') f.close()
3:使用 print()
函数并将输出重定向到文件:
with open('filename.txt', 'w') as f: print('Hello, world!', file=f)
4:使用第三方库,如numpy
、pandas
等,以更方便的方式写入数据到文件:
import numpy as np data = np.array([[1, 2, 3], [4, 5, 6]]) np.savetxt('filename.txt', data)
5:使用 csv
模块写入 CSV 文件:
import csv data = [['Name', 'Age'], ['Alice', 30], ['Bob', 35], ['Charlie', 40]] with open('filename.csv', 'w', newline='') as f: writer = csv.writer(f) writer.writerows(data)
猴子补丁
下面列举一个最简单的猴子补丁
class Dog(): def __init__(self,name): self.name = name def bark(self): print(f"{self.name} is wangwangwang") def eat(self): print(f"dog is eatting") if __name__ == '__main__': snoopy = Dog("snoopy") snoopy.bark() Dog.eat = eat snoopy.eat()
例如上述代码中,Dog类中是没有属性eat的,但你调用eat方法还是可以调用的,这类方式就叫猴子补丁。猴子补丁的工作原理是利用Python的动态性质。在Python中,类和模块的属性和方法都可以在运行时动态地添加、修改或删除。通过猴子补丁,我们可以在程序运行期间修改代码的行为,而不必修改源代码。但是实际使用时需要谨慎考虑。过度使用猴子补丁可能会导致代码的不稳定性和可读性降低,因此应该尽量避免滥用这种技术。
异常处理
自定义异常
class CustomError(Exception):#建立一个名为CustomError的类名,同时继承自内置的Exception类 def __init__(self, message):#初始定义 self.message = message def Error(): raise CustomError("你想声明的错误类型")#在代码中遇到特定错误情况时,使用raise关键字抛出自定义异常。
异常处理try-except块
-
try块:在
try
块中编写可能引发异常的代码。如果在执行try
块中的代码时出现异常,则异常会被捕获,不会使程序中断。 -
except块:
except
块用于捕获try
块中可能抛出的异常。在except
块中可以指定要捕获的异常类型。如果未指定异常类型,则捕获所有类型的异常。异常被捕获后,程序会执行except
块中的代码来处理异常。try: # 可能引发异常的代码块 # 可能会抛出异常的代码 except [异常类型] as [异常变量]: # 异常处理代码块
Finally块
finally块: 使用finally
关键字定义的代码块总是在try
语句块执行完毕后执行,无论是否发生异常。
try: # 一些可能引发异常的代码 except CustomError: # 处理自定义异常 except Exception as e: # 处理其他异常 finally: # 执行清理操作,如关闭文件或释放资源
正则表达式
正则表达式是一种强大的文本模式匹配和搜索工具,用于在字符串中查找和匹配特定模式的文本。你可以暂时理解为计算机识别文本的一种方式,它由一系列字符和特殊字符组成,用于描述字符串的模式。由于正则表达式的匹配规则太过灵活。这里就简单介绍一下一些基本的正则表达式
-
普通字符: 大多数字符在正则表达式中都是普通字符,它们匹配自身。例如,正则表达式
hello
匹配字符串中的 "hello"。 -
转义字符: 使用反斜杠
\
将某些字符转义为特殊字符。例如,\.
匹配句点(.
),\d
匹配任意数字,\s
匹配空白字符。 -
字符类别: 使用方括号
[]
定义一个字符类别,表示可以匹配其中任意一个字符。例如,[aeiou]
匹配任何一个元音字母。 -
元字符: 元字符是具有特殊含义的字符,包括但不限于:
.
: 匹配除换行符以外的任意字符。^
: 匹配字符串的开头。$
: 匹配字符串的结尾。\b
: 匹配单词的边界。\d
: 匹配任意数字。\w
: 匹配任意字母、数字或下划线。\s
: 匹配任意空白字符。[]
: 字符集合,匹配括号内的任意一个字符。|
: 或,用于匹配两个或多个表达式中的任意一个。()
: 分组,将其中的表达式作为一个整体。 -
量词: 量词用于指定前面的字符可以出现的次数。
*
: 匹配前一个字符零次或多次。+
: 匹配前一个字符一次或多次。?
: 匹配前一个字符零次或一次。{n}
: 匹配前一个字符恰好出现 n 次。{n,}
: 匹配前一个字符至少出现 n 次。{n,m}
: 匹配前一个字符至少出现 n 次,最多出现 m 次。
import re #最简单的匹配样式 a = 'wy' print(re.match('wy', a))#match函数 print(re.match('\d\d\d', '012'))# \d 匹配一个数字字符
贪婪匹配
贪婪匹配是指正则表达式尽可能多地匹配输入字符串的特性。在贪婪匹配中,量词(如*
、+
、?
、{m,n}
)会尽量匹配尽可能多的字符,直到达到条件不满足为止。
例如,考虑正则表达式 .*
匹配任意字符零次或多次。如果将其应用于字符串 "abc123def456",它会匹配整个字符串,因为 .*
将尽可能多地匹配字符,直到字符串的末尾。
贪婪匹配可能导致意外的结果,特别是在使用带有其他模式的复杂正则表达式时。为了避免贪婪匹配,可以在量词后面加上问号 ?
,将其变为非贪婪匹配。例如,.*?
表示匹配任意字符零次或多次,但尽可能少地匹配字符,直到下一个模式成功匹配或达到字符串的结尾。
groups # 返回一个元组 记录所有括号获取的值 group(num) #0 整个正则表达式相匹配的字符串 1 返回一个获取符合的字符串