您好,登錄后才能下訂單哦!
分頁顯示是一種非常常見的瀏覽和顯示大量數據的方法,屬于web編程中最常處理的事件之一。
類屬性應用需求: 對于京東商城中顯示電腦主機的列表頁面,每次請求不可能把數據庫
中的所有內容都顯示到頁面上,而是通過分頁的功能局部顯示,所以在向數據庫中請求
數據時就要顯示的指定獲取從第start條到第end條的所有數據 這個分頁的功能包括:
? 根據用戶請求的當前頁和總數據條數計算出 start 和 end
? 根據start 和 end 去數據庫中請求數據
? 是否有上一頁has_prev、下一頁has_next
? 上一頁prev、下一頁next
? 總頁數pages, 數據總條數total、當前頁信息items
"""
class Pagintor(object):
"""實現商品分頁的類"""
def __init__(self, objects_list, page=1, per_page=5):
"""
:param objects_list: 商品列表
:param page: 當前需要顯示的頁碼信息
:param per_page: 每頁顯示的數據個數
"""
self.objects_list = objects_list
self.page = page
self.per_page = per_page
@property
def start(self):
return (self.page - 1) * self.per_page
@property
def end(self):
return self.page * self.per_page
@property
def total(self):
"""
數據總條數total
:return:
"""
return len(self.objects_list)
@property
def pages(self):
"""
總頁數pages
if 總商品數量%每頁顯示數量==0: 剛好當前頁顯示滿
else: 好友多與的部分, 在計算的結果上面加1
self.total = 5 pages=1
self.total = 6 pages=2
:return:
"""
result = self.total // self.per_page
if self.total % self.per_page == 0:
return result
else:
return result + 1
@property
def has_next(self):
return True if 0 < self.page + 1 <= self.pages else False
@property
def next(self):
next_page = self.page - 1
next_start = (next_page - 1) * self.per_page
next_end = self.page * self.per_page
return self.objects_list[next_start:next_end]
@property
def has_prev(self):
return True if 0 < self.page - 1 <= self.pages else False
@property
def prev(self):
prev_page = self.page - 1
prev_start = (prev_page - 1) * self.per_page
prev_end = self.page * self.per_page
return self.objects_list[prev_start:prev_end]
@property
def items(self):
"""
當前頁信息items
:return:
"""
return self.objects_list[self.start:self.end]
if __name__ == '__main__':
# 應用場景二: 某一個屬性不能直接返回, 需要計算的, 可以通過property屬性實現
goods = ["電腦" + str(i) for i in range(5)]
#需求: 顯示第三頁時, 開始的索引是? 結束的索引為多少?
pagintor = Pagintor(goods, page=1, per_page=6)
print("第1頁的商品信息為: ", goods[pagintor.start:pagintor.end])
print("是否有上一頁?", pagintor.has_prev)
print("總頁數?", pagintor.pages)
"""
class Person(object):
def __init__(self, name, age):
self.name = name
self.__age = age #私有屬性
@property
def is_age_vaild(self):
return 0 < self.__age <= 150
def get_age(self):
if self.is_age_vaild:
return self.__age
else:
raise Exception("年齡不合法")
def set_age(self, age):
if self.is_age_vaild:
self.__age = age
else:
raise Exception("年齡不合法")
def del_age(self):
print("年齡屬性刪除......")
#類屬性 即:在類中定義值為property對象的類屬性
age = property(fget=get_age, fset=set_age, fdel=del_age)
if __name__ == '__main__':
p1 = Person("張三", 30)
print(p1.age)
p1.age = 31
print(p1.age)
del p1.age
class Person(object):
def __init__(self, name, age, score):
self.name = name
self.__age = age # 私有屬性
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, score):
self.__score = score
@property
def is_age_vaild(self):
return 0 < self.__age <= 150
@property # 獲取age屬性時執行的內容
def age(self):
if self.is_age_vaild:
return self.__age
else:
raise Exception("年齡不合法")
@age.setter # 設置age屬性時執行的內容
def age(self, age):
if self.is_age_vaild:
self.__age = age
else:
raise Exception("年齡不合法")
@age.deleter # 刪除age屬性時執行的內容
def age(self):
print("年齡屬性刪除......")
if __name__ == '__main__':
p1 = Person("張三", 30, 100)
print(p1.age) # 獲取年齡(), 執行@property def age(self):
p1.age = 31 # 設置年齡, age=31
print(p1.age)
del p1.age # 刪除年齡屬性
from functools import wraps
def singleton(cls):
"""
實現單例模式的裝飾器
思路: 當實例化對象時, 判斷該類是否實例化過對象。
- 如果是, 返回之前實例化的對象。
- 如果不是, 實例化第一個對象, 并將實例化后的對象存儲起來(緩存)。
"""
instances = {} # {'Person': obj}
@wraps(cls)
def wrapper(*args, **kwargs):
name = cls.__name__
if instances.get(name):
# 直接返回緩存中的對象
return instances.get(name)
else:
# 第一次實例化對象
obj = cls(*args, **kwargs)
#類名作為key值, 對象作為value值, 存儲到instances字典中.
instances[name] = obj
return obj
return wrapper
@singleton
class Person(object):
pass
if __name__ == '__main__':
p1 = Person()
p2 = Person()
#面試題目: ==和is有什么區別?
print("單例模式是否成功?", p1 is p2)
魔術方法
在Python中,所有用""包起來的方法,都稱為【魔術方法】(eg: len, init__)。
魔術方法一般是為了讓顯示器調用的,你自己并不需要調用它們。
特殊屬性:
dir
查看屬性
返回類或者對象的所有成員名稱列表。dir() 函數就是調用dir()。
1). 如果dir([obj]) 參數obj包含方法 dir(),該方法將被調用。
2). 如果Obj 不包含 dir(),該方法將最大限度收集屬性信息
python 中new , init , call的區別?
1). new的功能是在生成對象之前執行的內容,接受的參數是cls 類, 負責對象的創建
2). init的功能是在對象生成之后執行的內容, 接受的參數是self 對象, 負責對象的初始化
3). call的功能是在調用對象時執行的內容, 可以模擬函數的行為
from datetime import date
class Person(object):
def __new__(cls, *args, **kwargs):
print("判斷當前類是否擁有instance屬性?", hasattr(cls, 'instance'))
if not hasattr(cls, 'instance'):
cls.instance = super(Person, cls).__new__(cls)
return cls.instance
def __init__(self, name):
self.name = name
p1 = Person("張三")
p2 = Person("張xxx")
print("單例模式是否成功? ", p1 is p2)
class Person(object):
# 1). 設置類屬性, 存儲已經創建好的對象。
_instance = None
def __new__(cls, *args, **kwargs):
print("new方法在實例化對象之前執行.....返回對象本身")
#2). 判斷是否已經實例化對象?
if cls._instance:
return cls._instance
else:
self = object.__new__(cls)
cls._instance = self
#返回父類object的new方法創建的對象.....
return self
def __init__(self):
print("構造方法實例化對象之后執行......")
if __name__ == '__main__':
p1 = Person()
p2 = Person()
print(p1, p2)"""
1). new的功能是在生成對象之前執行的內容,接受的參數是cls 類, 負責對象的創建
2). init的功能是在對象生成之后執行的內容, 接受的參數是self 對象, 負責對象的初始化
3). call的功能是在調用對象時執行的內容, 可以模擬函數的行為.
"""
class Person(object):
def __new__(cls):
print("__new__")
return object.__new__(cls)
def __init__(self):
print("__init__")
def __call__(self, *args, **kwargs):
print('__call__')
def __del__(self):
# 析構方法: 當對象被刪除或者從內存釋放時自動執行
print("__del__")
p1 = Person()
p1()
from functools import lru_cache
class Fib(object):
@lru_cache(maxsize=1000)
def __call__(self, n):
if n in (1, 2):
return 1
else:
return self(n-1) + self(n-2)
fib = Fib()
print(fib(100)) # 1 1 2 3 5 8"""
可視化
類型判斷要使用type或isinstance, 不能通過判斷print輸出是否帶引號來判斷輸出值的類型。
1). str()與repr()都是python中的內置函數,是直接用來格式化字符串的函數。
2). 當使用內置函數str(obj)時, 自動執行obj.str()魔術方法。
3). 當使用內置函數repr(obj)時, 自動執行obj.repr()魔術方法。
4). 當str魔術方法不存在時, 自動執行repr()魔術方法的內容。
類型轉換
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __int__(self):
return int(self.age)
#def __str__(self):
#return 'Person<%s>' %(self.name)
def __repr__(self):
return 'Person<%s>' %(self.name)
p1 = Person("fentiao", '100')
print(p1)
print(int(p1))
索引與切片
拓展小知識: slice() 函數實現切片對象,主要用在切片操作函數里的參數傳遞。
索引&切片魔術方法:
setitem:當屬性被以索引、切片方式賦值的時候會調用該方法
getitem:一般如果想使用索引、切片訪問元素時,就可以在類中定義這個方法
delitem:當使用索引、切片刪除屬性時調用該方法
class Student(object):
def __init__(self, name, scores):
self.name = name
self.scores = scores
def __getitem__(self, index):
"""實現獲取索引和切片值的魔術方法"""
print(index)
return self.scores[index]
def __setitem__(self, index, value):
"""實現修改/設置索引和切片值的魔術方法"""
self.scores[index] = value
def __delitem__(self, index):
del self.scores[index]
def __mul__(self, other):
"""重復操作"""
return self.scores * other
def __add__(self, other):
"""連接操作, 傳入的時對象"""
return [ item[0]+item[1] for item in zip(self.scores, other.scores)]
def __contains__(self, item):
"""成員操作符"""
return item in self.scores
def __iter__(self):
# iter可以將可迭代對象轉換成迭代器(可以調用next方法的)
return iter(self.scores)
stu1 = Student("張三", [100, 90, 100])
stu2 = Student("里斯", [100, 80, 100])
#1). 索引和切片的測試
#print(stu1[1:]) # 獲取索引/切片值
#stu1[1:] = (80, 80) # 設置索引/切片對應的value值
#print(stu1.scores)
#del stu1[1:] # 刪除索引/切片值
#print(stu1.scores)
##2). 連接、重復和成員操作符
#print(stu1*3)
#print(stu1 + stu2)
#print(150 in stu1)
for item in stu1:
print(item)
with語句安全上下文
with語句操作的對象必須是上下文管理器。那么,到底什么是上下文管理器呢?
1). 簡單的理解,擁有 enter() 和 exit() 方法的對象就是上下文管理器。
enter(self):進入上下文管理器自動調用的方法,在 with 執行之前執行。如果 有 as子句,該
方法的返回值被賦值給 as 子句后的變量;該方法可以返回多個值。
exit(self, exc_type, exc_value, exc_traceback):退出上下文管理器自動調用的方法。在
with 執行之后執行(不管有無異常)。
2). 當 with as 操作上下文管理器時,就會在執行語句體之前,先執行上下文管理器的 enter() 方法,
然后再執行語句體,最后執行 exit() 方法。
構建上下文管理器,常見的有 2 種方式:基于類實現和基于生成器實現。
方法一: 裝飾器 contextlib.contextmanager,來定義自己所需的基于生成器的上下文管理器
方法二: 基于類的上下文管理器: 只要一個類實現了 enter() 和 exit() 這 2 個方
法,程序就可以使用 with as 語句來管理它
class Connect(object):
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.f = open(self.filename)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
print('with語句執行之后......')
self.f.close()
#Connect就是上下文管理器。 擁有 __enter__() 和 __exit__() 方法的對象就是上下文管理器
with Connect('/etc/passwd') as conn:
pass
import contextlib
import tempfile
import shutil
@contextlib.contextmanager
def make_temp_dir():
try:
tmp_dir = tempfile.mkdtemp()
yield tmp_dir
finally:
shutil.rmtree(tmp_dir)
with make_temp_dir() as f:
pass
class Int(object):
def __init__(self, number, weight):
self.number = number
self.weight = weight
def __gt__(self, other):
"""判斷大于的魔術方法"""
return self.number * self.weight > other.number * other.weight
def __ge__(self, other):
"""判斷大于等于的魔術方法"""
return self.number * self.weight >= other.number * other.weight
def __eq__(self, other):
"""判斷等于的魔術方法"""
return self.number * self.weight == other.number * other.weight
i1 = Int(20, 3)
i2 = Int(20, 3)
print(i1 > i2)
print(i1 < i2)
print(i1 >= i2)
print(i1 == i2)
print(i1 != i2)
from functools import wraps
import time
def timeit(unit='s'):
def wrapper1(fun): # fun=add
@wraps(fun)
def wrapper(*args, **kwargs):
if unit == 's':
start_time = time.time()
result = fun(*args, **kwargs) # add(1, 2) result=3
end_time = time.time()
print("%s函數運行時間為%.2f s" %(fun.__name__, end_time-start_time))
return result
else:
print("當前功能不支持......")
return wrapper
return wrapper1
#類裝飾器: 裝飾器需要傳遞的參數通過__init__傳遞進入.被裝飾函數執行的內容在__call__魔術方法中編寫。
class TimeIt(object):
def __init__(self, unit='s'):
self.unit = unit
def __call__(self,fun):
@wraps(fun)
def wrapper(*args, **kwargs):
if self.unit == 's':
start_time = time.time()
result = fun(*args, **kwargs) #add(1, 2) result=3
end_time = time.time()
print("%s函數運行時間為%.2f s" % (fun.__name__, end_time - start_time))
return result
else:
print("當前功能不支持......")
return wrapper
#@timeit(unit='s') #@wrapper1 ==> add = wrapper1(add) ===> add =wrapper
#def add(num1, num2):
#time.sleep(0.333)
#return num1 + num2
"""
@TimeIt(unit='h')
#1). TimeIt_obj = TimeIt(unit='h')
#2). @TimeIt_obj
#3). add=TimeIt_obj(add)
#4). add = wrapper
"""
@TimeIt(unit='s')
def add(num1, num2):
time.sleep(0.333)
return num1 + num2
#add(1, 2) ==> wrapper(1, 2)
add(1, 2)
from functools import partial
max_100 = partial(max,10, 100) # 返回對象
print(max_100(1, 2, 3)) # 100"""
from wtforms import StringField,SubmitField
import os
#作為基類/父類
class FileAcceptor(object):
def __init__(self, accepted_extensions):
"""
eg: ['.png', '.jpg']
:param accepted_extensions: 可以接受的擴展名
"""
self.accepted_extensions = accepted_extensions
def __call__(self, filename):
"""
eg: hello.jpg
:param filename: 需要判斷的文件名
:return:
"""
#base = 'hello', ext='.jpg'
base, ext = os.path.splitext(filename)
return ext in self.accepted_extensions
#子類
class ImageFileAcceptor(FileAcceptor):
def __init__(self):
image_ext = ('.jpg', '.jepg', '.png')
super(ImageFileAcceptor, self).__init__(image_ext)
#子類
class ExcelFileAcceptor(FileAcceptor):
def __init__(self):
image_ext = ('.xls', '.xlsx')
super(ExcelFileAcceptor, self).__init__(image_ext)
if __name__ == '__main__':
filenames = [
'hello.jpg',
'hello.xls',
'hello.txt'
]
"""
1). ImageFileAcceptor() 實例化對象, 執行__new__和__init__魔術方法。
2). imagefileacceptor_obj
3). imagefileacceptor_obj('hello.jpg') True
3). imagefileacceptor_obj('hello.xls') False
3). imagefileacceptor_obj('hello.txt') False
4). ['hello.jpg']
"""
images_file = filter(ImageFileAcceptor(), filenames)
excels_file = filter(ExcelFileAcceptor(), filenames)
print(list(images_file))
print(list(excels_file))
def create_class(name):
if name == 'foo':
class Foo(object):
pass
return Foo
else:
class Bar(object):
pass
return Bar
cls = create_class(name='foo1')
print(cls.__name__)
#type函數語法:
#type(類名, 父類名稱的元組, 屬性信息)
#class Person(object):
#country= 'China'
def hello(self):
print("hello")
Person = type('Person',(object, ), {'country':'China', 'hello':hello})
p1 = Person()
print(p1.country)
p1.hello()
魔術方法匯總
基本的魔法方法
有關屬性的魔術方法
比較操作符
算數運算符
反運算
增量賦值運算
一元操作符
類型轉換
上下文管理(with 語句)
容器類型
元類
類也是對象
Python一切皆對象
Linux一切皆文件
元類是類的類,是類的模板
元類的實例為類,正如類的實例為對象。
類的本質是對象, 于是可以對類做如下的操作:
#實現單例模式的方法:
#1. 裝飾器
#2. new魔術方法
#3. metaclass自定義元類
class Singleton(type):
type(name, bases, attrs)
自定義元類實現單例模式, 父類是type
#所有類和實例化對象之間的關系; eg: {'Person': Pseron()}
cache = {}
#1). 為什么是__call__魔術方法?
def __call__(cls):
#判斷類是否已經實例化, 如果沒有, 實例化后存儲到緩存中。 最后將緩存的信息返回給用戶。
if cls not in cls.cache:
cls.cache[cls] = super(Singleton, cls).__call__()
return cls.cache[cls]
#type('Pseron', (), {})
#創建以各類Person, 指定創建Person類的類(元類)是type.
#2. metaclass是在做什么? 指定元類為Singleton。
class Person(object, metaclass=Singleton): # Person = Singleton.__new__(Person, (objects, ), {})
pass
#Person是Singleton元類實例化出的對象, Person()就是對象(), 執行Singleton.__call__魔術方法.
p1 = Person()
p2 = Person()
print(p1, p2)
#99%情況不需要自己自定義元類。
抽象基類
抽象基類有兩個特點:
1.規定繼承類必須具有抽象基類指定的方法
2.抽象基類無法實例化
基于上述兩個特點,抽象基類主要用于接口設計
實現抽象基類可以使用內置的abc模塊
import abc
class Human(metaclass=abc.ABCMeta):
"""基類, 定義一個抽象類"""
@abc.abstractmethod
def introduce(self):
print("introduce.....")
@abc.abstractmethod
def hello(self):
print('hello')
class Person(Human):
# 1).規定繼承類必須具有抽象基類指定的方法
def introduce(self):
print('person')
def hello(self):
print('person hello')
#2). 抽象基類無法實例化
#h = Human()
p = Person()
p.introduce()
p.hello()
動態語言與靜態語言的不同?
import time
from datetime import date
#d = date.today()
#print("對象類型: ", type(d)) # <class 'datetime.date'>
#print("判斷是否有year這個屬性?", hasattr(d, 'year')) # True
#print("判斷是否有time這個屬性?", hasattr(d, 'time')) # False
##setattr(d, 'time', '10:10:10') # 報錯
class Date(object):
# __slots__ 來限制該對象能添加的屬性信息
__slots__ = '__year', '__month', '__day'
def __new__(cls, year, month, day):
self = object.__new__(cls)
self.__year = year
self.__month = month
self.__day = day
return self
@property
def year(self):
return self.__year
@property
def month(self):
return self.__month
@property
def day(self):
return self.__day
@classmethod
def today(cls):
time_t = time.localtime()
return cls(time_t.tm_year, time_t.tm_mon, time_t.tm_mday)
def __str__(self):
return '%s-%s-%s' %(self.__year, self.__month, self.__day)
d = Date(2019, 10, 10)
print("對象類型: ", type(d)) # <class 'datetime.date'>
print("判斷是否有year這個屬性?", hasattr(d, 'year')) # True
print("判斷是否有time這個屬性?", hasattr(d, 'time')) # False
#setattr(d, 'time', '10:10:10') # Error
#print('time:', getattr(d, 'time')) # Error
print(Date.today())
#1). 整數在程序中的使用非常廣泛,Python為了優化速度,使用了小整數對象池,
#避免為整數頻繁申請和銷毀內存空間。
#2). Python對小整數的定義是[-5,257)
>>> a = 1
>>> id(a)
139883638752032
>>> b = 1
>>> id(b)
139883638752032
>>> c = 257
>>> d = 257
>>> id(c), id(d)
(139883633580400, 139883633580432)
>>> e=-5;f=-5
>>> id(e), id(f)
(139883638751840, 139883638751840)
#********************************2. 字符串駐留機制 ********************************
#1). string interning(字符串駐留): 它通過維護一個字符串常量池(string intern pool),
#從而試圖只保存唯一的字符串對象,達到既高效又節省內存地處理字符串的目的。
>>> a = 'hello'
>>> b = 'hello'
>>> id(a), id(b)
(139883511138480, 139883511138480)
>>> c = 'pythonchjdshfcejhfkjrehfkjrehfkjrehfregjrkhgkjrg'
>>> d = 'pythonchjdshfcejhfkjrehfkjrehfkjrehfregjrkhgkjrg'
>>> id(c),id(d)
(139883633099360, 139883633099360)
#2). 字符串(含有空格),不可修改,沒開啟intern機制,不共用對象,引用計數為0,銷毀。
>>> a = 'a b'
>>> b = 'a b'
>>> id(a), id(b)
(139883511138608, 139883511138544)
#導致引用計數+1的情況
>>> #1). 對象被創建,例如a=23
...
>>> name = 'fentiao'
>>>
>>> #2). 對象被作為參數,傳入到一個函數中
...
>>> import sys
>>> sys.getrefcount(name)
2
>>> #3). 對象被引用,例如b=a
...
>>> cat_name = name
>>> sys.getrefcount(name)
3
>>> #4). 對象作為一個元素,存儲在容器中,例如list1=[a,a]
...
>>> l = [name, 'hello', 'python']
>>> sys.getrefcount(name)
4
#***************************導致引用計數-1的情況*************************
>>> #1). 對象的別名被顯式銷毀,例如del a
...
>>> del cat_name
>>> sys.getrefcount(name)
3
>>> #2). 對象的別名被賦予新的對象,例如a=24
>>> name1 = name
>>> sys.getrefcount(name)
4
>>> name1 = 'hello'
>>> sys.getrefcount(name)
3
>>> #4). 對象所在的容器被銷毀,或從容器中刪除對象
...
>>> l
['fentiao', 'hello', 'python']
>>> del l[0]
>>> sys.getrefcount(name)
2
#****************************gc模塊使用***********************************
#1). 分代回收的頻率
>>> gc.get_threshold()
(700, 10, 10)
>>>gc.set_threshold(700, 90, 90)
KeyboardInterrupt
#2). 垃圾回收機制是否開啟
>>>gc.isenabled()
True
>>>gc.disable()
>>>gc.isenabled()
False
>>> gc.enable()
>>>gc.isenabled()
True
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。