python之面向对象

7.1 面向对象的基本内容

7.1.1 格式

  • 对象和类的关系,对象是类的实例

  • 具有相同方法和属性的一类事物称为类

  • 一个拥有具体属性值和动作的具体个体

class Files:    #类中的函数不再称为函数,称为方法
def write(self,name):
       print(name)
       return 666
   def read(self,name):
       print(name)
  def append(self,name):
       print(name)
obj = Files()   #创建该类的对象
result = obj.write('alex')   #通过对象调用方法
print(result)  
  • 类内部数据(包括嵌套的类)在解释器解释的时候就执行,方法内部 调用的时候才执行

class Foo(object):
   print(123)     #一运行就执行

   def func(self):
       pass

   class Base(object):
       print(456)

7.1.2 面向对象的特性

  • 特性:面向对象有三个主要特征,分别是封装性、继承性和多态性。

7.1.2.1 封装
  • 封装分为数据储存的封装和对方法的封装归类

class Person:
   def __init__(self,n,a,g):
       self.name = n
       self.age = a
       self.gender = g
   def show(self):
  temp = '我是%s,年龄%s,性别%s'%(self.name,self.age,self.gender,)
  print(temp)
obj = Person('薛奎','20','太监')  #将数据直接封装到对象里,方便使用 ,得有__init__
obj.shouw()
class Files:
   def write(self,content):
       with open(self.file,mode='w',encoding ='utf-8')as f1:
           f1.write(content)
           f1.close()
   def read(self):
       with open(self.file,mode='r',encoding='utf-8')as f2:
           content = f2.read()
           f2.close()
obj = Files()   #又称实例化一个对象
obj.file = 'read.txt'    #obj就是方法中的self ******
obj.write('123')
obj.read()    
7.1.2.2 继承
class Base:
    def f1(self):
        pass
class Foo(base):  #类(类)即代表括号外是派生类, 里面是基类,运行类内部,没有的会去基类里寻找
    def f2(self):
        pass
obj = Foo()
obj.f1()
obj.f2()
  • 多个类中如果有公共的方法,可以放到基类中避免重复编写。

class Base:
    def f1(self):
        print('base.f1')
class Foo(Base):
	def f2(self):
		self.f1()
		print('foo.f2')
	def f1(self):
		print('foo.f1')
obj = Foo()
obj.f2()    #结果 'foo.f1'  'foo.f2'   obj是实例化的foo,优先在 Foo中寻找
class Base:
    def f1(self):
        self.f2()
        print('base.f1')
	def f2(self):
		print('base.f2')
class Foo(Base):
	def f2(self):
		print('foo.f2')
obj = Foo()
obj.f1()  #结果  'foo.f2' 'base.f1' 
  • 注意事项:self 到底是谁?self 是哪个类创建的,就从此类开始找,自己没有就找父类。

7.1.2.3 多态
  • 一个类表现出来的多种状态

  • 什么是鸭子模型?

    对于一个函数而言,python对参数的类型并不受限制,传入的参数也可以是任何类型,但是在函数中如果有一些方法(send),那么就会默认对传入的参数有了一定的限制,即传入的参数必须要有send方法。这就是鸭子模型。
  • Python本身没有多态的概念,本身必须遵循多态

  • 函数重写就是多态的体现形式。即多个类继承同一个父类,多个类有的会重写这个方法有的不会,结构调用这些不同的类,结果也不同。

7.1.3 基础概念

  • 什么是类 : 具有相同方法和属性的一类事物

  • 什么是对象、实例 : 一个拥有具体属性值和动作的具体个体

  • 实例化 :从一个类 得到一个具体对象的过程

7.1.4 面向对象应用场景

  • 函数(业务功能)比较多,可以使用面向对象来进行归类。

  • 想要做数据封装(创建字典存储数据时,面向对象)。

  • 游戏示例:创建一些角色并且根据角色需要再创建人物。

7.2 类成员

7.2.1 实例变量

class Foo:
    def __init__(self,name):
        self.name = name
    def info(self):
        pass
obj1 = Foo('alex')
obj2 = Foo('eric')   #这俩都是实例变量,由对象引入的变量

7.2.2 类变量

class Foo:
    city = '北京'     #类变量
def __init__(self,name):
    self.name = name
def func(self):
    pass
obj1 = Foo('李杰')
obj2 = Foo('女神')
  • 定义就是写在类的下一级和方法同级

  • 访问:类.类变量名称 / 对象.类变量名称

7.2.3 绑定方法/普通方法

  • 定义:至少有一个self参数执行:先创建对象,由对象.方法()。

  • 执行:先创建对象,由对象.方法()

class Foo:
    def __init__(self):
        self.name = 123
    def func(self, a, b):
        print(self.name, a, b)
obj = Foo()
obj.func(1,2)

7.2.4 静态方法

  • 定义:@staticmethod装饰器 参数没有限制

  • 执行:类.静态方法名() 对象.静态方法() (不推荐)

