首页 > 代码库 > 35.python全栈之路:面对对象进阶

35.python全栈之路:面对对象进阶

面对对象进阶

1.多继承中的self 

class A:
    def bar(self):
        print(‘BAR‘)
        self.f1()
‘‘‘
self本身代表的D类的对象d1
d1如果要在他的父类中去寻找f1
首先应该去C类
‘‘‘

class B(A):
    def f1(self):
        print(‘B‘)


class C:
    def f1(self):
        print(‘C‘)


class D(C, B):
        pass


d1 = D()
d1.bar()
  流程分析:
  1. d1 = D(),最终找到了object里面的__init__方法创建了对象d1
  2. d1.bar(),执行bar方法,先去C里找,再去B里面找,最后在A中找到了
  3. 执行A中的bar方法,遇到self.f1(),此时self依然表示对象d1
  4. 依然先去C里面找方法f1,最终在C中找到了

2.构造方法

  2.1 普通构造方法
class Animal:
    def __init__(self):
        print(‘A构造方法‘)
        self.ty = ‘动物‘


class Cat(Animal):
    def __init__(self):
        print(‘B构造方法‘)
        self.n = ‘猫‘


a = Animal()
c = Cat()
print(a.__dict__)
print(c.__dict__)
‘‘‘
A构造方法
B构造方法
{‘ty‘: ‘动物‘}
{‘n‘: ‘猫‘}
‘‘‘
  2.2 如果我们想将父类的字段ty封装子类Cat创建的对象中去呢?
class Animal:
    def __init__(self):
        print(‘A构造方法‘)
        self.ty = ‘动物‘


class Cat(Animal):
    def __init__(self):
        print(‘B构造方法‘)
        self.n = ‘猫‘
        self.ty = ‘动物‘
        # 执行父类的构造方法


a = Animal()
c = Cat()
print(a.__dict__)
print(c.__dict__)
‘‘‘
A构造方法
B构造方法
{‘ty‘: ‘动物‘}
{‘n‘: ‘猫‘, ‘ty‘: ‘动物‘}
‘‘‘
  2.3 如果父类的字段较多,创建子类的时候想继承这些字段,需要重复的代码量很大

   我们可以执行父类的构造方法super

class Animal:
    def __init__(self):
        print(‘A构造方法‘)
        self.ty = ‘动物‘
        self.chi = ‘吃‘
        self.he = ‘喝‘
        self.la = ‘拉‘

# 方法1
class Cat(Animal):
    def __init__(self):
        print(‘B构造方法‘)
        self.n = ‘猫‘
        super(Cat, self).__init__()  # 找到Cat的父类,执行其父类的构造方法

‘‘‘
方法2
class Cat(Animal):
    def __init__(self):
        print(‘B构造方法‘)
        self.n = ‘猫‘
        Animal.__init__(self)
‘‘‘

a = Animal()
c = Cat()
print(a.__dict__)
print(c.__dict__)
‘‘‘
A构造方法
B构造方法
A构造方法
{‘ty‘: ‘动物‘, ‘chi‘: ‘吃‘, ‘he‘: ‘喝‘, ‘la‘: ‘拉‘}
{‘n‘: ‘猫‘, ‘ty‘: ‘动物‘, ‘chi‘: ‘吃‘, ‘he‘: ‘喝‘, ‘la‘: ‘拉‘}
‘‘‘

3.面对对象中的反射

  3.1基本用法
class Foo:
    def __init__(self, name):
        # 类的字段
        self.name = name

    def show(self):
        print(‘show‘)


obj = Foo(‘alex‘)

# 通过类,找到类的方法
r1 = hasattr(Foo, ‘show‘)
print(r1)
‘‘‘
True
‘‘‘

# 通过对象,既可以找到对象的成员,也可以找到类里的成员
r2 = hasattr(obj, ‘name‘)  # 找到对象的成员
r3 = hasattr(obj, ‘show‘)  # 通过类对象指针,可以找到类的方法
print(r2, r3)
‘‘‘
True True
‘‘‘
  3.2 通过字符导入模块,用反射操作类的成员
技术分享
class Foo:
    def __init__(self, name):
        # 类的字段
        self.name = name

    def show(self):
        print(show)
