Skip to main content Link Menu Expand (external link) Document Search Copy Copied

变量

  • python的内存变量不需要类型
  • Python万物皆对象,在栈内存永远存储的是数据的堆内存地址,堆内存存储的数据值。

变量的注解

在 Python 中定义变量是不需要指定类型的。但是在 Python 中, 变量注解(Variable Annotations)是 Python 3.5 引入的一个新特性, 它允许开发者为变量和函数参数提供预期的类型信息。

name: str = "逗比"  # 定义姓名
age: int = 30  # 定义年龄
height: float = 1.78  # 定义升高
is_has_jj: bool = True  # 定义是否有jj

is 关键字

a = 10
b = 20
print(a is b)				# False,a和b指向的是不同的地址

a = 10
b = a
print(a is b)				# True,a和b指向的是相同的地址

小整数对象池

这是因为编译器Cpython中存在小整数池[-5, 256],在解释器启动的时候就自动开辟了, 在全局范围内重复使用,不会被垃圾回收。

有时,同时创建2个相同的超过了-5,256的数据,也可能会相等,因为python自身做了优化,间隔很小的时间,创建2个相同的元素,他们的地址相同。

id 函数

使用 id 函数获取变量的内存地址:

a = 10
b = 10
print(a is b)
print(id(a))
print(id(b))

---output---

True
4299450960
4299450960

del 关键字

del的作用是删除变量,解除变量和堆中对象的关联。

type 函数

print(type(10))
print(type(3.14))
print(type("100"))

字符串

text1 = "我是一个字符串"
text2 = '我是一个字符串'
text3 = """我是一个字符串,
我还可以换行"""
str = "Hello \'Python\'"

str = "Hello \\t \"Python\""
str = "Hello \t \"Python\""

---output---
我是一个字符串
我是一个字符串
我是一个字符串
    我还可以换行
Hello 'Python'
Hello \t "Python"
Hello 	 "Python"

占位符

name = "张三"
age = 18
money = 3.14
print("Hello, 我是%s, 年龄%-4d, 我有%.4f块钱" % (name, age, money))

---output---
Hello, 我是张三, 年龄18  , 我有3.1400块钱

快速格式化

通过在字符串前面添加一个f,可以在字符串中使用 {} 嵌入变量。

name = "张三"
age = 18
money = 3.14
print(f"Hello, 我是{name}, 年龄{age}, 我有{money}块钱")

---output---
Hello, 我是张三, 年龄18, 我有3.14块钱

流程控制

range

    for i in range(5):
        print(i)
    print("----")
    for i in range(5, 10):
        print(i)
    print("----")
    for i in range(5,10,2):
        print(i)

0
1
2
3
4
----
5
6
7
8
9
----
5
7
9

容器

list

    name_list = ["zhangsan", "lisi", 1, "zhaoliu", 3, "chenba"]  # 定义一个容器
    print(name_list[-1])
    print(name_list[-3])
    print(name_list[2])
    print(len(name_list))
    print(name_list.index(1, 0, 4))
    # add
    name_list.append(1)
    # insert
    name_list.insert(1, "OK")
    print(name_list)
    # del
    name_list.pop(4)
    print(name_list)
    del name_list[4]
    print(name_list)
    # count
    cnt = name_list.count(1)
    print(cnt)
    # 列表推导式
    int_list =[1,2,3,5,4]
    new_list = [i*2 for i in int_list]
    print(new_list)
    # join
    str_list =["1","2","3","5","4"]
    print("_".join(str_list))

---output---
chenba
zhaoliu
1
6
2
['zhangsan', 'OK', 'lisi', 1, 'zhaoliu', 3, 'chenba', 1]
['zhangsan', 'OK', 'lisi', 1, 3, 'chenba', 1]
['zhangsan', 'OK', 'lisi', 1, 'chenba', 1]
2
[2, 4, 6, 10, 8]
1_2_3_5_4

切片

序列[起始下标:结束小标:步长]

num_list = [1, 2, 3, 4, 5]
new_list2 = num_list[1:4]
new_list = num_list[:4:2]
new_list = num_list[:]
new_list = num_list[3:1:-1]

tuple

因为元组中的元素是不能修改的,修改会报错。

set

    name_set = {"zhangsan", "lisi", 1, "zhaoliu", 3, "chenba"} # 定义一个容器
    print(name_set)
    name_set.add("add")
    name_set.pop()
    name_set.remove("add")
    name_set.union(name_set)
    name_set.difference(name_set)
    name_set.difference_update(name_set)

dict

    dict_a = {"d":1,"a":3}
    dict_a.get("d")

