Python进阶知识

目录

一、装饰器和闭包

1、装饰器 decorator

2、闭包 closure

二、迭代器与生成器

二、面向对象编程

1、概念

2、类和对象

2.1 概念

2.2 定义类和创建对象

2.3  __init__(self):

2.4 self的理解

3、魔术方法

3.1__str__()

3.2 __new__()

4、析构方法

5、类的继承*

5.1 单继承

5.2 多继承

5.3 重写和调用父类方法

6、多态

7、类方法和静态方法

8、私有化属性和方法--保护和控制数据

8.1私有化属性

 8.2 私有化方法

9、property属性函数

实现方法1-- 类属性

实现方法2:装饰器*

 11、异常处理

 Python内置异常类型:

Exception:万能类型、可以捕获所有异常

自定义异常

12、动态添加属性和方法

12.1 动态添加属性

12.2动态添加方法(需要用到types模块)

12.3 动态绑定类方法和静态方法

13、__slots__属性


一、装饰器和闭包

1、装饰器 decorator

定义:在不修改目标函数代码的前提下,为目标函数添加新功能的函数。

本质上就是一个函数(或类)

作用:为函数增加新功能,减少重复性操作,使代码简洁

使用场景:性能测试、打印日志等

使用装饰器的步骤:

  1. 定义装饰器
  2. 通过@调用装饰器
import time
#定义装饰器
def timer(function):
    def wrapper():
        time_start=time.time()
        function()
        time_end=time.time()
        cost_time=time_end-time_start
        print("花费时间:{}秒".format(cost_time))
    return wrapper

#通过@调用装饰器
@timer
def func1():
    print('我是一个函数1')

@timer
def func2():
    print('我是一个函数2')

func1()
func2()

# 我是一个函数1
# 花费时间:0.0秒
# 我是一个函数2
# 花费时间:0.0秒

2、闭包 closure

定义:在一个内部函数里,对外部作用域(但不是全局作用域)里变量进行引用,这个内部函数就是闭包

def f():
    a=1
    def g():
        nonlocal a#只访问不更改不需要nonlocal,更改需要添加nonlocal
        a += 1
        print(a)
    return g

g1=f()
g2=f()

g1()#2
g1()#3
g1()#4
g2()#2
def f():
    a=[[],[]]
    def g():
        a[0].append(111)
        print(a)
        print(id(a[0]),id(a[1]))

    return g

g1=f()
g2=f()

g1()
g1()
g2()
#[[111], []]
#2043067833216 2043066699392
#[[111, 111], []]
#2043067833216 2043066699392
#[[111], []]
#2043067833664 2043067832704

二、迭代器与生成器

 迭代:一种操作,逐个获取数据的过程称为迭代,如for循环

可迭代对象()、[ ]、{ }、文件对象都是可以迭代的

迭代器 iterator:它包含一组元素,每次调用会返回自身的下一个元素,一个迭代器对象必须是定义了_iter()_方法和next()方法的

  • 所有可迭代对象都可以用 lter() 函数转变为迭代器
  • 迭代器对象可以用next() 不断返回下一个数据,但是当所有元素都被返回时,再执行next(),程序会报错--stoplteration
  • 不能提前知道序列长度,即不能使用len()计算序列长度

生成器 generator :是特殊的迭代器

定义:在Python中,使用了yield的函数 就是生成器

在调用生成器运行的过程中,每次遇到yield时,函数会暂停并保存当前所有运行信息,返回yield值,并在下一次执行next()方法时从当前位置继续运行

#简单的生成器示例:利用生成器输出1-10000000000的数
list=(i for i in range(1,10000000001))
for item in list:
    print(item)

注意:这里是(),而不是[ ],如果使用列表,内存会爆炸

# 生成器
def gen(num):
    while num>0:
        yield num
        num -= 1
    return

g=gen(5)#调用生成器函数,返回一个生成器对象到g里

first=next(g)#使用next函数时才开始真正运行他的函数本体,此时first=5
for i in g: #每次都call了个next
    print(i)