class Foo:
    @staticmethod
    def f1():       #直接通过类就可以调用,不用绑定参数self
        print(123)
Foo.f1() #也可以obj.f1()也可以 不推荐

7.2.5 类方法

  • 定义:@classmethod装饰器

  • 要点:得有cls参数,当前类

  • 执行:类.类方法() 对象.类方法() (不推荐)

class Foo:
    @classmethod
    def f2(cls,a,b):
        print('cls是当前类',cls)
        print(a,b)  
Foo.f2(1,2)  #通过类直接执行
# 问题: @classmethod和@staticmethod的区别?
"""一个是类方法一个静态方法。
定义:
类方法:用@classmethod做装饰器且至少有一个cls参数。
静态方法:用staticmethod做装饰器且参数无限制。
调用:
类.方法直接调用。
对象.方法也可以调用。

7.2.6 属性

  • 定义:property装饰器 / 只有一个self参数

  • 执行:对象.方法不用加括号

class Foo:
    @property
    def func(self):
        print(123)
        return 666
obj = Foo()
print(obj.func)  #不用加括号  123   666

7.3 成员修饰符

  • 公有,公共访问

  • 私有,只有自己内部可以访问(同一类之间的函数之间也可以,但不适用派生类和基类)

  • 类也不可以访问自己私有的类变量

class Foo:
    def __fun(self):
        print('msg')
    def show(self):
        self.__fun()
obj = Foo()
obj.__fun()  #无法访问,  对象访问类内部
obj.show()   #通过访问show 可以再调用__fun
  • 强制访问

class Foo:
    def __init__(self,name):
        self.__x = name
obj = Foo('alex')
print(obj._Foo__x)   _Foo 强制访问

7.4 类嵌套

  • 函数:参数可以是任意类型的

  • 字典:对象和类都可以作为字典的key和value

class StackConfig(object):
    list_display = '李邵奇'
    def changelist_view(self):
        print(self.list_display)   #搞清楚self每次是谁的对象
class UserConfig(StackConfig):
    list_display = '利奇航'
    class AdminSite(object):
        def __init__(self):
            self._register = {}
        def registry(self,key,arg=StackConfig):
            self._register[key] = arg
        def run(self):
            for key,value in self._register.items():
                obj = value()
                obj.changelist_view()
site=AdminSite()             #创建AdminSite类的对象
site.registry(1)			#构建字典1:StackConfig
site.registry(2,StackConfig) #构建字典2:StackConfig
site.registry(3,UserConfig)  #构建字典3:UserConfig
site.run()				  #执行run方法,结果 '李邵奇' '李邵奇'  '利奇航'

7.5 类中的特殊成员

7.5.1 __init__

  • 将实例的对象初始化

class Foo(object):
    def __init__(self,a):
        self.a = a
obj = Foo('alex')  

7.5.2 __new__

  • 类没有定义new的时候,自动找父类的__new__方法

  • init负责实例化对象,而new则是在类实例化的时候是否要用这个init方法,即构造方法

  • 一般涉及到用new是需要重载父类的new方法来达到结果

class Foo(object):
    def __new__(cls,*args,**kwargs):
        return object.__new__(cls) #基类的new

7.5.3 __call__

  • 对象直接加括号,直接输出

class Foo(object):
    def __call__(self,*args,**kwargs):
        print('执行方法')
obj = Foo()
obj()
# 也等于  Foo()()

7.5.4 __setitem__ __getitem__ __delitem__

class Foo(object):

    def __setitem__(self, key, value):
        pass

    def __getitem__(self, item):
        return item + 'uuu'

    def __delitem__(self, key):
        pass


obj1 = Foo()
obj1['k1'] = 123   # 内部会自动调用 __setitem__方法
val = obj1['xxx']  # 内部会自动调用 __getitem__方法
print(val)
del obj1['ttt']    # 内部会自动调用 __delitem__ 方法

7.5.5 __str__

  • 打印对象,自动调用这个方法 ,用作是一个对象的描写,只有打印生效

class Foo(object):
    def __str__(self):
        return 'asdf'
obj = Foo()
print(obj)

7.5.6 __dict__

  • 去对象中找到对应变量并转化为字典

class Foo(object):
    def __init__(self,name,age,email):
        self.name = name
        self.age = age
        self.email = email
obj = Foo('alex',19,'xxx@qq.com')
print(obj)
print(obj.name)
print(obj.age)
print(obj.email)
val = obj.__dict__
print(val)

7.5.7 __enter__ __exit__ 上下文管理

#方法1
class Context:
    def __enter__(self):
        print('进入')
        return self

    def do_something(self):
        print('内部执行')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('推出')

#方法2  放到另一个类
class Foo(object):
    def do_something(self):
        print('内部执行')
class Context:
    def __enter__(self):
        print('进入')
        return Foo()

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('推出')

with Context() as ctx:
    print('内部执行')
    ctx.do_something()

7.5.8 __add__

  • 两个对象相加,(其实都可以)

class Foo(object):
    def__add__(self,other):
        return 13
obj1 = Foo()
obj2 = Foo()
val  = obj1 + obj2
print(val)

7.5.9 __repr__

  • 如果有str和repr,打印对象 调用str方法,打印列表或其他对象容器,调用repr方法

  • 如果只有str,无论什么时候都是调用str,repr也是同理

  • 实际应用上,str面向对象 repr面向更多面向程序员

  • 打印使用str 调用使用repr

 class D(object):
     def __str__(self):
         return "a __str__"
     def __repr__(self):
        return "a __repr__"

>>> dr = D()
>>> print dr
a __str__
>>> dr
a __repr__

7.6 可迭代对象

  • 只要能被for循环,内部就有iter方法

  • 在类中实现__iter__方法且返回一个迭代器(或者是生成器)

class Foo(object):
    def __iter__(self):   #实现方法
        return iter([1,2,3,4])  #返回迭代器

class Foo(object):    #生成器是特殊的迭代器
    def __iter__(self): 
        yield 1
        yield 2
        ...
        
obj = Foo()

7.7 约束

  • 寻找方便:在源代码或者别人写的代码中加入代码,根据查看基类代码,要在子类中都要添加此send

  • 别人也方便:从上往下看,可以看到基类中存在raise中的约束,也方便掌握代码结构

  • 更加规范:代码不会轻易出BUG

  • 没有也可以,只要不调用这个send也不会出错,只是为了规范,同上。

class base(object):
	def send(self):
        raise NotImplementedError('子类中必须有方法')
class Foo(base):
    def send(self):
        print('我是真的')
class Fooo(base):
    def send(self):
        print('我也是真的')
class Foooo(base):
    def func(self):
        print('我不知道发生了什么')
obj = Foooo()
obj.send()    #报错 NotImplementedError 提醒

7.8 反射

  • 实现了根据输入的字符查找元素并操作

  • 根据字符串形式去操作对象中的元素

7.8.1 getattr

  • 根据字符串的形式去某个对象中操作他的成员,(对象,‘方法’)

class Foo(object):
    def __init__(self,name):
        self.name = name
    def login(self):
        print('对了对了')

obj = Foo('alex')# 获取变量
v1 = getattr(obj,'name')# 获取方法
method_name = getattr(obj,'login')
method_name()

7.8.2 setattr

  • 根据字符串的形式去某个对象中设置成员,(对象,‘要设置的元素’,‘要设置的结果’)

class Foo(object):
    def __init__(self,name):
        self.name = name
obj = Foo(888)
v1 = setattr(obj,'name',7)   #obj.name = 7    改变原值
print(obj.name)

7.8.3 delattr

  • 根据字符串的形式去某个对象中删除成员,(‘要删除哪个对象里的’,‘要删除的变量或元素’)

class Foo:
    pass

obj = Foo()

obj.k1 = 999
print(obj.k1)    # 999
delattr(obj,'k1')
print(obj.k1)     #已删除  'Foo' object has no attribute 'k1'

7.8.4 hasattr

  • 根据字符串形式去某个对象中判断是否有该成员 (‘对象’,‘元素’)

from wsgiref.simple_server import make_server

class View(object):
    def login(self):
        return '登陆'

    def logout(self):
        return '等处'

    def index(self):
        return '首页'


def func(environ,start_response):
    start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
    #
    obj = View()
    # 获取用户输入的URL
    method_name = environ.get('PATH_INFO').strip('/')
    if not hasattr(obj,method_name):
        return ["sdf".encode("utf-8"),]
    response = getattr(obj,method_name)()
    return [response.encode("utf-8")  ]

# 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。
server = make_server('192.168.12.87', 8000, func)
server.serve_forever()

7.9 单例模式

  • 无论实例化多少次,永远都是第一次实例化的对象

  • 优点是可以增加效率,防止链接太多导致的崩溃

class Singleton(object):
    instance = None
    def __new__(cls,*args,**kwargs):
        if not cls.instance:
            cls.instance = object.__new__(cls)
        return cls.instance
#当运行第一次,创建new的对象,赋值给类变量instance,之后在使用这个类,对象相同
obj1 = Singleton()
obj2 = Singleton()
class FileHelper(object):
   instance = None
   def __init__(self, path):
       self.file_object = open(path,mode='r',encoding='utf-8')
   def __new__(cls, *args, **kwargs):
       if not cls.instance:
           cls.instance = object.__new__(cls)
   return cls.instance
obj1 = FileHelper('x')
obj2 = FileHelper('x')  #无论打开多少次都是同一个链接

7.10 项目结构目录

  • bin 程序入口 可执行文件

  • config 配置文件

  • db 数据

  • lib 公共代码

  • src 业务代码

  • 项目设计的要求:通过改变配置文件,不改变其他代码(即源代码),可以达成调解代码的目的。是项目设计的最终需求

posted @ 2019-11-02 17:03  Kn19ht  阅读(163)  评论(0)    收藏  举报