18. 面向对象进阶

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

概要:

  • 成员

    • 变量

      • 实例变量
      • 类变量
    • 方法
      • 绑定方法
      • 类方法
      • 静态方法
    • 属性
  • 成员修饰符(公有/私有)

  • “对象嵌套”

  • 特殊成员

1.成员

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

  • 变量

    • 实例变量
    • 类变量
  • 方法
    • 绑定方法
    • 类方法
    • 静态方法
  • 属性

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

1.1 变量

  • 实例变量,属于对象,每个对象中各自维护自己的数据。
  • 类变量,属于类,可以被所有对象共享,一般用于给对象提供公共数据(类似于全局变量)。

class LOL(object):country = "德玛西亚"def __init__(self, name, age):self.name = nameself.age = agedef show(self):message = f"{self.country}-{self.name}-{self.age}"print(message)print(LOL.country)  # 德玛西亚p1 = LOL("盖伦", 18)
print(p1.name)
print(p1.age)
print(p1.country)  # 德玛西亚p1.show()  # 德玛西亚-盖伦-18

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

易错点 & 面试题

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

class LOL(object):country = "德玛西亚"def __init__(self, name, age):self.name = nameself.age = agedef show(self):message = f"{self.country}-{self.name}-{self.age}"print(message)print(LOL.country)  # 德玛西亚p1 = LOL("盖伦", 18)
print(p1.name)  # 盖伦
print(p1.age)  # 18
print(p1.country)  # 德玛西亚
p1.show()  # 德玛西亚-盖伦-18p1.name = "root"  # 在对象p1中将name重置为 vn
p1.num = 16  # 在对象p1中新增实例变量 num=16
p1.country = "诺克萨斯"  # 在对象p1中新增实例变量 country="诺克萨斯"print(p1.country)  # print(p1.country)   # 诺克萨斯
print(LOL.country)  # 德玛西亚
class LOL(object):country = "德玛西亚"def __init__(self, name, age):self.name = nameself.age = agedef show(self):message = f"{self.country}-{self.name}-{self.age}"print(message)print(LOL.country)  # 德玛西亚LOL.country = "艾欧尼亚"p1 = LOL("盖伦", 18)
print(p1.name)  # 盖伦
print(p1.age)  # 18
print(p1.country)  # 艾欧尼亚

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

class Base(object):country = "德玛西亚"class LOL(Base):def __init__(self, name, age):self.name = nameself.age = agedef show(self):message = f"{self.country}-{self.name}-{self.age}"print(message)# 读
print(Base.country)  # 德玛西亚
print(LOL.country)  # 德玛西亚obj = LOL("盖伦", 18)
print(obj.country)  # 德玛西亚# 写
Base.country = "战争学院"
LOL.country = "艾欧尼亚"
obj.country = "祖安"

面试题

class Parent(object):x = 1class Child1(Parent):passclass Child2(Parent):passprint(Parent.x, Child1.x, Child2.x) # 1 1 1Child1.x = 2
print(Parent.x, Child1.x, Child2.x) # 1 2 1Parent.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 = nameself.age = agedef f1(self):print("绑定方法", self.name)@classmethoddef f2(cls):print("类方法", cls)@staticmethoddef f3():print("静态方法")# 绑定方法(对象)
obj = Foo("盖伦",18)
obj.f1() # Foo.f1(obj)# 类方法
Foo.f2()  # cls就是当前调用这个方法的类。(类)
obj.f2()  # cls就是当前调用这个方法的对象的类。# 静态方法
Foo.f3()  # 类执行执行方法(类)
obj.f3()  # 对象执行执行方法

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