#4
#3
#2
#1

迭代器和生成器的区别

从使用者角度,生成器和迭代器是没什么区别的,使用方法几乎一样

        生成器有send用法,在生成器yield之后,把yield的东西变成一个值,这个值还可以继续赋给生成器函数中的其他变量

#send用法
def gen(num):
    while num>0:
        tmp=yield num #将yield的值赋给tmp
        if tmp is not None:
            num=tmp
        num-=1

g=gen(5)
first=next(g) #first=g.send(None)
print(f"first:{first}")
print(f"send:{g.send(10)}")#10赋值给tmp,num=tmp=10,next()出10

for i in g:
    print(i)

# first:5
# send:9
# 8
# 7
# 6
# 5
# 4
# 3
# 2
# 1

从背后原理,迭代器是将迭代时的状态保存到一个对象里的;生成器是将状态保存到frame,它的状态是函数记录到哪一步,而不是通过一个变量记录状态,更为简洁

生成器的代码量比传统的迭代器少很多

二、面向对象编程

oop三大特征:继承、多态、封装

1、概念

面向过程:一开始学习的,按照解决问题的步骤编程【根据业务逻辑从上到下编程】

函数式:将某功能代码封装到函数中,下次使用直接调用,无需重复编写

面向对象编程:将数据与函数绑在一起封装,这样能够更快速的开发程序,减少重复代码的重写过程 oop(object oriented programming),是一种解决软件复用的设计和编程方法,这种方法将软件系统中相近相似的操作逻辑和操作应用数据、状态,以的形式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用

面向过程适合做小项目,面向对象适合做大项目

2、类和对象

2.1 概念

类:一个模板,模板里包含多个函数,函数中实现一些功能(汽车图纸、车类)

是一组具有相同或相似属性和行为的多个对象的组合

对象:类的实例化,可以执行类中的函数(宝马)

2.2 定义类和创建对象

定义类:类结构=类名(首字母大写)+属性+方法行为

实例方法:在类内部,用def可以定义实例方法,与一般函数不同的是实例方法必须包含参数,默认第一个参数是self(名字标识可以是其他名字,但这个位置必须被占用)

# class 类名:
#     属性
#     方法
class Person:#类名:首字母大写
    #属性
    name='小明'#类属性
    age=20
    #方法(行为) 实例方法
    def eat(parms):
        parms.name='小红'#实例属性
        print('eating')
        pass
    def run(self):
        print('running')
        pass
    pass

创建对象

格式:对象名=类名()

#创建对象[类的实例化]
xm=Person()
#调用函数
xm.eat()
print('{}的年龄是:{}岁'.format(xm.name,xm.age))

属性

  • 类属性:类对象所拥有的属性(定义在类内部,实例方法外)
  • 实例属性:实例对象拥有的属性,只能通过实例对象访问(实例方法内定义的【通过类似于self.变量名】变量)
class Student:
    name='李明'#类属性
    def __init__(self,age):
        self.age=age#实例属性
        pass
    pass

lm=Student(18)
print(Student.name)
print(lm.name)#类属性可以被类对象和实例对象访问
print(lm.age)#实例属性只能通过实例对象访问
print('不能通过类对象访问实例属性')
print(Student.age)

# 李明
# 李明
# 18
# 不能通过类对象访问实例属性
# Traceback (most recent call last):
#   File "E:\资源下载\workspace\shixun\pythonProject2\2.17多态.py", line 47, in <module>
#     print(Student.age)
# AttributeError: type object 'Student' has no attribute 'age'

类属性和实例属性的访问原理:

2.3  __init__(self):

Python自带的内置函数

是一个初始化方法,用来定义实例属性和初始化数据,在创建对象时自动调用

class Person:
    def __init__(self):
        self.name='小倩'
        self.age=20
    def run(self):
        print('running')
        pass
    pass

xq=Person()#创建新对象时,__init__自动调用
print(xq.name)
#小倩

传递参数(后面实例方法都可以直接使用该参数)

class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def eat(self,food):
        print(self.name+'喜欢吃'+food)

