python语法知识

1.深拷贝与浅拷贝

注意:深拷贝指的是复制内容,单独开辟一个内存,浅拷贝指的是两个变量同时指向一个内存ID。

python中的数据类型

  • 数值类型、字符串、元组、列表、字典、集合

可变数据类型和不可变数据类型

  • 可变数据类型:list(列表)、dict(字典)、set(集合)
  • 不可变数据类型:数值类型(int、float、bool)、string(字符串)、tuple(元组)
x = 3
print(id(x))  # 140706618349392
x += 6
print(id(x))  # 140706618349584

关于可变数据类型和不可变数据类型的解释:

可变数据类型:该数据类型对应的变量的值发生了变化时,如果它对应的内存地址不发生改变

不可变数据类型:该数据类型对应的变量的值发生了变化时,如果它对应的内存地址发生了改变 相当于是说:(该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。)

总结:可变数据类型更改值后,内存地址不发生改变。不可变数据类型更改值后,内存地址发生改变。

my_list = [1,2,3]
print(id(my_list))  # 1564984732544
my_list.append(4)
print(id(my_list))  # 1564984732544
# 变量的值发生了改变,但是地址却没有发生变化,因此列表是可变数据类型

a = 1
print(id(a))  # 140719026214672 
a = 2
print(id(a))  # 140719026214704 
# 变量的值发生了改变,且地址发生变化,因此数字是不可变的数据类型
import copy
a = 1
print(id(a))  # 140719026214672
b = copy.copy(a)  
print(id(b))  # 140719026214672
c = a
print(id(c))  # 140719026214672

d = [1,2,3]
print(id(d))  # 2636649249536
e = copy.copy(d)
print(id(e))  # 2636649233088
e.append(5)
print(e)      # [1, 2, 3, 5]  列表e的改变不会影响d的改变,因为e和d已经指向了不同的内存地址 
print(d)      # [1, 2, 3]   
f = d      
print(id(f))  # 2636649249536

深拷贝

a = [1,2,3]
b = copy.deepcopy(a)  # 深拷贝,会重新再创建一个新的对象,开辟新的内存地址
print(id(a))  # 1701957615232
print(id(b))  # 1701958732736

2.多进程

多进程是指一个程序同时执行多个进程,每个进程都拥有自己的独立地址空间,可以并行执行,且一个进程崩溃不会影响其他进程的执行。多进程可以利用多核CPU的优势,适用于CPU密集型任务。Python中的multiprocessing模块提供了多进程的支持。

import multiprocessing
# 定义了一个 worker 函数作为进程要执行的任务
def worker(num):
    """定义一个进程执行的任务"""
    print('Worker %d is running...' % num)
    return

if __name__ == '__main__':
    # 创建 4 个进程并将其添加到进程池中
    # multiprocessing.Pool 创建了一个进程池,并向其中添加了 4 个进程(批量创建进程并进行并行处理)
    pool = multiprocessing.Pool(processes=4)  # multiprocessing.Pool 创建了一个进程池,并向其中添加了 4 个进程
    for i in range(4):
        # 将任务添加到进程池中
        pool.apply_async(worker, (i,))
    # 关闭进程池,不再接受新的任务
    pool.close()
    # 等待所有进程执行完毕再执行下面的这行代码
    pool.join()
    print('All workers are done.')

2.1apply_async函数

apply_async()是Python中multiprocessing库中的一个函数,用于启动一个异步进程任务。它的参数解释如下:

func: 要异步执行的函数或方法对象。
args: 传递给func函数的参数列表,以元组形式传递。
kwds: 传递给func函数的关键字参数列表,以字典形式传递。
callback: 可选参数,是一个回调函数,用于在子进程执行完任务后调用。
error_callback: 可选参数,是一个回调函数,用于在子进程出错时调用。
pool: 可选参数,是一个进程池对象,用于执行异步任务。如果不指定,会使用默认进程池。
import multiprocessing
import time
def add(x, y):
    return x + y

def print_result(result):
    print(f"The result is: {result}") # 输出:The result is: 3

if __name__ == '__main__':
    # 开辟一个进程池,对象为pool
    with multiprocessing.Pool(processes=4) as pool:
        # apply_async()函数将add函数作为异步任务提交到进程池中,参数args为(1,2),
        # 表示传递给add函数的两个参数分别为1和2。callback参数则指定了回调函数print_result
        # add函数的返回值会作为参数传递到print_result函数中
        result = pool.apply_async(add, args=(1, 2), callback=print_result)
        pool.close()
        pool.join()

