首页 > 编程语言 >Python进阶二

Python进阶二

时间:2023-05-29 19:23:53浏览次数:36  
标签:__ 进阶 Python self 对象 实例 方法 函数

面向对象编程

类和实例

类:关键字class,类就是创建一个模板;实例就是将模板实例化
构造方法:__init__负责绑定类的一些必须的属性,当实例化的时候,必须接受这些属性。在类里面也可以定义函数(在里面叫方法),第一个参数必须是self,其他就跟正常函数没有啥区别了。

访问限制

当我们使用__init__方法定义一些类的属性,在外面还是可以被直接更改,可以在定义的时候在前面加一个__,确定为私有变量,外面不能直接访问了,通过实例对象也不能看了。只能再写方法才能看。(跟大二上学Java的时候一样,就是再写set方法和get方法)

继承和多态

继承
就是跟Java一样,class类的时候,右边的括号写继承那些类,子类可以获得父类的所有方法。
多态
就是当子类和父类都有同一种方法后, 字类的这个方法就会覆盖父类的这个方法。

获取对象信息

type()方法,这个就很熟悉了。还有isinstance()这个方法返回True和false。
如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个列表里面包含字符串,字符串都是这个对象的属性和方法。
三个方法getattr()、setattr()和hasattr(),我们可以直接操作一个对象的状态。

class MyObject(object):
    def __init__(self):
        self.x = 9
    def power(self):
        return self.x * self.x
obj = MyObject()

#还有一个小提醒,想给实例对象添加某个属性
obj.name = "li"
#这个就相当于在init里面加个self.name=name了。

hasattr(obj, 'x') #对象obj有属性'x'吗?返回True
setattr(obj, 'y', 19) # 设置一个属性'y'为19
getattr(obj, 'y') # 获取属性'y',返回的是19
getattr(obj, 'z', 404) # 获取属性'z',如果不存在
#,返回默认值404
#也可以用这个三个函数获取方法,同样的用法,就不写了。

实例属性和类属性

class Student():
    name_1 = "我是类属性"
    def __init__(self,name):
        self.name = name    #这个是实例属性

在类里面用init构造函数写的属性是实例属性,就是实例出来的对象有的属性,而直接在类里面定义的就是这个类本身有的属性,两个属性名字建议不要起一样的。

面向对象高级编程

__slots__方法

限制输入属性的
当我们创建一个类后,实例对象之后,需要给这个对象添加某个属性,可以直接添加(上面有代码),但是需要给对象添加某个方法的时候,可以这样

class Student():
    pass
#这个是给实例对象添加属性
a = Student()
a.name = "环"
#添加方法
from types import MethodType
def add_way(self):#注意这里要添加参数self。
    print("这个对象添加了这个方法")
a.add_way = MethodType(add_way,a)#主要是这一句
a.add_way()

但是这个给实例对象添加方法,其他这个类的实例对象不能用,所以为了给所有的实例对象都能用这个方法,可以给类绑定这个方法,可以这样做:

Student.add_way = add_way#主要是这句
b = Student()
b.add_way()
#还是上面的那个函数

跟给实例对象绑定方法不一样,给类绑定方法简洁一些。

如果我们想要限制实例对象的属性,只允许这个类的实例对象添加这几个属性。可以使用__slots__方法:

clasa Student():
    __slots__ = ("name","age")
#只允许实例对象添加这两个属性,添加其他属性就会报错
a = Student()
a.name = "环"#这句没有报错
a.score = 99#这句就会报错

还有一条就是,定义__slots__的这个类,限制实例属性的这个方法只对这个类的实例对象有限制,而对这个类的子类没有影响。

使用@property

又是一个装饰器
前面学的,当在类里面定义私有实例属性的时候,需要再写set方法和get方法来更改和访问这个属性。
python中的@property装饰器,就是负责把一个方法变成属性调用的

class Student(object):
    def get_score(self):
         return self._score
    def set_score(self, value):
        #这段if就是对输入的参数筛选的,不用管
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
a = Student()
a.set_score(30)
print(a.get_score())
#这个就是学Java那时候的一样,但是没有init这个构造函数,没有开始就设置实例属性,而是set方法获取,get方法来访问,里面没有init方法但是那个get方法就相当于是个构造方法,所以实例对象的时候不需要传值。