xm=Person('小明',21)
xm.eat('苹果')

2.4 self的理解

self和对象指向同一内存地址,self是对象的引用,可以理解为对象自己

class Person:
    def eat(self):
        print('self=%s',id(self))
        pass
    pass

xm=Person()
xm.eat()
print('xm=%s',id(xm))
#self=%s 1760559500112
#xm=%s 1760559500112
  • self只有在类中定义实例方法时才有意义,在调用时不必传入相应参数,而是由解释权自动指向
  • self的名称可以更改,只是约定俗成的定义成了self
  • self指的是类实例对象本身

self传参:

class Person:
    def __init__(self,pro):
        self.pro=pro
    def eat(self,name,food,pro):
        print('%s喜欢吃%s,修的专业是%s,%s'%(name,food,self.pro,pro))
        pass
    pass

xm=Person('通信工程')
xm.eat('小明','榴莲','hhh')
# 小明喜欢吃榴莲,修的专业是通信工程,hhh

3、魔术方法

定义:Python中的一些内置好的特定方法,方法名为“__xxx__”,前后有两个下划线

  • 在进行特定操作时,魔术方法会自动调用

常见的魔术方法:

3.1__str__()

定义了__str__方法,在打印对象时,会执行__str__方法(__str__只能return一个字符串)

class Animal:
    def __init__(self,name,colour):
        self.name=name
        self.colour=colour
    def __str__(self):
        return '我的名字是%s,我的颜色是%s'%(self.name,self.colour)

dog=Animal('旺财','白色')
print(dog)
#我的名字是旺财,我的颜色是白色
#改变打印对象的内容

class Animal:
    def __init__(self,name,colour):
        self.name=name
        self.colour=colour

dog=Animal('旺财','白色')
print(dog)
# <__main__.Animal object at 0x000001E49FEF6FD0>
#直接输出对象的地址

3.2 __new__()

调用对象实例的方法,每调用一次生成一个新对象,cls是class的缩写

class Animal(object):
    def __init__(self,name,colour):
        self.name=name
        self.colour=colour
        print('__init__函数执行')
    def __str__(self):
        return '我的名字是%s,我的颜色是%s'%(self.name,self.colour)
    def __new__(cls, *args, **kwargs):
        print('__new__函数执行')
        # return object.__new__(cls)#这里真正创建对象实例

dog=Animal('旺财','白色')
print(dog)
#__new__函数执行
#None
#解释:还没有生成对象实例
class Animal(object):
    def __init__(self,name,colour):
        self.name=name
        self.colour=colour
        print('__init__函数执行')
    def __str__(self):
        return '我的名字是%s,我的颜色是%s'%(self.name,self.colour)
    def __new__(cls, *args, **kwargs):
        print('__new__函数执行')
        return object.__new__(cls)#这里真正创建对象实例
#        return super().__new__(cls)#若没有父类object,用super()创建对象实例

dog=Animal('旺财','白色')
print(dog)
# __new__函数执行
# __init__函数执行
# 我的名字是旺财,我的颜色是白色

#先执行__new__(),创建对象实例后执行__init__
#__new__()创建实例框架,__init__丰满

__new__方法在__init__方法前执行

__new__方法不能调用自己的__new__方法,即:return cls.__new__(cls)

  • 否则会报错:RecursionError:maximum recursion depth exceeded超过最大递归深度

__new__和__init__的区别

  • __new__:类的实例化方法,必须返回该实例,不然对象创建不成功
  • __init__:做对象的初始化工作,也可以认为是实例的构造方法,接受该实例self并对其构造
  • __new__至少一个参数是cls,代表要实例化的类,该参数在实例化时由Python解释器自动提供
  • __new__要早于__init__函数执行

课后问答

4、析构方法

当一个对象被删除或销毁时,Python解释器默认调用__del__()方法,这个方法也称析构方法,也是一种魔术方法

  • 用于对象的释放,对象一旦被释放,不能再使用

程序执行结束自动调用__del__()