3. 多线程

多线程是指在一个程序中同时执行多个线程,每个线程共享程序的地址空间和数据,但是每个线程都有自己的独立栈空间和寄存器,可以并发执行。多线程适用于I/O密集型任务,如网络请求等。Python中的threading模块提供了多线程的支持。

import threading

# 定义一个函数,用于输出数字 1-10
def print_numbers():
    for i in range(1, 11):
        print(i)

# 定义一个函数,用于输出字母 a-j
def print_letters():
    for letter in 'abcdefghij':
        print(letter)

if __name__ == '__main__':
    # 创建两个线程,分别执行 print_numbers 和 print_letters 函数
    t1 = threading.Thread(target=print_numbers)
    t2 = threading.Thread(target=print_letters)
    
    # 启动两个线程
    t1.start()
    t2.start()

    # 主线程通过join()方法等待子线程执行完毕
    # 等待两个线程执行完毕
    t1.join()
    t2.join()
    # 由于两个线程是并发执行的,因此输出结果可能会出现数字和字母交错的情况。

4. 锁

多线程编程中,锁是用于保护共享资源的机制,它能够确保同一时刻只有一个线程可以访问共享资源避免多个线程同时对同一资源进行读写操作而导致的数据不一致或错误的问题

import threading

class Counter:
    def __init__(self):
        # value属性用于存储计数器的值,还有一个lock属性用于保护value属性
        self.value = 0
        self.lock = threading.Lock()   # lock属性:创建了一个锁

    def increment(self):
        # 在添加的时候,用锁对当前的线程上锁。
        with self.lock:
            self.value += 1
        # 以上的语句也可以换成如下:当前的线程拿到锁之后,可以保证其他的线程阻塞
        # self.lock.acquire()
        # self.value += 1
        # self.lock.release()

def worker(counter):
    for i in range(10000):
        counter.increment()

if __name__ == '__main__':
    counter = Counter()   # 创建了一个Counter类的对象
    # 列表中保存了4个线程对象
    # 每个线程都调用Counter对象的increment方法,对计数器进行加一操作
    threads = [threading.Thread(target=worker, args=(counter,)) for _ in range(4)]
    for t in threads:
        t.start()
    # 如果主线程不等待子线程结束再执行的话,有可能最后得到的答案不是40000
    for t in threads:
        t.join()
    print(counter.value)

5. 协程

协程是一种轻量级的线程,与线程相比,它的切换代价更低,可以在同一线程中切换执行不同的协程,实现并发编程。

import asyncio
# 使用了asyncio模块,定义了两个协程(count和main)


# count协程打印"One",等待1秒,然后打印"Two"。
async def count(num):
    print(num)
    # await asyncio.sleep(1) 表示当前的协程会被挂起(挂起并不会释放CPU资源),等待1秒钟后再继续执行后面的语句。
    await asyncio.sleep(1)
    print(num)

'''输出:
1
2
3
1
2
3
'''


# main协程使用asyncio.gather()函数并发执行count协程三次
# 意味着会有三个count协程同时运行。
async def main():
    # 使用await关键字等待所有的count协程运行完毕
    await asyncio.gather(count(1), count(2), count(3))

if __name__ == "__main__":
    # 主程序中调用asyncio.run()函数运行main协程
    asyncio.run(main())

6.with语句

在 Python 中,with 语句用于管理资源的访问,例如文件访问、网络连接等等。它可以确保在代码执行完毕之后自动清理资源,避免资源泄露和错误。

with 语句的语法格式为 with 对象 as 对象的别名,其中 对象 必须实现 __enter__ 和 __exit__ 两个方法。当 with 语句开始执行时,会自动调用 对象.__enter__() 方法获取资源,with 语句结束时,会自动调用 对象.__exit__() 方法释放资源。在 with 语句内部,可以通过 对象的别名 来访问资源。

