【漫漫转码路】Python Day 16

一、面向对象属性的函数

1、delattr

delattr(object,name):删除object的属性name(此处可以是类属性,也可以是实例属性)

2、getattr

getattr:(object,name[,default]):获取object的name属性,如果找不到该属性,则返回default,不设置default则报错

3、hasattr

hasattr(object,name):判断object是否有name,返回True或False,是基于getattr实现的

4、setattr

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之后,可以找到了

二、面向对象——功能(方法)

放在类里面的函数,就是方法;
方法包括对象方法、类方法、静态方法

1、对象方法:

对象方法的创建及调用

# 例如
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

2、类方法:

类方法的创建要在前面加装饰器@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__的好处是可以自动调用,自动初始化
类方法是类下面的实例对象都具备的特征,可以统一写在一起,
对象方法是个体特别拥有的特殊方法

3、静态方法:

静态方法的创建需要用@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

三、面向对象三大特性

封装、继承、和多态性,今天先说两个

1、封装

在属性或方法前面加两个下划线__,声明为私有属性或方法,只能在类内部被调用,外部不能调用,但是可以通过建立内部函数,建立与类的联系,来调用封装的属性或方法
特殊方法(魔术方法)也是封装

# 例如
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  # 成功显示私有属性

2、继承

所有类都默认继承object,只是一般不写出来
子类继承父类后,会拥有父类中所有的非私有属性和方法
继承是对子类而言可以简化代码,对父类而言,可以扩充功能
继承分类为单继承和多重继承

(1)单继承

又分为多个类继承同一个和连续继承
多个类继承同一个

# 例如
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

(2)多重继承

# 例如
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也没有,就报错)
初始化方法也一样,自己没有,就调用父类的

(3)方法重写:

当父类的方法不能够满足需求的时候,可以在子类重写父类的方法
即在子类再次创建一个函数

# 例如
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('红色')
# 终端显示
幸运的颜色是红色
喜欢的颜色是红色  # 父类不变

(4)super

子类重写父类之后,无法调用父类相同的方法,
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)就是空

你可能感兴趣的:(转码,python,开发语言,改行学it,人工智能,深度学习)