day18 面向对象进阶
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiIXZ05WZj91YpB3I2EzX4xSZz91ZsAzNfRHLGZkRGZkRfJ3bs92YsAjMfVmepNHLwJDT2A1QiVTTtplNQNkY1AnMMZTQClGVF5UMR9Fd4VGdsATNfd3bkFGazxSUhxGatJGbwhFT1Y0Mk9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLxI2MkJDZ4IWOlFjMwQzYhJ2MhRjYyUDM3EWZ2I2Y0kzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
课程目标:掌握面向对象进阶相关知识点,能沟通更加自如的使用面向对象来进行编程。
今日概要:
- 成员
- 变量
- 实例变量
- 类变量
- 方法
- 绑定方法
- 类方法
- 静态方法
- 属性
- 变量
- 成员修饰符(公有/私有)
- “对象嵌套”
- 特殊成员
1.成员
面向对象中的所有成员如下:
- 变量
- 实例变量
- 类变量
- 方法
- 绑定方法
- 类方法
- 静态方法
- 属性
通过面向对象进行编程时,会遇到很多种情况,也会使用不同的成员来实现,接下来我们来逐一介绍成员特性和应用场景。
1.1 变量
- 实例变量,属于对象,每个对象中各自维护自己的数据。
- 类变量,属于类,可以被所有对象共享,一般用于给对象提供公共数据(类似于全局变量)。
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)
print(p1.country)
p1.show()
>>输出结果:
轩小陌
20
中国
中国-轩小陌-20
提示:当每个对象中都存在的相同的实例变量时,可以选择把它放在类变量中,这样就可以避免在对象中维护多个相同数据。
易错点 & 面试题
第1题:注意读和写的区别。
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 = "美国" # 在Person类中奖country重新赋值为"美国"
p1 = Person("轩小陌",20)
print(p1.name) # 轩小陌
print(p1.age) # 20
print(p1.country) # 美国
第2题:继承关系中的读写
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" # 将Base类中的country重新赋值为'China'
Person.country = "泰国" # 在Person类中新增类变量country='泰国'
obj.country = "日本" # 在对象中obj中新增实例变量country='日本'
第3题:面试题
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("轩小陌",20)
# 绑定方法(对象)
obj.f1() 或
Foo.f1(obj)
>>输出结果:
绑定方法 轩小陌
# 类方法
Foo.f2() 或 # cls就是当前调用这个方法的类。
obj.f2() # cls就是当前调用这个方法的对象的类。
>>输出结果:
类方法 <class '__main__.Foo'>
# 静态方法
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("轩小陌")
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
@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"
}
)
关于属性的编写有两种方式:
- 方式一,基于装饰器
class C(object): @property def x(self): print('property') @x.setter def x(self, value): print('setter', value) @x.deleter def x(self): print('deleter') obj = C() obj.x obj.x = 123 del obj.x >>输出结果: property setter 123 deleter
- 方式二,基于定义变量
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中成员的修饰符就是指的是:公有、私有。
- 公有,在任何地方都可以调用这个成员。
- 私有,只有在类的内部才可以调用该成员(成员是以两个下划线开头,则表示该成员为私有)。
示例1:
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)
>>输出结果:123
v1 = self.get_age()
print(v1)
>>输出结果:轩小陌
# 私有成员
print(obj.__name)
>>输出结果:报错,由于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()
>>输出结果:
公有的get_age
公有的proxy
私有的__get_data方法
示例3:
class Foo(object):
@property
def __name(self):
print("私有的__name")
@property
def proxy(self):
print("公有的proxy")
self.__name
return 1
obj = Foo()
v1 = obj.proxy
print(v1)
>>输出结果:
公有的proxy
私有的__name
1
特别提醒:父类中的私有成员,子类无法继承。
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()
>>输出结果:
base.num
AttributeError: 'Foo' object has no attribute '_Foo__data'
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()
>>输出结果:
base.num
base.__data
注意:一般来说私有成员是无法被外部调用的,但如果用一些特殊的语法也可以从外部进行调用(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()
>>输出结果:
19
123
1234
那么,什么时候该使用公有,什么时候该使用私有呢?这取决于成员是否可以作为独立的功能暴露给外部,让外部调用并使用。
- 如果可以,使用公有。
- 如果不可以,仅作为内部其他方法的一个辅助,使用私有。
3.对象嵌套
在基于面向对象进行编程时,对象之间可以存在各种各样的关系,例如:组合、关联、依赖等(Java中的称呼),简单来说就是各种嵌套。
下面我们就用示例来了解常见的嵌套的情景:
情景1:
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:
item.message()
c1 = Classes("三年二班")
c1.add_student(s1)
c1.add_students([s2, s3])
print(c1.title)
print(c1.student_list)
>>输出结果:
三年二班
[
<__main__.Student object at 0x00000208CB971940>,
<__main__.Student object at 0x00000208CB9718E0>,
<__main__.Student object at 0x00000208CB9717C0>
]
情景2:
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)
>>输出结果:
轩小陌 19 Python全栈
Alex 19 Python全栈
日天 19 Linux云计算
情景3:
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)
>>输出结果:
轩小陌 Python全栈 北京校区
Alex Python全栈 北京校区
日天 上海校区 Linux云计算
4.特殊成员
在Python的类中存在一些特殊的方法,这些方法的格式为:
__方法__
,这种方法在内部均有特殊的含义,常见的特殊方法有:
4.1 __init__
,初始化方法
__init__
class Foo(object):
def __init__(self, name):
self.name = name
obj = Foo("轩小陌")
4.2 __new__
,构造方法
__new__
class Foo(object):
def __init__(self, name):
print("第二步:初始化对象,在空对象中创建数据")
self.name = name
def __new__(cls, *args, **kwargs):
print("第一步:先创建空对象并返回")
return object.__new__(cls)
obj = Foo("轩小陌")
4.3 __call__
:实例化对象直接执行,会调用该方法。
__call__
class Foo(object):
def __call__(self, *args, **kwargs):
print("执行call方法")
obj = Foo()
obj()
4.4 __str__
:类中如果存在该方法,在输出实例化对象时会自动执行并返回值字符串。
__str__
class Foo(object):
def __str__(self):
return "哈哈哈哈"
obj = Foo()
print(obj)
4.5 __dict__
:获取实例化对象中所有的示例变量并以字典的形式返回。
__dict__
class Foo(object):
def __init__(self, name, age):
self.name = name
self.age = age
obj = Foo("轩小陌",19)
print(obj.__dict__)
4.6 __getitem__
、 __setitem__
、 __delitem__
__getitem__
__setitem__
__delitem__
class Foo(object):
def __getitem__(self, item):
print(item)
def __setitem__(self, key, value):
print(key,value)
def __delitem__(self, key):
print(key)
obj = Foo()
obj["x1"] # 自动触发__geritem__方法
obj['x2'] = 123 # 自动触发__setitem__方法
del obj['x3'] # 自动触发__delitem__方法
>>输出结果:
x1
x2 123
x3
4.7 __enter__
、 __exit__
:上下文管理方法,成对出现
__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: # with+对象 as xx:类内部会自动执行__enter__方法
print(data) # 当with中的代码执行完毕,类内部会自动执行__exit__方法
>>输出结果:
进入
666
退出
实例:
'''
数据连接:每次对远程的数据进行操作时候都必须经过以下步骤:
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 __enter__(self):
return self
def do_something(self):
print('内部执行')
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with Context() as ctx:
print('内部执行')
ctx.do_something()
4.8 __add__
、 __sub__
、 __mul__
、 __truediv__
等。
__add__
__sub__
__mul__
__truediv__
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")
v3 = v1 + v2 # 对象+值:内部会执行对象.__add__方法,并将+后面的值当做参数传递进去。
print(v3)
>>输出结果:
alex-sb
4.9 __iter__
__iter__
4.9.1 迭代器
'''
迭代器类型的定义:
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 = next(obj1)
print(v1)
>>输出结果:1
v2 = next(obj1)
print(v2)
>>输出结果:2
v3 = next(obj1)
print(v3)
>>输出结果:StopIteration
obj2 = IT()
for item in obj2:
# 首先会执行迭代器对象的__iter__方法并获取返回obj2对象,然后返回的对象会一直反复执行__next__方法并返回给item
print(item)
>>输出结果:
1
2
迭代器对象支持通过__next__取值,如果取值结束则自动抛出StopIteration。
for内部循环时,先执行__iter__方法,获取一个迭代器对象,然后不断执行的__next__取值,有异常StopIteration则终止循环。
4.9.2 生成器
# 创建生成器函数
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)
如果按照迭代器的规则来看,其实生成器类也是一种特殊的迭代器类。
4.9.3 可迭代对象
如果一个类中有__iter__方法且返回一个迭代器对象,则称以这个类创建的对象为可迭代对象。
class Foo(object):
def __iter__(self):
return 迭代器对象(生成器对象)
obj = Foo() # obj是 可迭代对象。
# 可迭代对象可以通过for进行循环,在循环的内部先执行__iter__方法,获取其迭代器对象,然后再在内部执行该迭代器对象的__next__方法,逐步取值。
for item in obj:
pass
示例1:
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)
示例2:基于可迭代对象&迭代器实现:自定义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)
示例3:基于可迭代对象&生成器 实现:自定义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 = [11,22,33,44]
v2 = (11,22,33,44)
v3 = {11,22,33,44}
v4 = {k1:11,k2:22}
# 以上均为可迭代对象,在其内部声明了一个__iter__方法并且返回一个迭代器对象。
判断一个对象是否为可迭代对象/迭代器:
from collections.abc import Iterator, Iterable
v1 = [11, 22, 33]
print( isinstance(v1, Iterator) ) # 判断是否是迭代器,依据是是否有__iter__和__next__
>>输出结果:False
v2 = v1.__iter__()
print( isinstance(v2, Iterator) ) # 判断是否是迭代器
>>输出结果:True
v1 = [11, 22, 33]
print( isinstance(v1, Iterable) ) # 判断是否可迭代,依据是是否有__iter__且返回迭代器对象。
>>输出结果:True
v2 = v1.__iter__()
print( isinstance(v2, Iterable) ) # 判断是否可迭代,依据是是否有__iter__且返回迭代器对象。
>>输出结果:True
'''
isinstance(v1, Iterator)为True,则为迭代器
isinstance(v1, Iterator)为False,isinstance(v1, Iterable)为True,则为可迭代对象
'''
今日总结
- 面向对象编程中的成员
- 变量
- 实例变量
- 类变量
- 方法
- 绑定方法
- 类方法
- 静态方法
- 属性
- 变量
- 成员修饰符
- 对象中的数据嵌套
- 特殊成员
- 重要概念:
- 迭代器
- 生成器
- 可迭代对象
今日作业
- 列举面向对象的成员并简述他们的特点。
1、变量:实例变量(通过对象调用,属于对象),类变量(属于类,可通过类和对象进行调用) 2、方法:绑定方法(默认有self参数,self代指该对象,可通过对象和类进行调用,)、类方法(默认有cls参数,cls代指该类,可通过类和对象进行调用)、静态方法(无默认参数,通过类和对象进行调用,本身与对象和类没有直接关系) 3、属性(在方法前面进行声明后,后续调用该方法时可通过特殊的形式进行调用)
- @staticmethod 和 @classmethod的作用是什么?
声明静态方法和类方法
- 面向对象中如何让成员变为私有。
在成员名前加上双下划线即可让该成员编程私有
-
方法的作用?__new__
__new__是构造方法,在类创建对象时先执行该函数,创建空对象并返回,然后再执行初始化方法
- 简述你理解的:迭代器、生成器、可迭代对象。
迭代器:类内部含有__iter__和__next__方法,可通过for循环先执行__iter__方法生成迭代器对象,再一直执行__next__方法获取数据,直到遇到异常而结束循环。 生成器:一种特殊的迭代器。 可迭代对象:类内部含有__iter__方法,可通过for循环执行__iter__方法生成一个迭代器对象,再一直执行该迭代器对象对应的迭代器类中的__next__方法,直到遇到异常而结束循环。
- 看代码写结果
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) >>输出结果:666 print(obj1.a1) >>输出结果:1 obj1.num = 18 obj1.a1 = 99 print(obj1.num) >>输出结果:18 print(obj1.a1) >>输出结果:99 print(obj2.a1) >>输出结果:1 print(obj2.num) >>输出结果:999 print(Foo.a1) >>输出结果:1 print(obj1.a1) >>输出结果:99
- 看代码写结果,注意返回值。
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) >>输出结果: f3 f2 999 None
- 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】
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
- 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】
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() >>输出结果: f1 f2 f3
- 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】
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() >>输出结果: f1 f2 f3
- 看代码写结果【如果有错误,则标注错误即可,并且假设程序报错可以继续执行】
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
- 看代码写结果
class Foo(object): def __init__(self, age): self.age = age def display(self): print(self.age) data_list = [Foo(8), Foo(9)] for item in data_list: print(item.age, item.display()) >>输出结果: 8 8 None 9 9 None
- 看代码写结果
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) >>输出结果: 1 1 666 666
- 看代码写结果
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 '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'> ] [ <__main__.Foo object at 0x0000015AB342BD60>, <__main__.Foo object at 0x0000015AB342BCD0>, <__main__.Foo object at 0x0000015AB3271A00>, <__main__.Foo object at 0x0000015AB3271730>, <__main__.Foo object at 0x0000015AB3271610>, <__main__.Foo object at 0x0000015AB32714F0>, <__main__.Foo object at 0x0000015AB3262E80>, <__main__.Foo object at 0x0000015AB3262BE0>, <__main__.Foo object at 0x0000015AB3262A90>, <__main__.Foo object at 0x0000015AB3262A30> ] [ <__main__.Foo object at 0x0000015AB3262850>, <__main__.Foo object at 0x0000015AB32626A0>, <__main__.Foo object at 0x0000015AB3262580>, <__main__.Foo object at 0x0000015AB31F5F40>, <__main__.Foo object at 0x0000015AB31F5220>, <__main__.Foo object at 0x0000015AB31D51F0>, <__main__.Foo object at 0x0000015AB31D5400>, <__main__.Foo object at 0x0000015AB31D57F0>, <__main__.Foo object at 0x0000015AB31D5790>, <__main__.Foo object at 0x0000015AB31D5730> ]
- 看代码写结果
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) >>输出结果: 1 2 3
- 看代码写结果
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) >>输出结果: 1 666 2 666 3 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)) >>输出结果:3 for k, row in site._registry.items(): row.changelist(5) >>输出结果: 19 5 20 5 666 33
- 看代码写结果(如有报错,请标注报错位置)
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("xuanxiaomo") print(v1[1]) print(v2[2]) >>输出结果: l 报错,StarkConfig类中没有__getitem__方法,无法通过v2[2]调用
- 补全代码
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()
- 看代码写结果
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() >>输出结果: 我是轩小陌,年龄18,属于人事部 我是alex,年龄18,属于销售部
- 分析代码关系,并写出正确的输出结果。
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) >>输出结果: 中国 <__main__.Node object at 0x0000017737EE18B0> 河南省 <__main__.Node object at 0x0000017737EE1610> 河北省
- 分析代码关系,并写出正确的输出结果。
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.children = [对象1] root.add(Node("河北省")) # root.children = [对象1,对象2] root.add(Node("陕西省")) # root.children = [对象1,对象2,对象3] root.add(Node("山东省")) # root.children = [对象1,对象2,对象3,对象4] root[1].add(Node("石家庄")) # 对象2.children = [对象5] root[1].add(Node("保定")) # 对象2.children = [对象5,对象6] root[1].add(Node("廊坊")) # 对象2.children = [对象5,对象6,对象7] root[3].add(Node("潍坊")) # 对象4.children = [对象8] root[3].add(Node("烟台")) # 对象4.children = [对象8,对象9] root[3].add(Node("威海")) # 对象4.children = [对象8,对象9,对象10] root[1][1].add(Node("雄安")) # 对象6.children = [对象11] root[1][1].add(Node("望都")) # 对象6.children = [对象11,对象12] 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) >>输出结果: 中国 河南省 河北省 石家庄 廊坊 雄安