函数
字符串
- 字符串的
rstrip()
方法能删除字符串末尾的空白 splitlines()
方法逐行读取lstrip()
删除左端空格
创建副本
python的函数在传递列表后如果要对列表进行修改操作的话,我们的原列表如果需要保留,那么作为传递得的列表需要时一个副本,这样进行修改操作不会影响到原始列表
要创建副本,一般使用切片[:]
,在调用时创建列表的副本:
function_name(list_name[:])
传递任意数量的实参
在python函数中我们会遇到不能确定传入多少参数到一个函数中的情况,这种情形下我们可以用*
加在形参名称前来解决:
def function_name(*args)
这样我们在调用函数时,传递进去的所有参数都会被添加到一个元组当中被传递给函数,即使我们只传入一个参数也是如此
('item1')
('item1','item2','item3')
tips:通用形参名*args
,也是这样收集任意数量的位置实参
使用任意数量的关键字实参
有时候会遇到预先不知道要传递给函数会是什么样的信息,这种情况下可以使用**
前缀来传递函数任意数量的键值对信息:
def function_name(**kwargs)
**kwargs
创建出的字典可以让函数接收任意数量的键值对,在函数中可以像访问其他字典一样访问kwargs
函数实参顺序规则
Python中不同类型的实参有着严格的顺序规则,Python函数参数的顺序应该遵循以下规则:
- 位置实参
- 带有默认值的实参
*args
(用于收集任意数量的位置实参)**kwargs
(用于收集任意数量的关键字实参)
例如:
def my_function(a, b, c=0, d=0, *args, **kwargs):
print(f"a: {a}")
print(f"b: {b}")
print(f"c: {c}")
print(f"d: {d}")
print(f"args: {args}")
print(f"kwargs: {kwargs}")
# 调用函数
my_function(1, 2, 3, 4, 5, 6, 7, x=8, y=9, z=10)
该例子输出为:
a: 1
b: 2
c: 3
d: 4
args: (5, 6, 7)
kwargs: {'x': 8, 'y': 9, 'z': 10}
类
\_\_init\_\_()方法
__init__()
方法在类创建实例时由Python自动运行,init两边都有两个下划线避免Python默认方法与普通方法发生名称冲突,如果缺少下划线在创建实例时Python不会运行这个方法。
__init__()
方法定义时形参self
必不可少且必须位于其他形参前,Python在创建实例时自动传入实参self
,该实参是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
以self
为前缀的变量可以在所有方法使用,可以通过类的任意实例来访问,像self.xxx
这样的可以通过实例访问的变量称为属性。
示例:
class Restaurant:
def __init__(self, restaurant_name, cuisine_type):
self.restaurant_name = restaurant_name
self.cuisine_type = cuisine_type
def describe_restaurant(self):
print(f'Restaurant Name:{self.restaurant_name}')
print(f'Cuisine Type:{self.cuisine_type}')
def open_restaurant(self):
print(f'{self.restaurant_name} is opening')
restaurant = Restaurant('McDonald\'s', 'Fast food')
restaurant.describe_restaurant()
restaurant.open_restaurant()
运行结果:
Restaurant Name:McDonald's
Cuisine Type:Fast food
McDonald's is opening
Python类的数据成员
Python的所有数据成员都是"公有的"Python 中的类并没有像 C++ 或 Java 那样严格的访问控制机制(private
、protected
、public
)。然而,Python 社群有一些约定来模拟这种行为。
公有成员(Public): 默认情况下,所有成员都是公有的。
class MyClass: def __init__(self): self.public_member = "This is public."
受保护的成员(Protected): 按照约定,一个下划线前缀的成员被视为受保护的。它仍然可以被外部访问,但这样的用法通常不推荐。
class MyClass: def __init__(self): self._protected_member = "This is protected."
私有成员(Private): 使用双下划线前缀的成员会被视为私有成员。Python 会改写(名为 name mangling)这些成员的名称,所以直接访问它们会比较困难(但不是不可能)。
class MyClass: def __init__(self): self.__private_member = "This is private."
虽然这样的成员在技术上仍然可以被外部访问,但这需要使用特殊的语法:
obj = MyClass() print(obj._MyClass__private_member) # 输出 "This is private."
- 约定的公有和私有成员: 除了这些规则,Python 还有一些特殊的属性和方法名称约定。例如,以双下划线开始和结束的方法(
__init__
,__call__
, 等)是特殊方法,通常不应被视为私有成员。
总体而言,Python 更侧重于“成年人的同意”("we're all consenting adults here")这一理念,意味着它依赖于程序员遵循这些不强制执行的命名约定,而不是强制限制成员的访问。这给予了更多的灵活性,但也要求程序员更加小心。
Python类列表默认值以及会出现的问题
使用可变的默认参数是Python中的一个常见的陷阱,下面是一个简单的例子:
class MyClass:
def __init__(self):
self.my_list = [] # 初始化一个空列表作为属性
# 创建类的实例
obj = MyClass()
# 输出实例的my_list属性,应该是一个空列表
print(obj.my_list)
# 向列表中添加元素
obj.my_list.append(1)
obj.my_list.append(2)
obj.my_list.append(3)
# 输出更新后的列表
print(obj.my_list) # 输出 [1, 2, 3]
下面这个方式可以避免这个问题:
class MyClass:
def __init__(self, initial_list=None):
if initial_list is None:
self.my_list = []
else:
self.my_list = initial_list
# 创建类的实例,并传入一个初始列表
obj = MyClass([1, 2, 3])
# 输出实例的my_list属性
print(obj.my_list) # 输出 [1, 2, 3]
但是if...else的条件控制还是很繁琐,我们可以使用or
来代替:
class MyClass:
def __init__(self, initial_list=None):
self.my_list = initial_list or []
在Python中,or
运算符返回第一个为"真"的值。因此,如果initial_list
为None
(在Python中被认为是"假"的),则or
运算符将返回其后面的值,即空列表[]
。
类的继承和组合
Python类的继承是在class后面的类名跟一个(),()内是要继承的类的名字,该类要在__init__
方法中使用super().__init__
调用父类的__init__
方法来初始化构造父类。
一个类中可以将另一个类的实体化对象作为该类中的属性。
下面是类的继承和组合的简单示例:
class User:
def __init__(self, first_name, last_name, sex):
self.fname = first_name
self.lname = last_name
self.sex = sex
self.login_attempts = 0
def describe_user(self):
print(f'User name is {self.fname} {self.lname}')
print(f'User sex is {self.sex}')
def greet_user(self):
print(f'Hello! {self.fname} {self.lname}')
def increment_login_attempts(self):
self.login_attempts += 1
def reset_login_attempts(self):
self.login_attempts = 0
class Admin(User):
def __init__(self, first_name, last_name, sex, privileges=None):
super().__init__(first_name, last_name, sex)
self.privileges = Privileges()
class Privileges:
def __init__(self):
self.privileges = ('can add post', 'can delete post', 'can ban user')
def show_privileges(self):
print(f'Admin\'s privileges are {self.privileges}')
admin = Admin('t', 't', 'man', ('can add post', 'can delete post', 'can ban user'))
admin.privileges.show_privileges()
运行结果:
Admin's privileges are ('can add post', 'can delete post', 'can ban user')
文件和异常
读取文件
读取文件需要pathlib
模块,通过模块导入Path
类,Path
对象指向一个文件,可以用来核实文件是够存在,读取的文件的内容,以及将新数据写入文件。
from pathlib import Path
初始化Path
对象需要将文件的相对路径或者绝对路径当做实参传入:
path = Path('text_files/filename.txt')#相对路径(linux)
path = Path('/home/data_files/text_files/filename.txt')#绝对路径(linux)
读取文件内容需要用到Path类的read_text()
方法,该方法会将文件对象的全部内容作为一个字符串返回,这个字符串相比于原始文件唯一不同的地方就是末尾会多一个空行,可以使用字符串的rstrip()
来消除字符串末尾的空白:
contents = path.read_text().rstrip()
逐行访问可以使用字符串的splitlines()
函数,该函数返回一个列表包括文件中的所有行,可以对其遍历访问:
lines = path.read_text().splitlines()
for line in lines:
print(line)
写入文件
可以使用Path
类中的write_text()
方法来进行文件写入,该方法接受单个实参,即要写入文件的字符串,没有终端输出。Python只能将字符串写入文本文件,其他格式需要使用str()
来进行转换。
使用write_text()
方法时如果path变量对应的路径指向的文件不存在就会创建它。
要进行多行写入时,需要创建一个字符串将多行内容传递给这一个字符串,在将此字符串传递给write_text()
方法:
from pathlib import Path
contents = 'I love programming.\n'
contents += 'Ilove creating new games.\n'
contents += 'I also love working with data.\n'
path = Path('programming.txt')
path.write_text('contents')
tips:使用该方法需谨慎,如果原文件已有内容存在,write_text()
方法删除其内容并将制定的内容写入。
异常
try_except代码块
python在发生异常时会创建一个异常对象,如果未对异常进行处理,程序将终止并显示一个traceback,其中包含有关异常的报告。异常是使用try_except
代码块处理的,下面给出一个使用try_except
代码块来处理ZeroDivisionError
异常的示例
try:
print(5/0)
except ZeroDivisionError:
print("You can't divide by zero!")
如果try
代码块中的代码运行起来没有问题,python将跳过except代码块,如果try
代码块中的代码出现错误,python会查找与之匹配的except
代码块并运行其中的代码。
else代码块
只有try代码块成功执行才需要继续执行的代码,都应该放到else
代码块中:
try:
print(5/0)
except ZeroDivisionError:
print("You can't divide by zero!")
else:
print('over')
静默
如果想让程序在发生异常时既不进行处理也不进行traceback,我们可以用pass
来保持静默:
try:
--snip--
except FileNotFoundError:
pass
else:
--snip--
except中的pass告诉python什么都不要做,虽然执行except但什么都不会发生。