前戏

import time
import sys
import temp
# 动态属性 方法,静态属性 类属性
# 组合,一个类的属性是另一个类的对象
# 组合可以实现在__main__中修改,同步到类中
'''
pys9 =Classes('python_s9',python)
print(pys9.course.name)
python.name = 'Python全栈'
print(pys9.course.name)
'''
# 命名空间 类和对象分别存在不中的命名空间中,对象能找到类,类找不到对象
# 类不能调用对象中的名字,对象找不到自己空间中的名字之后调用类的
'''
面向对象的三大特性,继承,多态和封装
继承:
单继承
父类(超类、基类)
子类(派生类),派生方法和派生属性
多继承
不会超过三个父类(三层),子类自己有用自己的,没有用离子类最近的那个父类的方法
抽象类和接口类
经典类和新式类,继承规则不同,经典类深度优先和新式类广度优先
super只能在python3中使用
super只是根据mro广度优先顺序找上一个类
多态
鸭子类型:不依赖父类的情况下实现两个相似的类中的同名方法
封装
私有的
只能在类的内部调用,子类都无法继承
@property
@staticmethod
@classmethod当一个方法只使用了类的静态变量时,就给这个方法加上,默认传cls
'''


isinstance和issubclass

class A:
pass


class B(A):
pass


a = A()
print(isinstance(a, A)) # 判断对象是不是这个类的对象
print(issubclass(B, A)) # 前面的是子类,后面的是父类,判断是不是后面的子类,和上面的一样是布尔型


反射

是用字符串类型的名字去操作变量,减小安全问题

eval('1+2+3')
name = 1
eval('print(name)') # 会产生安全隐患


反射对象中的属性

class A:
price = 20

def fun(self):
print('in func')


a = A()
a.name = 'alex'
ret = getattr(a, 'name') # 通过变量名的字符串形式取到的值
print(ret)
变量名 = input('>>>')
print(getattr(a, 变量名))


反射对象中的方法

class A:
price = 20

def fun(self):
print('in func')


a = A()
a.name = 'alex'
ret = getattr(a, 'func')
ret()


反射类的属性和类的方法

temp.py,新建要导的文件

day = 'Mondy'


def wahaha():
print('fncdjfjbg')


class C:
pass

print(getattr(A, 'price'))
if hasattr(A, 'func'):
getattr(A, 'func')()
print(temp.day)
print(getattr(temp, 'day'))
getattr(temp, 'wahaha')()


内置模块

也可以使用,反射自己模块中的变量

str和repr

def qqxing():
print('qqxing')


year = 2021
print(sys.modules[__name__].year)
print(getattr(sys.modules[__name__], 'qqxing'))()
print(getattr(sys.modules[__name__], 'year')) # 不能写'__main__',导包时回无法分辨main
print(time.strftime('%Y-%m-%d %H:%M:S'))
print(getattr(time, 'strftime')('%Y-%m-%d %H:%M:S'))
print(getattr(temp, 'C')())
hasattr()
getattr() # 一队
setattr() # 设置修改一个变量


class A:
pass


a = A()
setattr(a, 'name', 'nezha')
setattr(A, 'name', 'alex')
print(A.name)
print(a.name)
delattr() # 删除一个变量,一对
delattr(a, 'name')
print(a.name) # 找类中的变量名
# 双下内置方法
print(repr(1))
print(repr('1'))


class Teacher:
def __init__(self, name, salary) -> None:
self.name = name
self.salary = salary

def __str__(self):
return 'A is object%s' % self.name

def __repr__(self) -> str:
return str(self.__dict__)

def func(self):
return 'fndj'


a = Teacher('nazha', 250)
print(a)
print(str(a))
# object 里面有一个str,调用返回调用这个方法的内存地址
print(a) # 打印一个对象的时候就是调用a.__str__,获取返回值
lis = [1, 2, 3, 4, 5] # 实例化,实例化一个列表类的对象
print('%s:%s' % ('A', a)) # %s str() 直接打印,实际用的都是__str__
print(repr(a)) # 实际上走的都是__repr__,用来一个%r
# repr()是str()的备胎
# str()不能做repr()的备胎
# str(obj)的时候,实际上是内部的__str__方法,如果str方法有,返回不许是个字符串
# 如果没有__str__方法,会找本类中的__repr__方法,再没有再找父类中的__str__
# repr() 只找__repr__,没有找父类的
# 内置的方法有很多,不一定都在object中


len方法

class A:
def __init__(self, name, student) -> None:
self.name = name
self.student = []

def __len__(self):
return len(self.student)


a = A('全站')
print(len(a)) # 对象没有类方法就会报错,不找父类
a.student.append('二哥')
a.student.append('泰格')
len(a)


析构函数

class A:
def __del__(self):
print('已执行')


a = A()
# del a # 删除会报错,即删除了变量,又删除了方法,而且先执行
print(a)
# 内部由引用计数的机制,计数变成0的时候会回收,超过栈中超过700,有闲置的会删掉
lis = []
for i in range(1000):
lis.append(A())
a = lis.pop()
time.sleep(3)
a.f = open() # 打开文件,第一在操作系统中打开了一个文件,拿到了文件操作符,存在内存中
del a # a.f拿到的文件操作符消失在了内存中
# 在__del__(self):
# self.f.close() 在执行del删除之前做一些收尾工作,关闭文件


__call__方法

class A:
def __init__(self, name) -> None:
self.name = name

def __call__(self):
for k in self.__dict__:
print(k, self.__dict__[k])


a = A('alex')() # 类似于a = A('alex'),a(),对象加上(),相当于执行了call方法