day18 面向对象进阶
课程目标:掌握面向对象进阶相关知识点,能沟通更加自如的使用面向对象来进行编程。
今日概要:
-
成员
-
-
实例变量
-
类变量
-
-
方法
-
绑定方法
-
类方法
-
静态方法
-
-
属性
-
-
成员修饰符(公有/私有)
-
“对象嵌套”
-
特殊成员
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("武沛齐",20) print(p1.name) print(p1.age) print(p1.country) # 中国 p1.show() # 中国-武沛齐-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("武沛齐",20) print(p1.name) # 武沛齐 print(p1.age) # 20 print(p1.country) # 中国 p1.show() # 中国-武沛齐-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("武沛齐",20) print(p1.name) # 武沛齐 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("武沛齐",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 # 在 Child类中新增实例变量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("武沛齐",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 的作用?
一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。而使用 @staticmethod或@classmethod,就可以不需要实例化,直接 类名.方法名() 来调用。
既然@staticmethod和@classmethod都可以直接 类名.方法名() 来调用,那他们有什么区别呢
从它们的使用上来看,
- @staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用 函数 一样。
- @classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
- @classmethod 是一个函数修饰符,它表示接下来的是一个 类方法
类方法的第一个参数cls,而实例方法的第一个参数是self,表示该类的一个实例。 - 普通对象方法至少需要一个self参数,代表类对象实例
- 类方法有类变量cls传入,从而可以用cls做一些相关的处理。并且有子类继承时,调用该类方法时,传入的类变量cls是子类,而非父类。
对于类方法,可以通过类来调用,也可以通过类的一个实例来调用 - 静态方法则没有,它基本上跟一个全局函数相同,一般来说用的很少
如果在@staticmethod中要调用到这个类的一些属性方法,只能直接 类名.属性名 或 类名.方法名。
而@classmethod因为持有cls参数,可以来调用 类的属性,类的方法,实例化对象 等,避免硬编码。
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("武沛齐") 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 装饰,表示x为类的属性,只可访问,不可修改 @property def x(self): pass # 如果有@x.setter 装饰,表示类的属性x可修改 @x.setter def x(self, value): pass # @x.deleter 装饰,表示类的属性x可删除,删除后,该类无此属性 @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("武沛齐", 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("武沛齐", 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("武沛齐", 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("武沛齐", 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("武沛齐", 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("武沛齐", 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("武沛齐", 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("武沛齐", 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("武沛齐")
-
__new__,构造方法()class Foo(object): def __init__(self, name): print("第二步:初始化对象,在空对象中创建数据") self.name = name def __new__(cls, *args, **kwargs): print("第一步:先创建空对象并返回") return object.__new__(cls) obj = Foo("武沛齐")
-
__call__(对象(),会自动执行call方法)class Foo(object): def __call__(self, *args, **kwargs): print("执行call方法") obj = Foo() obj()
-
__str__(里面必须返回字符串 有助于测试 )没有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("武沛齐",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("武沛齐", 19) obj["x1"] # 没有__getitem__会报错 obj['x2'] = 123 # 自动触发 __setitem__ del obj['x3'] #自动触发__delitem__
-
__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: # enter返回 值 data接收 data = 666
# 内部先执行enter print(data) # 等with内代码执行完毕 后 自动执行exit方法超前知识:数据连接,每次对远程的数据进行操作时候都必须经历。
1.连接 = 连接数据库
2.操作数据库
3.关闭连接class SqlHelper(object): def __enter__(self): self.连接 = 连接数据库 return 连接 def __exit__(self, exc_type, exc_val, exc_tb): self.连接.关闭 # 写一个类可以自动实现连接和关闭 用with语法 (这样我们就可以只关注操作的部分) with SqlHelper() as 连接: 连接.操作..
# 面试题(补充代码,实现如下功能) class Context: def do_something(self): print('内部执行') with Context() as ctx: print('内部执行') ctx.do_something()上下文管理的语法。(遇到with 这个类里面肯定有
__enter__、__exit__) -
__add__等(+-*/)(两个对象相加 内部肯定定义了add方法)。( 对象+值,内部会去执行 对象.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) # v3 = 999
-
__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__且返回迭代器对象。
-
总结
-
面向对象编程中的成员
-
变量
-
实例变量
-
类变量
-
-
-
方法 - 绑定方法 - 类方法 - 静态方法
-
属性
-
-
成员修饰符
-
对象中的数据嵌套
-
特殊成员
-
重要概念:
-
迭代器
-
生成器
-
可迭代对象
-
作业
列举面向对象的成员并简述他们的特点。 @staticmethod 和 @classmethod的作用是什么? 面向对象中如何让成员变为私有。 __new__方法的作用? 简述你理解的:迭代器、生成器、可迭代对象。 看代码写结果 class Foo(object): a1 = 1 def __init__(self,num): self.num = num def 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 = 99 print(obj1.num) print(obj1.a1) print(obj2.a1) print(obj2.num) print(obj2.num) print(Foo.a1) print(obj1.a1) 看代码写结果,注意返回值。 class Foo(object): def f1(self): return 999 def f2(self): v = self.f1() print('f2') return v def f3(self): print('f3') return self.f2() def run(self): result = self.f3() print(result) obj = Foo() v1 = obj.run() print(v1) 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】 class Foo(object): def f1(self): print('f1') @staticmethod def f2(): print('f2') obj = Foo() obj.f1() obj.f2() Foo.f1() Foo.f2() 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】 class Foo(object): def f1(self): print('f1') self.f2() self.f3() @classmethod def f2(cls): print('f2') @staticmethod def f3(): print('f3') obj = Foo() obj.f1() 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】 class Base(object): @classmethod def f2(cls): print('f2') @staticmethod def f3(): print('f3') class Foo(Base): def f1(self): print('f1') self.f2() self.f3() obj = Foo() obj.f1() 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】 class Foo(object): a1 = 1 __a2 = 2 def __init__(self,num): self.num = num self.__salary = 1000 def 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): def __init__(self, age): self.age = age def 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()) 看代码写结果 class Base(object): def __init__(self, a1): self.a1 = a1 def 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) 看代码写结果 class Foo(object): def __init__(self, num): self.num = num v1 = [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 StarkConfig(object): def __init__(self, num): self.num = num def 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) 看代码写结果 class StarkConfig(object): def __init__(self, num): self.num = num def 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) 看代码写结果 class StarkConfig(object): def __init__(self, num): self.num = num def 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] = v site = 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) 看代码写结果(如有报错,请标注报错位置) class StarkConfig(object): def __init__(self, num): self.num = num def 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('alex') v2 = StarkConfig("wupeiqi") print(v1[1]) print(v2[2]) 补全代码 class Context: pass with Context() as ctx: ctx.do_something() 看代码写结果 class Department(object): def __init__(self,title): self.title = title class Person(object): def __init__(self,name,age,depart): self.name = name self.age = age self.depart = depart def message(self): msg = "我是%s,年龄%s,属于%s" %(self.name,self.age,self.depart.title) print(msg) d1 = Department('人事部') d2 = Department('销售部') p1 = Person('武沛齐',18,d1) p2 = Person('alex',18,d1) p1.message() p2.message() 分析代码关系,并写出正确的输出结果。 class Node(object): def __init__(self, title): self.title = title self.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) 分析代码关系,并写出正确的输出结果。 class Node(object): def __init__(self, title): self.title = title self.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) # 1. 列举面向对象的成员并简述他们的特点。 """ - 变量 - 实例变量,属于对象。每个对象中中都封装各自的值。只能通过的对象来进行调用。 - 类变量,属于类。每个类中各自保存的数据。可以通过对象和类来进行读取。 - 方法 - 绑定方法,默认有一个self参数,由对象进行调用(此时self就等于调用方法的这个对象)【对象&类均可调用】 - 类方法,默认有一个cls参数,用类或对象都可以调用(此时cls就等于调用方法的这个类)【对象&类均可调用】 - 静态方法,无默认参数,用类和对象都可以调用。【对象&类均可调用】 - 属性 基于方法+property装饰器实现可以实现,可以实现 obj.属性名 obj.属性名 = 123 del 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. 看代码写结果 """ 666 1 18 99 1 999 999 1 99 """ # 7. 看代码写结果,注意返回值。 """ f3 f2 999 None """ # 8. 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】 """ class Foo(object): def f1(self): print('f1') @staticmethod def f2(): print('f2') obj = Foo() obj.f1() # f1 obj.f2() # f2 Foo.f1() # 报错 Foo.f2() # f2 """ # 9.看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】 """ f1 f2 f3 """ # 10.看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】 """ f1 f2 f3 """ # 11.看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】 """ class Foo(object): a1 = 1 __a2 = 2 def __init__(self, num): self.num = num self.__salary = 1000 def 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.看代码写结果 """ 8 8 None 9 9 None """ # 13.看代码写结果 """ 1 1 666 666 """ # 14.看代码写结果 """ class Foo(object): def __init__(self, num): self.num = num v1 = [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.看代码写结果 """ 1 2 3 """ # 16.看代码写结果 """ 1 666 2 666 3 666 """ # 17. 看代码写结果 """ 3 19 5 20 5 666 33 """ # 18. 看代码写结果 """ class StarkConfig(object): def __init__(self, num): self.num = num def 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('alex') v2 = StarkConfig("wupeiqi") print(v1[1]) # l print(v2[2]) # 报错 """ # 19.补全代码 """ class Context: def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): pass def do_something(self): pass with Context() as ctx: ctx.do_something() """ # 20.看代码写结果 """ 我是武沛齐,年龄18,属于人事部 我是alex,年龄18,属于人事部 """ # 21.分析代码关系,并写出正确的输出结果。 """ 中国 Node对象(title=河南省) 河南省 Node对象(title=河北省) 河北省 """ # 22. 分析代码关系,并写出正确的输出结果。 """ 中国 河南省 河北省 石家庄 廊坊 雄安 """

浙公网安备 33010602011771号