1010._面向对象

语言分类

面向机器

机器容易理解的语言,是一些机器指令,代表有汇编语言

面向过程

做一件事情,按步骤实现,第一步做什么,第二步做什么,如果情况A出现怎么处理,情况B处理怎么处理。适用问题规模小,可以按步骤实现,代表C语言

面向对象OOP

5*

是一种认识世界、分析世界的方法论。将万事万物抽象成为各种对象。

适用问题规模大,复杂的情况,代表C++、Java、Python

类class是一个抽象的概念

对象object,实例instance,都是一个实体,是个具体的概念

数据类,对应属性;动作类,操作类,行为,对应方法,类是对数据和操作的封装。

类中方法也是属性

表达式又名解析式,用来构建list,set, dict, 比for循环效率高,使用列表表达式会立即生成新列表,占用大量的内存和cup;生成器的构建方式有生成器表达式,或者在函数中使用yield关键字,生成器是一个惰性对象,不会立即占用大量内存和cup,可以通过for循环和next方法获得里面的元素,生成器是一种迭代器。

面向对象3要素5*

1.封装

第一,将属性和方法封装

第二,将数据和操作适当暴露给客户,对外提供一些接口, 该隐藏的隐藏,暴露的方法有property中的getter,setter方法. 可以用装饰器实现,也可以自己写函数加到property实例中;隐藏的方法有在属性和方法前面加一个下划线或者两个下划线

2.继承

分为单一继承和多继承,父类的属性和方法可以直接继承过来,

尽量多继承,不要在父类上改写,尽量自己写,OCP开闭原则

单一继承

# 父类 超类 基类
# 子类 派生类
# 继承过程也叫派生过程
class Animal:
    def __init__(self, name):
        self._name = name

    def shout(self):
        print('{} , shouts'.format(self.__class__.__name__))
        # 在父类中,通过实例取得,子类的名字

class Cat(Animal): pass

c = Cat('tutu')
c.shout()
print(c.__class__.__base__)  #Animal
print(c.__class__.__bases__) #元组(Animal, )
print(c.__class__.__mro__) #通过属性获得mro,方法解析顺序,元组里面放的是类Cat Animal object
print(Cat.mro())  #  通过方法获得mro, 方法解析顺序,返回列表,同上
print(Animal.__subclasses__())  #Cat
print(int.__subclasses__())  #布尔型

# # object是根基类,没有父类,父类为None
# print(type(Cat)) type类型
# print(type(object)) type类型

多继承(少用)

python使用MRO(method resolution order 方法解析顺序),解决基类搜素顺序的问题。内部通过C3算法实现,采用深度优先原则

多继承 :一个类继承自多个类,称为多继承
缺点:二义性
原则:OCP原则,多用继承,少修改
用途:复用,在子类上实现对基类的增强,实现多肽

3.多态

面向对象编程最灵活的地方,动态绑定,同一个方法在,不同的类型上

表现不同。例如继承自动物类的人类、猫类的操作’吃’方法不同

多肽:继承加覆盖
同一套方法,在不同的子类上表现不同
这就是多肽

python中的面向对象

定义:类名大驼峰(标识符),class关键字,定义后产生类对象,绑定到标识符上。

class ClassName:
	语句块
#实例化的真实过程,先调用了类的 obj = MyClass.__new__()
#然后调用了obj.__init__()方法,但是__init__()的返回值只能是None,
#内部做了优化所以,实例化之后返回一个对象,每次实例化都走一次__init__
#实例化与初始化
#先实例化再初始化
#__init__称为初始化,出厂配置,构造器,构造方法,dunder方法,第一参数必须是实例
#类属性与类方法
#类属性与类方法本质上都是类属性
#类方法method,就是函数,可以通过类标识符.函数名,访问这个属性
#点号,就是成员访问符

普通方法,类方法,静态方法

例子:

class Path:
    def __init__(self):
        self.name = 'tom'

    def method(self, m):  #普通方法,需要2个参数,类调用时不会注入第一参数,实例调用时,
        # 会将实例自身作为第一参数注入。
        print('普通方法:', self, m)

    @classmethod
    def class_method(cls, b):  #类方法,无论类调用还是实例调用,都会将类作为第一参数注入
        print('class method :', cls, b)

    @staticmethod  #(用的少)静态方法, 无论类调用还是实例调用,都不会注入第一参数
    def static_method(b, a):
        print('static method :', b, a)

