delattr(object,name):删除object的属性name(此处可以是类属性,也可以是实例属性)
getattr:(object,name[,default]):获取object的name属性,如果找不到该属性,则返回default,不设置default则报错
hasattr(object,name):判断object是否有name,返回True或False,是基于getattr实现的
setattr(object, name, value):在object中增加名为name的属性,其值为value
# 例如
class Animals():
food = 'raw'
def __init__(self, kind, color, age):
self.kind = kind
self.color = color
self.age = age
cat1 = Animals('cat', 'white', '3')
res1 = getattr(cat1, 'kind', '找不到')
print(res1)
delattr(cat1, 'kind')
res2 = getattr(cat1, 'kind','找不到')
print(res2)
res3 = hasattr(cat1, 'kind')
print(res3)
setattr(cat1, 'kind', 'cat')
print(cat1.kind)
# 终端显示
cat
找不到 # 删除kind之后返回‘找不到’
False # 说明cat1中没有kind
cat # setattr了kind之后,可以找到了
放在类里面的函数,就是方法;
方法包括对象方法、类方法、静态方法
对象方法的创建及调用
# 例如
class Animals():
food = 'raw'
def __init__(self, kind, color, age):
self.kind = kind
self.color = color
self.age = age
def eat(self, food): # 定义对象方法,其中self是实例对象,隐式接收实例对象(无论self这里叫什么,都不影响他是一个实例对象)
return f'{self}喜欢吃{food}'
cat1 = Animals('cat', 'white', '3') # 实例化
print(cat1.eat('fish')) # 调用参数,传实参的时候不需要传self,只传后面的参数即可
print(Animals.eat(cat1, 'fish')) # 用类去调用的时候,需要传self参数,即实例对象
# 终端显示
<__main__.Animals object at 0x00000180E6E9F040>喜欢吃fish # self是实例对象,是地址
<__main__.Animals object at 0x0000019C44B8F040>喜欢吃fish
类方法的创建要在前面加装饰器@classmethod
# 例如
class Animals():
food = 'raw'
def __init__(self, kind, color, age):
self.kind = kind
self.color = color
self.age = age
def eat(self, food):
return f'{self}喜欢吃{food}'
@classmethod # 类方法装饰器
def sex(cls, sexy): # 定义类方法,同样的,cls默认隐式接收类,无论cls叫什么,都不影响
return f'性别是{sexy}'
cat1 = Animals('cat', 'white', '3')
# print(cat1.eat('fish'))
# print(Animals.eat(cat1, 'fish'))
print(Animals.sex('女的')) # 调用类方法
print(cat1.sex('女的')) # 用实例对象调用类方法
# 终端显示
性别是女的
性别是女的 # 实例对象调用和类调用是一样的
注意:
类方法解决作用域的问题
不同类,是不同的局部作用域,局部作用域之间的变量不能直接调用,但是有类方法,有实例对象就可以直接调用,只要指定对象,就可以调用
__init__()可以手动调用,但是手动调用的时候,要补全参数,可以把他当做一个普通的函数;
# 例如
class Animals():
food = 'raw'
def init(self, kind, color, age): # 取消自动调用,变成手动调用
self.kind = kind
self.color = color
self.age = age
cat1 = Animals() # 注意,此时调用父类的__new__和__init__,不能定制化,不能传参数
cat1.init('cat', 'white', '3') # 手动调用init
print(cat1.kind)
# 终端显示
cat
注意:
__init__的好处是可以自动调用,自动初始化
类方法是类下面的实例对象都具备的特征,可以统一写在一起,
对象方法是个体特别拥有的特殊方法
静态方法的创建需要用@staticmethod
静态方法装饰器
静态方法可以用实例对象调用,也可以用类方法调用
# 例如
class Animals():
food = 'raw'
def __init__(self, kind, color, age):
self.kind = kind
self.color = color
self.age = age
def eat(self, food):
return f'{self}喜欢吃{food}'
@staticmethod #静态方法装饰器
def what(): #定义静态方法,注意此处不能传参数
print(f'喜欢吃{Animals.food}')
cat1 = Animals('cat', 'white', '3')
Animals.what() #可以用类调用
cat1.what() #也可以用实例对象调用
# 终端显示
喜欢吃raw # 结果一致
喜欢吃raw
封装、继承、和多态性,今天先说两个
在属性或方法前面加两个下划线__,声明为私有属性或方法,只能在类内部被调用,外部不能调用,但是可以通过建立内部函数,建立与类的联系,来调用封装的属性或方法
特殊方法(魔术方法)也是封装
# 例如
class Animals():
__food = 'raw'
def __init__(self, kind, color, age):
self.__kind = kind # 封装,编程私有化实例属性
self.__color = color
self.__age = age
cat1 = Animals('cat', 'white', '3')
print(cat1.__kind) # 调用实例属性
print(Animals.__food)
# 终端显示
AttributeError: 'Animals' object has no attribute '__kind' #报错
对于封装属性及方法的调用:通过函数,创建内部连接
对象方法和类方法,对象属性和类属性都可以通过这种方法去调用
子类无法继承父类的私有属性和方法
# 例如
class Animals():
__food = 'raw'
def __init__(self, kind, color, age):
self.__kind = kind
self.__color = color
self.__age = age
def jiandie(self): # 创建函数,非私有函数
return self.__kind # 该函数返回私有属性
cat1 = Animals('cat', 'white', '3')
print(cat1.jiandie()) # 调用非私有的函数,并打印返回值
# 终端显示
cat # 成功显示私有属性
所有类都默认继承object,只是一般不写出来
子类继承父类后,会拥有父类中所有的非私有属性和方法
继承是对子类而言可以简化代码,对父类而言,可以扩充功能
继承分类为单继承和多重继承
又分为多个类继承同一个和连续继承
多个类继承同一个
# 例如
class A:
pass
class B(A): # B继承A
pass
class C(A): # C继承A
pass
连续继承
# 例如
class A:
pass
class B(A): # B继承A
pass
class C(B): # C继承B
pass
# 例如
class A:
pass
class B:
pass
class C(A, B): # C继承A和B,**顺序是从左到右**
pass
# 例如
class ozp:
color = '黑白黄'
class yzp:
color = '黄'
class fzp(ozp, yzp): # 多重继承父类
pass
print(fzp.color)
# 终端显示
黑白黄 # 从左往右继承,ozp有color,故先调用oap的color
查找顺序:
自己→父类(从左向右)→object→报错(如果object也没有,就报错)
初始化方法也一样,自己没有,就调用父类的
当父类的方法不能够满足需求的时候,可以在子类重写父类的方法
即在子类再次创建一个函数
# 例如
class ozp:
@classmethod
def color(cls, color):
print(f'喜欢的颜色是{color}')
class yzp:
@classmethod
def color(cls, color):
print(f'不喜欢的颜色是{color}')
class fzp(ozp, yzp):
@classmethod
def color(cls, color): # 当父类的函数无法满足需求(资环的颜色,不喜欢的颜色都不能描述)可以在子类新建函数,重写父类,但是重写的父类不是Inplace操作
print(f'幸运的颜色是{color}')
fzp.color('红色')
ozp.color('红色')
# 终端显示
幸运的颜色是红色
喜欢的颜色是红色 # 父类不变
子类重写父类之后,无法调用父类相同的方法,
super():调用指定的类的父类
用于子类重写父类之后,再调用父类的方法
# 例如
class ozp:
def __init__(self):
pass
def color(cls, color):
print(f'喜欢的颜色是{color}')
class yzp:
def color(cls, color):
print(f'不喜欢的颜色是{color}')
class fzp(ozp, yzp):
def color(cls, color):
print(f'幸运的颜色是{color}')
pr1 = fzp()
pr1.color('红色')
super(fzp, pr1).color('白色') # 调用pr1的类(fzp)的父类中的方法(color),对于多重继承,会按照从左向右的顺序继承
# 终端显示
幸运的颜色是红色
喜欢的颜色是白色 # 调用到ozp的color方法
如果super()什么都不传,默认当前的类和当前的self
# 例如
class ozp:
# @classmethod
def __init__(self):
pass
def color(cls, color):
print(f'喜欢的颜色是{color}')
class yzp:
# @classmethod
def color(cls, color):
print(f'不喜欢的颜色是{color}')
class fzp(ozp, yzp):
# @classmethod
def color(cls, color):
print(f'幸运的颜色是{color}')
super().color('白色') # super什么都不传
pr1 = fzp()
pr1.color('红色')
# 终端显示
幸运的颜色是红色
喜欢的颜色是白色 # 调用父类
# 例如
list1 = [1, -2, 3]
def set1(x):
list_1.append(x)
return list_1
list_1 = []
# [1, -2], [1, -2]
res = list(map(set1, list1))
print(res)
# 终端显示
[[1, -2, 3], [1, -2, 3], [1, -2, 3]]
注意:
记住:map函数是最后一次性返回,不是中间返回,是在最后运算完之后一次性返回
此处结果为什么是[[1, -2, 3], [1, -2, 3], [1, -2, 3]]
而不是[[1], [1, -2], [1, -2, 3]]
?
因为第一次返回list_1
的时候,list_1 = [1]
,没有问题,但是第二次的时候,list_1.append(x)
是inplace操作,直接修改原数据,此时list_1 = [1, -2]
,连同第一次返回的list_1
也一起被修改了,
以此类推,返回三次list_1
,最终形态list_1 = [1, -2, 3]
,因此返回这个结果!!!
注意:
如果在res = list(map(set1, list1))
中将list去掉,即不将迭代器转换成list形式,print(list_1)
就是空