testmoudle.py
# 通过字符串导入模块
c = __import__(‘testmoudle‘, fromlist=True)  # 模块名有嵌套的话
# 通过反射获取模块中的类
class_name = getattr(c, ‘Foo‘)
# 根据类创建一个对象
obj = class_name(‘alex‘)
# 通过反射获取name对应的值
val = getattr(obj, ‘name‘)
print(val)
‘‘‘
alex
‘‘‘

  

4.类的成员

  成员

    字段:普通字段(每个对象都不同的数据),静态字段(每个对象都有一份

    方法:普通方法(使用对象封装的数据),静态方法(无需使用对象封装的内容),类方法(自动将类名传入

    特性:将方法以字段的形式调用 

  快速判断是由类执行还是对象执行

    有self,对象调用

    无self,类调用

class Province:
    # 静态字段
    country = ‘China‘

    def __init__(self, name):
        # 普通字段
        self.name = name
        # self.country = ‘china‘

    # 普通方法
    def show(self):
        print(‘show‘)

    # 类方法
    @classmethod
    def xxoo(cls):  # cls == class
        print(‘xxoo‘)

    # 静态方法
    @staticmethod
    def xo(arg1, arg2):
        print(‘xo‘)

    def start(self):
        temp = ‘%s sb‘ % self.name
        return temp

    # 特性,将方法伪造成字段,用于获取
    @property
    def end(self):
        temp = ‘%s sb‘ % self.name
        return temp

    @end.setter
    def end(self, value):
        print(value)


hebei = Province(‘河北‘)

Province.xo(1, 2)

# 方法本需要加括号访问
# @property后 可以以访问字段的方式去访问
obj = Province(‘alex‘)
ret1 = obj.start()
ret2 = obj.end
print(ret1, ret2)

# 获取字段
# print(obj.name)
# 设置字段
# obj.name = ‘123‘
# print(obj.name)

print(obj.end)  # 获取
obj.end = 123  # 设置

‘‘‘
************ 规范 **************
1.通过类访问的有: 静态字段,静态方法,类方法(静态方法的特殊形式)
    Province.country
    Province.xo(1, 2)
2.通过对象访问的有:普通字段,类的方法
    hebei.name
    hebei.show()
************ 规范 **************

3.静态字段存在的意义
    将每个对象都存在的东西只在类里保存一份就行
  

4.静态方法存在的意义
    普通方法执行前需要先创建对象
    静态方法不需要先创建对象,类
    似于将一个普通的函数放在类中,
        在c#和java中非常有用因为他们只能
        面向对象,必须要创建类
    
5.类方法和静态方法一样,只能通过类访问
    区别在于
        静态方法,参数任意
        类方法会自动获取当前类的类名,作为参数传入
    
‘‘‘

  

5.成员修饰符

  对于私有的,只有自己可以访问,其他(包括子类)都不能访问

  5.1 对于字段
class Foo:
    A = ‘aa‘
    __A = ‘aa‘

    def __init__(self):
        self.name = ‘alex‘
        self.__name = ‘wuwen‘

    def aaa(self):
        print(Foo.__A)
        print(self.__name)

    def bbb(self):
        pass

class Bar(Foo):

    def fetch(self):
        print(self.__name)

# 静态字段
print(Foo.A)   # 共有在类外类里均可访问
#print(Foo.__A)
obj = Foo()    # 私有只能在类里访问
obj.aaa()

# 普通字段
print(obj.__name)  # 不能在外部访问
obj.aaa()  #  可在外部访问

obj1 = Bar()  #  执行父类的构造方法
print(obj.__name)  # 继承的子类在外部不能访问

obj1.fetch()  # 不能访问
obj1.aaa()    # 不能访问
  5.2 对于方法
class Foo:

    def __init__(self):
        pass

    def __aaa(self):
        print(‘aaa‘)

    def bbb(self):
        self.__aaa()

    @staticmethod
    def __eee():
        print(‘ddd‘)

    @staticmethod
    def fff():
        Foo.__eee()


# 普通方法
obj = Foo()
#obj.__aaa()  # 不能直接访问
obj.bbb()     # 间接访问

# 静态方法
# Foo.__eee() # 静态方法在外部通过类无法访问
Foo.fff()     # 间接访问私有的静态方法

# 类方法与特性均是一样的道理
  5.3 python与其他语言的区别之处,强行访问私有成员

    对象._类+私有成员

class Foo:


    def __init__(self):
        self.name = ‘alex‘
        self.__name = ‘wuwen‘

    def aaa(self):
        print(self.__name)

    def bbb(self):
        pass

obj = Foo()
# obj.__name  不能直接访问
print(obj._Foo__name)  # 强行访问
‘‘‘
wuwen
‘‘‘

  

6.类的特殊成员

  __init__

  __del__

  __call__

  __getitem__

  __setitem__

  __delitem__

  __new__

  __metaclass__

  6.1 对于字典的一些操作,由dict创建的对象为什么可以使用[ ]del等快捷键操作该对象

    __init__

    __getitem__

    __setitem__

    __delitem__

# dic = dict(k1=123, k2=456)  因为dic类中有__init__方法
# print(dic[‘k1‘])  为什么对象可以加[]呢  因为dic类中有__getitem__方法
# dic[‘k1‘] = 456   因为dic类中有__setitem__方法
# del dic[‘k2‘]     因为dic类中有__delitem__方法

class Foo:
    def __init__(self):
        print(‘init‘)

    def __call__(self, *args, **kwargs):
        print(‘call‘)

    def __getitem__(self, item):
        print(item)

    def __setitem__(self, key, value):
        print(key, value)

    def __delitem__(self, key):
        print(‘模拟删除成功!!‘)


obj = Foo()
obj()  # 对象后面加()执行__call__
obj[‘66‘]  # 对象后加[]执行__getitem__
obj[‘77‘] = 77
del obj[‘77‘]
‘‘‘
init
call
66
77 77
‘‘‘
  6.2 对于列表,他的切片操作又是如何在类中实现的呢?

    __getitem__

r = list([11, 22, 33, 44, 55, 66, 77])
ret = r[1:6:2]  # 切片
print(ret)


class Foo:
    def __getitem__(self, item):
        print(item, type(item))


obj = Foo()
obj()
obj[1:3]  # 切片的时候,将1:3传入一个slice类得到一个对象再传入getitem
‘‘‘
slice(1, 3, None) <class ‘slice‘>
‘‘‘
  6.3  __dict__
class Foo:
    ‘‘‘
    我是类的注释
    ‘‘‘

    def __init__(self):
        self.name = ‘alex‘
        self.gender = ‘female‘

    def __call__(self, *args, **kwargs):
        print(‘call‘)

    def __getitem__(self, item):
        print(item, type(item))

    def __setitem__(self, key, value):
        print(key, value)

    def __delitem__(self, key):
        print(‘模拟删除成功!!‘)


obj = Foo()
print(obj.__dict__)  # 查看对象封装的字段
‘‘‘
{‘name‘: ‘alex‘, ‘gender‘: ‘female‘}
‘‘‘
print(Foo.__dict__)  # 查看类的成员
‘‘‘
{‘__module__‘: ‘__main__‘, ‘__doc__‘: ‘\n    我是类的注释\n    ‘, ‘__init__‘: <function Foo.__init__ at 0x000000000220BA60>, 
‘__call__‘: <function Foo.__call__ at 0x000000000220BAE8>, ‘__getitem__‘: <function Foo.__getitem__ at 0x000000000220BB70>, 
‘__setitem__‘: <function Foo.__setitem__ at 0x000000000220BBF8>, ‘__delitem__‘: <function Foo.__delitem__ at 0x000000000220BC80>, 
‘__dict__‘: <attribute ‘__dict__‘ of ‘Foo‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Foo‘ objects>}
‘‘‘
  6.4  类似于字符串,列表,为什么我们可以用for循环这个对象呢?

    事实上:如果for循环对象的时候,默认执行类中的__iter__方法,是一个生成器

    所以一个对象可以被for循环的话,说明这个对象的类中有__iter__ 方法

li = [1, 2, 3]  #  等价于 li = list([])
for i in li:
    print(i)
‘‘‘
1
2
3
‘‘‘

# 实现一个简单版本的list类
class Foo:

    def __iter__(self):
        yield 1
        yield 2
        yield 3


li = Foo()
for i in li:
    print(i)
‘‘‘
1
2
3
‘‘‘
  6.5 __new__和__metaclass__

        

 

35.python全栈之路:面对对象进阶