# 普通方法例子
print(Path.method) #<function Path.method
print(Path().method) #bound method
Path().method(18) #实例调用时,第一参数为实例
Path.method('tom', 18) #类调用时,第一参数可以随便给一个值

#类方法例子
Path.class_method('tom')  #第一参数都为类,函数里面只要遇到self,就都是类
Path().class_method('tom')  #第一参数都为类

#静态方法
Path.static_method('11', '22')  #第一参数都不注入,需要传入两个参数
Path.static_method('11', '22')  #第一参数都不注入,需要传入两个参数

类对象与实例对象的_class_ __name__ __dict__

class Person:
    height = 170

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def getage(self):
        print(self.name, __class__.__name__, self.__class__.__name__,type(self).__name__)
        # 后3种都可以取到类的__name__

pclass = Person
pinstance = Person('Tom', 18)

# __name__
pclass.__name__  # Person, 只有类可以取到名字,实例如果不定义取不到name

# __class__
pclass.__class__  # type
pinstance.__class__  # Person

# __dict___
pclass.__dict__  # {'height': 170 , '__init__':  ,'getage':,  '__doc__': }
pinstance.__dict__  # {'name': 'tom', 'age': 18}

print(*Person.__dict__.items(), sep='\n') #查看当前类的所有,__dict__

函数与类中出现+=比较

class Person:
  height = 170
  def __init__(self, name, age):
    self.name = name
    self.age = age

p = Person('tom', 12)
p.height += 10 # 不会报错,不会走__init__,只会到类中去找height属性
p.height

def f():
    a = 10
    def f1():
        a += 1
        print(a)
    return f1
# f()()  报错

# 另一些例子
class Person:    
    def __init__(self, name, age=18):
        self.name = name
        self.age = age
        
    def growup(self, i=1):
        self.age += i
        print(self.age)
        
    def growup1(self, i=1):
        i += 1
        print('i', i)
        
    a = 1    
    def growup2(self):
        __class__.a += 1
        print('a', __class__.a)
    
    b = 2
    def growup3(self):
        b += 1
        
p = Person('tom')
p.growup()
p.growup1()
p.growup2()
p.growup3() #会报错

访问控制

私有,公有,protected

  • self.__age = 1 私有属性,只能中使用_Person.__age, 当前类名加私有属性名,实例不可以访问, 想查看到_Person.__age,需要调用,

    实例 .__dict__

  • _self._age = 1 protected保护的属性,名字还是_age, 可以访问和修改

  • self.age = 1 公有属性

  • 同样适用于类的方法,分为私用,保护,公有方法,因为
    method也是一种属性

继承中的访问控制

# 一下例子用来测试,正常代码不要这么写

class Animal:
    __COUNT = 100
    HEIGHT = 0

    def __init__(self, age, weight, height):
        self.__COUNT += 1
        self.age = age
        self.__weight = weight
        self.HEIGHT = height

    def eat(self):
        print('{}  eat'.format(self.__class__.__name__))

    def __getweight(self):
        print(self.__weight)

    @classmethod
    def showcount(cls):
        print(cls)
        print(cls.__dict__)
        print(cls.__COUNT)

    @classmethod
    def __showcount2(cls):
        print(cls.__COUNT)

    def showcount3(self):
        print(self.__COUNT)


class Cat(Animal):
    NAME = 'CAT'
    __COUNT = 200

# 测试(只是为了测试)
c = Cat(3, 5, 15)
c.eat()

# print(c.__COUNT)  #私有属性不可以通过实例直接访问访问
# CAT类的字典中_Cat__COUNT,访问方式_Cat__COUNT
# Animal类的字典中_Animal__COUNT ,访问方式_Animal__COUNT
# 实例的字典中没有这个属性,实例的字典中有_Animal__COUNT,访问方式_Animal__COUNT
print(Cat._Cat__COUNT)  # 200
print(Animal._Animal__COUNT)  # 100
print(c._Animal__COUNT)  # 101

# c.__getweight()  父类的私有方法不可以通过,实例访问
c._Animal__getweight()  #在实例字典中找到了_Animal__weight,值为5