class CustomObject:
    def __init__(self):
        print("Object initialized")
    
    def __enter__(self):
        print("Entered with statement")
        # __enter__ 方法的返回值可以被用作 as 子句中变量的值。这里因为返回的是对象本身,因此obj就代表的是对象
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
    	'''
    	exc_type:表示异常的类型,如果 with 语句块没有发生异常,则为 None。
		exc_val:表示异常的值,即异常对象,如果 with 语句块没有发生异常,则为 None。
		exc_tb:表示异常的 traceback 对象,如果 with 语句块没有发生异常,则为 None。
    	'''
        print("Exited with statement")
        # 这个函数return False 表示将异常重新抛出,即不忽略异常。如果不希望将异常重新抛出,则可以返回 True 或者不返回任何值。
    
    def do_something(self):
        print("Object is doing something")
# 当创建 CustomObject 类的实例并将其用在 with 语句中时,__enter__() 方法会被调用。当 with 语句结束时,__exit__() 方法会被调用。
# 在这个方法中,我们可以执行一些必要的清理操作,例如关闭文件或者释放资源。
# 当 with 语句结束时,__exit__() 方法会被调用。在这个方法中,我们可以执行一些必要的清理操作,例如关闭文件或者释放资源。
# 如果在 with 语句块内部发生了异常,那么异常信息将会被传递给 __exit__() 方法。
with CustomObject() as obj:
    # 输出:
    '''
    Object initialized
    Entered with statement   
    Object is doing something
    Exited with statement
    '''
    obj.do_something()

7. 高阶函数

在 Python 中,高阶函数指的是能够接受一个或多个函数作为参数,并返回一个新函数的函数。这种函数的灵活性和可重用性非常高,能够实现更加复杂的功能。

Python 内置了很多高阶函数,如 map()、filter()、reduce() 等。其中,map() 和 filter() 可以将一个函数作用于一个迭代器的每个元素,并返回一个新的迭代器。而 reduce() 可以将一个函数作用于两个元素,并将其结果再和下一个元素作用,以此类推,返回一个单一的值。

下面是一个简单的例子,展示如何使用 map() 和 filter() 对一个列表进行操作:

# 定义一个列表
lst = [1, 2, 3, 4, 5]

# 使用 map() 函数将列表中的元素平方
squared_lst = list(map(lambda x: x**2, lst))
print(squared_lst)  # 输出 [1, 4, 9, 16, 25]

# 使用 filter() 函数筛选出列表中的偶数
even_lst = list(filter(lambda x: x % 2 == 0, lst))
print(even_lst)  # 输出 [2, 4]

除了内置的高阶函数之外,我们也可以自定义高阶函数。下面是一个简单的例子,展示如何定义一个接受一个函数作为参数的高阶函数:

# 定义一个接受函数作为参数的高阶函数
def apply_func(func, lst):
    return [func(x) for x in lst]

# 定义一个函数
def square(x):
    return x**2

# 调用高阶函数 apply_func()
squared_lst = apply_func(square, [1, 2, 3, 4, 5])
print(squared_lst)  # 输出 [1, 4, 9, 16, 25]

在这个例子中,我们定义了一个高阶函数 apply_func(),它接受一个函数和一个列表作为参数,并返回一个新列表,其中每个元素都是将传入的函数应用于原列表中的元素得到的结果。我们还定义了一个函数 square(),用于计算平方。最后,我们调用了 apply_func() 函数,并将 square() 函数和一个列表作为参数传入。

8. 回调函数

回调函数是作为参数传递给另一个函数,以便在某些条件满足时被调用的函数。通常情况下,回调函数作为参数传递给高阶函数。

例如,考虑下面这个函数map(),它是一个高阶函数,接受一个函数和一个可迭代对象作为参数,并返回一个包含该函数对每个元素应用后的结果的迭代器。

def map(func, iterable):
    for element in iterable:
        yield func(element)

现在假设我们有一个函数double(),它可以将一个数乘以2,我们可以将double()作为参数传递给map(),并对一个列表进行操作,例如:

def double(x):
    return x * 2

result = map(double, [1, 2, 3, 4, 5])
print(list(result))  # [2, 4, 6, 8, 10]

在上面的例子中,double()就是一个回调函数,用于指定map()所要应用的函数。

9.面向对象(类)

9.1属性和方法

实例属性

实例属性是绑定在类的实例上的属性,每个实例都可以有自己的实例属性。实例属性在类的方法中通过self关键字进行访问和设置

class MyClass:
    def __init__(self):
        self.instance_attr = 10

    def instance_method(self):
        print(self.instance_attr)

obj = MyClass()
print(obj.instance_attr)  # 访问实例属性
obj.instance_method()     # 调用实例方法