function


def triple_print(a: int, b: None, c=3):
    """
    默认值
    b:None
    c=3

    list = [1, 2, 3]
    triple_print(*list)这样调用是序列实参

    dict01 = {"a": 1, "c": 3, "b": 2}
    triple_print(**dict01)这样调用是字典实参
    
    triple_print(b=3,a=4,c=5)这样是通过参数名称来传递值
    """
    print(f"{a},{b},{c}")


def four_print(a=2, *b, d, **c) -> tuple:
    """
    -> tuple标明了函数的返回值类型
    *b:是一个元组,接收任意个数的参数
    **c:通过字典可以接收到数据
    # args 是一个元组,接收任意个数的参数
    可以多返回值
    """
    print(f"{a},{b},{c},{d}")
    return a, b

变更的作用域

  • 局部变量:函数内部定义的变量,函数执行完毕后,变量会自动销毁
  • 全局变量:函数外部定义的变量,函数执行完毕后,变量仍然存在
  • globa 关键字,获取全局变量
num = 10

def fun_a():
    num = 20
    print(f"函数内:{num}")

fun_a()
print(f"函数外:{num}")

输出的是函数内:20 函数外:10

通过 global 关键字告诉程序我这个是全局变量

输出的是函数内:20 函数外:20

 

Union类型

from typing import Union

my_list: list[Union[int, str]] = [1, "name"]			# 定义了list中的元素是多种数据类型
my_dict: dict[str, Union[int, str]] = {"name": "zhangsan", "age": 18}		# 定义了value可以是多种类型


def fun(data: Union[int, str]) -> Union[int, str]:					# 定义返回值的类型注解
    pass

def fun(data: Union[int, str]) -> list[Union[int, str]]:		# 定义list返回值的类型注解
    pass

class Student:

    stu_count = 0; 这是一个类变量

    def __init__(self, sid, name, age):
        self.sid = sid					# 学号
        self.name = name				# 姓名
        self.age = age					# 年龄
        Student.stu_count += 1

    @classmethod
    这个类方法没有self变量所以不能通过实例来访问只能通过类名来访问
    def get_stu_count(cls):
        print(f"一共创建了{Student.stu_count}个学生")


stu1 = Student("001", "张三", 18)
stu2 = Student("002", "李四", 19)
stu2 = Student("003", "王五", 17)
Student.get_stu_count()

static method

静态方法的作用是用来定义一些工具类函数。

在静态方法中不能访问实例成员和类成员。

class Math_Util:

    @staticmethod
    def get_max(a, b):							# 获取大的数
        return a if a > b else b

    @staticmethod
    def get_min(a, b):							# 获取小的数
        return a if a < b else b


max_num = Math_Util.get_max(11, 15)
print(max_num)

min_num = Math_Util.get_min(11, 15)
print(min_num)

inner method

def __str__(self):
        return f"sid:{self.sid}, name:{self.name}, age:{self.age}"
def __lt__(self, other):# other表示另一个对象,返回值为True或Flase
        return self.age < other.age
def __le__(self, other):# other表示另一个对象,返回值为True或Flase
        return self.age <= other.age
def __eq__(self, other):# other表示另一个对象,返回值为True或Flase
        return self.age == other.age
def __repr__(self):
        return f"Student('{self.sid}', '{self.name}', {self.age})"
        
stu1 = Student("001", "张三", 18)
stu_str = repr(stu1)                # 获取__repr__()方法返回的string数据
print(stu_str)

stu2 = eval(stu_str)                # 将string执行,返回的是一个对象,相当于克隆了一个对象
print(stu2.name)
print(stu1 == stu2)
        

私有属性和方法

定义私有成员的方式:

定义私有成员变量:变量名以 __开头,2个下划线开头 定义私有成员方法:方法名以 __开头,2个下划线开头

class Phone:

    def __init__(self):
        self.producer = "华为"        # 手机品牌
        self.__voltage = 12          # 电压

    def call(self):
        print("打电话")
        print(f"手机品牌:{self.producer}")
        print(f"手机电压:{self.__voltage}")

    # 定义一个私有方法
    def __get_run_voltage(self):
        print(f"当前电压:{self.__voltage}")

phone = Phone()
phone._Phone__voltage = 24					# 修改私有属性
phone.call()
phone._Phone__get_run_voltage()			# 调用私有方法

私有属性和私有方法是骗人的障眼法,完全可以通过 _类型__私有属性 和 _类型__私有方法 的形式来调用。

getter和setter的初级进化

producer = property(get_producer, set_producer)
voltage = property(get_voltage, set_voltage)