实例属性的访问顺序

class C:
    def __init__(self):
        print('C init ~~~~~')


class A(C):
    def __init__(self):
        #super().__init__()
        print('A init ~~~~')


class B(A):
    def __init__(self):
        #uper().__init__()
        print('B init ~~~~')
# 构造实例对象时,先找B中的__new__,再找
# A中的__new__, 都没找到,最后找的是object
# 中的__new__; 出厂配置时,初始化的顺序B,A,C
# 如果B中有则只初始化B,如果AC中都有只初始化A
# 如果只有C中有,则只初始化C, 如果想都初始化
# 则需要加2个super
b = B()

# 使用super()加载类中的方法,然后在子类中增强

# 继承的正常使用方法1
class Animal:
    def __init__(self, age):
        self.age = age

    def getage(self):
        print(self.age)

class Cat(Animal):
    def __init__(self, age, weight):
        super().__init__(age)
        self.weight = weight

c = Cat(1, 10)
c.getage()  # 1

# 继承的正常使用方法2(getage函数的位置改变了)
class Animal:
    def __init__(self, age):
        self.age = age

class Cat(Animal):
    def __init__(self, age, weight):
        super().__init__(age)
        self.weight = weight

    def getage(self):
        print(self.age)

c = Cat(1, 10)
c.getage()  # 1

以下代码只是为了测试

class Animal:
    __COUNT = 100
    HEIGHT = 0

    def __init__(self, age, weight, height):
        self.__COUNT += 1
        self.age = age
        self.__weight = weight
        self.HEIGHT = height

    def eat(self):
        print('{}  eat'.format(self.__class__.__name__))

    def __getweight(self):
        print(self.__weight)

    @classmethod
    def showcount(cls):
        print(cls)
        print(cls.__dict__)
        print(cls.__COUNT)

    @classmethod
    def __showcount2(cls):
        print(cls.__COUNT)

    def showcount3(self):
        print(self.__COUNT)


class Cat(Animal):
    NAME = 'CAT'
    __COUNT = 200

#
c = Cat(3, 5, 15)
c.eat()

# print(c.__COUNT)  #私有属性不可以通过实例直接访问访问
# CAT类的字典中_Cat__COUNT,访问方式_Cat__COUNT
# Animal类的字典中_Animal__COUNT ,访问方式_Animal__COUNT
# 实例的字典中没有这个属性,实例的字典中有_Animal__COUNT,访问方式_Animal__COUNT
print(Cat._Cat__COUNT)  # 200
print(Animal._Animal__COUNT)  # 100
print(c._Animal__COUNT)  # 101

# c.__getweight()  父类的私有方法不可以通过,实例访问
c._Animal__getweight()  #在实例字典中找到了_Animal__weight,值为5

super用法

#继承的测试例子(正常代码不要这么写):

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

class Cat(Animal):
    def __init__(self, age, weight):
        super().__init__(age)
        self.weight = weight

    def getage(self):
        print(self.age)


c = Cat(5, 10)
c.getage()  # 5

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


    def getage(self):
        print(self.__age)

class Cat(Animal):
    def __init__(self, age, weight):
        super().__init__(age)  # 等价于super(Cat, self).__init__(age)
        # 执行完super,在c实例的字典中多了一个_Animal__age : 3
        print(super())  # 打印当前类,和当前类对象,所以super接受的参数也是这两个
        self.__age = age + 1  # 执行完这一句,在c对象的字典中多了一个_Cat__age:4
        self.weight = weight

c = Cat(3, 10)
c.getage()  # Cat类中没有getage方法,所以到父类中找getage方法,找的是c实例中的_Animal__age方法,所以返回3


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


class Cat(Animal):
    def __init__(self, age, weight):
        super().__init__(age)
        self.__age = age + 1
        self.weight = weight

    def getage(self):
        print(self.__age)

c = Cat(3, 10)
c.getage()  # 4

class A:
    def __init__(self, a, d=10):
        self.a = a
        self.__d = d

    def showd(self):
        return self.__d

class B(A):
    def __init__(self, b, c):
        self.b = b
        self.c = c
        A.__init__(self, b+c, b-c)
        #super(C, f).__init__(2)

    def printvalues(self):
        print(self.b)
        print(self.a)
        return self.showd()