class Animal:
    def __init__(self,name):
        self.name=name
        print('__init__执行')
    def __del__(self):
        print('__del__执行')
    pass

cat=Animal('cat')
print('程序等待中。。。')

# __init__执行
# 程序等待中。。。
# __del__执行

对象被删除时,也会自动调用__del__方法

class Animal:
    def __init__(self,name):
        self.name=name
        print('__init__执行')
    def __del__(self):
        print('__del__执行')
    pass

cat=Animal('cat')
del cat#手动去清理对象
print('*'*20)

# __init__执行
# __del__执行
# ********************

5、类的继承*

Python面向对象的三大特征:封装、继承、多态

封装:把内容封装到某个地方,便于后面的使用【其实就是使用初始化构造方法将内容封装到对象中,然后通过对象直接或者self来获取封装的内容】

继承:即子可以继承父的内容(属性和行为)

  • 将多个类共有的方法提取到【父类】中,然后通过继承,极大提高了效率,减少代码的重复编写

5.1 单继承

class Animal:
    def eat(self):
        print('eating')

class Cat(Animal):
    pass


cat1=Cat()
cat1.eat()
#eating

5.2 多继承

子类继承多个父类,用逗号分隔  class C(A,B)

问题是:当多个父类中存在相同方法时,应该调用哪一个呢?

class E:
    def eat(self):
        print('E.eat')
class D:
    def eat(self):
        print('D.eat')
class C(E):
    # def eat(self):
    #     print('C.eat')
        pass
class B(D):
    pass
class A(B,C):
    pass

a1=A()
a1.eat()#查找顺序,A中没有,找B,B中没有,找C
print(A.__mro__)
# D.eat
# (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)

__mro__方法:查询执行顺序

继承的传递性:爸爸继承了爷爷,儿子继承爸爸,也继承了爷爷

5.3 重写和调用父类方法

子类中有个跟父类方法名称一样的方法,相当于重写父类方法(方法覆盖)

重写父类方法后,子类调用父类方法时,调用的是子类的方法

class Father:
    def eat(self):
        print('爸爸')
    pass

class Son(Father):
    def eat(self):
        print('儿子')
    pass
son=Son()
son.eat()
print(Son.__mro__)
# 儿子
# (<class '__main__.Son'>, <class '__main__.Father'>, <class 'object'>)

调用父类方法

class Dog:
    def __init__(self,name,color):
        self.name=name
        self.color=color
    def bark(self):
        print('汪汪汪。。')

class Keji(Dog):
    def __init__(self,name,color,age):#重写父类方法
        # Dog.__init__(self,name,color)#调用父类方法1--手动调用
        super().__init__(name,color)#调用父类方法2--自动调用:super()自动查找父类方,进而调用方法
        self.age=age
    def dark(self):
        print('啊啊啊。。')
        super().bark()#调用父类方法
        print('啊啊啊。。')
    def msg(self):
        print('名字:%s,颜色:%s,年龄:%s'%(self.name,self.color,self.age))

keji=Keji('柯基','黄白',2)
keji.dark()
keji.msg()
# 啊啊啊。。
# 汪汪汪。。
# 啊啊啊。。
# 名字:柯基,颜色:黄白,年龄:2

super():假如继承了多个父类,则会按顺序查找

class Animal:
    def bark(self):
        print('动物叫。。')

class Keji(Animal,Dog):
    def __init__(self,name,color,age):#重写父类方法
        # Dog.__init__(self,name,color)#调用父类方法1
        super().__init__(name,color)#调用父类方法2:super()自动查找父类方,进而调用方法
        self.age=age
    def dark(self):
        print('啊啊啊。。')
        super().bark()#调用父类方法
        print('啊啊啊。。')
    def msg(self):
        print('名字:%s,颜色:%s,年龄:%s'%(self.name,self.color,self.age))

keji=Keji('柯基','黄白',2)
keji.dark()
keji.msg()
# 啊啊啊。。
# 动物叫。。
# 啊啊啊。。
# 名字:柯基,颜色:黄白,年龄:2