使用装饰器之后

class Student(object):
    #注意,这个跟上面的代码,在函数名这里变了
    @property#@property装饰的是get_score函数
    def score(self):
         return self._score
    @score.setter#这个看装饰器的名字也知道,装饰的是赋值函数
    def score(self, value):
        self._score = value

a = Student()
a.score = 50  #实际是a.get_score(50)
print(a.score)#里面的a.score实际就是a.get_score

一般@property用于只会返回参数的函数,这样实例对象调用的时候,只需要a.函数名就可以获得这个函数的返回值了。写法一般就写个返回值就行了
而@函数名.setter这个装饰器一般跟@property连用,@property会返回值,这个就是获得值,写法跟构造方法一样。
注意,这俩装饰器连用的时候,需要函数名一样。

特别注意:再写带有装饰器的函数的时候,返回值跟函数名千万不能一样,上面的代码,返回的值前面都带有一共横杠,就是跟函数名区别的,不然会陷入死循环。
练习题:

多重继承

这个简单就记得一个类可以继承多个类就行了。
一个子类可以继承多个类:class Studnet(Person,Son):这个就是继承了两个类。这个就是多重继承。
这种多重继承的设计就叫做MixIn。而只支持单一继承的Java没有。

定制类

插入一个小知识,len()方法,平时直接用len()就会返回容器的长度,但在类的里面需要这个方法能直接返回实例属性还是类属性的长度,就必须在前面调用__len__(self):

class Student():
    def __init__(self,name):
        self.name = name
    def __len__(self):
        return self.name

其实还有很多这种实用的小方法可以帮助我们定制类。

  1. str
    正常如果我们打印一个实例对象,会出来地址对象这些比较乱的东西。

    所以可以使用定义__str__这个方法,返回我们能自己看的这个实例对象

    其实这里面涉及到内部的一个__repr__()函数,正常被调用的是这个函数,返回的是这个函数的值,当定义__str__函数之后,就优先str这个函数,其实也可以在后面加一个这句话:repr = str ,也是可行的。

  2. iter
    这个方法会返回一个可迭代对象,跟len写进类里面的方法一样,把这个方法写进类里return self,就是返回自身实例对象的意思,所以需要在里面写一个next()里面不断返回值。例如:

class Fib():
    def __init__(self):
        self.a,self.b = 0,1#初始化两个计数器
    #返回自身的实例对象作为可迭代对象
    def __iter__(self):
        return self
    def __next__(self):
        self.a,self.b = self.b,self.a+self.b
        if self.a > 100:#退出循环条件
            raise StopIteration
        return self.a

for i in Fib():#在for循环里就是不断调用next方法。
    print(i)

  1. getitem
    上面写的Fib()这个实例对象,虽然可以不断返回斐波那契数列的值,但是不能像list那样,所以要表现得像list那样按照下标取出元素,需要实现getitem()方法:
class Fib():
    def __getitem__(self, item):
        a,b = 1,1
        for i in range(item):
            a,b = b,a+b
        return a

f = Fib()
print(f[0])
print(f[1])
print(f[2])
print(f[3])
print(f[4])

列表还能实现切片的功能,实例Fib()对象之后,传入的值可以像上面是个int也可以是个切片,但是上面这个函数无法识别,所以需要判断出是个切片然后再写出切片的功能,切片也是一种数据类型,也是个对象。

class Fib():
    def __getitem__(self, item):
        a,b = 1,1
        if isinstance(item,int):
            for i in range(item):
                a,b = b,a+b
            return a
        if isinstance(item,slice):
            start = item.start
            end = item.stop
            l = []
            if start is None :
                start = 0
            for i in range(end):
                a,b = b,a+b
                if i == start:
                    l.append(a)
                    start += 1
            return l
f = Fib()
print(f[0:9])#z注意传入切片的时候不加括号