b = B(2, 3)
print(b.printvalues()) # b=2, a=5 _A__d=-1

print(b.showd()) # -1

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

    @property
    def name(self):
        return self._name  #不可以用return self.name, 会形成递归

    def shout(self):
        print('{} shouts'.format(self.__class__.__name__))


class Cat(Animal):
    def __init__(self, name):
        super().__init__(name)
    def shout(self):  #override
        # super()  #等价于super(self.__class__, self) super(Cat, self)
        super().shout()
        # 等价于super(Cat, self).shout()
        # Animal.shout(self) 不推荐
        # self.__class__.__base__.shout(self) #坚决不用,认识就可以
        print('miao miao')


c = Cat('tutu')
c.shout()  # 'Cat shout'
print(c.name)  # tutu

属性装饰器

# 注意事项
class People:
    def __init__(self, name):
        self._name = name

    # @property     # 会形成递归,因为加上property后,name变成self的属性,name(self)等价于self.name
    # def name(self):
    #     return self.name

    # @property     # 初始化时会先执行self.name = name,在报递归错误之前,会报cannot set attribute 错误
    # def name(self):
    #     return self.name

    @property
    def name(self):
        return self._name
      
p = People('name: tutu')
print(p.name)
# 属性装饰器2个例子
class Person:
    def __init__(self):
        self.__eyecolor = 'blue'

    @property
    def eyecolor(self):
        return self.__eyecolor

    @eyecolor.setter
    def eyecolor(self, value):
        self.__eyecolor = value

    @eyecolor.deleter # 用的不多
    def eyecolor(self):
        del self.__eyecolor

p = Person()
print(p.__dict__['_Person__eyecolor'])

#p.__eyecolor #访问不到
print(p.eyecolor) #eyecolor函数可以,当作属性来用
p.eyecolor = 'yellow' #修改属性,如果这个属性是只度模式,则不用写下面的settern和deleter方法
del p.eyecolor

# 与上面的方法类似
class Person:
    def __init__(self):
        self.__eyecolor = 'blue'

    def geteyecolor(self): return self.__eyecolor

    def seteyecolor(self, value): self.__eyecolor = value

    def deleyecolor(self): del self.__eyecolor

    eyecolor = property(geteyecolor, seteyecolor, deleyecolor, "I'm the 'eyecolor' property.")

p = Person()
print(p.geteyecolor()) #需要加括号
p.seteyecolor('yellow')
print(p.geteyecolor())

魔术方法5*

容器相关方法

# 将购物出改装成容器练习
# 也可以通过继承的方式将购物出改装成容器
class Item:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def __str__(self):
        return '名称:{},价格:{}'.format(self.name, self.price)

    __repr__ = __str__

class Cart:
    def __init__(self):
        self.items = []

    def additem(self, item):
        self.items.append(item)
        return self

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

    def __str__(self):
        return str(self.items)

    def __iter__(self):
        yield from self.items
        # 等价于,return iter(self.items)

    def __getitem__(self, index):
        return self.items[index]

    def __setitem__(self, key, value):
        self.items[key] = value

    __add__ = additem

    # __repr__ = __str__

c = Cart()
# 大小
print(len(c))
#__bool__
#调用函数bool(), 返回布尔值,没有定义__bool__,就找__len__返回长度,非0为真
#如果__len__也没有定义,那么所有实例都返回真值

class A: pass

a = A()
print(bool(a))  #True
print(bool(A))  #True

class A:
    def __len__(self):
        return 0

a = A()
print(bool(a))  #False
print(bool(A))  #True 只对实例起作用,对类A,不起作用

# add及可视化
c.additem(Item('car', 200)).additem(Item('earphone', 10))
print(c) #如果类Cart中没有__str__,则返回一个object,如果类Item中没有__str__
# 则外层的object有包括几个object,类Cart中__str_显示最外层的列表,类Item中__str__
# 显示里层的名称和价格
c + Item('macbook', 300) + Item('phone', 400)
print(c)


# 遍历,返回一个新的迭代器对象
# 因为类中有__iter__方法,所以迭代实例c, 相当于迭代yield from形成的生成器对象
# 因为类Item中有__str__方法,所以可以看到具体的内容
for i in c:
    print(i)