6、多态

定义:就是多种状态(形态),就是同一种行为,对于不同子类【对象】有不同的行为表现

想实现多态必须满足的两个条件:

  1. 继承:多态必须发生在父态和子态之间
  2. 重写:子类重写父类方法

作用:增加程序的灵活性和扩展性

鸭子类型:在程序设计中,鸭子类型是动态类型的一种风格。“鸭子测试”可以表述为:“当一个鸟走起来像鸭子,叫起来像鸭子,那么这只鸟可以称为鸭子”

class Animal:
    def say(self):
        print("动物叫")
    pass

class Dog(Animal):
    def say(self):
        print('汪汪汪')
    pass
class Cat(Animal):
    def say(self):
        print('喵喵喵')
    pass

# dog=Dog()
# dog.say()
# cat=Cat()
# cat.say()

def common(obj):
    obj.say()
i=[Dog(),Cat()]
for item in i:
    common(item)
# 汪汪汪
# 喵喵喵

7、类方法和静态方法

类方法:类对象所拥有的方法,用装饰器@classmate标识,类方法的第一个参数必须是类对象,一般以cls作为第一个参数。

可以通过类对象、实例对象调用

class Student:
    name='李华'#类属性

    @classmethod
    def get_name(cls):
        return cls.name#访问类属性

    @classmethod
    def change_name(cls,new_name):
        cls.name=new_name#在类方法中修改类属性的值


print(Student.get_name())#类对象引用
lh=Student()
print(lh.get_name())#实例对象引用
# 李华
# 李华
Student.change_name("小花")
print(Student.get_name())#类对象引用
xh=Student()
print(xh.get_name())#实例对象引用
# 小花
# 小花

静态方法:类对象所拥有的方法,需要用@staticmethod来表示静态方法

class Student:
    name='李华'#类属性
    @staticmethod
    def getdate():
        return  Student.name

print(Student.getdate())#类对象引用
lh=Student()
print(lh.getdate())#实例对象引用
# 李华
# 李华

静态方法一般不会通过实例对象访问

为什么使用静态方法?

静态方法主要用来存放逻辑性代码,在静态方法中,不会涉及到类中方法和属性的操作,数据资源能得到有效利用

#引入第三方时间模块
import time
class Timetest:
    @staticmethod
    def showtime():
        return time.strftime("%H:%M:%S",time.localtime())
    pass

print(Timetest.showtime())
# 15:46:56
  • 类方法的第一个参数是类对象cls,进而去引用类对象的属性和方法
  • 实例方法的第一个参数必须是self,通过self去引用类属性或实例属性,若存在相同名称实例属性和类属性,实例属性优先级最高
  • 静态方法不需要定义额外参数,需要引用属性时,可通过类对象或实例对象去引用

8、私有化属性和方法--保护和控制数据

8.1私有化属性

保护属性安全,不得随意修改,将属性定义成私有化属性,添加可调用的方法去访问

使用私有化属性的场景:

  1. 把特定属性隐藏,不想让类的外部直接调用(不能在外部直接访问,在类的内部可以随意访问)
  2. 保护这个属性,不想让该属性的值随意改变(内部可以修改)
  3. 保护属性,不想让派生类【子类】去继承(子类不能继承父类的私有属性)

语法:两个下划线开头,声明属性为私有属性,不能在类的外部被使用或直接访问

class Person:
    def __init__(self):
        self.name='李四'
        self.__age=18#属性私有化(外部不能访问,内部可以访问)
        pass
    def __str__(self):
        return('{}的年龄是{}'.format(self.name,self.__age))

x1=Person()
print(x1)
print(x1.name)
print(x1.__age)#通过类对象在外部访问(私有化后,不能在外部直接访问)

# Traceback (most recent call last):
#   File "E:\资源下载\workspace\shixun\pythonProject2\2.17多态.py", line 125, in <module>
#     print(x1.__age)#通过类对象在外部访问(私有化后,不能在外部直接访问)
# AttributeError: 'Person' object has no attribute '__age'
# 李四的年龄是18
# 李四

 8.2 私有化方法