类属性

类属性是绑定在类上的属性,它在所有类的实例之间共享。类属性通过类名进行访问和设置,也可以通过实例进行访问,但是对类属性的修改只会影响该实例的属性,不会影响其他实例的属性。在这里插入代码片

class MyClass:
    class_attr = 20

    def instance_method(self):
        print(MyClass.class_attr)

obj1 = MyClass()
print(obj1.class_attr)    # 访问类属性20
obj1.instance_method()    # 调用实例方法20

obj2 = MyClass()
print(obj2.class_attr)    # 访问类属性20

MyClass.class_attr = 30   # 修改类属性
print(obj1.class_attr)    # 访问类属性,输出:30
print(obj2.class_attr)    # 访问类属性,输出:30

obj1.class_attr = 40      # 注意:这里并不是改变类的属性,而是动态地设置这个对象的属性!

print(obj1.class_attr)    # 访问类属性,输出:40
print(obj2.class_attr)    # 访问类属性,输出:30
# 由于obj2没有这个属性,因此还是访问的是类属性

保护属性和私有属性

在Python中,以双下划线开头的成员变量是私有成员(__member),以单下划线开头的成员变量是受保护的成员(_member)。虽然它们都具有命名约定上的含义,但在访问权限和约定上有一些区别。

私有成员(__member):

私有成员被视为类的内部实现细节,对外部不可见。
类的内部可以直接访问私有成员
类的外部无法直接访问私有成员,但可以通过特定的名称修饰方式访问。
受保护的成员(_member):

受保护的成员被视为类的内部实现细节,但可以在派生类中访问。
类的内部可以直接访问受保护的成员
类的外部可以直接访问受保护的成员,但约定上应该尽量避免直接访问
以下是一个示例,说明私有成员和受保护的成员的区别:

class MyClass:
    def __init__(self):
        self.__private_member = 42
        self._protected_member = "Hello"

class MySubclass(MyClass):
    def __init__(self):
        super().__init__()

obj = MyClass()
print(obj._protected_member)  # 访问受保护的成员   Hello

sub_obj = MySubclass()
print(sub_obj._protected_member)  # 在派生类中访问受保护的成员 Hello

# 注意,以下代码访问私有成员的方式并不推荐,仅用于说明
print(obj._MyClass__private_member)  # 访问私有成员    42
print(sub_obj._MyClass__private_member) # 访问私有成员 42

对象默认的魔法方法

__dir__() 方法和 __hash__() 方法都属于 Python 中的特殊方法(也称为魔术方法或双下划线方法)。

__dir__() 方法是一个用于返回对象的属性列表的方法。当我们调用obj.__dir__()时,实际上是调用了对象的 __dir__() 方法。该方法返回一个包含对象的属性名称的列表。这些属性可以是对象的实例变量、方法、类变量等。默认情况下,如果一个类没有定义 __dir__() 方法,那么会使用默认的实现,即返回对象的属性名称列表

__hash__() 方法是用于计算对象的哈希值的方法。哈希值是一个整数,用于快速比较对象是否相等。在 Python 中,可哈希的对象可以作为字典的键或集合的成员。默认情况下,对象的哈希值是基于对象的内存地址计算得到的,即每个对象都有一个唯一的哈希值。如果一个类没有定义 __hash__() 方法,那么会继承父类的 __hash__() 方法实现。

需要注意的是,__dir__() 方法和 __hash__() 方法都是可选的,如果不需要自定义行为,可以直接使用默认的实现。如果需要自定义行为,可以在类中重写这些方法来实现特定的功能。

示例:

class MyClass:
    pass
    # def __dir__(self):
    #     return ['attribute1', 'attribute2', 'method1', 'method2']
    
    # def __hash__(self):
    #     return 42

obj = MyClass()

print(obj.__dir__())  # ['attribute1', 'attribute2', 'method1', 'method2']
print(obj.__hash__())  # 42

重载 // 运算符

__floordiv__() 是 Python 中的特殊方法(也称为魔术方法或双下划线方法),用于实现整数除法运算符 // 的行为。

当我们对两个对象使用 // 运算符时,实际上是调用左操作数对象的 __floordiv__() 方法,并将右操作数作为参数传递给该方法。该方法负责执行整数除法的操作,并返回结果。

下面是一个示例:

class MyClass:
    def __floordiv__(self, other):
        return self.value // other