print('=' * 10)


# __getitem__,key可以是索引或者键(可哈希)
# 加[]相当与调用实例的__getitem__方法
print(c[0])


# __setitem__
# 相当于调用实例的__setitem__方法
c[0] = 'tutu'
print(c)

#in 成员运算符
#__contains__方法如果没有实现
#就调用__iter__方法,判断目标字符串是否在,迭代器中
print('tutu' in c)

#__missing__字典或子类使用__getitem__(),如果key, 不存在会调用此方法

构造器与析构器

class Person:
    def __init__(self, name): #构造器,构造函数,资源申请
        self.name = name

    def __del__(self): #析构器,构造函数,资源释放
        print('del instance', self)

def test():
    p = Person('tom')
    del p   #del x 并不直接调用 x.__del__() --- 前者会将 x 的引用计数减一,而后者仅会在 x 的引用计数变为零时被调用
    # 即在函数程序执行过程中引用计数变成0,调用了__del__
    print('*' * 10)
test()  # 执行完函数,不会打印:del instance <__main__.Person object at 0x10236c588>
# 因为在函数内部类对象的引用计数已经被清0了,会在*好上面打印,起作用的是def

def test():
    p = Person('tom')
    print('*' * 5)
test()  # 执行完函数,才会执行__del__ 在*号之后打印:del instance <__main__.Person object at 0x10236c588>

# p = Person('tom')
# print(p.name) # 执行完最后一句print,才会执行__del__,打印:del instance <__main__.Person object at 0x10236c588>

#实例化 ?????????????????
#__new__是静态方法,所以第一参数必须手动给,这个方法很少用到
# 即使创建了该方法,也会调用一次,super().__new__(cls)
class A:
    def __new__(cls, *args, **kwargs):
        super().__new__(cls)

    def __init__(self, name, age):
        self.name = name
        self.age = age


a = A('tom', age=20)
print(a.name)

__call__方法

# 在类中定义一个__call__方法,**实例**就可以像函数一样调用

class Adder:
    def __call__(self, *args):
        self.result = sum(args)
        return self.result

# 以下两种调用方法等效

print(Adder()(*range(5)))

a = Adder()
print(a.__call__(*range(5)))

a = Adder()
print(callable(Adder))  #实例与类都是可调用的
print(callable(a))

# 函数调用的本质:

# 正常的函数调用,bin() ,实际是调用了bin.__call__()

__hash__

# 判断一个对象是否可hash, isinstance(p1, collections.Hashable)
# list实例为什么不可以hash?
# 因为List类中有__hash__ = None, 但是list本身是可以hash的,print(hash(list)),
# 所有的类都继承自object, object类中有__hash__(),所以所有的类都是可hash的,
# 如果所有的类不可hash,需要在object中设置

class A:
    pass

print(A)
print(A())  #什么都不写,类和实例也都可hash
print('=' * 10)

class A:
    __hash__ = None
print(hash(A)) #可hash,
#print(hash(A())) #不可hash,因为None类型不可以这么使用None(A())
# print(A.__hash__())  # 不等价于 hash(A), 因为前面不可调用,但是后面
# 可hash


#集合去重的本质,需要hash值相同,并且内容相同
class A:
    def __init__(self, name):
        self.name = name

    def __hash__(self):
        return hash(self.name)

    def __eq__(self, other):
        return self.name == other.name

    def __str__(self):
        return str(self.name)

    __repr__ = __str__


a = A('tom')
b = A('tom')
print(a is b)  #False
print(a == b)  #True
print(hash(a)) #5241461326091852353
print(hash(b)) #同上
print({a, b})  #去重了只剩下,tom


a = A('tom')
b = A('jerry')
print(a is b)  #False
print(a == b)  #False
print(hash(a)) #5241461326091852353
print(hash(b)) #不同上
print({a, b})  #{tom, jerry} 没有去重


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

    def __hash__(self):
        return 123

    def __eq__(self, other):
        return self.name == other.name

    def __str__(self):
        return str(self.name)

    __repr__ = __str__


a = A('tom')
b = A('tom')
print(a is b)  #False
print(a == b)  #True
print(hash(a)) #123
print(hash(b)) #同上
print({a, b})  #去重了只剩下,tom