import os
import requestsclass Download(object):def __init__(self, folder_path):self.folder_path = folder_path@staticmethoddef 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 = namedef f1(self):return 123@propertydef f2(self):return 123obj = Foo("盖伦")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_numif not current_page.isdecimal():self.current_page = 1returncurrent_page = int(current_page)if current_page < 1:self.current_page = 1returnself.current_page = current_pagedef start(self):return (self.current_page - 1) * self.per_page_numdef end(self):return self.current_page * self.per_page_numuser_list = [f"用户-{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_numif not current_page.isdecimal():self.current_page = 1returncurrent_page = int(current_page)if current_page < 1:self.current_page = 1returnself.current_page = current_page@propertydef start(self):return (self.current_page - 1) * self.per_page_num@propertydef end(self):return self.current_page * self.per_page_numuser_list = [f"用户-{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):@propertydef x(self):pass@x.setterdef x(self, value):pass@x.deleterdef x(self):passobj = C()obj.x
    obj.x = 123
    del obj.x
    
  • 方式二,基于定义变量

    class C(object):def getx(self): passdef setx(self, value): passdef delx(self): passx = 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 = environself.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.txtself.path = '%s/%s' % (script_name.rstrip('/'),path_info.replace('/', '', 1))self.META = environself.META['PATH_INFO'] = path_infoself.META['SCRIPT_NAME'] = script_nameself.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 = 0self._stream = LimitedStream(self.environ['wsgi.input'], content_length)self._read_started = Falseself.resolver_match = Nonedef _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._postdef _set_post(self, post):self._post = post@propertydef FILES(self):if not hasattr(self, '_files'):self._load_post_and_files()return self._filesPOST = property(_get_post, _set_post)

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

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

class Foo(object):def __init__(self, name, age):self.name = nameself.age = age@propertydef func(self):return 123obj = Foo("盖伦", 123)
print(obj.name)
print(obj.func)

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

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

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

class Foo(object):def __init__(self, name, age):self._name = nameself.age = age@propertydef name(self):return f"{self.name}-{self.age}"obj = Foo("盖伦", 123)
print(obj._name)
print(obj.name)

2.成员修饰符

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

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

示例一:

class Foo(object):def __init__(self, name, age):self.__name = nameself.age = agedef get_data(self):return self.__namedef get_age(self):return self.ageobj = Foo("盖伦", 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):@propertydef __name(self):print("公有的get_age")@propertydef proxy(self):print("公有的proxy")self.__namereturn 1obj = 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 = 123self.age = 19def __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 = nameself.age = agedef message(self):data = f"我是一名学生,我叫:{self.name},我今年{self.age}岁"print(data)s1 = Student("盖伦", 19)
s2 = Student("vn", 19)
s3 = Student("ez", 19)class Classes(object):""" 班级类 """def __init__(self, title):self.title = titleself.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 = nameself.age = ageself.class_object = class_objectdef message(self):data = f"我是一名{self.class_object.title}班的学生,我叫:{self.name},我今年{self.age}岁"print(data)class Classes(object):""" 班级类 """def __init__(self, title):self.title = titlec1 = Classes("德玛西亚")
c2 = Classes("艾欧尼亚")user_object_list = [Student("盖伦", 19, c1),Student("vn", 19, c1),Student("ez", 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 = nameself.age = ageself.class_object = class_objectdef message(self):data = f"我是一名{self.class_object.title}班的学生,我叫:{self.name},我今年{self.age}岁"print(data)class Classes(object):""" 班级类 """def __init__(self, title, school_object):self.title = titleself.school_object = school_objectclass School(object):""" 学校类 """def __init__(self, name):self.name = names1 = School("诺克萨斯校区")
s2 = School("战争学院校区")c1 = Classes("德玛西亚", s1)
c2 = Classes("艾欧尼亚", s1)user_object_list = [Student("盖伦", 19, c1),Student("vn", 19, c1),Student("ez", 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 = nameobj = Foo("盖伦")
    
  • __new__,构造方法

    class Foo(object):def __init__(self, name):print("第二步:初始化对象,在空对象中创建数据")self.name = namedef __new__(cls, *args, **kwargs):print("第一步:先创建空对象并返回")return object.__new__(cls)obj = Foo("盖伦")
    
  • __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 = nameself.age = ageobj = Foo("盖伦",19)
    print(obj.__dict__)
    
  • __getitem____setitem____delitem__

    class Foo(object):def __getitem__(self, item):passdef __setitem__(self, key, value):passdef __delitem__(self, key):passobj = Foo("盖伦", 19)obj["x1"]
    obj['x2'] = 123
    del obj['x3']
    
  • __enter____exit__

    class Foo(object):def __enter__(self):print("进入了")return 666def __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 = namedef __add__(self, other):return f"{self.name}-{other.name}"v1 = Foo("vn")
    v2 = Foo("sb")# 对象+值,内部会去执行 对象.__add__方法,并将+后面的值当做参数传递过去。
    v3 = v1 + v2
    print(v3)
    
  • __iter__

    • 迭代器

      # 迭代器类型的定义:1.当类中定义了 __iter__ 和 __next__ 两个方法。2.__iter__ 方法需要返回对象本身,即:self3. __next__ 方法,返回下一个数据,如果没有数据了,则需要抛出一个StopIteration的异常。官方文档:https://docs.python.org/3/library/stdtypes.html#iterator-types# 创建 迭代器类型 :class IT(object):def __init__(self):self.counter = 0def __iter__(self):return selfdef __next__(self):self.counter += 1if 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 1yield 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 = 0def __iter__(self):return selfdef __next__(self):self.counter += 1if self.counter == 3:raise StopIteration()return self.counterclass 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 = numself.counter = -1def __iter__(self):return selfdef __next__(self):self.counter += 1if self.counter == self.num:raise StopIteration()return self.counterclass Xrange(object):def __init__(self, max_num):self.max_num = max_numdef __iter__(self):return IterRange(self.max_num)obj = Xrange(100)for item in obj:print(item)
      
      class Foo(object):def __iter__(self):yield 1yield 2obj = Foo()
      for item in obj:print(item)
      
      # 基于可迭代对象&生成器 实现:自定义rangeclass Xrange(object):def __init__(self, max_num):self.max_num = max_numdef __iter__(self):counter = 0while counter < self.max_num:yield countercounter += 1obj = Xrange(100)
      for item in obj:print(item)
      

      常见的数据类型:

      v1 = list([11,22,33,44])v1是一个可迭代对象,因为在列表中声明了一个 __iter__ 方法并且返回一个迭代器对象。
      
      from collections.abc import Iterator, Iterablev1 = [11, 22, 33]
      print( isinstance(v1, Iterator) )  # false,判断是否是迭代器;判断依据是__iter__ 和 __next__。
      v2 = v1.__iter__()
      print( isinstance(v2, Iterator) )  # Truev1 = [11, 22, 33]
      print( isinstance(v1, Iterable) )  # True,判断依据是是否有 __iter__且返回迭代器对象。v2 = v1.__iter__()
      print( isinstance(v2, Iterable) )  # True,判断依据是是否有 __iter__且返回迭代器对象。
      

总结

  1. 面向对象编程中的成员

    • 变量

      • 实例变量
      • 类变量
  • 方法
    - 绑定方法
    - 类方法
    - 静态方法

    • 属性
  1. 成员修饰符
  2. 对象中的数据嵌套
  3. 特殊成员
  4. 重要概念:
    • 迭代器
    • 生成器
    • 可迭代对象

练习

  1. 列举面向对象的成员并简述他们的特点。

    - 变量- 实例变量,属于对象。每个对象中中都封装各自的值。只能通过的对象来进行调用。- 类变量,属于类。每个类中各自保存的数据。可以通过对象和类来进行读取。
    - 方法- 绑定方法,默认有一个self参数,由对象进行调用(此时self就等于调用方法的这个对象)【对象&类均可调用】- 类方法,默认有一个cls参数,用类或对象都可以调用(此时cls就等于调用方法的这个类)【对象&类均可调用】- 静态方法,无默认参数,用类和对象都可以调用。【对象&类均可调用】
    - 属性基于方法+property装饰器实现可以实现,可以实现obj.属性名obj.属性名 = 123del obj.属性名语法和方法的对应关系。
    
  2. @staticmethod 和 @classmethod的作用是什么?

    @classmethod,将一个方法变换类方法;类和方法都可以调用,且cls默认是当前执行该方法的类。
    @staticmethod,将一个方法变换为静态方法,静态方法的调用可以是类也可以对象,无默认参数。
    
  3. 面向对象中如何让成员变为私有。

    前面加上 __
    
  4. __new__方法的作用?

    __new__是构造方法,用于创建对象(空对象),在__init__方法执行之前。
    
  5. 简述你理解的:迭代器、生成器、可迭代对象。

    迭代器,含有__iter__方法和__next__方法,__iter__返回自身,__next__可以获取数据(终止是抛出StopIteration异常。可以被for循环。生成器,在定义时是函数中重要包含yield就是生成器函数,执行函数获得生成器对象(一种特殊的迭代器);可以通过next取值 & 也可以通过for循环取值。可迭代对象,含有 __iter__方法,且返回一个迭代器对象。可以被for循环。
    
  6. 看代码写结果

    class Foo(object):a1 = 1def __init__(self,num):self.num = numdef show_data(self):print(self.num+self.a1)obj1 = Foo(666)
    obj2 = Foo(999)print(obj1.num)
    print(obj1.a1)obj1.num = 18
    obj1.a1 = 99print(obj1.num)
    print(obj1.a1)print(obj2.a1)
    print(obj2.num)
    print(obj2.num)
    print(Foo.a1)
    print(obj1.a1)"""
    666
    1
    18
    99
    1
    999
    999
    1
    99
    """
    
  7. 看代码写结果,注意返回值。

    class Foo(object):def f1(self):return 999def f2(self):v = self.f1()print('f2')return vdef f3(self):print('f3')return self.f2()def run(self):result = self.f3()print(result)obj = Foo()
    v1 = obj.run()
    print(v1)"""
    f3
    f2
    999
    None
    """
    
  8. 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】

    class Foo(object):def f1(self):print('f1')@staticmethoddef f2():print('f2')obj = Foo()
    obj.f1()
    obj.f2()Foo.f1()
    Foo.f2()
    
    class Foo(object):def f1(self):print('f1')@staticmethoddef f2():print('f2')obj = Foo()
    obj.f1() # f1
    obj.f2() # f2Foo.f1() # 报错
    Foo.f2() # f2
    
  9. 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】

    class Foo(object):def f1(self):print('f1')self.f2()self.f3()@classmethoddef f2(cls):print('f2')@staticmethoddef f3():print('f3')obj = Foo()
    obj.f1()"""
    f1
    f2
    f3
    """
    
  10. 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】

    class Base(object):@classmethoddef f2(cls):print('f2')@staticmethoddef f3():print('f3')class Foo(Base):def f1(self):print('f1')self.f2()self.f3()obj = Foo()
    obj.f1()"""
    f1
    f2
    f3
    """
    
  11. 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】

    class Foo(object):a1 = 1__a2 = 2def __init__(self,num):self.num = numself.__salary = 1000def show_data(self):print(self.num+self.a1)obj = Foo(666)print(obj.num)
    print(obj.a1)
    print(obj.__salary)
    print(obj.__a2)
    print(Foo.a1)
    print(Foo.__a2)
    obj.show_data()
    
    class Foo(object):a1 = 1__a2 = 2def __init__(self, num):self.num = numself.__salary = 1000def show_data(self):print(self.num + self.a1)obj = Foo(666)print(obj.num)  # 666
    print(obj.a1)  # 1
    print(obj.__salary)  # 报错
    print(obj.__a2)  # 报错
    print(Foo.a1)  # 1
    print(Foo.__a2)  # 报错
    obj.show_data()  # 667
    
  12. 看代码写结果

    class Foo(object):def __init__(self, age):self.age = agedef display(self):print(self.age)data_list = [Foo(8), Foo(9)]
    # print(data_list[0].age)
    # data_list[1].display()for item in data_list:print(item.age, item.display()) """
    8
    8 None
    9
    9 None
    """
    
  13. 看代码写结果

    class Base(object):def __init__(self, a1):self.a1 = a1def f2(self, arg):print(self.a1, arg)class Foo(Base):def f2(self, arg):print('666')obj_list = [Base(1), Foo(2), Foo(3)]for item in obj_list:item.f2(1)"""
    1 1
    666
    666
    """
    
  14. 看代码写结果

    class Foo(object):def __init__(self, num):self.num = numv1 = [Foo for i in range(10)]
    v2 = [Foo(5) for i in range(10)]
    v3 = [Foo(i) for i in range(10)]print(v1)
    print(v2)
    print(v3)
    
    class Foo(object):def __init__(self, num):self.num = numv1 = [Foo for i in range(10)]
    v2 = [Foo(5) for i in range(10)]
    v3 = [Foo(i) for i in range(10)]print(v1)  # [类,类,类...]
    print(v2)  # [对象(num=5),对象(num=5),对象(num=5)..]
    print(v3)  # [对象(num=0),对象(num=1),对象(num=2)..]
    
  15. 看代码写结果

    class StarkConfig(object):def __init__(self, num):self.num = numdef changelist(self, request):print(self.num, request)config_obj_list = [ StarkConfig(1),  StarkConfig(2),  StarkConfig(3) ]
    for item in config_obj_list:print(item.num)"""
    1
    2
    3
    """
    
  16. 看代码写结果

    class StarkConfig(object):def __init__(self, num):self.num = numdef changelist(self, request):print(self.num, request)config_obj_list = [StarkConfig(1), StarkConfig(2), StarkConfig(3)]
    for item in config_obj_list:item.changelist(666)"""
    1 666
    2 666
    3 666
    """
    
  17. 看代码写结果

    class StarkConfig(object):def __init__(self, num):self.num = numdef changelist(self, request):print(self.num, request)def run(self):self.changelist(999)class RoleConfig(StarkConfig):def changelist(self, request):print(666, self.num)class AdminSite(object):def __init__(self):self._registry = {}def register(self, k, v):self._registry[k] = vsite = AdminSite()site.register('盖伦', StarkConfig(19))
    site.register('root', StarkConfig(20))
    site.register("admin", RoleConfig(33))print(len(site._registry))for k, row in site._registry.items():row.changelist(5)"""
    3
    19 5
    20 5
    666 33
    """
    
  18. 看代码写结果(如有报错,请标注报错位置)

    class StarkConfig(object):def __init__(self, num):self.num = numdef run(self):self()def __call__(self, *args, **kwargs):print(self.num)class RoleConfig(StarkConfig):def __call__(self, *args, **kwargs):print(345)def __getitem__(self, item):return self.num[item]v1 = RoleConfig('vn')
    v2 = StarkConfig("wupeiqi")print(v1[1]) # l
    print(v2[2]) # 报错
    
  19. 补全代码

    class Context:passwith Context() as ctx:ctx.do_something()
    
    class Context:def __enter__(self):return selfdef __exit__(self, exc_type, exc_val, exc_tb):passdef do_something(self):passwith Context() as ctx:ctx.do_something()
    
  20. 看代码写结果

    class Department(object):def __init__(self,title):self.title = titleclass LOL(object):def __init__(self,name,age,depart):self.name = nameself.age = age self.depart = departdef message(self):msg = "我是%s,年龄%s,属于%s" %(self.name,self.age,self.depart.title)print(msg)d1 = Department('人事部')
    d2 = Department('销售部')p1 = LOL('盖伦',18,d1)
    p2 = LOL('vn',18,d1)p1.message()
    p2.message()"""
    我是盖伦,年龄18,属于人事部
    我是vn,年龄18,属于人事部
    """
    
  21. 分析代码关系,并写出正确的输出结果。

    class Node(object):def __init__(self, title):self.title = titleself.children = []def add(self, node):self.children.append(node)def __getitem__(self, item):return self.children[item]root = Node("德玛西亚")root.add(Node("河南省"))
    root.add(Node("河北省"))print(root.title)
    print(root[0])
    print(root[0].title)
    print(root[1])
    print(root[1].title)"""
    德玛西亚
    Node对象(title=河南省)
    河南省
    Node对象(title=河北省)
    河北省
    """
    
  22. 分析代码关系,并写出正确的输出结果。

    class Node(object):def __init__(self, title):self.title = titleself.children = []def add(self, node):self.children.append(node)def __getitem__(self, item):return self.children[item]root = Node("德玛西亚")root.add(Node("河南省"))
    root.add(Node("河北省"))
    root.add(Node("陕西省"))
    root.add(Node("山东省"))root[1].add(Node("石家庄"))
    root[1].add(Node("保定"))
    root[1].add(Node("廊坊"))root[3].add(Node("潍坊"))
    root[3].add(Node("烟台"))
    root[3].add(Node("威海"))root[1][1].add(Node("雄安"))
    root[1][1].add(Node("望都"))print(root.title)
    print(root[0].title)
    print(root[1].title)
    print(root[1][0].title)
    print(root[1][2].title)
    print(root[1][1][0].title)"""
    德玛西亚
    河南省
    河北省
    石家庄
    廊坊
    雄安
    """
    

18. 面向对象进阶相关推荐

  1. Python之面向对象进阶

    Python之面向对象进阶 进阶有:Python 类的成员.成员修饰符.类的特殊成员. 一.类的成员 类的成员可以分为三大类:字段.方法和属性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据 ...

  2. Day 23 面向对象进阶

    目录 面向对象进阶 类的继承 什么是继承 为什么要用继承 对象的继承 对象查找属性的顺序 类的派生 类的组合 菱形继承问题 类的分类 菱形继承问题 多态与多态性 多态 多态性 面向对象进阶 类的继承 ...

  3. JavaSE——面向对象进阶(封装、this、static、代码块、包、权限修饰符、main方法详解)

    第2节 面向对象进阶 一.封装与private 概述: 封装的意义在于保护或者防止代码(数据)被我们无意中破坏.保护成员属性,不让类以外的程序直接访问和修改. 封装原则: 隐藏对象的属性和实现细节,仅 ...

  4. Python面向对象进阶和socket网络编程

    写在前面 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese:def __init__(self, ...

  5. Java大数据-Week2-Day2面向对象进阶

    第二章第三节 面向对象进阶 文章目录 第二章第三节 面向对象进阶 前言 封装 this关键字 静态static 包 包2 权限修饰符 代码块 main方法详解 总结 前言 # 第三章第3节 面向对象进 ...

  6. python进阶课程目标 学习内容_Python学习教程(Python学习路线):第九天-面向对象进阶...

    面向对象进阶 在前面的章节我们已经了解了面向对象的入门知识,知道了如何定义类,如何创建对象以及如何给对象发消息.为了能够更好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程 ...

  7. Day09.面向对象进阶

    面向对象进阶 文章目录 面向对象进阶 前言 一. @property装饰器 二. \_\_slots\_\_魔法 三. 静态方法和类方法 四. 类之间的关系 五. 继承和多态 六. 综合案例 案例1: ...

  8. python进阶路线知乎_Python学习教程(Python学习路线):第九天-面向对象进阶

    面向对象进阶 在前面的章节我们已经了解了面向对象的入门知识,知道了如何定义类,如何创建对象以及如何给对象发消息.为了能够更好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程 ...

  9. Python基础内容训练11(面向对象进阶)

    面向对象进阶 一 综合案例 案例1 :简单的计算器 # 实现一个计算器可以进行简单的基本操作,以及打印结果def jia(n1, n2):return n1 + n2def jian(n1, n2): ...

最新文章

  1. bat脚本交互输入_基于winserver操作系统的自动清理Oracle3天前归档日志脚本分享...
  2. B-Trees【设计数据密集型应用】
  3. 比尔盖茨2016好书推荐
  4. 【Spring学习】spring开发包介绍
  5. Web 应用程序的自动化测试
  6. Asp.Net Core 轻松学-经常使用异步的你,可能需要看看这个文章
  7. jquery层级原则器(匹配后代元素div)
  8. bat循环执行带参数_C++:main处理命令行选项/main函数的参数
  9. c语言字符数组不写,C语言数组
  10. 华为鸿蒙系统使用视频,原生鸿蒙系统,华为WATCH 3上手视频曝光
  11. java xml setdoctype_如何在Java中使用DOM将自定义doctype标记添加到带有xhtml标记的xml中?...
  12. qtp12版本下载安装破解教程
  13. 价格厚道!855最强机皇发布:看完心动了吗?
  14. 举个栗子!Tableau 技巧(97):离线安装 Linux 版 Tableau Server
  15. FIT2CLOUD飞致云被权威研究机构评选为中国混合云管理软件领导者
  16. IDEA复制文件名快捷键设置
  17. 读取和修改JPEG图片文件的头信息EXIF和JFIF
  18. 刻意练习:机器学习实战 -- Task01. 决策树
  19. Oracle Temp临时表空间及其故障处理
  20. 如何使用友盟统计(自定义事件)

热门文章

  1. 注册商标VS购买商标
  2. 利用DoHome APP和音箱控制LED灯实验参考步骤
  3. C# Linq First 和 FirstOrDefault的区别
  4. linux数据入表格,数据导入,导出 表操作
  5. 破解华为电脑耳机弹窗+超级终端
  6. Docker win10家庭版安装
  7. 青岛市海鲜饭店餐饮油烟污染如何解决?-安科瑞餐饮油烟监测系统
  8. 街头篮球服务器维护了是什么意思,新闻中心-自由篮球-FreeStyle2-官方网站-世纪天成游戏-街头篮球 正统续作...
  9. 批处理之家 --专注于批处理 http://www.bathome.net/
  10. 【论文】一张图了解理学硕士论文中图表尺寸规范(适用于一般性情况)