obj = MyClass()
obj.value = 10
result = obj // 3
print(result)  # 输出 3

在上述示例中,我们定义了一个名为 MyClass 的类,其中定义了 __floordiv__() 方法。该方法接受一个参数 other,表示右操作数。在方法的实现中,我们执行了整数除法操作 self.value // other,并返回结果。

通过定义 __floordiv__() 方法,我们可以自定义对象在整数除法运算中的行为。这使得我们可以在自定义类中使用 // 运算符,并根据需求灵活地处理除法运算。

成员方法

成员方法是定义在类中的方法,可以访问和操作实例属性。成员方法的第一个参数通常是self,用于表示方法所属的实例。

class MyClass:
    def __init__(self):
        self.instance_attr = 10

    def instance_method(self):
        print(self.instance_attr)

obj = MyClass()
obj.instance_method()    # 调用成员方法

类方法

类方法是定义在类中的方法,使用@classmethod装饰器修饰。类方法可以访问和修改类属性,但无法访问实例属性。类方法的第一个参数通常是cls,用于表示类本身。

class MyClass:
    class_attr = 20

    @classmethod
    def class_method(cls):
        print(cls.class_attr)

MyClass.class_method()   # 调用类方法

静态方法

静态方法是定义在类中的方法,使用@staticmethod装饰器修饰。静态方法不能访问实例属性和类属性,它与类和实例无关,可以看作是类中的普通函数。

class MyClass:
    @staticmethod
    def static_method():
        print("This is a static method")

MyClass.static_method()   # 调用静态方法

总结:

  1. 实例属性是绑定在类的实例上的属性,每个实例都可以有自己的实例属性。
  2. 类属性是绑定在类上的属性,它在所有类的实例之间共享
  3. 成员方法是定义在类中的方法,可以访问和操作实例属性
  4. 类方法是定义在类中的方法,可以访问和修改类属性,但无法访问实例属性
  5. 静态方法是定义在类中的方法,与类和实例无关,不能访问实例属性和类属性

继承

继承机制父类初始化

当一个子类继承自父类时,子类可以有自己的初始化方法,即__init__方法。子类的初始化方法可以通过调用父类的初始化方法来继承父类的属性和行为,同时可以定义子类特有的属性和行为。

以下是一个示例,展示了子类如何继承父类的初始化方法,并添加自己的属性:

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

    def speak(self):
        print("I am an animal.")

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # 调用父类的初始化方法
        self.breed = breed

    def speak(self):
        print("Woof!")

dog = Dog("Buddy", "Golden Retriever")
print(dog.name)   # 输出:Buddy
print(dog.breed)  # 输出:Golden Retriever
dog.speak()       # 输出:Woof!

在上述示例中,Animal类有一个初始化方法__init__,接受一个参数name并将其赋值给实例变量self.name。Dog类继承自Animal类,并添加了一个初始化方法__init__,接受两个参数name和breed。在Dog类的初始化方法中,通过super().__init__(name)调用父类Animal的初始化方法,从而继承了Animal类的属性。然后,Dog类新增了一个属性self.breed,表示狗的品种。最后,我们创建了一个Dog类的实例dog,并访问了其继承自父类和自身定义的属性和方法。

通过子类的初始化方法,我们可以灵活地扩展父类的属性和行为,并实现子类特有的功能。

经典类和新式类

经典类是指没有显式继承自任何类的类,其定义不需要继承自 object。在 Python 2.x 中,如果一个类没有显式继承自 object,那么它就是一个经典类。

新式类是指显式继承自 object 的类,它是 Python 2.x 中引入的一种改进。在 Python 3.x 中,所有的类都被默认视为新式类,即使没有显式继承自 object。

新式类相比经典类具有以下特点:

  1. 继承顺序的变化:新式类使用广度优先搜索的方法来解析方法调用的继承顺序,而经典类使用深度优先搜索。这导致新式类的方法解析顺序更符合直觉,能够更好地处理多继承情况。
  2. 属性和方法的特殊处理:新式类支持更多的特殊属性和方法,如 、__class__、__slots__、__getattribute__ 等。
  3. 内置函数 super() 的使用:新式类中,可以使用 super() 内置函数来调用父类的方法,而经典类中没有这个功能。

在 Python 3.x 中,我们通常只使用新式类,不再需要关注经典类的区别。在定义类时,一般都会显式地继承自 object,以确保创建的是新式类。例如:

# Python 3.x 中的新式类定义
class MyClass(object):
    pass

注意:在 Python 3.x 中,即使不显式继承自 object,创建的类仍然是新式类。下面的代码和上面的代码等效:

# Python 3.x 中的新式类定义(隐式继承自 object)
class MyClass:
    pass

多继承

在 Python 中,多继承指一个类可以同时继承多个父类的特性。这使得一个类可以从多个父类中继承属性和方法,提供了更大的灵活性。下面是一个简单的例子来说明多继承的用法:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        print(f"{self.name} is making a sound.")

class Flyable:
    def fly(self):
        print("I can fly!")

class Swimmable:
    def swim(self):
        print("I can swim!")

class Duck(Animal, Flyable, Swimmable):
    pass

# 创建 Duck 类的实例
duck = Duck("Donald")

# 调用继承自 Animal 类的方法
print(duck.name)       # 输出: Donald
duck.speak()           # 输出: Donald is making a sound.

# 调用继承自 Flyable 类的方法
duck.fly()             # 输出: I can fly!

# 调用继承自 Swimmable 类的方法
duck.swim()            # 输出: I can swim!

在上述例子中,我们定义了三个父类 Animal、Flyable 和 Swimmable,然后通过在子类 Duck 的定义中列出这些父类,实现了多继承。Duck 类继承了 Animal、Flyable 和 Swimmable 类的属性和方法。

通过多继承,Duck 类实例化的对象 duck 可以调用父类的方法,包括 Animal 类的 speak() 方法,Flyable 类的 fly() 方法和 Swimmable 类的 swim() 方法。这展示了多继承在 Python 中的基本用法。请注意,多继承的使用需要谨慎,避免出现复杂的继承关系和方法冲突。

多态

在面向对象编程中,多态是指同一种操作或方法可以在不同的对象上具有不同的实现方式,即不同的对象可以对相同的消息作出不同的响应。

下面是一个简单的例子来说明多态的概念:

class Animal:
    def speak(self):
        pass

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

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

class Duck(Animal):
    def speak(self):
        print("Quack!")

# 创建不同的动物实例
dog = Dog()
cat = Cat()
duck = Duck()

# 调用动物的 speak 方法
dog.speak()   # 输出: Woof!
cat.speak()   # 输出: Meow!
duck.speak()  # 输出: Quack!

在上述例子中,我们定义了一个基类 Animal,并派生了三个子类 Dog、Cat 和 Duck。每个子类都重写了基类的 speak 方法,实现了各自的声音输出。

通过创建不同的动物实例,并调用它们的 speak 方法,我们可以看到尽管调用了相同的方法名,但不同的对象对同一方法作出了不同的响应。这就是多态的体现,同一种方法根据对象的不同而表现出不同的行为。

多态性使得我们可以编写更加通用的代码,通过面向对象的方式来处理不同类型的对象,提高了代码的可扩展性和复用性。

10.比较运算符链式写法

在 Python 中,比较运算符支持链式写法,即可以同时比较多个值。这种链式写法使得我们能够简洁地比较多个值之间的关系。

比较运算符链式写法的语法是将多个比较表达式连接起来,每个比较表达式之间使用比较运算符进行连接。

以下是比较运算符链式写法的示例:

print(3>2==2) # True
# 等价于:print(3>2 and 2 == 2)

11. for-else 和 while-else

在 Python 中,for-else 和 while-else 是一种特殊的语法结构,用于在循环结束后执行一些特定的操作。

for-else 语句:

for item in iterable:
    # 循环体
    # 可以通过 break 语句提前结束循环
else:
    # 循环正常结束后执行的代码块

在 for 循环中,如果没有执行 break 语句提前结束循环,那么在循环结束后会执行 else 语句块中的代码。

while-else 语句:

while condition:
    # 循环体
    # 可以通过 break 语句提前结束循环
else:
    # 循环正常结束后执行的代码块

在 while 循环中,如果没有执行 break 语句提前结束循环,那么在循环结束后会执行 else 语句块中的代码。

在两种语句中,else 语句块是可选的,可以根据需要选择是否使用。else 语句块中的代码会在循环正常结束后执行,即没有提前结束循环的情况。

12. 逗号表达式

Python 中有逗号表达式。逗号表达式允许在一条语句中使用逗号分隔多个表达式,并返回最后一个表达式的值。

