python面向对象(2)

简介: python面向对象(2)

2. 三大特性

面向对象编程在很多语言中都存在,这种编程方式有三大特性:封装、继承、多态。

2.1 封装

封装主要体现在两个方面:

  • 将同一类方法封装到了一个类中,例如上述示例中:匪徒的相关方法都写在Terrorist类中;警察的相关方法都写在Police类中。
  • 将数据封装到了对象中,在实例化一个对象时,可以通过__init__初始化方法在对象中封装一些数据,便于以后使用。

2.2 继承

传统的理念中有:儿子可以继承父亲的财产。

在面向对象中也有这样的理念,即:子类可以继承父类中的方法和类变量(不是拷贝一份,父类的还是属于父类,子类可以继承而已)。

父类

子类


基类

派生类

96447814-120fc980-1245-11eb-938d-6ea408716c72.png

class Base:
    def func(self):
        print("Base.func")
class Son(Base):
    def show(self):
        print("Son.show")
s1 = Son()
s1.show()
s1.func() # 优先在自己的类中找,自己没有才去父类。
s2 = Base()
s2.func()
class Base:
    def f1(self):
        pass
class Foo(Base):
    def f2(self):
        pass
class Bar(Base):
    def f3(self):
        pass
o1 = Foo()
o1.f2()
o1.f1()

练习题

class Base:
    def f1(self):
        print('base.f1')
class Foo(Base):
    def f2(self):
        print('foo.f2')
obj = Foo()
obj.f1()
obj.f2()
class Base:
    def f1(self):
        print('base.f1')
class Foo(Base):
    def f2(self):
        print('before')
        self.f1() # 调用了f1方法   obj.f1()
        print('foo.f2')
obj = Foo()
obj.f2()
>>> before
>>> base.f1
>>> foo.f2
class Base:
    def f1(self):
        print('base.f1')
class Foo(Base):
    def f2(self):
        print("before")
        self.f1() # obj,Foo类创建出来的对象。 obj.f1
        print('foo.f2')
  def f1(self):
        print('foo.f1')
obj = Foo()
obj.f1() # obj对象到底是谁?优先就会先去谁里面找。
obj.f2()
>>> before
>>> foo.f1
>>> foo.f2
class Base:
    def f1(self):
        print('before')
        self.f2() # slef是obj对象(Foo类创建的对象) obj.f2
        print('base.f1')
  def f2(self):
        print('base.f2')
class Foo(Base):
    def f2(self):
        print('foo.f2')
obj = Foo()
obj.f1() # 优先去Foo类中找f1,因为调用f1的那个对象是Foo类创建出来的。
>>> before
>>> foo.f2
>>> base.f1
b1 = Base()
b1.f1()
>>> before
>>> base.f2
>>> base.f1
class TCPServer:
    def f1(self):
        print("TCPServer")
class ThreadingMixIn:
    def f1(self):
        print("ThreadingMixIn")
class ThreadingTCPServer(ThreadingMixIn, TCPServer): 
    def run(self):
        print('before')
        self.f1()
        print('after')
obj = ThreadingTCPServer()
obj.run()
>>> before
>>> ThreadingMixIn
>>> after
class BaseServer:
    def serve_forever(self, poll_interval=0.5):
        self._handle_request_noblock()
    def _handle_request_noblock(self):
        self.process_request(request, client_address)
    def process_request(self, request, client_address):
        pass
class TCPServer(BaseServer):
    pass
class ThreadingMixIn:
    def process_request(self, request, client_address):
        pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): 
    pass
obj = ThreadingTCPServer()
obj.serve_forever()

96447814-120fc980-1245-11eb-938d-6ea408716c72.png

小结:

  • 执行对象.方法时,优先去当前对象所关联的类中找,没有的话才去她的父类中查找。
  • Python支持多继承:先继承左边、再继承右边的。
  • self到底是谁?去self对应的那个类中去获取成员,没有就按照继承关系向上查找 。