a = A('tom')
b = A('jerry')
print(a is b)  #False
print(a == b)  #False
print(hash(a)) #123
print(hash(b)) #同上
print({a, b})  #{tom, jerry} 没有去重

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

    def __hash__(self):
        return 123

    def __str__(self):
        return str(self.name)

    __repr__ = __str__


a = A('tom')
b = A('tom')
print(a is b)  #False
print(a == b)  #False  如果类中没写__eq__那么这一行相当于判断is,地址是否相同
print(hash(a)) #123
print(hash(b)) #同上
print({a, b})  #{tom, tom},没有去重复
print(hash(1)) #居然等于1

可视化方法

class Person:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return '<A {} >'.format(self.name)

    def __bytes__(self):
        return str(self).encode()

    __repr__ = __str__
p = Person('tom')
print(p)
print(str(p))
print(repr(p))
print('{}'.format(p))
print(bytes(p))  # b'<A tom >'

运算符重载

# 当类中需要进行大量运算时使用,int类几乎实现了所有操作符,可以作为参考
# 自己是现实只需要实现3中运算符,其他3种可以推断出来
# __eq__ 由等于可以推出不等于
# __ge__ 由大于等于可以推断出小于等于
# __gt__ 由大于可以推断出小于
class A:
    def __init__(self, name, age=18):
        self.name = name
        self.age = age

    def __eq__(self, other):  #等效于 ==
        return self.age == other.age

    def __gt__(self, other):
        return self.age > other.age

    def __ge__(self, other):
        return self.age >= other.age

    def __add__(self, other):
        return self.age + other.age

    def __iadd__(self, other):
        self.age += other.age
        return self.age

    def __sub__(self, other):
        pass

    def __isub__(self, other):
        pass

    def __str__(self):
        return self.name

    __repr__ = __str__

a = A('tom')
b = A('jerry', 25)
# 可以直接对两个实例进行排序
# 因为实例中含有__str__方法,所以会显示名字[tom, jerry],默认是升序,实际比较
# 的是实例,名字只是显示
print(sorted([a, b]))

print(a == b)
print(a > b)
print(a <= b)
print(a != b)

# 在类上面加一个装饰器@total_ordering,但是这个装饰器效率不高,一般不用
# from functools import total_ordering

print('=' * 10)
print(a + b)
a += b
print(a)

# 另一个例子
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return self.x + other.x, self.y + other.y

    # #方法1
    # def __iadd__(self, other):
    #     self.x, self.y = self + other
    #     return self

    # #方法2
    # def __iadd__(self, other):
    #     return Point(*(self + other))

    # #方法3
    # def __iadd__(self, other):
    #     self.x += other.x
    #     self.y += other.y
    #     return self

    #方法4
    def __iadd__(self, other):
        self.x = self.x + other.x
        self.y = self.y + other.y
        return self


    def __str__(self):
        return str((self.x, self.y))

p1 = Point(1, 2)
p2 = Point(2, 1)
p1 += p2  #为什么一定要有返回值呢???????????????
print(p1)

查看属性的方法__dir__

# 特殊属性
# __name__  类、函数、方法等的名字,实例没有
# __module__ 类定义所在的模块名字
# __class__ 实例或者类所属的类
# __bases__ 类的基类,返回一个元组,顺序为它们在基类列表中出现的顺序
# __doc__ 类或者函数的文档字符串,如果没有定义则为None
# __mro__ 类的继承顺序,class.mro()返回的结果保存在,__mro__中
# __dict__ 类或者实例的属性

#查看属性的方法__dir__
#dir()函数操作实例就是调用__dir__()
# dir(obj)
# obj的类型:
# 模块名,返回的**列表**包含模块的属性名和变量名
# 例如:print(dir('OOP魔术方法练习.py'))
# 类或者类型,返回的列表包含类的属性名,及它祖先的属性名
# 类的实例,
# 有__dir__方法,返回可迭代对象的返回值
# 没有__dir__方法,返回列表包含,实例的属性名,类的属性名,祖先类的属性名
# dir() #里面什么都不写
# 在模块中,返回模块的属性和变量名
# 在方法或者函数中,返回本地作用域的变量名

# 内建函数:
print(locals()) # 返回当前作用域中,变量**字典**
print(globals()) # 返回当前模块全局变量的字典

