day18 面向對象進階
課程目标:掌握面向對象進階相關知識點,能溝通更加自如的使用面向對象來進行程式設計。
今日概要:
- 成員
- 變量
- 執行個體變量
- 類變量
- 方法
- 綁定方法
- 類方法
- 靜态方法
- 屬性
- 變量
- 成員修飾符(公有/私有)
- “對象嵌套”
- 特殊成員
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) >>輸出結果: 中國 河南省 河北省 石家莊 廊坊 雄安