2.3 多态

多态,按字面翻译其实就是多种形态。

  • 其他编程语言多态
  • Python中多态

其他编程语言中,是不允许这样类编写的,例如:Java

class Cat{  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
}
class Dog {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
    public void work() {  
        System.out.println("看家");  
    }  
}
public class Test {
   public static void main(String[] args) {
       obj1 = Cat()
     obj2 = Cat()
       show(obj1)
       show(obj2)
    obj3 = Dog()
        show(obj3)
   }  
    public static void show(Cat a)  {
      a.eat()
    }  
}
abstract class Animal {  
    abstract void eat();  
}  
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
}
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
    public void work() {  
        System.out.println("看家");  
    }  
}
public class Test {
   public static void main(String[] args) {
       obj1 = Cat()
       show(obj1)
     obj2 = Dog()
     show(obj2)
   }  
    public static void show(Animal a)  {
      a.eat()
    }  
}

在java或其他语言中的多态是基于:接口 或 抽象类和抽象方法来实现,让数据可以以多种形态存在。

在Python中则不一样,由于Python对数据类型没有任何限制,所以他天生支持多态。

def func(arg):
    v1 = arg.copy() # 浅拷贝
    print(v1)
func("lbw")
func([11,22,33,44])
class Email(object):
    def send(self):
        print("发邮件")
class Message(object):
    def send(self):
        print("发短信")
def func(arg):
    v1 = arg.send()
    print(v1)
v1 = Email()
func(v1)
v2 = Message()
func(v2)

在程序设计中,鸭子类型(duck typing)是动态类型的一种风格。在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型,例如:一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟可以被称为鸭子。


小结:


封装,将方法封装到类中 或 将数据封装到对象中,便于以后使用。


继承,将类中的公共的方法提取到基类中去实现。


多态,Python默认支持多态(这种方式称之为鸭子类型),最简单的基础下面的这段代码即可。

def func(arg):
    v1 = arg.copy() # 浅拷贝
    print(v1)
func("lbw")
func([11,22,33,44])

3. 扩展:再看数据类型

在初步了解面向对象之后,再来看看我们之前学习的:str、list、dict等数据类型,他们其实都一个类,根据类可以创建不同类的对象。

96447814-120fc980-1245-11eb-938d-6ea408716c72.png

# 实例化一个str类的对象v1
v1 = str("lbw") 
# 通过对象执行str类中的upper方法。
data = v1.upper()
print(data)

总结

类和对象的关系。


面向对象编程中常见的成员:


绑定方法


实例变量


self到底是什么?


面向对象的三大特性。


面向对象的应用场景


数据封装。


封装数据 + 方法再对数据进行加工处理。


创建同一类的数据且同类数据可以具有相同的功能(方法)。


补充:在Python3中编写类时,默认都会继承object(即使不写也会自动继承)。


class Foo:

   pass


class Foo(object):

   pass

这一点在Python2是不同的:


继承object,新式类


不继承object,经典类

面向对象进阶

目标:掌握面向对象进阶相关知识点,能沟通更加自如的使用面向对象来进行编程。


概要:


成员


变量


实例变量


类变量


方法


绑定方法


类方法


静态方法


属性


成员修饰符(公有/私有)


“对象嵌套”


特殊成员


1.成员

面向对象中的所有成员如下:


变量


实例变量


类变量


方法


绑定方法


类方法


静态方法


属性


通过面向对象进行编程时,会遇到很多种情况,也会使用不同的成员来实现,接下来我们来逐一介绍成员特性和应用场景。

1.1 变量

  • 实例变量,属于对象,每个对象中各自维护自己的数据。
  • 类变量,属于类,可以被所有对象共享,一般用于给对象提供公共数据(类似于全局变量)。
class Person(object):
    country = "中国" #类变量
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def show(self):
        # message = "{}-{}-{}".format(Person.country, self.name, self.age)
        message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)