方法重载(overload)
函数名字相同,但是参数的类型不同, 其他语言可以使用,但是python的重载,如下面的例子所示, 同一个add函数可以实现,整数相加,字符串相加,也可以接受多个参数, 即灵活的形参,python语法本身就实现了其他语言的重载

class Add:
    def add(self, a, b):
        return a + b
Add().add(1, 2)
Add().add('a', 'b')

override 重写,覆盖

猴子补丁(发现python的方法或类写的不好,用的不多)

from test2 import Person
from test3 import get_score
def monkeypatch4Person():
    Person.get_score = get_score
monkeypatch4Person()
# 修改了Person,中的get_score方法

增加子类功能的3种方法

1、直接继承然后修改,2、给子类增加一个装饰器, 3、Mixin
Mixin就是其他类混合进来,同时带来了类的属性和方法,本质上是多继承,是一种组合的设计模式。和装饰器比较,两者的装饰效果一样,但是Mixin是类,可以继承。
Mixin类的使用原则:

  • Mixin类中不应该显示的出现__init__方法

  • Mixin类通常不能独立工作,因为它是准备混入别的类中,实现部分功能

  • Mixin类的祖先类也应该是Mixin类

    # 直接继承
    class Document: #因为有print方法未实现,所以称为抽象基类
        def __init__(self, content):
            self.content = content
    
        def print(self):
            raise NotImplementedError
    
    
    class Word(Document):
        def print(self):
            print(self.content, 'word style')
    
    
    class Pdf(Document):
        def print(self):
            print(self.content, 'pdf style')
    
    class Test(Document): #在python中,这个子类可以不实现父类中的print方法,
        # 但是在其他语言中,如果继承自父类,但是父类的抽象方法,未能全部实现,
        # 则这个子类也属于抽象类,抽象类不可以实例化
        pass
    
    
    w = Word('tutu')
    w.print()
    
    #装饰器
    class Document:
        def __init__(self, content):
            self.content = content
    
    
    class Word(Document):
        pass
    
    # 装饰器1
    def printable(cls):
        def wrapper(content):
            cls.print = lambda: print(content)
            return cls
        return wrapper
    
    # 装饰器2
    def printable(cls):
        def wrapper(content):
            def fn():
                print(content)
            cls.print = fn
            return cls
        return wrapper
    
    # 装饰器3 **********************************
    def printable(cls):
        def fn(self): # 这3行等价于 cls.print = lambda self: print(self.content)
            print(self.content)
        cls.print = fn
        return cls
    
    # 装饰器4,注意使用print时,不要出现递归
    def printable(cls):
        def _print(self):  # 写在类的外面的,但是需要给类添加的方法,第一个参数必须为self
            print(self.content)
        cls.print = _print
        return cls
    
    @printable  #PrintableWord = printable(PrintableWord)
    class PrintableWord(Word):pass
    
    p = PrintableWord('abs')
    p.print()
    
    # Mixin,多继承
    # PrintableMixin一般值需要里面的print方法,里面一般不写__init__
    class Document:
        def __init__(self, content):
            self.content = content
    
    class Word(Document):
        pass
    
    class PrintableMixin:
        def print(self): #这个两个print不会出现递归,因为第一个print相当于有一个隐藏的名字,
            # 只能通过这两种方法调用,PrintableMixin.print(instance)  p.print()
            print(self.content)
    
    class PrintableWord(PrintableMixin, Word):pass
    
    p = PrintableWord('abs')
    p.print()
    #print(PrintableMixin.__dict__)
    
    
    # Mixin增强
    class Document:
        def __init__(self, content):
            self.content = content
    
    class Word(Document):
        pass
    
    # Mixin功能,多继承
    class PrintableMixin:
        def print(self):
            print(self.content)
    
    class SuperPrintableMixin(PrintableMixin):
        def print(self):
            print('增强之前打印:', self.content)
            super().print()
            print('增强之后打印:')
    
    class PrintableWord(SuperPrintableMixin, Word): pass
    
    p = PrintableWord('abs')
    p.print()
    
    

python2.7与python本质区别(了解)

python2.7中与python3的不同:
都不同python3
type(A), dir(A)
a.__class__

dir() 函数的用法
dir(A) 收集对象的属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值