除了通过定义__getitem__()方法来使对象能像列表一样,还可以做一些改动,改成字典,元组,具体实现,边看文档变自己练习。

  1. getattr
    这个getattr,后面的attr全写开就是attribute(属性,特征),当我们在类里面写这个方法之后,实例对象后,当访问一些类里面没有的属性或则和方法的时候,python解释器会去这个方法里面找相应的相应的属性和方法名,如果找到就按着返回的返回值,没有就会默认返回None。
    这个只是访问一些没有的属性的时候可以这样。

    还有可以返回一些方法。

    注意__getattr__方法里面,return的时候只需要返回函数的名字,不加括号,调用的时候加括号,说明这是个函数。

  2. call
    python里面有对象和对象的方法(方法就是函数),当我们写好类之后,需要把这个类给实例化对象,然后可以通过这个对象来调用类里面的一些方法。有没有一种写在类的函数,可以使用对象本身来调用。

    call函数就是可以通过自己本身来调用的,但也可以这样想,函数和对象之间的界限也可以模糊。能被调用的就是一个callable(可调用的)对象。

使用枚举类

枚举类型是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。
使用普通类来实现枚举:

@unique#装饰器需要写在这
#装饰器不仅仅是只能装饰函数,也能装饰类。
class color():
    YELLOW  = 1#RED是键,数字是值
    RED     = 2
    GREEN   = 3
    PINK    = 4
# 访问枚举项
print(color.YELLOW)#需要根据value的值获得枚举常量

但枚举类要求里面的键不能相同,而且不能在外部修改。而且这样定义比较麻烦,所以可以使用python内置的enume模块(不是前面那个enumerate返回元素跟索引的那个函数)。

  1. 枚举类不能被实例化为对象
  2. 枚举类里面定义的Key = Value,在类外部不能修改Value值。
  3. 导入Enum之后,一个枚举类中的Key和Value,Key不能相同,Value可以相,但是Value相同的各项Key都会当做别名。
  4. @unique装饰器可以帮助我们检查保证没有重复值。
    但是像上面那样创建枚举类比较麻烦,可以直接使用Enum()函数来创建枚举类。
from enum import Enum