print(Person.country) # 中国
p1 = Person("lbw",20)
print(p1.name)
print(p1.age)
print(p1.country) # 中国
p1.show() # 中国-lbw-20

提示:当把每个对象中都存在的相同的示例变量时,可以选择把它放在类变量中,这样就可以避免对象中维护多个相同数据。

易错点 & 面试题

第一题:注意读和写的区别。

class Person(object):
    country = "中国"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def show(self):
        message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)
print(Person.country) # 中国
p1 = Person("lbw",20)
print(p1.name) # lbw
print(p1.age) # 20
print(p1.country) # 中国
p1.show() # 中国-lbw-20
p1.name = "root"     # 在对象p1中讲name重置为root
p1.num = 19          # 在对象p1中新增实例变量 num=19
p1.country = "china" # 在对象p1中新增实例变量 country="china"
print(p1.country)   # china
print(Person.country) # 中国
class Person(object):
    country = "中国"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def show(self):
        message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)
print(Person.country) # 中国
Person.country = "美国"
p1 = Person("lbw",20)
print(p1.name) # lbw
print(p1.age) # 20
print(p1.country) # 美国

第二题:继承关系中的读写

class Base(object):
    country = "中国"
class Person(Base):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def show(self):
        message = "{}-{}-{}".format(Person.country, self.name, self.age)
        # message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)
# 读
print(Base.country) # 中国
print(Person.country) # 中国
obj = Person("lbw",19)
print(obj.country) # 中国
# 写
Base.country = "china"  #父类修改
Person.country = "泰国" #子类新增
obj.country = "日本"    #子类的实例化对象新增

面试题

class Parent(object):
    x = 1
class Child1(Parent):
    pass
class Child2(Parent):
    pass
print(Parent.x, Child1.x, Child2.x) # 1 1 1
Child1.x = 2
print(Parent.x, Child1.x, Child2.x) # 1 2 1
Parent.x = 3
print(Parent.x, Child1.x, Child2.x) # 3 2 3

1.2 方法

绑定方法,默认有一个self参数,由对象进行调用(此时self就等于调用方法的这个对象)【对象&类均可调用】


类方法,默认有一个cls参数,用类或对象都可以调用(此时cls就等于调用方法的这个类)【对象&类均可调用】


静态方法,无默认参数,用类和对象都可以调用。【对象&类均可调用】

class Foo(object):
    def __init__(self, name,age):
        self.name = name
        self.age = age
    def f1(self):
        print("绑定方法", self.name)
    @classmethod
    def f2(cls):
        print("类方法", cls)
    @staticmethod
    def f3():
        print("静态方法")
# 绑定方法(对象)
obj = Foo("lbw",20)
obj.f1() # 或者Foo.f1(obj)
# 类方法
Foo.f2()  # cls就是当前调用这个方法的类。(类)
obj.f2()  # cls就是当前调用这个方法的对象的类。
# 静态方法
Foo.f3()  # 类执行执行方法(类)
obj.f3()  # 对象执行执行方法

在Python中比较灵活,方法都可以通过对象和类进行调用;而在java、c#等语言中,绑定方法只能由对象调用;类方法或静态方法只能由类调用。

import os
import requests
class Download(object):
    def __init__(self, folder_path):
        self.folder_path = folder_path
    @staticmethod
    def download_dou_yin():
        # 下载抖音
        res = requests.get('.....')
        with open("xxx.mp4", mode='wb') as f:
            f.write(res.content)
    def download_dou_yin_2(self):
        # 下载抖音
        res = requests.get('.....')
        path = os.path.join(self.folder_path, 'xxx.mp4')
        with open(path, mode='wb') as f:
            f.write(res.content)
obj = Download("video")
obj.download_dou_yin()

面试题:

在类中 @classmethod 和 @staticmethod 的作用?

1.3 属性

属性其实是由绑定方法 + 特殊装饰器 组合创造出来的,让我们以后在调用方法时可以不加括号,例如:

class Foo(object):
    def __init__(self, name):
        self.name = name
    def f1(self):
        return 123
    @property
    def f2(self):
        return 123
obj = Foo("lbw")
v1 = obj.f1()
print(v1)
v2 = obj.f2
print(v2)

示例:以之前开发的分页的功能。

class Pagination:
    def __init__(self, current_page, per_page_num=10):
        self.per_page_num = per_page_num
        if not current_page.isdecimal():
            self.current_page = 1
            return
        current_page = int(current_page)
        if current_page < 1:
            self.current_page = 1
            return
        self.current_page = current_page
    def start(self):
        return (self.current_page - 1) * self.per_page_num
    def end(self):
        return self.current_page * self.per_page_num
user_list = ["用户-{}".format(i) for i in range(1, 3000)]
# 分页显示,每页显示10条
while True:
    page = input("请输入页码:")
    # page,当前访问的页码
    # 10,每页显示10条数据
  # 内部执行Pagination类的init方法。
    pg_object = Pagination(page, 20)
    page_data_list = user_list[ pg_object.start() : pg_object.end() ]
    for item in page_data_list:
        print(item)
class Pagination:
    def __init__(self, current_page, per_page_num=10):
        self.per_page_num = per_page_num
        if not current_page.isdecimal():
            self.current_page = 1
            return
        current_page = int(current_page)
        if current_page < 1:
            self.current_page = 1
            return
        self.current_page = current_page
    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num
    @property
    def end(self):
        return self.current_page * self.per_page_num
user_list = ["用户-{}".format(i) for i in range(1, 3000)]
# 分页显示,每页显示10条
while True:
    page = input("请输入页码:")
    pg_object = Pagination(page, 20)
    page_data_list = user_list[ pg_object.start : pg_object.end ]
    for item in page_data_list:
        print(item)

其实,除了咱们写的示例意外,在很多模块和框架的源码中也有porperty的身影,例如:requests模块。

import requests
# 内部下载视频,并将下载好的数据分装到Response对象中。
res = requests.get(
    url="https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200f240000buuer5aa4tij4gv6ajqg",
    headers={
        "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 FS"
    }
)
# 去对象中获取text,其实需要读取原始文本字节并转换为字符串
res.text

关于属性的编写有两种方式:

  • 方式一,基于装饰器
class C(object):
    @property
    def x(self):
        pass
    @x.setter
    def x(self, value):
        pass
    @x.deleter
    def x(self):
    pass
obj = C()
obj.x
obj.x = 123
del obj.x

方式二,基于定义变量

class C(object):
    def getx(self): 
  pass
    def setx(self, value): 
  pass
    def delx(self): 
  pass
    x = property(getx, setx, delx, "I'm the 'x' property.")
obj = C()
obj.x
obj.x = 123
del obj.x

Django源码一撇:

class WSGIRequest(HttpRequest):
    def __init__(self, environ):
        script_name = get_script_name(environ)
        # If PATH_INFO is empty (e.g. accessing the SCRIPT_NAME URL without a
        # trailing slash), operate as if '/' was requested.
        path_info = get_path_info(environ) or '/'
        self.environ = environ
        self.path_info = path_info
        # be careful to only replace the first slash in the path because of
        # http://test/something and http://test//something being different as
        # stated in https://www.ietf.org/rfc/rfc2396.txt
        self.path = '%s/%s' % (script_name.rstrip('/'),
                               path_info.replace('/', '', 1))
        self.META = environ
        self.META['PATH_INFO'] = path_info
        self.META['SCRIPT_NAME'] = script_name
        self.method = environ['REQUEST_METHOD'].upper()
        # Set content_type, content_params, and encoding.
        self._set_content_type_params(environ)
        try:
            content_length = int(environ.get('CONTENT_LENGTH'))
        except (ValueError, TypeError):
            content_length = 0
        self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
        self._read_started = False
        self.resolver_match = None
    def _get_scheme(self):
        return self.environ.get('wsgi.url_scheme')
    def _get_post(self):
        if not hasattr(self, '_post'):
            self._load_post_and_files()
        return self._post
    def _set_post(self, post):
        self._post = post
    @property
    def FILES(self):
        if not hasattr(self, '_files'):
            self._load_post_and_files()
        return self._files
    POST = property(_get_post, _set_post)