语法:方法名前加两个下划线

  • 私有化的方法不能被【子类】继承
  • 外部不能直接调用,内部可以调用

__xxx:方法私有化

__xxx__:魔术方法,Python自有,开发者不要创建

xxx_:避免属性名与Python关键字冲突

9、property属性函数

让调用者能直接以访问属性的方式,而且又能控制的方式

实现方法1-- 类属性

class Animal(object):
    def __init__(self):
        self.__age=18#私有化属性
    def dog(self):#访问私有属性
        return self.__age
    def chance(self,age):#修改私有实例属性
        if age<0:
            print('年龄不能小于0')
            pass
        else:
            self.__age=age
    #定义一个类属性,实现直接访问属性的形式去访问私有的属性
    age=property(dog,chance)

a1=Animal()
print(a1.age)#访问私有属性
#18
a1.age=2#修改私有属性
print(a1.age)
#2

实现方法2:装饰器*

即在方法上使用装饰器

class Animal(object):
    def __init__(self):
        self.__age=18#私有化属性

    @property#通过装饰器修饰添加属性标志,提供一个getter方法
    def dog(self):#访问私有属性
        return self.__age

    @dog.setter#提供一个setter方法
    def chance(self,parms):#修改私有实例属性
        if parms<0:
            print('年龄不能小于0')
            pass
        else:
            self.__age=parms
            pass


a1=Animal()
print(a1.dog)#访问私有属性
#18
a1.chance=2#修改私有属性
print(a1.dog)
#2

10、__new__方法(参考3.2)和单例模式

单例模式:一种常用的软件设计模式

目的:确保某个类中只有一个实例存在

实现步骤:利用类属性保存初次创建的实例对象,第二次实例化对象的时候判断类属性是否保存实例对象,如果有就返回类属性保存的,如果没有就调用父类__new__方法创建新的实例对象

class Student(object):
    __instance=None
    def __init__(self,name,age):
        self.name=name
        self.age=age
        pass
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance=super(Student,cls).__new__(cls)#没有保存实例,就保存
            return cls.__instance
        else:
            return  cls.__instance
        pass
    pass

xm=Student('LH',19)
print(id(xm))
xh=Student('XH',20)
print(id(xh))

# 2390515351312
# 2390515351312
#id相同,说明实例化两次对象,都是同一对象

 11、异常处理

语法格式:

try:
    可能出现错误的代码块
except:
    出错后执行的代码块
else:
    没有错误执行的代码块
finally:
    不管有没有出错都要执行的代码块
try:
    x=x/2
    print(x)
except NameError as msg:
    print(msg)

#name 'x' is not defined

 Python内置异常类型:

Exception:万能类型、可以捕获所有异常

自定义异常

  • 要直接或间接继承Error或Exception
  • 用raise关键字抛出异常
class Toolong(Exception):
    def __init__(self,leng):
        self.leng=leng
        pass
    def __str__(self):
        return '你的长度为%s,过长了。。'%self.leng
    pass


def name_test():
    name=input('请输入你的名字:')
    try:
        if len(name)>4:
            raise Toolong(len(name))
        else:
            print(name)
            pass
        pass
    except Toolong as msg:
        print(msg)
    finally:
        print('执行完毕')

name_test()
# 请输入你的名字:chenq
# 你的长度为5,过长了。。
# 执行完毕

12、动态添加属性和方法

动态语言能在运行时改变其结构;Python、php、JavaScript是动态语言,c、c#、Java是静态语言

所有,Python在程序运行过程中添加属性和方法

12.1 动态添加属性

#动态添加属性
class Animal:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def say(self):
        print('%s 年龄:%s'%(self.name,self.age))
    pass

cat=Animal('小猫',2)
cat.say()

cat.color='花色'#给对象动态添加属性
print(cat.color)
Animal.color='白色'#给类动态添加属性
print(Animal.color)

#小猫 年龄:2
#花色
#白色

12.2动态添加方法(需要用到types模块)