在 Python 中,逗号表达式的优先级是最低的,而比较运算符的优先级较高。这意味着在同一个表达式中,比较运算符的操作会先执行,然后才是逗号表达式的求值。

x = 1 + 2, 3 + 4, 5 + 6
print(x)  # (3, 7, 11)

13. 字典中的键

在 Python 中,字典的键可以是不可变的数据类型,例如整数、浮点数、字符串、元组等。这是因为字典中的键是用于唯一标识和访问对应值的,需要具有不可变性才能保证键的唯一性和稳定性

常见的可用作字典键的数据类型包括整数、浮点数、字符串等基本数据类型,以及元组(当元组中的元素都是不可变的时候)等。

而对于可变的数据类型,例如列表、字典本身等,是不能作为字典的键的,因为它们具有可变性,可能会导致字典中的键值对关系混乱或不可预测。

需要注意的是,字典的值可以是任意类型的数据,包括不可变类型和可变类型。但字典的键必须是不可变类型。

14.集合中的元素

集合中的元素可以是任意可哈希(hashable)的数据类型。可哈希的数据类型是指在其生命周期内具有不可变的特性,可以作为字典的键或集合的元素。

常见的可哈希类型包括数字(整数、浮点数)、字符串、元组(当元组中的所有元素都是可哈希类型时),以及自定义的不可变对象。

字典是不可哈希的数据类型,因为字典是可变的,即字典对象的内容可以随时修改。因此,字典本身不能作为集合中的元素。但是,如果字典的键是可哈希类型,那么字典的键可以作为集合的元素。

下面是一些例子:

# 字符串作为集合元素
set1 = {'apple', 'banana', 'orange'}
print(set1)   # {'banana', 'orange', 'apple'}

# 元组作为集合元素
set2 = {(1, 2), (3, 4), (5, 6)}
print(set2)   # {(1, 2), (3, 4), (5, 6)}

# 字典的键作为集合元素
set3 = {'apple', 'banana', 'orange', 'apple'}
dict1 = {1: 'apple', 2: 'banana', 3: 'orange'}
set4 = set(dict1.keys())
print(set4)   # {1, 2, 3}

集合之间的比较

在Python中,可以使用比较运算符对集合进行比较,包括以下几种比较操作:

  1. 相等性比较(==):判断两个集合是否包含相同的元素。如果两个集合包含相同的元素,则它们被视为相等;否则,它们被视为不相等。

  2. 不等性比较(!=):判断两个集合是否不相等。如果两个集合不包含相同的元素,则它们被视为不相等;否则,它们被视为相等。

  3. 子集比较(<= 或 <):判断一个集合是否是另一个集合的子集。如果集合A的所有元素都包含在集合B中,则A被视为B的子集。如果使用 <= 运算符,表示A可以等于B;如果使用 < 运算符,表示A必须严格是B的子集,即A不能等于B。

  4. 超集比较(>= 或 >):判断一个集合是否是另一个集合的超集。如果集合A包含集合B的所有元素,则A被视为B的超集。如果使用 >= 运算符,表示A可以等于B;如果使用 > 运算符,表示A必须严格是B的超集,即A不能等于B

下面是一些示例:

set1 = {1, 2, 3}
set2 = {2, 3, 4}

print(set1 == set2)  # False,两个集合不相等
print(set1 != set2)  # True,两个集合不相等
print(set1 < set2)   # False,set1不是set2的子集
print(set1 <= set2)  # False,set1不是set2的子集
print(set1 > set2)   # False,set1不是set2的超集
print(set1 >= set2)  # False,set1不是set2的超集

set3 = {1, 2}
set4 = {1, 2, 3}

print(set3 == set4)  # False,两个集合不相等
print(set3 != set4)  # True,两个集合不相等
print(set3 < set4)   # True,set3是set4的子集
print(set3 <= set4)  # True,set3是set4的子集
print(set3 > set4)   # False,set3不是set4的超集
print(set3 >= set4)  # False,set3不是set4的超集

集合的运算

集合的交集和并集是集合运算中常用的两种操作。

交集运算使用符号 & 或者 intersection() 方法。它返回两个集合中共有的元素构成的新集合。

示例:

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
intersection_set = set1 & set2
# 或者
intersection_set = set1.intersection(set2)
print(intersection_set)  # 输出: {4, 5}