写在最后,对属性进行一个补充:

由于属性和实例变量的调用方式相同,所以在编写时需要注意:属性名称 不要 实例变量 重名。

class Foo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    @property
    def func(self):
        return 123
obj = Foo("lbw", 123)
print(obj.name)
print(obj.func)

一旦重名,可能就会有报错。

class Foo(object):
    def __init__(self, name, age):
        self.name = name  # 报错,错认为你想要调用 @name.setter 装饰的方法。
        self.age = age
    @property
    def name(self):
        return "{}-{}".format(self.name, self.age)
obj = Foo("lbw", 123)
class Foo(object):
    def __init__(self, name, age):
        self.name = name 
        self.age = age
    @property
    def name(self):
        return "{}-{}".format(self.name, self.age) # 报错,循环调用自己(直到层级太深报错)
    @name.setter
    def name(self, value):
        print(value)
obj = Foo("lbw", 123)
print(obj.name)

如果真的想要在名称上创建一些关系,可以让实例变量加上一个下划线。

class Foo(object):
    def __init__(self, name, age):
        self._name = name
        self.age = age
    @property
    def name(self):
        return "{}-{}".format(self._name, self.age)
obj = Foo("lbw", 123)
print(obj._name)
print(obj.name)

2.成员修饰符

Python中成员的修饰符就是指的是:公有、私有。

  • 公有,在任何地方都可以调用这个成员。
  • 私有,只有在类的内部才可以调用改成员(成员是以两个下划线开头,则表示该成员为私有)。

示例一:

class Foo(object):
    def __init__(self, name, age):
        self.__name = name
        self.age = age
    def get_data(self):
        return self.__name
    def get_age(self):
        return self.age
obj = Foo("lbw", 123)
# 公有成员
print(obj.age)
v1 = self.get_age()
print(v1)
# 私有成员
# print(obj.__name) # 错误,由于是私有成员,只能在类中进行使用。
v2 = obj.get_data()
print(v2)

示例2:

class Foo(object):
    def get_age(self):
        print("公有的get_age")
    def __get_data(self):
        print("私有的__get_data方法")
    def proxy(self):
        print("公有的proxy")
        self.__get_data()
obj = Foo()
obj.get_age()
obj.proxy()

示例3:

class Foo(object):
    @property
    def __name(self):
        print("公有的get_age")
    @property
    def proxy(self):
        print("公有的proxy")
        self.__name
        return 1
obj = Foo()
v1 = obj.proxy
print(v1)

特别提醒:父类中的私有成员,子类无法继承。

class Base(object):
    def __data(self):
        print("base.__data")
    def num(self):
        print("base.num")
class Foo(Base):
    def func(self):
        self.num()
        self.__data() # # 不允许执行父类中的私有方法
obj = Foo()
obj.func() #报错
class Base(object):
    def __data(self):
        print("base.__data")
    def num(self):
        print("base.num")
        self.__data() 
class Foo(Base):
    def func(self):
        self.num()
obj = Foo()
obj.func()#这样可以执行了

写在最后,按理说私有成员是无法被外部调用,但如果用一些特殊的语法也可以(Flask源码中有这种写法,大家写代码不推荐这样写)。

class Foo(object):
    def __init__(self):
        self.__num = 123
        self.age = 19
    def __msg(self):
        print(1234)
obj = Foo()
print(obj.age)
print(obj._Foo__num)
obj._Foo__msg()

成员是否可以作为独立的功能暴露给外部,让外部调用并使用。

  • 可以,公有。
  • 不可以,内部其他放的一个辅助,私有。