这是给属性绑定了getter和setter方法,这样,在访问属性的时候,会直接调用getter和setter方法。

所以 self.producer 和 phone.producer 都是调用的是方法,而不是属性,通过执行结果可以看出来,或者通过断点调试。

getter和setter的终极写法

class Phone:

    def __init__(self, producer, voltage):
        self.producer = producer        # 访问的不是属性,是方法
        self.voltage = voltage          # 访问的不是属性,是方法

    @property
    def producer(self):
        return self.__producer

    @producer.setter
    def producer(self, producer):
        self.__producer = producer

    @property
    def voltage(self):
        return self.__voltage

    @voltage.setter
    def voltage(self, voltage):
        if voltage < 36:
            self.__voltage = voltage
        else:
            raise ValueError("参数错误")        # 限制传入的参数值,进行报错处理


phone = Phone("华为", 12)
print(phone.producer)				# 调用的是方法,不是属性
print(phone.voltage)

phone.producer = "小米"			 # 调用的是方法,不是属性
phone.voltage = 24
print(phone.producer)
print(phone.voltage)

每个属性对应两个与属性名相同的方法,分别用于获取和设置属性,并在方法上添加 @property 和 @属性.setter 注解。

__slots__

我们之前可以通过 对象.属性 = 值 随时为一个对象添加属性。

__slots__ 的作用就是限制一个类创建的实例只能有固定的属性,不能随意添加属性。

class Phone:

    __slots__ = ("producer", "__voltage")

    def __init__(self, producer, voltage):
        self.producer = producer
        self.__voltage = voltage


phone = Phone("华为", 12)
phone.size = 6          # 报错:AttributeError: 'Phone' object has no attribute 'size'

继承判定函数

  • type() 函数:type()函数可以判断某个对象是否是某个类型,注意:子类的对象不是父类的对象的类型。
  • isinstance()函数:isinstance()函数可以判断某个对象是否是某个类型的实例,子类对象也是父类对象的实例。
  • issubclass()函数:issubclass()函数可以用来判断一个类是否是另外一个类的子类。

多继承的解析顺序

如果继承的多个父类拥有同样的属性和方法,那么会使用哪个父类的呢?

会使用先继承的父类的,后继承的无效,如果父类中都没有,则会去父类的父类寻找,一直向上找。

即使类没有写明继承其他类,但是所有的类都直接或间接继承自Object类。

抽象类

含有抽象方法的类成为抽象类。抽象方法就是没有方法体,方法体为空的方法。

class Vehicle:
    def transport(self, destination):
        pass

JSON

import json

class Student:

    def __init__(self, sid, name, age):
        self.sid = sid
        self.name = name
        self.age = age

if __name__ == '__main__':
    # 将字典转换为JSON数据

    stu_dict = {"sid": "001", "name": "zhangsan", "age": 18}

    json_data = json.dumps(stu_dict, ensure_ascii=False)  # 使用dumps()方法,将字典转换为JSON数据
    print(json_data)
    print(type(json_data))

    # 将JSON数据转换为字典

    json_data = '{"sid": "001", "name": "张三", "age": 18}'

    stu_dict = json.loads(json_data)  # 使用loads()方法,将JSON数据转换为字典
    print(stu_dict["name"])

    # 对象转换为JSON

    stu = Student("001", "张三", 98)
    stu_json = json.dumps(stu.__dict__, ensure_ascii=False)  # 获取对象的字典格式
    print(f"对象转换为json:{stu_json}")

    # JSON转换为对象
    json_str = '{"sid": "001", "name": "张三", "age": 98}'

    stu_dict = json.loads(json_str)  # 首先将JSON字符串转换为字典
    print(stu_dict["name"])

    stu = Student(**stu_dict)  # 然后通过双星号字典形参传递给构造方法,创建对象,这个类,需要有构造方法
    print(stu.name)

模块和包

每一个以 .py 结尾的python文件就是一个模块。 包是一个一个文件夹,下面有许多的模块

import 模块名								# 导入单个模块
import 模块名1, 模块名2				# 导入多个模块
import time             # 导入时间模块,就有一个time的py文件


from 模块名 import 功能名
from 模块名 import 功能名 as 别名			# 功能也可以起别名
from time import sleep      # 只导入模块中的sleep方法

from 模块名 import *
from time import *      # 只导入模块中所有的函数

模块的搜索顺序

python解释器在导入模块的时候,会搜索当前目录指定模块名的文件,如果有就直接导入,如果没有在搜索系统目录。

所以在开发的时候,给文件起名,不要和系统的模块文件重名,否则会导致调用的系统功能无效。