0
点赞
收藏
分享

微信扫一扫

Python(二、面向对象)

Mhhao 2021-09-27 阅读 68

封装


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'>
举报

相关推荐

0 条评论