3.对象嵌套

在基于面向对象进行编程时,对象之间可以存在各种各样的关系,例如:组合、关联、依赖等(Java中的称呼),用大白话来说就是各种嵌套。

下面我们就用示例来学习常见的嵌套的情景:

情景一:

class Student(object):
    """ 学生类 """
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def message(self):
        data = "我是一名学生,我叫:{},我今年{}岁".format(self.name, self.age)
        print(data)
s1 = Student("lbw", 19)
s2 = Student("Alex", 19)
s3 = Student("日天", 19)
class Classes(object):
    """ 班级类 """
    def __init__(self, title):
        self.title = title
        self.student_list = []
    def add_student(self, stu_object):
        self.student_list.append(stu_object)
    def add_students(self, stu_object_list):
        for stu in stu_object_list:
            self.add_student(stu)
    def show_members(self):
        for item in self.student_list:
            # print(item)
            item.message()
c1 = Classes("三年二班")
c1.add_student(s1)
c1.add_students([s2, s3])
print(c1.title)
print(c1.student_list)

情景二:

class Student(object):
    """ 学生类 """
    def __init__(self, name, age, class_object):
        self.name = name
        self.age = age
        self.class_object = class_object
    def message(self):
        data = "我是一名{}班的学生,我叫:{},我今年{}岁".format(self.class_object.title, self.name, self.age)
        print(data)
class Classes(object):
    """ 班级类 """
    def __init__(self, title):
        self.title = title
c1 = Classes("Python全栈")
c2 = Classes("Linux云计算")
user_object_list = [
    Student("lbw", 19, c1),
    Student("Alex", 19, c1),
    Student("日天", 19, c2)
]
for obj in user_object_list:
    print(obj.name,obj.age, obj.class_object.title)

情景三:

class Student(object):
    """ 学生类 """
    def __init__(self, name, age, class_object):
        self.name = name
        self.age = age
        self.class_object = class_object
    def message(self):
        data = "我是一名{}班的学生,我叫:{},我今年{}岁".format(self.class_object.title, self.name, self.age)
        print(data)
class Classes(object):
    """ 班级类 """
    def __init__(self, title, school_object):
        self.title = title
        self.school_object = school_object
class School(object):
    """ 学校类 """
    def __init__(self, name):
        self.name = name
s1 = School("北京校区")
s2 = School("上海校区")
c1 = Classes("Python全栈", s1)
c2 = Classes("Linux云计算", s2)
user_object_list = [
    Student("lbw", 19, c1),
    Student("Alex", 19, c1),
    Student("日天", 19, c2)
]
for obj in user_object_list:
    print(obj.name, obj.class_object.title ,  obj.class_object.school_object.name)

4.特殊成员

在Python的类中存在一些特殊的方法,这些方法都是 __方法__ 格式,这种方法在内部均有特殊的含义,接下来我们来讲一些常见的特殊成员:

__init__,初始化方法

class Foo(object):
    def __init__(self, name):
        self.name = name
obj = Foo("lbw")

__new__,构造方法

class Foo(object):
    def __init__(self, name):
        print("第二步:初始化对象,在空对象中创建数据")
        self.name = name
    def __new__(cls, *args, **kwargs):
        print("第一步:先创建空对象并返回")
        return object.__new__(cls)
obj = Foo("lbw")

__call__

class Foo(object):
    def __call__(self, *args, **kwargs):
        print("执行call方法")
obj = Foo()
obj()
  • __str__
class Foo(object):
    def __str__(self):
        return "哈哈哈哈"
obj = Foo()
data = str(obj)
print(data)

__dict__

class Foo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
obj = Foo("lbw",19)
print(obj.__dict__)

__getitem____setitem____delitem__

class Foo(object):
    def __getitem__(self, item):
        pass
    def __setitem__(self, key, value):
        pass
    def __delitem__(self, key):
        pass
obj = Foo("lbw", 19)
obj["x1"]
obj['x2'] = 123
del obj['x3']

