一、魔法函数
1.1、概念:
魔法函数(magic methods)是指以双下划线开头和结尾的特殊方法,用于实现对象的特定行为和操作。这些魔法函数可以让我们自定义对象的行为,例如实现对象的比较、算术运算、属性访问等。常见的魔法函数包括__init__
(构造函数)、__str__
(返回对象的字符串表示)、__add__
(实现对象的加法运算)、__eq__
(实现对象的相等比较)等。通过实现这些魔法函数,我们可以让我们的自定义对象更加灵活和强大。
原本没有这个能力,把这个函数写出来就有了
1.2、比较操作
-
lt(self, other)定义小于号的行为:x < y
比大小
- def __lt__():
# 比大小
def __lt__(self, other):
return self.age < other.age
# 测试lt
d1 = Dog1(age=20)
d2 = Dog1(age=18)
d3 = Dog1(age=19)
print(d1 < d2) # 答案False
-
le(self, other)定义小于等于号的行为:x <= y
-
eq(self, other)定义等于号的行为:x == y
-
ne(self, other)定义不等号的行为:x != y
-
gt(self, other)定义大于号的行为:x > y
-
ge(self, other)定义大于等于号的行为:x >= y
1.3、常见的魔法函数
-
初始化def __init__():
class Dog:
namee: str
age: int
# 初始化(相当于Java里面的构造函数)
def __init__(self, namee='hhh', age=18):
self.namee = namee
self.age = age
# 测试init传不传参数
#new一个出来Dog
d1 = Dog('jack',19)#必须传两个参数,因为初始化上有两个,否则报错
#如果只想传一个就用默认值
d1.Dog(age=20)#传了一个它自己self
通过关键字传参,指定传参
d1 = Dog1(age=20)
print(d1) # 是对象@。。。,显示用tosting一样
输出对象
没有重载 ,如果即想要有参有想要无参,只能传默认值(希望某个值不填)
class Dog:
name: str
age: int
#不能前面有后面没有(name和age都要有)
def __init__(self, name='', age=18):
self.name = name
self.age = age
d1=Dog()
必须带参数因为初始化上有两个,否则报错
-
def __str__(self):
相当于toString
class Dog:
name: str
age: int
def __str__(self):
return f'{self.namee},{self.age}'
# 测试str
d1 = Dog(age=20)
print(d1) # 是对象@。。。,显示用tosting一样
-
def __bool__(self):
bool 可用于逻辑判断部分
def __bool__(self):
return self.age > 18
#测试bool
print(bool(T(17) and T(19)))
-
def __call__():
允许一个类的实例像函数一样被调用,可以把类当成装饰器使用
class Dog:
def __call__(self, *args, **kwargs):
print("类的实例可以像函数一样被调用")
# 测试call
d1=Dog1(age=20)
#多了个括号
d1()
-
def __del__(self):
del 是析构方法,当对象的引用计数变为0时,这个对象会被销毁掉,可以用用于关闭资源
#del 是析构方法,当对象的引用计数变为0时,这个对象会被销毁掉,可以用用于关闭资源
def __del__(self):
print("对象被销毁")
#测试del
t = Dog1()
# t指向0,此前创建的T的实例被销毁
t = 0
-
def __len__(self):
len 是内置函数,len(t) 会调用实例的 len 方法,len一般用在集合中,如果想测量狗,就要重写len
class Dog:
def __len__(self):
return 100
d1 = Dog()
print(len(d1))
1.4、属性管理
属性寻找规则: 先找实例的 dict ,再去查找类的 dict
class Plane(object) :
#类属性
categoryf='飞机'
# 实例化两个飞机,categoryf飞机种类
p1, p2 = Plane('ccc'), Plane('bb')
#把类改了
Plane.category = '拖拉机'
print(f'{p1.category},{p2.category}')
#输出:拖拉机,拖拉机
#p1重新赋值
p1.category = '小飞机'
print(f'{p1.category},{p2.category}')
#输出:小飞机,拖拉机
#p1删除
del p1.category
print(f'{p1.category},{p2.category}')
#输出:拖拉机,拖拉机
原因:
# 类对象里面有一个字典
print(Plane.__dict__)
# 实例化对象也有一个字典
print(p1.__dict__)
总:两个里面都有category这个属性,优先拿自己的(在没有别人的情况下)
1.5、类属性与实例属性区分
class Plane(object) :
#类属性
categoryf='飞机'
def __init__(self, name):
#实例属性
self.name = name
属性装在字典里面,所有还能例外方式赋值
把age直接给字典
p1.__dit__['age']=10
python中对象的属性为什么可以动态变化?
类属性同样是存储在字典中,只是这个字典是类的字典 可以通过类名和对象名来调用,但是只能通过类名修改,类属性对于该类对象是共享的 类的属性和方法存在在类的 dict 之中
二、封装
2.1、概念:
(对属性做限制,封装若有若无)
使用一个下划线就等于向使用者宣布这个属性是私有的,但你仍然可以直接对其修改,单个 下划线更像是一种约定,而非技术上的强硬限制。即便使用了双下划线,也仍然有办法直接对其修改, 但这已经不是类所要解决的问题了,一个人执意破坏数据,他总是能找到办法。
__强制
2.2、封装方式
封装方式一:
class Cat:
#私有化
__age: int # __强制
def __init__(self, age):
self.__age = age
#会找不到,因为私有化了,要get set
c1 = Cat(19)
print(c1.__age)也不能这样调
#正确调法
c1.set_age(30)
print(c1.get_age())
#方法一
#get set
def get_age(self,age):
return self.__age
def set_age(self,age):
if age >20:
print('死了')
else:
self.__age=age
#测试 没有get和set强行修改,也可以修改的__dict__
c1 = Cat(19)
#直接改字典
print(c1.__dict__)
封装方式二
# 封装方法2(装饰器)
class Pig:
#私有化
__age: int # __强制
def __init__(self, age):
self.__age = age
#装饰器
@property
def age(self):
return self.__age
@age.setter
def age(self,age):
self.__age= age
两个封装区别
方式一如果想添加代码就要一个一个加,因为不同地方调用了那个方法,方式二就不用
使用 @property 装饰器修饰 方法后,你就可以像使用属性一样使用 某个属性 ,如果你希望可以对 某个属性进行赋值,那么需要用 @ 某个属性.setter 装饰器再装饰一个方法,该方法完成对 属性的赋值操 作。我们认为自己直接操作了对象的属性,但其实我们是在使用类的方法,而且关键的是省去了调用方法时 的那对小括号
2.3、方法拓展
类方法可以用类名调用
#类方法
@classmethod
def run(cls):
#可以操作类属性,不能操作对象属性因为没有self
print(cls.__age)
#用类调用
Pig.run()
#静态方法,什么东西都没带,不能类属性也不能调对象属性,只是单纯函数而已
@staticmethod
def say():
print("hello world")
三、继承
3.1、概念
如果没有指定基类,会默认继承 object 类, object 是所有类的基类,它提供了一些常见方法
3.2、语法:
class Dog(多个父类,就进原则,如果是obj可以默认不写):
3.3、区别
类属性Dog.xx 实例属性self.xx
类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
class Dog:
pass
class Cat:
pass
#一个父亲一个母亲
class Lion(Dog, Cat):
pass
查看继承谁
#方式一:__bases__
print(Lion.__bases__)
#方式二:__mro__ 更详细
print(Lion.__mro__)
跟谁亲,就近原则
场景:在一个类要实现多个类,可以产生方法冲突
class Lion(Dog, Cat):
pass
class Dog:
food:'叭叭叭'
def say(self):
print('我要吃'+self.food)
class Cat:
food='yyyyy'
def say(self):
print('我要吃' + self.food)
#希望调父类方法:
#调用错误的 ----不能用类去调,say是对象
print(Lion.say())
#正确的
Lion().say()
print(Lion.food)
四·、多态
4.1、概念:
在一个时期有不同的状态
#动物类
class Animal(object):
#表演的方法
def play(self):
pass
#老虎类继承了动物类
class Tiger(Animal):
#重写方法
def play(self):
print("正在表演老虎吃人")
#狮子类继承了动物类
class Lion(Animal):
def play(self):
print("正在表演狮子跳火圈")
#人类与
class Person(object):
#与动物玩耍
def show(self, a: Animal):
print("动物开始表演了")
a.play()
p = Person()
#一个老虎
tiger = Tiger()
#一个狮子
lion = Lion()
谁表演
# 让老虎表演
p.show(tiger)
# 让狮子表演
p.show(lion)
五、模块(Python文件)
在Java习惯:不同作用的类放在一起,形成包 --->导包
导入模块=相当于Alt+/
5.1、概念:
Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。 模块让你能够有逻辑地组织你的 Python 代码段。 把相关的代码分配到一个模块里能让你的代码更好用,更易懂。 模块能定义函数,类和变量,模块里也能包含可执行的代码
5.2、语法:
import modu
5.3不同方式导模块
#方法一导入全部方法 取个别名
import modu as m
m.p()
m.hello()
#方法二单独某个方法
from modu import hello,P
hello()
P()
#方法三单独一个方法取个别名
from modu import hello as h
h()
#方法四导全部,但是是自己想要给别人的全部
from modu import *
P()
搭配 __all__ = [] 使用
#另外一个页面
__all__ = ['Cat']
Class Cat:
pass
def hello():
5.4、导入包
import package.module
import package.module as xx
from package.module import xx
from package.module import xx as xx
#导包
#方法一要 包名点类名取别名
import soud.s1 as s
s.say1()
#方法二要在init里面写all
from soud import *
s1
搭配 __init__.py中的__all__ = [] 使用
六、标准模块collections
collections实现了许多特定容器,这些容器在某些情况下可以替代内置容器 dict, list, tuple, set, 原因 在于,他们提供了在某个方面更加强大的功能。
6.1、Counter 统计对象的个数
数据太多,可以计算它每个字母出现的次数
keys = "Hold fast,and let go;" \
"understand this paradox," \
"and you stand at the very gate of wisdom."
cs = Counter(keys)
print(cs)
\回车代表换行
6.2、ChainMap 合并多个字典,还可以用**
dic1 = {'python': 100}
dic2 = {'java': 99}
cm = ChainMap(dic1, dic2)
cm = dict(cm)#转字典
print(cm)
6.3、OrderedDict 有序字典 (3.6之后字典自带)
6.4、defaultdict默认字典
不会引发KeyError的字典,如果拿一个没有的会报错,它可以使它不报错返回0 在创建这种字典时,必须传入一个工厂函数,比如int, float, list, set。defaultdict内部有一个 missing(key) 方法,当key不存在时,defaultdict会调用 missing 方法根据你所传入的工厂函数返回一个默认值。你传入的工厂函数是int,那么返回的就是0, 如果传入的是list,返回的就是空列表
d1={
"java":100,
"python":99
}
print(d1['c++'])#没有c++这个课程,报错,但是有时候我们不希望它报错
eg:
#指定类型
dic = defaultdict(int)
dic['a'] = 1
dic['b'] = 2
dic['c'] = 3
print(dic['f'])
6.5、deque 一个类似列表的容器
栈就相当于客栈:先进后出
队列相当于排队:先进先出
方法:
-
类似列表的容器,支持在两端快速的追加和删除元素。
-
append (在末尾追加数据)
-
appendleft (在头部追加数据)
-
pop (删除并返回指定索引的数据,默认是末尾数据)
-
popleft(删除并返回头部数据)
-
insert(在指定位置插入数据)
-
remove(删除指定数据)
七、functools函数工具
7.1、singledispatch 单处理的泛型函数(单个调动)
#以前写法
#学生类
class Stu(object):
def wake_up(self):
print('起床')
#警察类
class Police:
def wake_up(self):
print('起床')
#new了一个学生一个警察
stu = Stu()
police = Police()
def wake_up(obj):
#isinstance判断某个类是不是它的子类
if isinstance(obj, Stu):
print('今天周末休息,让孩子们再睡一会')
elif isinstance(obj, Police):
print('警察很辛苦,又要起床了')
obj.wake_up()
else:
print('不处理')
wake_up(stu)
wake_up(police)
wake_up('一个字符串')
#现在写法
from functools import singledispatch
class Stu(object):
def wake_up(self):
print('起床')
class Police:
def wake_up(self):
print('起床')
stu = Stu()
police = Police()
#装饰器
@singledispatch
def wake_up(obj):
print('不处理')
@wake_up.register(Stu)
def wake_stu(obj):
print('今天周末休息,让孩子们再睡一会')
@wake_up.register(Police)
def wake_police(obj):
print('警察很辛苦,又要起床了')
obj.wake_up()
wake_up(stu)
wake_police(police)
wake_up('一个字符串')
7.2、wraps 装饰器修饰
python标准模块functools提供的wraps函数可以让被装饰器装饰以后的函数保留原有的函数信息,包括 函数的名称和函数的注释doc信息。
#做成了装饰器
def hello(func):
#加了这个装饰器以后输出say
@wraps(func)
def inner():
pass
return inner
@hello
def say():
pass
#输出inner,就比如是答非所问了
point(say. __name__)
7.3、reduce 规约函数
reduce(对集合做操作)的作用是从左到右对一个序列的项累计地应用有两个参数的函数,以此合并序列到一个单一值,简单来说就是把集合合成一个整体
与filter()过滤、map()一样的集合做操作,reduce要导包
计算1-100的和
reduce(lambda a,b:a+b,range(1,100))#1,2,3,4....
#a第一次是1,b为2 a+b=3
#a第二次是3 b是后面那个就是3
相加起来拼成一个字符串
ns=[{"name":"a"},{"name":"b"},{"name":"c"}]
#字符串后面加个空字符串
print(reduce(lambda a,b:a+b['name'],ns,""))
#int后面加个0
print(reduce(lambda a,b:a+b['age'],ns,0))
八、异常
8.1、.抓异常try
try:
print(1 / 0)
except Exception as e:#分母不能为0
print(e)
else:
print('no error')#没异常出
finally:
print('close')#不管有没有异常都出来
8.2、自定义异常类 raise抛出异常
try:
raise TypeException('类型不匹配')
except Exception as e:
print(e)
def eat(obj):
#方法一raise
if isinstance(obj,str):
pass
else:
raise Exception("类型不是我想要的")
#方法二断言assert
assert isinstance(obj str),"类型不符合"
eat(123)