1 函数
1.1 函数基础
- 定义
def 函数名():
代码1
代码2
...
- 调用
函数名()
- 函数的说明文档
def 函数名():
""" 函数说明文档 """
- 查看函数的说明文档
help(函数名)
1.2 变量的作用域
-
局部变量
- 所谓局部变量是定义在函数体内部的变量,即只在函数体内部生效。
-
全局变量
- 所谓全局变量,指的是在函数体内、外都能生效的变量。
-
如何在函数体内部修改全局变量?
a = 100
def testA():
print(a)
def testB():
# global 关键字声明a是全局变量
global a
a = 200
print(a)
testA() # 100
testB() # 200
print(f'全局变量a = {a}') # 全局变量a = 200
1.3 函数的返回值
return a, b
写法,返回多个数据的时候,默认是元组类型。- return后面可以连接列表、元组或字典,以返回多个值。
1.4 函数的参数
1.4.1 位置参数
- 位置参数:调用函数时根据函数定义的参数位置来传递参数。
- 传递和定义参数的顺序及个数必须一致。
1.4.2 关键字参数
- 通过“键=值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。
def user_info(name, age, gender):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')
user_info('Rose', age=20, gender='女')
user_info('小明', gender='男', age=16)
- 函数调用时,如果有位置参数时,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序。
1.4.3 缺省参数
- 缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值
- 所有位置参数必须出现在默认参数前,包括函数定义和调用
def user_info(name, age, gender='男'):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}')
user_info('TOM', 20)
user_info('Rose', 18, '女')
1.4.4 不定长参数
- 包裹位置传递
def user_info(*args):
print(args)
# ('TOM',)
user_info('TOM')
# ('TOM', 18)
user_info('TOM', 18)
注意:传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型,这就是包裹位置传递。
- 包裹关键字传递
def user_info(**kwargs):
print(kwargs)
# {'name': 'TOM', 'age': 18, 'id': 110}
user_info(name='TOM', age=18, id=110)
综上:无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程。
1.5 拆包和交换变量值
1.5.1 拆包
- 拆包:元组
def return_num():
return 100, 200
num1, num2 = return_num()
print(num1) # 100
print(num2) # 200
- 拆包:字典
dict1 = {'name': 'TOM', 'age': 18}
a, b = dict1
# 对字典进行拆包,取出来的是字典的key
print(a) # name
print(b) # age
print(dict1[a]) # TOM
print(dict1[b]) # 18
1.5.2 交换变量值
a, b = 1, 2
a, b = b, a
print(a) # 2
print(b) # 1
1.6 引用
-
在python中,值是靠引用来传递来的。
-
我们可以用
id()
来判断两个变量是否为同一个值的引用。 -
我们可以将id值理解为那块内存的地址标识。
1.6.1 引用当做实参
def test1(a):
print(a)
print(id(a))
a += a
print(a)
print(id(a))
# int:计算前后id值不同
b = 100
test1(b)
# 列表:计算前后id值相同
c = [11, 22]
test1(c)
1.6.2 可变类型与不可变类型
所谓可变类型与不可变类型是指:数据能够直接进行修改,如果能直接修改那么就是可变,否则是不可变.
- 可变类型
- 列表
- 字典
- 集合
- 不可变类型
- 整型
- 浮点型
- 字符串
- 元组
1.7 lambda表达式
1.7.1 lambda语法
lambda 参数列表 : 表达式
- lambda表达式的参数可有可无,函数的参数在lambda表达式中完全适用。
- lambda表达式能接收任何数量的参数但只能返回一个表达式的值。
1.7.2 lambda的参数形式
- 无参数
fn1 = lambda: 100
print(fn1())
- 一个参数
fn1 = lambda a: a
print(fn1('hello world'))
- 默认参数
fn1 = lambda a, b, c=100: a + b + c
print(fn1(10, 20))
- 可变参数:*args
fn1 = lambda *args: args
print(fn1(10, 20, 30))
注意:这里的可变参数传入到lambda之后,返回值为元组。
- 可变参数:**kwargs
fn1 = lambda **kwargs: kwargs
print(fn1(name='python', age=20))
1.7.3 lambda的应用
- 带判断的lambda
fn1 = lambda a, b: a if a > b else b
print(fn1(1000, 500))
- 列表数据按字典key的值排序
students = [
{'name': 'TOM', 'age': 20},
{'name': 'ROSE', 'age': 19},
{'name': 'Jack', 'age': 22}
]
# 按name值升序排列
students.sort(key=lambda x: x['name'])
print(students)
# 按name值降序排列
students.sort(key=lambda x: x['name'], reverse=True)
print(students)
# 按age值升序排列
students.sort(key=lambda x: x['age'])
print(students)
1.8 高阶函数
- 把函数作为参数传入,这样的函数称为高阶函数,高阶函数是函数式编程的体现。函数式编程就是指这种高度抽象的编程范式。
def sum_num(a, b, f):
return f(a) + f(b)
result = sum_num(-1, 2, abs)
print(result) # 3
- 函数式编程大量使用函数,减少了代码的重复,因此程序比较短,开发速度较快。
1.8.1 内置高阶函数
- map(func, lst):
- 参数一:函数
- 参数二:容器
- 返回值:新容器
- reduce(func,lst)
- 参数一:函数
- 参数二:容器
- 返回值:value
- filter(func, lst)
- 参数一:函数
- 参数二:容器
- 返回值:容器
2. 面向对象
2.1 类
Python中类分为:经典类(不推荐) 和 新式类
- 语法
class 类名():
代码
......
注意:类名要满足标识符命名规则,同时遵循大驼峰命名习惯。
- 体验
class Washer():
def wash(self):
print('我会洗衣服')
- 拓展:经典类
不由任意内置类型派生出的类,称之为经典类
class 类名:
代码
......
2.1.1 创建对象
对象又名实例。
- 语法
对象名 = 类名()
2.1.2 self
self指的是调用该函数的对象
2.2 添加和获取对象属性
- 类外面添加对象属性
对象名.属性名 = 值
- 类外面获取对象属性
对象名.属性名
- 类里面获取对象属性
self.属性名
- 类里面设置对象属性
self.属性名=值
2.3 魔法方法
在Python中,__xx__()
的函数叫做魔法方法,指的是具有特殊功能的函数。
2.3.1 __init__()
-
初始化对象
-
在创建一个对象时默认被调用
-
__init__(self)
中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去。 -
还可以带其他参数
__init__(self, width, height)
2.3.2 __str__()
- 当使用print输出对象的时候,默认打印对象的内存地址。
- 如果类定义了
__str__
方法,那么就会打印从在这个方法中 return 的数据。
2.3.3 __del__()
- 当删除对象时,python解释器也会默认调用
__del__()
方法。
2.4 继承
不由任意内置类型派生出的类,称之为经典类。
class 类名:
代码
......
- 拓展2:新式类
class 类名(object):
代码
- 在Python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫做派生类。
2.4.1 多继承
class Prentice(School, Master):
pass
- 注意:当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法。
2.4.2 子类调用父类的同名方法和属性
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class School(object):
def __init__(self):
self.kongfu = '[黑马煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class Prentice(School, Master):
def __init__(self):
self.kongfu = '[独创煎饼果子配方]'
def make_cake(self):
# 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
# 调用父类方法,但是为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化
def make_master_cake(self):
Master.__init__(self) # python2.0中的方式,不推荐使用了
Master.make_cake(self)
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
daqiu = Prentice()
daqiu.make_cake()
daqiu.make_master_cake()
daqiu.make_school_cake()
daqiu.make_cake()
2.4.3 多层继承
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class School(object):
def __init__(self):
self.kongfu = '[黑马煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class Prentice(School, Master):
def __init__(self):
self.kongfu = '[独创煎饼果子配方]'
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
# 徒孙类
class Tusun(Prentice):
pass
xiaoqiu = Tusun()
xiaoqiu.make_cake()
xiaoqiu.make_school_cake()
xiaoqiu.make_master_cake()
2.4.2 supper()
python3新加的,代替了之前的调用父类同名属性和方法方式
- 使用super() 可以自动查找父类。调用顺序遵循
__mro__
类属性的顺序。比较适合单继承使用。
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class School(Master):
def __init__(self):
self.kongfu = '[黑马煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
# 方法2.1
# super(School, self).__init__()
# super(School, self).make_cake()
# 方法2.2
super().__init__()
super().make_cake()
class Prentice(School):
def __init__(self):
self.kongfu = '[独创煎饼果子技术]'
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
# 子类调用父类的同名方法和属性:把父类的同名属性和方法再次封装
def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
# 一次性调用父类的同名属性和方法
def make_old_cake(self):
# 方法一:代码冗余;父类类名如果变化,这里代码需要频繁修改
# Master.__init__(self)
# Master.make_cake(self)
# School.__init__(self)
# School.make_cake(self)
# 方法二: super()
# 方法2.1 super(当前类名, self).函数()
# super(Prentice, self).__init__()
# super(Prentice, self).make_cake()
# 方法2.2 super().函数()
super().__init__()
super().make_cake()
daqiu = Prentice()
daqiu.make_old_cake()
2.5 私有权限
2.5.1 定义私有属性和方法
- 设置私有权限:设置某个实例属性或实例方法不继承给子类。
- 在属性名和方法名 前面 加上两个下划线 __。
- python中的私有属性其实时伪私有属性,还是可以访问到,访问方式为
_类名__私有属性
2.5.2 获取和修改私有属性值
- 在Python中,一般定义函数名
get_xx
用来获取私有属性,定义set_xx
用来修改私有属性值。
2.6 类属性
2.6.1 设置和访问类属性
- 类属性就是 类对象 所拥有的属性,它被 该类的所有实例对象 所共有。
- 类属性可以使用 类对象 或 实例对象 访问。
class Dog(object):
tooth = 10
wangcai = Dog()
xiaohei = Dog()
print(Dog.tooth) # 10
print(wangcai.tooth) # 10
print(xiaohei.tooth) # 10
类属性的优点
- 记录的某项数据 始终保持一致时,则定义类属性。
- 实例属性 要求 每个对象 为其 单独开辟一份内存空间 来记录数据,而 类属性 为全类所共有 ,仅占用一份内存,更加节省内存空间。
2.6.2 修改类属性
类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建了一个实例属性。
class Dog(object):
tooth = 10
wangcai = Dog()
xiaohei = Dog()
# 修改类属性
Dog.tooth = 12
print(Dog.tooth) # 12
print(wangcai.tooth) # 12
print(xiaohei.tooth) # 12
# 不能通过对象修改属性,如果这样操作,实则是创建了一个实例属性
wangcai.tooth = 20
print(Dog.tooth) # 12
print(wangcai.tooth) # 20
print(xiaohei.tooth) # 12
2.7 实例属性
class Dog(object):
def __init__(self):
self.age = 5
def info_print(self):
print(self.age)
wangcai = Dog()
print(wangcai.age) # 5
# print(Dog.age) # 报错:实例属性不能通过类访问
wangcai.info_print() # 5
2.8 类方法
2.8.1 类方法特点
- 需要用装饰器
@classmethod
来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls
作为第一个参数。
2.8.2 类方法使用场景
- 当方法中 需要使用类对象 (如访问私有类属性等)时,定义类方法
- 类方法一般和类属性配合使用
-一个对象访问某个属性时,首先查找对象属性,找不到才会查找类属性
- 不推荐通过对象获取类属性:当赋值时可能有些歧义
class Dog(object):
__tooth = 10
@classmethod
def get_tooth(cls):
return cls.__tooth
wangcai = Dog()
result = wangcai.get_tooth()
print(result) # 10
2.9 静态方法
2.9.1 静态方法特点
- 需要通过装饰器
@staticmethod
来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)。 - 静态方法 也能够通过 实例对象 和 类对象 去访问。
- 总结
- 如果一个方法需要访问对象属性,则可以设置为对象方法
- 若果一个方法需要访问类属性,则可以设置为类方法
- 如果一个方法既不访问对象属性也不访问类属性,则可以设置为静态方法
2.9.2 静态方法使用场景
- 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
- 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
class Dog(object):
@staticmethod
def info_print():
print('这是一个狗类,用于创建狗实例....')
wangcai = Dog()
# 静态方法既可以使用对象访问又可以使用类访问
wangcai.info_print()
Dog.info_print()