__enter____exit__

class Foo(object):
    def __enter__(self):
        print("进入了")
        return 666
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("出去了")
obj = Foo()
with obj as data:
    print(data)

超前知识:数据连接,每次对远程的数据进行操作时候都必须经历。

1.连接 = 连接数据库

2.操作数据库

3.关闭连接

class SqlHelper(object):
    def __enter__(self):
        self.连接 = 连接数据库
        return 连接
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.连接.关闭
with SqlHelper() as 连接:
    连接.操作..
with SqlHelper() as 连接:
    连接.操作...
# 面试题(补充代码,实现如下功能)
class Context:
    def do_something(self):
        print('内部执行')
with Context() as ctx:
    print('内部执行')
    ctx.do_something()
上下文管理的语法。

__add__ 等。

class Foo(object):
    def __init__(self, name):
        self.name = name
    def __add__(self, other):
        return "{}-{}".format(self.name, other.name)
v1 = Foo("alex")
v2 = Foo("sb")
# 对象+值,内部会去执行 对象.__add__方法,并将+后面的值当做参数传递过去。
v3 = v1 + v2
print(v3)

__iter__

  • 迭代器
# 迭代器类型的定义:
    1.当类中定义了 __iter__ 和 __next__ 两个方法。
    2.__iter__ 方法需要返回对象本身,即:self
    3. __next__ 方法,返回下一个数据,如果没有数据了,则需要抛出一个StopIteration的异常。
  官方文档:https://docs.python.org/3/library/stdtypes.html#iterator-types
# 创建 迭代器类型 :
  class IT(object):
        def __init__(self):
            self.counter = 0
        def __iter__(self):
            return self
        def __next__(self):
            self.counter += 1
            if self.counter == 3:
                raise StopIteration()
            return self.counter
# 根据类实例化创建一个迭代器对象:
    obj1 = IT()
    # v1 = obj1.__next__()
    # v2 = obj1.__next__()
    # v3 = obj1.__next__() # 抛出异常
    v1 = next(obj1) # obj1.__next__()
    print(v1)
    v2 = next(obj1)
    print(v2)
    v3 = next(obj1)
    print(v3)
    obj2 = IT()
    for item in obj2:  # 首先会执行迭代器对象的__iter__方法并获取返回值,一直去反复的执行 next(对象) 
        print(item)
迭代器对象支持通过next取值,如果取值结束则自动抛出StopIteration。
for循环内部在循环时,先执行__iter__方法,获取一个迭代器对象,然后不断执行的next取值(有异常StopIteration则终止循环)。

生成器

# 创建生成器函数
    def func():
        yield 1
        yield 2
# 创建生成器对象(内部是根据生成器类generator创建的对象),生成器类的内部也声明了:__iter__、__next__ 方法。
    obj1 = func()
    v1 = next(obj1)
    print(v1)
    v2 = next(obj1)
    print(v2)
    v3 = next(obj1)
    print(v3)
    obj2 = func()
    for item in obj2:
        print(item)
如果按照迭代器的规定来看,其实生成器类也是一种特殊的迭代器类(生成器也是一个中特殊的迭代器)

可迭代对象

# 如果一个类中有__iter__方法且返回一个迭代器对象 ;则我们称以这个类创建的对象为可迭代对象。
class Foo(object):
    def __iter__(self):
        return 迭代器对象(生成器对象)
obj = Foo() # obj是 可迭代对象。
# 可迭代对象是可以使用for来进行循环,在循环的内部其实是先执行 __iter__ 方法,获取其迭代器对象,然后再在内部执行这个迭代器对象的next功能,逐步取值。
for item in obj:
    pass
class IT(object):
    def __init__(self):
        self.counter = 0
    def __iter__(self):
        return self
    def __next__(self):
        self.counter += 1
        if self.counter == 3:
            raise StopIteration()
        return self.counter
class Foo(object):
    def __iter__(self):
        return IT()
