Python基础学习
一、格式化输出
%s
操作符输出
age = 10
name = "贾宝玉"
score = 90.5
print("姓名:%s 年龄:%s 分数:%.2f" %(name, age, score))
format
函数输出
age = 10
name = "林黛玉"
print("姓名:{}, 年龄:{}".format(name, age))
f-strings
输出**[推荐]**
name = "林黛玉"
age = 20
print(f"姓名:{name}, 年龄:{age}")
二、+号的使用
- 数值:相加
- 字符串:拼接
print(100 + 100) # 200
print("100" + "100") # 100100
print("100" + 100) # 报错
三、浮点类型
浮点类型计算后,存在精度损失,可以使用Decimal
类进行精确计算
from decimal import Decimal
b = Decimal("8.1") / Decimal("3.0")
print(b)
四、布尔型
- 布尔类型可以和其他数据类型进行比较,比如数字、字符串等,在比较时
Python
会将True
视为1
,False
视为0
b1 = True
b2 = False
print(b1 + 1) # 2
print(b2 + 1) # 1
- 在
Python
中,非0
被视为真值,0
被视为假值
if 0:
print("哈哈哈") #不会打印哈哈哈
if 3:
print("嘻嘻") #打印嘻嘻
if "老师":
print("嘚嘚") #打印嘚嘚
五、字符串类型
Python
不支持单字符类型,单字符在Python
中也是作为一个字符串
使用
str = "a"
print(type(a)) #str
- 用三个单引号
'''内容'''
,或三个双引号"""内容"""
可以使字符串内容保持原样输出
content = '''the sentence "where there is a will, there is a way" is very good'''
print(content)
- 在字符串前面加
r
,可以使整个字符串不会被转义
# 1、未加r的时候
str1 = "jack\ntom\tking"
print(str1)
# jack
# tom king
# 2、加r的时候
str2 = r"jack\ntom\tking"
print(str2)
# jack\ntom\tking
六、字符串驻留机制
Python
仅保存一份相同且不可变字符串,不同的值被存放在字符串的贮留池中,Python
的驻留机制对相同的字符串只保留一份拷贝,后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量。
id()
函数:可以返回对象/数据的内存地址
str1 = "hello"
str2 = "hello"
str3 = "hello"
print(f"str1的地址:{id(str1)}") #1504339972704
print(f"str2的地址:{id(str2)}") #1504339972704
print(f"str3的地址:{id(str3)}") #1504339972704
2.驻留机制几种情况讨论(注意 :需要在交互模式下:win+r -> python
,但在ide中内容相同则地址一样)
1. 字符串是由26个英文字母大小写,0-9,_组成,内容相同则地址一样
2. 字符串长度为0或1时,内容相同则地址一样
3. 字符串在编译时进行驻留,而非运行时
4. [-5,256]的整数数字
3 . 字符串驻留机制的好处
当需要值相同的字符串时,可以直接从字符串池里拿来使用,避免频繁的创建和销毁,提升效率和节约内存
七、类型转换
- 显示类型转换
i = 10
j = float(i)
print(type(j), j) # float 10.0
k = str(i)
print(type(k), k) # str 10
- 不管什么值的
int
,float
都可以转成str
,str(x)
将对象x
转换为字符串 int
转换float
时,会增加小数部分,123->123.0
float
转换int
时,会去掉小数部分,123.56->123
- 强制转换后,并不会影响
原变量
指向的数据/值的数据类型
a = 10
b = float(a)
print("a的值:", a, "a的数据类型:", type(a)) # 10, int
print("b的值:", b, "b的数据类型:", type(b)) # 10.0 float
八、算数运算
//
:取整除,返回商的整数部分(向下取整)9//2 == 4
,-9 // 2 == -5
**
:返回x的y次幂2 ** 4 == 16
- 在
python
中,8.1 / 3.0 = 2.699999997
,采用Decimal
模块
from decimal import Decimal
a = Decimal("8.1") / Decimal("3.0")
print(a) # 2.7
%
:取余,运算公式:a % b == a - a // b * b
print(10 % 3) # 1
print(-10 % 3) # 2
# -10 - (-10) // 3 * 3
# = -10 - (-4) * 3
# = 2
九、比较运算
比较运算符的结果要么是True
要么是False
is
:判断两个变量引用对象
是否为同一个(值相等但引用对象不一定相同
)
is not
:判断两个变量引用对象是否不同
a = 100
b = 100
if a is b:
print("ok") # ok
>
:返回True
或False
十、逻辑/布尔运算符
and
:x and y
,如果x
为False
,x and y 返回x
的值,否则返回y
的值
a = 10
b = 20
print(a and b) # 20
or
:x or y
,如果x
为True
则返回x
的值,否则返回y
的值
a = 10
b = 20
print(a or b) # 10
3.not
:not x
,如果x
为True
,返回False
,如果x
为False
,返回True
十一、三元运算符
max = a if a > b else b
如果a > b
,max = a
否则, max = b
十二、变量命名规则
变量
要小写,若有多个单词,使用下划线分开。常量全部大写函数名
一律小写,如果有多个单词,使用下划线隔开。另外,私有函数以双下划线开头类名
使用大驼峰命名:多个单词的首字母用大写单词开头:MyName
十三、键盘输入
使用input()
从控制台接受到的数据类型是str
十四、位运算符
~
:按位取反&
:按位与^
:按位异或,不一样则为1,相同为0|
:按位或,有一个为1,则为1<<
:左移,由右边的数指定移动的位数,符号位不变,低位补0
>>
:右移,由右边的数指定移动的位数,低位溢出,符号位不变,并用符号位补高位
十五、for循环
range
函数解读:不可变序列类型、左闭右开
、
# 生成一个[1,2,3,4,5]
r1 = range(1, 6, 1) # 左闭右开,步长为1
print(list(r1)) # 通过list()可以查看range()生成的序列包含的数据[1,2,3,4,5]
- range()`:range(6),表示从0到5
for
和else
配合使用:
for <variable> in <sequence>:
<statements>
else:
<statements>
for
循环正常的完成遍历,在遍历过程中,没有被打断,就会继续执行else
4 end=""
:表示输出不换行
十六、函数
- 默认参数需要放在参数列表后
def book_info(name, price, author='鬼叔', amount=100)
- 字符串和数值类型是不可变数据类型,当对应的变量的发生了变化时,它对应的内存地址会发生改变
- 函数作为参数传递,传递的不是数据,而是业务逻辑;一个函数可以接受多个函数作为参数传入
lambda函数
1.需求:将函数作为参数进行传递,但是这个函数只使用一次
,此时可以考虑使用lambda匿名函数
- 匿名函数基本语法:
lambda
形参列表:
函数体(一行代码
)
十七、数据容器
列表list
- 列表可以存放多个不同类型数据,允许有重复元素,并且是有序的
- 创建空列表
list1 = []
list2 = list()
- 下标从0开始;索引也可以从尾部开始:最后一个元素的索引为-1,往前一位为-2,以此类推
- 使用
列表.append(值)
方法来添加元素,使用del
语句来删除列表的元素
list = [1, 2, 3]
list.append(4)
print(list) # [1, 2, 3, 4]
del list[0]
print(list) # [2, 3, 4]
- 列表是可变序列,元素可以修改,修改后,列表变量指向地址不变,只是数据内容变化
元组(tuple)
模块和包
模块
基本语法:[from 模块名] import (函数 | 类 | 变量 | *) [as 别名]
- 导入一个或多个模块:
import 模块
使用:模块.xx
- 导入模块的指定功能
from 模块 import 函数、类、变量
from math import fabs
print(fabs(-1)) # 1
- 导入模块的全部功能
from 模块 import *
- 给导入的模块或者功能取别名
包
- 从结构上看,包是一个文件夹,包含了
__init__.py
文件和多个模块文件 - 导入包:
import 包名.模块
使用:包名.模块.功能
十八、类与对象
类
类提供了把数据和功能绑定在一起的方法。
# 定义一个cat类
class Cat:
age = None # 年龄属性
name = None # 名字属性
color = None # 颜色属性
# 通过cat类创建实例
cat1 = Cat()
# 通过对象名.属性名 给各个属性赋值
cat1.name = "小白"
cat1.age = 3
cat1.color = "白色"
print(f"cat1的名字:{cat1.name}")
对象传递机制
class Person:
age = None
name = None
a = Person()
a.age = 10
a.name = "jack"
b = a
print(f"b.name = {b.name}") #b.name = jack
b.age = 200
b = None
print(f"a.age = {a.age}") # a.age = 200
print(f"b.age = {b.age}") # 报错
b = None
将b指向None,而不是改变a变为None
对象的布尔值
Python
一切皆为对象,所有对象都有一个布尔值,通过内置函数bool()
可以获取对象的布尔值
下面对象的布尔值为False
False、数值0、None、空字符串、空列表、空字典、空元组、空集合
类中的成员方法
- 基本语法:
def 方法名(self
, 形参列表):
方法体 self
表示当前对象本身,哪个对象调用,self就代表哪个对象;当我们通过对象调用方法时,self
会隐式的传入;在方法内部,需要使用self
,才能访问到成员变量- 通过
self.属性名
可以访问对象的属性
对象的传递机制
作为对象传递改变属性值时,传递的是地址,因此会改变属性值
class Person:
name = None
age = None
def f1(person):
print(f"person的地址:{id(person)}")
person.name = "james"
person.age += 1
p = Person()
p.name = "jordan"
p.age = 20
print(f"p的地址:{id(p)},名字:{p.name},年龄:{p.age}") #
f1(p)
print(f"p的地址:{id(p)},名字:{p.name},年龄:{p.age}")
# 结果如下:
# p的地址:1911561721984,名字:jordan,年龄:20
# person的地址:1911561721984
# p的地址:1911561721984,名字:james,年龄:21
作用域
- 局部变量是指在成员方法中定义的变量,作用域在方法中;
- 属性作用域为整个类
- 属性和局部变量可以重名,访问属性时带上
self
,表示访问的是属性,没有带self
,则是访问局部变量
构造方法
构造方法是完成对象的初始化任务
- 基本语法:
def__init__
(self, 参数列表)
代码… - 在初始化对象时,会自动执行
__init__
方法
class Person:
# 构造方法
def __init__(self):
print("执行了__init__")
p = Person()
# 结果:
# 执行了 __init__
- 在初始化对象时,将传入的参数,自动传递给
__init__
方法
class Person:
name = None
age = None
# 构造方法
def __init__(self, name, age):
print(f"执行了__init__, {name}, {age}")
p = Person("kobe", 20)
# 执行了__init__, kobe, 20
- 构造方法是py预定义的,名称是
__init__
,注意init前后都有两个_ - 一个类只有一个
__init__
方法,即使写了多个,也只有最后一个生效 python
可以动态生成对象属性
下例中并没有定义属性,但由于动态生成对象属性,所以可以赋值
class Person:
# 构造方法
def __init__(self, name, age):
print(f"执行了__init__, {name}, {age}")
self.name = name
self.age = age
p = Person("kobe", 20)
print(p.name)
# kobe
构造方法不能有返回值
十九、面向对象编程
封装
- 类中的变量或方法以
__
开头命名,则该变量或方法为私有的,私有的变量或方法,只能在本类内部使用,类的外部无法使用 - 伪私有属性:由于
Python
语言的动态特性,会动态的创建属性,这个属性和我们在类中定义的私有属性并不是一个变量
继承
- 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过父类提供
公共
的方法去访问 Python
中,object
是所有其他类的基类Python
支持多重继承
:一个子类可以有多个父类- 在多重继承中 ,如果有同名的成员或方法,遵守从左到右的继承优先级(即:写左边的父类优先级高、写在右边的父类优先级低)
- 通过
super().xx
可以去调用父类的方法
调用父类成员
- 如果子类和父类出现同名的成员,可以通过
父类名
或super()
访问父类的成员
-访问父类成员方式1:
父类名.成员变量
父类名.成员方法(self)
注意:括号里面有self和调用方法不一样
-访问父类成员方式2:
super().成员变量
super().成员方法()
- 子类调用
self.成员/方法
,先在子类中寻找,如果没有再去父类中寻找 - 子类不能直接访问父类的私有成员
- 访问
不限于直接父类
,而是建立从子类向上级父类的查找关系A->B->C
- 建议使用
super()
方法
重写
重写又称覆盖,即子类继承父类的属性和方法后,根据业务需要,再重新定义同名
的属性或方法
类型注解
随着项目越来越大,代码越来越多,在这种情况下,如果没有类型注解,很容易不记得某一个方法的参数类型是什么,一旦传入了错误类型的参数,python
是解释性语言,只有运行时才能发现问题,这对大型项目来说很糟糕
- 变量的类型注解
变量:类型
n1: int = 10
n2: float = 10.2
- 实例对象类型注解
class Cat:
name = None
cat: Cat = Cat()
- 函数/方法类型注解
def 函数/方法名(形参名:类型,形参名:类型)->返回值类型:
函数/方法体
多态
- 不同对象调用相同的方法,表现出不同的状态,称为多态
- 多态通常作用在继承关系上
isinstance()
用于判断对象是否为某个类或其子类的对象
语法:isinstance(object, classinfo)
class AA:
pass
class BB(AA):
pass
class CC:
pass
b = BB()
print(isinstance(b, AA)) # True
print(isinstance(b, BB)) # True
print(isinstance(b, CC)) # False
当调用对象成员的时候,会和对象本身动态关联
二十、魔术方法
- 在
Python
中,所有以双下划线__包起来的方法,统称为魔术方法。普通方法需要调用,而魔术方法不需要调用就可以自动执行
。 - 魔术方法在类或对象的某些事件发生时会自动执行,让类具有“魔力”。
- 常见魔术方法:
__str__
:返回类型+地址。
重写__str__
方法,用于返回对象的属性信息,print(对象)或str(对象)时,都会自动调用该对象的__str__
__eq__
: 对象之间进行比较时,比较的是内存地址
是否相等,即判断是不是同一个对象。
重写__eq__
方法,可以用于判断对象内容/属性是否相等
Class对象和静态方法
- 类本身也是对象,即:Class对象
- 通过类名调用非静态成员方法:
类名.方法(类名)
@staticmethod
将方法 转换为静态方法- 静态方法不会接受隐式的第一个参数,要声明一个静态方法,语法:
class C:
@staticmethod
def f(arg1, arg2):...# 这里省略了self
- 静态方法 既可以由类调用
C.f()
,也可以由实例调用`C().f()
二十一、抽象类
- 默认情况下,
Python
不提供抽象类,Pythono
附带一个模块,该模块为定义抽象基类提供了基础,该模块名称为abc
- 当我们需要抽象基类时,让类继承
ABC(abc模块的ABC类)
,使用@abstractmethod
声明抽象方法,那么这个类就是抽象类
from abc import ABC, abstractmethod
class Animal(ABC):
def __init__(self, name, age):
self.name = name
self.age = age
# 抽象方法
@abstractmethod
def cry(self):
pass
# 编写子类
class Tiger(Animal):
def cry(self):
print(f"老虎嗷嗷叫...")
tiger = Tiger("老虎", 3)
tiger.cry()
- 抽象类的价值在于
设计
,是设计者设计好后,让子类继承并实现抽象类的抽象方法 - 抽象类不能实例化
- 抽象类需要继承
ABC
,并且需要至少一个抽象方法
- 抽象类可以有普通方法
- 如果一个类继承了抽象类,则他必须实现抽象类的所有抽象方法,否则它仍是一个抽象类
二十二、模版设计模式
- 模版设计模式能
解决的问题
:
1、当功能内部一部分实现是确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
2、编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模版模式。