Month = Enum('month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

Enum("第一个参数,用来写枚举类的类名",("第二个参数一般用来放枚举变量的元组")),上面代码又在前面写个Month,但是枚举类是不能创建实例对象的,我的理解就是第一个参数,其实就是个可以填充的参数,前面的填充过来。最后还是以Month为准。
每一个元组变量都有name和value这两个属性,name就是元组里面的变量名,value代表该枚举元素的序号(序号通常从1开始)。如果你再赋值,肯定以你赋值的为准。
python为枚举类提供了一个__members__方法,当枚举类调用这个方法,会返回字典,这个字典的键是变量名,值是一个枚举元素,有name和value这里属性。

元类

#使用type()来创建类
def f(self):#注意在外面写函数的时候还是需要写self的
    print("这个方法被调用了")
#前面还是得写个类名=,我的理解还是跟上面创建Enum枚举类一样,填充类名。
Student = type("Student",(),dict(add = f))#这样这个类就创建好了
a = Student()
a.add()

type()一般用来返回类或对象的属性,其实也可以被用来创建类
使用type()创建一个类,需要传入三个参数:

  1. class的名称;
  2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
  3. class的方法名称与函数绑定,这里我们把函数f绑定到方法名add上。(不知道为什么要用dict的写法,反正就这样写,而且需要绑定的函数在外面提前写,里面还是得加self的参数的)
    通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。所以在python内部,最后还是调用的type()来创建类。

metaclass这个叫元类
现在估计也不咋用,而且也看不懂,以后需要再来学。反正就是可以通过metaclass来修改类定义的,以后遇到再来看。
元类是面向对象高级最难理解的一块了,也是最后一块。

错误,调试和测试

错误

就是try-except,其实还有个finally就是写在后面一定会执行的。
还有一个抛出错误raise,这个就是主动抛出错误,自己知道哪错了,自己主动抛出错误。

调试

断言 assert

def foo(s):
    n = int(s)
    assert n != 0, 'n is zero!'
    return 10 / n

assert就是断言,断言后面是个表达式,如果表达式是Flase错误,就会返回后面那句话。可以通过-0(具体在哪写我也不知道),把这句断言给省略掉,就是pass的意思了。

logging

logging允许我们指定记录信息的级别,有debug,info,warning,error等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。
这个就是指定信息info。

pdb调试器

就是pycharm的debug设置断点啥的。还是得多练这个

单元测试

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。(需要看再补)

文档测试

Python内置的“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。同样,用到再来学。

IO进程

文件读写

读取文件f = open("路径","r"),然后调用f.read()方法来打印文件的所有内容,输出成str。最后f.close(),不然会占用内存。但是可以用with语句可以帮我们自动close。

with open('/path/to/file', 'r') as f:
    print(f.read())

还有要是文件很大,读进内存里放不下,可以在read()传入参数,来说明读入多少。还可以调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list。

要读取二进制文件,比如图片、视频等等,用'rb'模式打开文件即可,就在读取的时候把后面的"r"改成“rb”就可以了。

字符编码
要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数,例如,读取GBK编码的文件:

f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')
f.read()

写文件
跟读文件一样,不过读取的时候传入的是“w”或是“wb”,而且调用的是write方法。因为写文件是把写的操作放进内存,只有最后调用close才会写进磁盘,所以还是用with语句最好。

StringIO和BytesIO(读和写的操作不能同时用)

StringIO和BytesIO也是一个对象,可以直接在写在内存里,然后直接在内存中读取。但是得提前声明这是个StringIO和BytesIO对象。

StringIO

读入:
这个就是单独一个读入的操作,我写一个StringIO对象放进内存里,但是不能调用read()方法查看,但是有一个内置的getvalue()方法可以用来查看。

读取:
这个里面就是写操作,可以调用read()方法。

BytesIO

字节流跟字符流操作都是一样,不过字节流可以操作二进制的数据:
f.write('中文'.encode('utf-8'))
其他都跟字符流的操作一样。

操作文件和目录

就是os模块的一些操作
查看当前目录的绝对路径:
os.path.abspath('.') >'/Users/michael'
创建一个目录
os.mkdir('/Users/michael/testdir')
删除一个目录
os.rmdir('/Users/michael/testdir')
把两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()函数
os.path.join('/Users/michael', 'testdir')
'/Users/michael/testdir'

序列化

把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling。序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
Python提供了pickle模块来实现序列化。

这个就是把这个字典d给写进磁盘了。这里用的是pickle.dumps(),这个加了s就是只把这个数据给序列化成一个字节类型数据,能够写入文件里,(但是还没写,因为没有指定哪个文件)。所以还要另一个方法,pickle.dump(),比上面多一个s的多一个功能,就是还可以传入一个文件对象,然后把字节型数据给写入传入的文件里。:

f = open('dump.txt', 'wb')#随便一个文件,以二进制可写的形式读入
pickle.dump(d, f)
f.close()

反序列化

当我们要把对象从磁盘读到内存时(就是上面的操作反过来),可以直接用pickle.load()方法从一个file-like Object(这个obj就是可以用open()和read()方法的,StringIO和BytesIO也同样是这样)中直接反序列化出对象。我们打开另一个Python命令行来反序列化刚才保存的对象:

f = open('dump.txt', 'rb')
d = pickle.load(f)
f.close()
#这样d就是之前的那个字典了

JSON(重点)

要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如手机上都可以查看的XML。
但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。
所以来学习JSON
Python内置的有JSON转换的库

import json

d = dict(name="li",age=20,gender="男")
json.dumps(d)

把字典转换成JOSN字符串,其实就是这样的"{"age": 20, "score": 88, "name": "Bob"}"这就是转换的JSON字符串。
这样就是把这个字典d给转换成一个JSON类型(其实也是个字符串)的数据了,跟上面的dump()用法一样,没有加s,就是写进file-like Object里(就是写进一个文件里)。同样反序列化也是跟上面一样用的load和loads(),load()这个传入这个file-like Obj,反正就是load(),少一个s的重要些。

总之就记得dump()是转成JSON,load()是转回来。(dump(去),load(回))

也同样,最好是搭配with语句,省的忘了写close:

# 写成 JSON 数据 “去”
with open('data.json', 'w') as f:
    json.dump(data, f)
 
# 读取数据 “回”
with open('data.json', 'r') as f:
    data = json.load(f)

JOSN进阶

如果我们要传输自己定义的类的对象,首先得序列化,但是下面这样会明显报错,这是因为默认情况下,dumps()方法不知道如何将Student实例变为一个JSON字符串对象。就像默认知道怎么把字典对象转化成JSON字符串,但是对于一个新的Student是不知道的。
所以在dumps()里面可以有很多参数,这些参数以后会接触到的。

有个参数defalut就是把任意一个对象变成一个可序列为JSON的对象,需要写一个函数,这个函数把实例化的对象传入这函数,defalut参数就会把这个函数的返回值给序列里化。
所以上面的代码可以加一个参数,就能使用了。其中函数studentTodict就是把传入的类对象a给返回字典类型的对象,然后就能转成JSON字符串了。

上面是把对象给转换成JSON字符串,还有把JSON给转回对象,里面也需要写个函数,也需要load()里面的参数,具体在文档里。

剩下还有很多参数,需要慢慢再去学。

标签:__,进阶,Python,self,对象,实例,方法,函数
From: https://www.cnblogs.com/huanc/p/17441378.html

相关文章

  • Python进阶一
    使用MarkDown学习Python。(前面基础的都在XMind)进制转换转成十进制(一般是二进制,八进制,十六进制):所有转成十进制的,都只需要int(原数字的字符串格式,进制数)a="1001"s=int(a,2)这个就是把二进制的数字a转成十进制print(s)十进制转十六进制(使用函数hex())print(hex(1033......
  • Python进阶六
    网络编程TCP编程详细都写CSDN上了。使用来socket建立连接TCP连接是一种可靠的连接,这里建立基于TCP协议连接的socket,客户端主要是获取服务器信息的importsocket#前面这个套接字是表示IPV的就是IP地址的类型,是IPV4,有一个是AF_INET6表示IPV6。#第二个表示是流格式套接......
  • Python进阶五
    常用的第三方模块数据分析的常用模块(导师安排)numpynumpy就是操作多维数组,对象是ndarray,就相当于python自己内置的列表list,但是ndarray比list更高效。type(),dtype,astype:在numpy里面有比python内置更多的数据类型,也更精确,比如int32,uint(无符号整数),dtype和type(),都是返回......
  • 16 个必知必会的 Python 教程!
    1.三元运算符三元运算符是if-else语句的简写。语法是value_if_trueifconditionelsevalue_if_false。三元运算符是一行代码,可以替代多行if-else语句,使你的代码更加简洁。1a=52b=103max=aifa>belseb#value_if_trueifconditionelsevalue_if_fal......
  • Python进阶三
    进程和线程一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程;在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,把进程内的这些“子任务”称为线程(Thread),比如Word,它可以同时进行打字、拼写检查、打印等事情。......
  • Python进阶七
    访问数据库importsqlite3#连接一个数据库,要是没有就会自己创建一个conn=sqlite3.connect("MySQL.db")#创建一个游标,用于执行SQL语句cursor=conn.cursor()##创建表创建表的一般结构就是:createtable<表名>(<属性名字类型>,......);#或者也可以把要执行的语......
  • python中测试方法所用的时间—timeit
    方法代码使用timeit方法测试两个函数的运行速度importtimeitstrlist=['Thisisalongstringthatwillnitkeepinmemory.'forninrange(10000)]defuse_join():#使用字符串的join方法连接多个字符串return''.join(strlist)defues_plus():#使用运算符+连接多个字......
  • python使用hTTP方法
    Python中可以使用requests库来发送HTTP请求,其中包括GET、POST、PUT、DELETE等方法。下面是一个使用requests库发送HTTP请求的示例:importrequests#发送GET请求response=requests.get('ExampleDomain')#发送POST请求data={'key1':'value1','key2':'val......
  • python 实现google authenticator 认证
    importosimporttracebackimportpyotpfromqrcodeimportQRCode,constantsclassGoogleAuthenticatorClient:def__init__(self,secret_key=None):self.secret_key=secret_keydefcreate_secret(self):"""生......
  • python 读取、写入、追加、覆盖xls文件
    python读取、写入、追加、覆盖xls文件0、写在前面测试源xls是这样的1、读取xlsdefread_xls(filename:str,sheet_name:str)->List[list]:filename=os.path.abspath(filename)assertos.path.isfile(filename),f'{filename}isnotfile'assertfilen......