封装
def demo():
pass
# 可以查看对象内的所有属性以及方法
# print(dir(demo))
class Person:
def __init__(self, age):
# 这是初始化方法,类名()时会自动调用
self.age = age
pass
def eat(self):
# 哪个对象调用方法,self就是哪个对象的引用
print("吃饭" + self.name, self.age) # 吃饭qiang 20
self.run()
def run(self):
print("跑步")
def __str__(self):
print("重写该方法,可以实现类似toString的效果")
return "a"
def __del__(self):
print("内存即将被销毁时候调用")
p = Person(20)
# 该种直接添加属性方式虽然可以使用但是不推荐
p.name = "qiang"
p.eat()
print(p) # <__main__.Person object at 0x7f18229f2b70> 如果重写str方法如上,则此句输出a,即__str__的返回值
print(id(p)) # 140695980161848
# del关键字可以删除一个对象
# del p 如果没有该句则del是在print50个下划线之后才输出内容,因为p是全局变量,但是如有此句则del会先于输出下划线执行
print("-"*50)
# is运算符
"""
is 判断两个标识符是不是引用同一个对象,x is y 类似于id(x)==id(y)
is not 判断两个标识符是不是引用同一个对象,x is not y 类似于id(x)!=id(y)
is用于判断对象引用是否是同一个
==用于判断引用变量的值是否相等
python中None是空对象,None比较的时候建议使用is判断
"""
# 私有属性和方法
"""
开发过程中有些属性和方法不希望被外界访问
一般在属性或者方法名前增加两个下划线,定义就是私有的属性或者方法
但是这个私有是假的,实际只是对名称进行了处理:
在名称前加上_类名=>_类名_名称
"""
"""
_x:单前置下划线,被称作保护变量或者方法,from soem import * 禁止导入,类对象和子类可以访问
__x: 双前置下划线,私有属性或者方法,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
__xx__:双前后下划线,用户名字空间的魔法对象或属性,例如__inint__ 不要自己这么定义
xx_:单后置下划线,用于避免与python关键字的冲突
"""
继承
# 继承:子类具有父类所有的属性和方法
class Person(object):
def __init__(self):
self.__age = 20
def run(self):
print("跑")
def eat(self):
print("吃饭")
def getAge(self):
return self.__age
class Boy(object):
def learn(self):
print("学习")
# 多继承(父继承之间不要使用同名属性和放法,不然代码很难调试)
# MRO(方法搜索顺序)
"""
python中针对累提供一个内置属性__mro__可以查看方法的搜索顺序
主要用于在多继承时判断方法,属性的调用顺序
根据输出结果:
多继承同名时候,从左到右顺序查找(对应的属性和方法。查找到就执行并且停止)
"""
class Student(Person, Boy):
"""子类中无法使用父类的私有属性和方法"""
def run(self):
"""重写父类的方法"""
print("学生跑")
def eat(self):
"""对父类方法进行扩展,通过super还可以调用父类方法"""
super().eat()
print("吃丰盛饭")
s = Student()
s.run()
s.eat()
# 但是可以通过调用父类的公有方法间接获取父类的私有属性
print(s.getAge())
s.learn()
# 新式类和经典类
"""
python中为所有对象提供的基类,提供一些内置的属性和方法,可以使用dir查看
新式类:以object为基类的类,推荐使用
经典类:不以object为基类的类,不推荐使用
在p3中没有指定父类,默认使用object作为基类,而p2则不会
新式类和经典类在多继承时,会影响方法的搜索顺序,为了保证2和3同时运行该代码建议统一继承object
"""
多态
# python中不允许重载,因为python中方法名也是变量,同名后者会覆盖前者,但是+运算符的针对不同类型
# 相加结果不同的情况,其实算是python中唯一的重载形式,运算符重载
# 多态:不同的子类对象调用相同父类方法产生不同的结果(前提是子类重写父类的方法)
class Person:
def __init__(self, name):
self.name = name
def run(self):
print("跑")
class Boy(Person):
def run(self):
print(self.name + "男孩跑")
class Girl(Person):
def run(self):
print(self.name + "女孩跑")
b = Boy("强")
b.run()
g = Girl("花")
g.run()
类属性、类方法、静态方法
class Person:
# 类属性
count = 20
def __init__(self, name, count):
# 实例属性
self.name = name
self.count = count
# 实例方法
def run(self):
print("跑")
@classmethod
def hehe(cls):
"""
由哪一个类调用,则cls就是哪一个类的引用,一般默认使用cls名称
cls可以调用访问类的类属性和其他的类方法,注意是类方法
"""
print("我是类方法")
@staticmethod
def test():
"""如果一个属性不需要访问实例属性或者类属性,则可以定义为静态方法"""
print("静态方法")
class Boy(Person):
count = 10
def run(self):
print(self.name + "男孩跑")
class Girl(Person):
def run(self):
print(self.name + "女孩跑")
print(Person.count) # 20 获取类属性
b = Boy("强", 11)
b.run()
# 获取属性值是向上查找机制,对象存在就去对象找属性,否则去类上找,然后才去父类属性上面找
print(Boy.count) # 10
print(b.count) # 11
g = Girl("花", 12)
g.run()
"""
访问类属性:
1.类名.类属性
2.对象.类属性(不推荐)
因为对象.类属性=值 只会给对象添加一个属性,而不会影响类属性的值,所以只能获取不能修改,不推荐
"""
Person.hehe()
# 调用静态方法,不需要创建对象
Person.test()
单例模式
"""
__new__:为对象分配空间,返回对象引用
__int__:对象初始化,定义实例属性
重写new一定要由返回值,而且如果没有返回值则不会分配内存空间,则init也不会调用
"""
# 单例模式
class Person:
instance = None
init_flag = False
def __new__(cls, *args, **kwargs):
"""创建对象时候,该方法被调用"""
# 为对象分配空间
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
# 单例初始化的动作也应该只执行一次
def __init__(self):
if Person.init_flag:
return
Person.init_flag = True
p = Person()
p1 = Person()
print(id(p), id(p1)) # 139736457788272 139736457788272
异常
# try:
# num = int(input("请输入整数"))
# except:
# print("请输入正确的整数")
"""
try:
pass
except 错误类型1:
pass
except (错误类型1,错误类型2):
# 针对错误类型2,3的处理
pass
except Exception as result:
print("未知错误%s"%result)
else:
print("没有异常时候执行")
finally:
print("无论是否有异常都会执行")
python解释器抛出异常时,最后一行错误信息的第一个单词就是错误类型
"""
# 主动抛出异常
pwd=input("请输入密码:")
if len(pwd)>8:
print(pwd)
else:
ex=Exception("长度不足")
raise ex
模块
"""
import 模块名
使用:
模块名.函数/类/全局变量
指定别名:一般针对模块名太长(别名符合大驼峰命名法)
import 模块 as 模块别名
from... import 导入:导入部分
from 模块名1 import 工具名
该种导入不同模块的同名函数,后导入会覆盖前面导入的(一般通过别名解决)
从模块导入所有工具:该方式不推荐,重名提示不好提示,唯一好处就是使用可以不需要模块.的方式,可以直接使用
from 模块名 import ×
模块导入顺序:
首先搜索当前目录,然后才搜索系统目录
注意:导入文件时候会执行所有没有缩进的代码
导入的模块中,全局变量,函数,类可以被提供给外界,其他的不行
补充:模块导入的坑
from 模块名 import ×:这种方式导入,如果导入的是一个不可变类型
而且多个外部模块都导入该模块,然后修改这个x的值,发现其他模块获取的时候是不变的
其实导入就是导入模块,然后在导入的模块给被导入模块起一个别名,所以针对不可变类型
都是获取的值拷贝。记得添加global,但是如果是可变数据类型,则不会出现这种情况
针对 import x:这种情况就不会出现上面的问题,因为拿到的是模块引用,而不是模块中具体的变量
同时还要注意,引入的模块中使用时要注意添加global,否则修改的时候其实相当于定义局部变量
"""
# __name__
"""
__name__属性可以做到,测试模块的代码只在测试情况下被运行,而在被导入时不会被执行
__name__是python的一个内置属性,记录一个字符串
如果是被其他文件导入的,__name__就是模块名
如果是当前执行的程序__name__就是__main__
所以可以通过判断__name__从而避免导入模块没有缩进的代码全部自动执行的问题:
if __name__=="main":
"""
包
"""
包:
包是一个包含多个模块的特殊目录
目录下有一个特殊文件__inint__.py
报名的命名方式和变量名一致,小写字母+_
优点:
使用import 包名 可以一次性导入包中 的所有模块
__inint__.py
# 创建message目录从当前目录导入模块列表
from . import send_message
from . import revice_message
导入包:使用
import message
messsage.send_message.send()
messsage.revice_message.revice()
"""
文件
f1 = open("test.txt")
txt = f1.read()
print(txt)
print(len(txt))
print("----")
txt2 = f1.read()
print(len(txt2)) # 0
# 如果忘记close则会影响后续对文件的访问,并且会造成系统资源消耗
f1.close()
"""
文件指针:
open会默认把文件指针放到文件的初始位置,调用read会把指针放在
读取内容的末尾,但是一旦读取完毕,指针都在文件最末尾,所以第二次读取文件则
读取出来的长度是0
"""
# 打开文件的方式
"""
open默认以只读方式打开文件,所以如上形式打开无法写入内容
r:只读 默认
w:只写,如果文件不存在会自动创建,文件存在会被覆盖
a:追加,如果文件不存在会创建,文件存在指针在文件末尾
r+:读写方式打开,文件不存在,抛出异常
w+:读写方式打开,文件不存在会创建,文件存在会被覆盖
a+:读写方式打开,文件存在则文件指针放在文件的末尾,文件不存在会创建新文件并写入
wb/rb:按照二进制位进行读取/写入的,不会将读取的字节转换成字符
"""
f2 = open("test.txt", "w+")
t1 = f2.write("hello")
f2.close()
语法糖:
with open("test.txt", "rb") as f:
print(f.read())
# 按照行读取文件
"""
针对大文件读取
"""
f3 = open("test.txt")
while True:
text = f3.readline()
# 判断是否读取到内容
if not text:
break
# 每读取一行的末尾已经有一个'\n'
print(text, end="")
f3.close()
# 文件复制
# 小文件
fr = open("test.txt")
fd = open("test1.txt", "w")
fd.write(fr.read())
fr.close()
fd.close()
# 大文件
frb = open("test.txt")
fdb = open("test1.txt", "w")
while True:
txt = frb.readline()
if not txt:
break
fdb.write(txt)
frb.close()
fdb.close()
文件或目录常用管理操作
"""
首先导入os模块
文件操作:
rename:重命名 os.rename(源文件名,目标文件名)
remove:重命名 os.remove(文件名)
目录操作:
os.listdir(目录名):目录列表
os.mkdir(目录名):创建目录
os.rmdir(目录名):删除目录
os.getcwd():获取当前目录
os.chdir(目标目录):修改工作目录
os.path.isdir(文件路径):判断是否是文件
"""
文本文件编码
"""
2.x默认是ascii编码
3.x默认是UTF-8编码
2.x中使用中文
在文件第一行添加
#*-*coding:utf8 *-*
或者
# coding=utf8
虽然可以使用汉字,但是在2.x中针对汉字的遍历等还是会出错
如下解决方案:
hello=u"世界"
添加u代表字符串utf8编码格式
"""
eval
"""
eval():将字符串当成有效的表达式来求值,并返回计算结果
"""
print(eval("1+1")) # 2
print(eval("'*'*10"))
# 将字符串转换成列表,同理字典什么的也可以
print(type(eval("[1,2,3,4]"))) # <class 'list'>