并集运算使用符号 | 或者 union() 方法。它返回两个集合中所有不重复的元素构成的新集合。

示例:

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
union_set = set1 | set2
# 或者
union_set = set1.union(set2)
print(union_set)  # 输出: {1, 2, 3, 4, 5, 6, 7, 8}

差集运算使用符号 - 或者 difference() 方法。它返回一个新的集合,包含存在于第一个集合而不存在于第二个集合的元素。

示例:

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
difference_set = set1 - set2
# 或者
difference_set = set1.difference(set2)
print(difference_set)  # 输出: {1, 2, 3}

对称差运算使用符号 ^ 或者 symmetric_difference() 方法。它返回一个新的集合,包含两个集合中不重复的元素。

示例:

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
symmetric_difference_set = set1 ^ set2
# 或者
symmetric_difference_set = set1.symmetric_difference(set2)
print(symmetric_difference_set)  # 输出: {1, 2, 3, 6, 7, 8}

15. csv文件的读写

当处理CSV文件时,我们可以使用Python的csv模块来读取和写入数据。

读取CSV文件的例子:

import csv

# 打开要读取的CSV文件
with open('data.csv', 'r') as file:
    # 创建一个CSV读取器
    reader = csv.reader(file)

    # 逐行读取CSV文件
    for row in reader:
        # 访问每行中的每个值
        for value in row:
            print(value, end=' ')
        print()  # 在每行后打印一个换行符

写入CSV文件的例子:

import csv

# 要写入CSV文件的数据
data = [
    ['姓名', '年龄', '国家'],
    ['John', '25', '美国'],
    ['Emma', '32', '加拿大'],
    ['Sophia', '28', '澳大利亚']
]

# 打开要写入的CSV文件
with open('output.csv', 'w', newline='') as file:
    # 创建一个CSV写入器
    writer = csv.writer(file)

    # 将数据写入CSV文件
    writer.writerows(data)

以上代码演示了如何使用Python的csv模块读取和写入CSV文件。读取CSV文件时,我们使用csv.reader对象逐行读取文件内容,并可以按需处理每个值。写入CSV文件时,我们使用csv.writer对象将数据按行写入文件。

16. json格式的转换

json.load()json.dump()用于读取和写入JSON格式的数据,而json.loads()和json.dumps()用于将JSON格式的数据转换为Python对象和将Python对象转换为JSON格式的数据

json.load()

json.load(): 从文件中读取JSON数据并将其解析为Python对象。它接受一个文件对象作为参数,并返回解析后的数据。例如:

import json

# 从文件中读取JSON数据
with open('data.json', 'r') as file:
    data = json.load(file)

# data 是一个包含解析后JSON数据的Python对象

json.dump()

json.dump(): 将Python对象转换为JSON格式的数据并写入文件。它接受一个Python对象和文件对象作为参数,并将对象转换为JSON格式的数据写入文件。例如:

import json

# 要转换为JSON并写入文件的Python对象
data = {
    'name': 'John',
    'age': 25,
    'country': 'USA'
}

# 将Python对象转换为JSON格式的数据并写入文件
with open('output.json', 'w') as file:
    json.dump(data, file)

json.loads()

json.loads(): 将JSON格式的字符串解析为Python对象。它接受一个JSON字符串作为参数,并返回解析后的Python对象。例如:

import json

# 要解析的JSON字符串
json_string = '{"name": "John", "age": 25, "country": "USA"}'

# 解析JSON字符串为Python对象
data = json.loads(json_string)

# data 是一个包含解析后JSON数据的Python对象
# data是一个字典

json.dumps()

json.dumps(): 将Python对象转换为JSON格式的字符串。它接受一个Python对象作为参数,并返回转换后的JSON格式的字符串。例如:

import json

# 要转换为JSON的Python对象
data = {
    'name': 'John',
    'age': 25,
    'country': 'USA'
}

# 将Python对象转换为JSON格式的字符串
json_string = json.dumps(data)

# json_string 是一个包含转换后的JSON字符串
# json_string的类型是字符串

总结:
load()和dump()用于读取和写入JSON文件。
loads()和dumps()用于将JSON字符串和Python对象之间进行转换。

json数据格式

  1. 字符串不能使用单引号进行引用,只能使用双引号进行引用。
  2. 使用键值对类型的数据,最后一个数据后面不能多写逗号,否则报错!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值