魔法函数(magic methods)是指以双下划线开头和结尾的特殊方法,用于实现对象的特定行为和操作。这些魔法函数可以让我们自定义对象的行为,例如实现对象的比较、算术运算、属性访问等。常见的魔法函数包括__init__
(构造函数)、__str__
(返回对象的字符串表示)、__add__
(实现对象的加法运算)、__eq__
(实现对象的相等比较)等。通过实现这些魔法函数,我们可以让我们的自定义对象更加灵活和强大。
原本没有这个能力,把这个函数写出来就有了
lt(self, other)定义小于号的行为:x < y
???比大小
??# 比大小
? ?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
?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()
必须带参数因为初始化上有两个,否则报错?
???相当于toString
??
?class Dog:
? ? ?name: str
? ? ?age: int
?
??def __str__(self):
?????????return f'{self.namee},{self.age}'
# 测试str
d1 = Dog(age=20)
print(d1) # 是对象@。。。,显示用tosting一样
??bool 可用于逻辑判断部分
?
??
? ?def __bool__(self):
??? ? ?return self.age > 18
? ? ? ?
? ? ?
?#测试bool
?print(bool(T(17) and T(19))) ?
?
允许一个类的实例像函数一样被调用,可以把类当成装饰器使用
class Dog:
??def __call__(self, *args, **kwargs):
? ? ? ?print("类的实例可以像函数一样被调用")
?# 测试call
? d1=Dog1(age=20)
#多了个括号
?d1()
??del 是析构方法,当对象的引用计数变为0时,这个对象会被销毁掉,可以用用于关闭资源
? #del 是析构方法,当对象的引用计数变为0时,这个对象会被销毁掉,可以用用于关闭资源
? ? ?def __del__(self):
??? ? ? ?print("对象被销毁") ? ? ?
? ? ? ? ?
?#测试del
?t = Dog1()
?# t指向0,此前创建的T的实例被销毁
?t = 0
? ? ? ? ?
??
?len 是内置函数,len(t) 会调用实例的 len 方法,len一般用在集合中,如果想测量狗,就要重写len
class Dog:
def __len__(self):
return 100
d1 = Dog()
print(len(d1))
属性寻找规则: 先找实例的 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这个属性,优先拿自己的(在没有别人的情况下)
class Plane(object)?:
#类属性
categoryf='飞机'
def __init__(self, name):
#实例属性
? ? ? ? ?self.name = name
? ? ? ?
?属性装在字典里面,所有还能例外方式赋值
把age直接给字典
p1.__dit__['age']=10
?python中对象的属性为什么可以动态变化?
类属性同样是存储在字典中,只是这个字典是类的字典 可以通过类名和对象名来调用,但是只能通过类名修改,类属性对于该类对象是共享的 类的属性和方法存在在类的 dict 之中
(对属性做限制,封装若有若无)
使用一个下划线就等于向使用者宣布这个属性是私有的,但你仍然可以直接对其修改,单个 下划线更像是一种约定,而非技术上的强硬限制。即便使用了双下划线,也仍然有办法直接对其修改, 但这已经不是类所要解决的问题了,一个人执意破坏数据,他总是能找到办法。
?__强制
?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 装饰器再装饰一个方法,该方法完成对 属性的赋值操 作。我们认为自己直接操作了对象的属性,但其实我们是在使用类的方法,而且关键的是省去了调用方法时 的那对小括号
???
? ? 类方法可以用类名调用
? ?#类方法
? ? ?@classmethod
? ? ?def run(cls):
? ? ? ? ?#可以操作类属性,不能操作对象属性因为没有self
? ? ? ? ?print(cls.__age)
#用类调用
?Pig.run()
? ? ?#静态方法,什么东西都没带,不能类属性也不能调对象属性,只是单纯函数而已
? ? ?@staticmethod
? ? ?def say():
? ? ? ? ?print("hello world")
? ? ? ? ?
如果没有指定基类,会默认继承 object 类, object 是所有类的基类,它提供了一些常见方法
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)
??
在一个时期有不同的状态
#动物类
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)
在Java习惯:不同作用的类放在一起,形成包 --->导包
?导入模块=相当于Alt+/
Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。 模块让你能够有逻辑地组织你的 Python 代码段。 把相关的代码分配到一个模块里能让你的代码更好用,更易懂。 模块能定义函数,类和变量,模块里也能包含可执行的代码
? import ?modu
?#方法一导入全部方法 取个别名
? 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():
?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实现了许多特定容器,这些容器在某些情况下可以替代内置容器 dict, list, tuple, set, 原因 在于,他们提供了在某个方面更加强大的功能。
数据太多,可以计算它每个字母出现的次数
?keys = "Hold fast,and let go;" \
????"understand this paradox," \
????"and you stand at the very gate of wisdom."
?cs = Counter(keys)
?print(cs)
\回车代表换行
?dic1 = {'python': 100}
?dic2 = {'java': 99}
?cm = ChainMap(dic1, dic2)
?cm = dict(cm)#转字典
?print(cm)
不会引发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'])
栈就相当于客栈:先进后出
队列相当于排队:先进先出
方法:
类似列表的容器,支持在两端快速的追加和删除元素。
append (在末尾追加数据)
appendleft (在头部追加数据)
pop (删除并返回指定索引的数据,默认是末尾数据)
popleft(删除并返回头部数据)
insert(在指定位置插入数据)
remove(删除指定数据)
?#以前写法
#学生类
?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('一个字符串')
python标准模块functools提供的wraps函数可以让被装饰器装饰以后的函数保留原有的函数信息,包括 函数的名称和函数的注释doc信息。
#做成了装饰器
def hello(func):
#加了这个装饰器以后输出say
@wraps(func)
def inner():
pass
return inner
@hello
def say():
pass
#输出inner,就比如是答非所问了
point(say. __name__)
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))
?try:
? ?print(1 / 0)
?except Exception as e:#分母不能为0
? ?print(e)
?else:
??print('no error')#没异常出
?finally:
??print('close')#不管有没有异常都出来
?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) ? ? ? ?