obj = Foo() # 可迭代对象
for item in obj: # 循环可迭代对象时,内部先执行obj.__iter__并获取迭代器对象;不断地执行迭代器对象的next方法。
    print(item)
# 基于可迭代对象&迭代器实现:自定义range
class IterRange(object):
    def __init__(self, num):
        self.num = num
        self.counter = -1
    def __iter__(self):
        return self
    def __next__(self):
        self.counter += 1
        if self.counter == self.num:
            raise StopIteration()
        return self.counter
class Xrange(object):
    def __init__(self, max_num):
        self.max_num = max_num
    def __iter__(self):
        return IterRange(self.max_num)
obj = Xrange(100)
for item in obj:
    print(item)
class Foo(object):
    def __iter__(self):
        yield 1
        yield 2
obj = Foo()
for item in obj:
    print(item)
# 基于可迭代对象&生成器 实现:自定义range
class Xrange(object):
    def __init__(self, max_num):
        self.max_num = max_num
    def __iter__(self):
        counter = 0
        while counter < self.max_num:
            yield counter
            counter += 1
obj = Xrange(100)
for item in obj:
    print(item)
常见的数据类型:
v1 = list([11,22,33,44])
v1是一个可迭代对象,因为在列表中声明了一个 __iter__ 方法并且返回一个迭代器对象。
from collections.abc import Iterator, Iterable
v1 = [11, 22, 33]
print( isinstance(v1, Iterator) )  # false,判断是否是迭代器;判断依据是__iter__ 和 __next__。
v2 = v1.__iter__()
print( isinstance(v2, Iterator) )  # True
v1 = [11, 22, 33]
print( isinstance(v1, Iterable) )  # True,判断依据是是否有 __iter__且返回迭代器对象。
v2 = v1.__iter__()
print( isinstance(v2, Iterable) )  # True,判断依据是是否有 __iter__且返回迭代器对象。

总结

  1. 面向对象编程中的成员
  • 变量
  • 实例变量
  • 类变量
  • 方法 - 绑定方法 - 类方法 - 静态方法
  • 属性
  1. 成员修饰符
  2. 对象中的数据嵌套
  3. 特殊成员
  4. 重要概念:
  • 迭代器
  • 生成器
  • 可迭代对象

相关文章
|
1月前
|
Java 程序员 C++
Python 面向对象详解!
本文详细介绍了Python中的面向对象编程(OOP),包括类、对象、继承、封装、多态和抽象等核心概念。通过具体示例,解释了如何使用类定义对象的属性和方法,以及如何通过继承实现代码重用。文章还探讨了封装和多态的重要性,并介绍了私有属性和抽象类的使用方法。最后,总结了OOP的四大支柱:封装、抽象、继承和多态,强调了这些概念在Python编程中的应用。适合Java程序员扩展Python编程知识。
68 2
|
29天前
|
Python
Python面向对象(2)
【10月更文挑战第14天】
Python面向对象(2)
|
3月前
|
Python
你真的会面向对象吗!解密Python“魔术方法”
你真的会面向对象吗!解密Python“魔术方法”
40 0
|
30天前
|
设计模式 程序员 C语言
Python面向对象
【10月更文挑战第13天】
Python面向对象
|
5月前
|
Python
Python进阶第一篇(Python的面向对象)
Python进阶第一篇(Python的面向对象)
|
6月前
|
存储 算法 安全
Python编程实验六:面向对象应用
Python编程实验六:面向对象应用
106 1
|
2月前
|
前端开发 Python
Python编程的面向对象有哪些(二)
Python编程的面向对象(二)—类的多态
|
2月前
|
IDE Java 开发工具
Python类与面向对象
Python类与面向对象
|
1月前
|
Python
Python编程-关于面向对象的一些
Python编程-关于面向对象的一些
|
6月前
|
人工智能 自然语言处理 开发者
Python基础教程——面向对象
Python基础教程——面向对象