语法:

import types#引入代码块
def 方法名(self):
    xxx
    pass

class 类名:
    xxx
pass

实例名=类名()
实例名.引入方法的新名字=types.MethodType(方法名,实例名)#动态添加方法
实例名.引入方法的新名字()#调用新方法
import types#引入types模块
def run(self):
    print("%s 岁的%s在跑。。"%(self.age,self.name))

class Animal:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    pass

cat=Animal('小猫',2)
cat.run=types.MethodType(run,cat)#动态添加方法
cat.run()#调用方法
#2 岁的小猫在跑。。

12.3 动态绑定类方法和静态方法

语法:类名.新名字=类方法名

@classmethod
def classTest(cls):
    print('这是个类方法')
    pass
@staticmethod
def staticTest():
    print("这是个静态方法")
    pass

class Animal():
    pass
#动态给类添加类方法、静态方法
Animal.classnewname=classTest
Animal.staticnewname=staticTest
#调用类方法,静态方法
Animal.classnewname()
Animal.staticnewname()

13、__slots__属性

作用:限制可以添加的实例属性

class Animal(object):
    __slots__ = ('name','age','weight')#限制添加的属性
    def __str__(self):
        return '%s 。。。%s'%(self.name,self.age)
    pass
xh=Animal()
xh.name='小花'
xh.age=20
xh.weight=45
# xh.height  被限制,运行会报错
print(xh)#小花 。。。20

__dict__:所有可用的属性都存储在这,占用内存高;使用__slots__后,实例中不再有__dict__

class Animal(object):
    # __slots__ = ('name','age','weight')#限制添加的属性
    def __str__(self):
        return '%s 。。。%s'%(self.name,self.age)
    pass
xh=Animal()
xh.name='小花'
xh.age=20
xh.weight=45
# xh.height  被限制,运行会报错
print(xh)#小花 。。。20
print(xh.__dict__)#没有设置__slots__时,所有可用的属性存储在这
# 小花 。。。20
# {'name': '小花', 'age': 20, 'weight': 45}

slots的作用:限制实例的属性;节约内存空间

子类继承父类时,若不声明slots,不继承父类的slots;声明slots后,子类限制属性=父类+自身

class Animal(object):
    __slots__ = ('name','age','weight')#限制添加的属性
    def __str__(self):
        return '%s 。。。%s'%(self.name,self.age)
    pass

class Dog(Animal):
    __slots__ = ('color')#未声明时,不继承父类__slots__,声明后,限制属性=父类+自身
    pass
dog=Dog()
dog.color='白色'
print(dog.color)
# 白色
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python进阶之路》是一本非常值得推荐的Python进阶书籍。这本书由一位经验丰富的Python大牛所著,作者拥有超过20年的Python开发经验。这本书涵盖了许多Python进阶知识点,如元编程、动态属性、属性描述符、异步处理等。书中详细列举了这些高级特性的使用方法,并讲解得非常透彻。如果你想从入门迈向进阶,这本书是必备的参考资料。 另外,《Python Cookbook》也是一本非常受欢迎的Python进阶书籍。这本书总结了大量精妙的编程技巧和实用的技术,无论你是Python新手还是老手,都会从中收获很多。豆瓣评分高达9.2分,可见其受到广大读者的认可。 除了以上两本书,《Python进阶技巧》也是一本非常值得一读的进阶书籍。这本书的作者将许多代码简化成了一行,展现了Python的高级技巧。虽然有些地方可能看起来有些夸张,但它确实帮助你了解Python的特性和一些不错的功能。而且,在关键时刻,这种技巧还可以让你轻松搞定其他人需要十几行代码才能完成的任务。对于想要进阶的同学来说,这本书的阅读是非常适合的。 总而言之,《Python进阶之路》、《Python Cookbook》和《Python进阶技巧》都是非常优秀的Python进阶书籍,适合想要深入学习Python的读者。 : 引用自《Python进阶之路》 : 引用自《Python Cookbook》 : 引用自《Python进阶技巧》

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值