流畅的python第一章_《流畅的Python》第一章学习笔记
一摞python風格的紙牌from collections import namedtuple
Card = namedtuple('Card', ['rank', 'suit']) # 構(gòu)建只有少數(shù)屬性但是沒有方法的對象
class FrenchDeck:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suites = '黑桃>紅桃>方塊>梅花'.split('>')
def __init__(self):
# 具名元祖實例化
self._cards = [Card(rank, suit)
for suit in self.suites
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, item):
"""
可迭代
把[]操作交給self._cards列表,支持切片操作
:param item:
:return:
"""
# 具名元祖支持索引取值
return self._cards[item]
def spades_high(card):
"""
排序
2最小,A最大
黑桃>紅桃>方塊>梅花
:param card:
:return:
"""
suit_values = {
"黑桃": 3,
"紅桃": 2,
"方塊": 1,
"梅花": 0
}
rank_value = FrenchDeck.ranks.index(card.rank)
return rank_value * len(suit_values) + suit_values[card.suit]
if __name__ == '__main__':
c = Card(1, 2)
print(c[1])
f = FrenchDeck()
print(len(f)) # 52 = (11 - 2 + 4) * 4
print(f[0]) # Card(rank='2', suit='spades')
print(f[:3]) # [Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
for i in f:
print(i)
for i in reversed(f):
print(i)
for i in sorted(f, key=spades_high):
print(i)
具名元祖自 Python 2.6 開始,namedtuple 就加入到 Python 里,用以 構(gòu)建只有少數(shù)屬性但是沒有方法的對象
在官方文檔中也翻譯為命名元祖
它賦予了每個位置一個含義,提供可讀性和自文檔性。通過名字獲取值
通過索引值獲取值
導入方法from collections import namedtuple
具名元祖源碼閱讀返回一個新的元組子類,名為 typenametest = namedtuple('mytest','test1 test2')
t = test(1, 2)
type(t) # __main__.mytestfield_names用空白或逗號分隔開元素名if isinstance(field_names, str):
field_names = field_names.replace(',', ' ').split()
field_names = list(map(str, field_names))rename為真時, 無效字段名會自動轉(zhuǎn)換成位置名。有效字段名:除了下劃線開頭的那些任何有效的Python 標識符。有效標識符由字母,數(shù)字,下劃線組成,但首字母不能是數(shù)字或下劃線,另外不能是關(guān)鍵詞
比如 ['abc', 'def', 'ghi', 'abc'] 轉(zhuǎn)換成 ['abc', '_1', 'ghi', '_3'] , 消除關(guān)鍵詞 def 和重復字段名 abc
isidentifier:判斷字符串是否是有效的 Python 標識符,可用來判斷變量名是否合法
iskeyword:包含全部關(guān)鍵字的凍結(jié)的集合from keyword import iskeyword as _iskeyword
if rename:
seen = set()
for index, name in enumerate(field_names):
if (not name.isidentifier()
or _iskeyword(name)
or name.startswith('_')
or name in seen):
field_names[index] = f'_{index}'
seen.add(name)defaults:默認值test = namedtuple('mytest', 'test1 test2', defaults=[1, 2])
test().test1 # 1
test().test2 # 2
test = namedtuple('mytest', 'test1 test2 test3', defaults=[1, 2])
test(0).test1 # 0
test(0).test2 # 1
test(0).test3 # 2module:設(shè)置 module 屬性值if module is None:
try:
module = _sys._getframe(1).f_globals.get('__name__', '__main__')
except (AttributeError, ValueError):
pass
if module is not None:
result.__module__ = moduletest = namedtuple('mytest', 'test1 test2 test3', module='aaa')
type(test(1, 2, 3)) # aaa.mytest_make:類方法從存在的序列或迭代實例創(chuàng)建一個新實例@classmethod
def _make(cls, iterable):
result = tuple_new(cls, iterable)
if _len(result) != num_fields:
raise TypeError(f'Expected {num_fields} arguments, got {len(result)}')
return resultPoint = namedtuple('Point', ['x', 'y'])
t = [11, 22]
Point._make(t)# Point(x=11, y=22)_asdict:返回一個新的字典def _asdict(self):
'Return a new dict which maps field names to their values.'
return _dict(_zip(self._fields, self))p = Point(x=11, y=22)
p._asdict()# {'x': 11, 'y': 22}_replace將指定域替換為新的值def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise ValueError(f'Got unexpected field names: {list(kwds)!r}')
return resultp = Point(x=11, y=22)
p._replace(x=33) # Point(x=33, y=22)_fields:列出字段名p._fields #('x', 'y')_field_defaults:字典將字段名稱映射到默認值A(chǔ)ccount = namedtuple('Account', ['type', 'balance'], defaults=[0])
Account._field_defaults# {'balance': 0}def namedtuple(typename, field_names, *, rename=False, defaults=None, module=None):
"""Returns a new subclass of tuple with named fields.
>>> Point = namedtuple('Point', ['x', 'y'])
>>> Point.__doc__ # docstring for the new class
'Point(x, y)'
>>> p = Point(11, y=22) # instantiate with positional args or keywords
>>> p[0] + p[1] # indexable like a plain tuple
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessible by name
33
>>> d = p._asdict() # convert to a dictionary
>>> d['x']
11
>>> Point(**d) # convert from a dictionary
Point(x=11, y=22)
>>> p._replace(x=100) # _replace() is like str.replace() but targets named fields
Point(x=100, y=22)
"""
# Validate the field names. At the user's option, either generate an error
# message or automatically replace the field name with a valid name.
if isinstance(field_names, str):
field_names = field_names.replace(',', ' ').split() # 將逗號轉(zhuǎn)換為空格后進行切割
field_names = list(map(str, field_names)) # 將列表中的全部內(nèi)容轉(zhuǎn)換為字符串類型
typename = _sys.intern(str(typename)) # 字符串駐留:提高字符串效率.同樣的字符串對象僅僅會保存一份,放在一個字符串儲蓄池中,是共用的
if rename:
"""
無效字段名會自動轉(zhuǎn)換成位置名
"""
seen = set()
for index, name in enumerate(field_names):
if (not name.isidentifier()
or _iskeyword(name)
or name.startswith('_')
or name in seen):
field_names[index] = f'_{index}'
seen.add(name)
for name in [typename] + field_names:# 判斷各個字段都是有效字段
if type(name) is not str:
raise TypeError('Type names and field names must be strings')
if not name.isidentifier():
raise ValueError('Type names and field names must be valid '
f'identifiers: {name!r}')
if _iskeyword(name):
raise ValueError('Type names and field names cannot be a '
f'keyword: {name!r}')
seen = set()
for name in field_names:
if name.startswith('_') and not rename:# 有下劃線開頭的內(nèi)容會報錯
raise ValueError('Field names cannot start with an underscore: '
f'{name!r}')
if name in seen:# 有重復的內(nèi)容會報錯
raise ValueError(f'Encountered duplicate field name: {name!r}')
seen.add(name)
field_defaults = {}
if defaults is not None:
defaults = tuple(defaults)
if len(defaults) > len(field_names):# 默認值長度大于總長度時候報錯
raise TypeError('Got more default values than field names')
field_defaults = dict(reversed(list(zip(reversed(field_names),
reversed(defaults)))))# 從后往前賦值
# Variables used in the methods and docstrings
field_names = tuple(map(_sys.intern, field_names)) # 轉(zhuǎn)換為元祖
num_fields = len(field_names)
arg_list = repr(field_names).replace("'", "")[1:-1]
# repr(field_names):'(\'rank\', \'suit\')'
# .replace("'", "")[1:-1]:變?yōu)?'rank, suit'
repr_fmt = '(' + ', '.join(f'{name}=%r' for name in field_names) + ')'
# '(rank=%r, suit=%r)'
tuple_new = tuple.__new__ 'rank, suit'
_dict, _tuple, _len, _map, _zip = dict, tuple, len, map, zip
# Create all the named tuple methods to be added to the class namespace
s = f'def __new__(_cls, {arg_list}): return _tuple_new(_cls, ({arg_list}))' # __new__的時候?qū)?nèi)容變?yōu)樵?#xff0c;后續(xù)訪問的時候可以用索引來查找內(nèi)容
namespace = {'_tuple_new': tuple_new, '__name__': f'namedtuple_{typename}'}
# Note: exec() has the side-effect of interning the field names
exec(s, namespace)# 動態(tài)執(zhí)行 Python 代碼 補充namespace的__new__方法
__new__ = namespace['__new__']
__new__.__doc__ = f'Create new instance of {typename}({arg_list})' # 為__new__方法添加說明
if defaults is not None:
__new__.__defaults__ = defaults
@classmethod
def _make(cls, iterable): # 定義_make方法
result = tuple_new(cls, iterable)
if _len(result) != num_fields:
raise TypeError(f'Expected {num_fields} arguments, got {len(result)}')
return result
_make.__func__.__doc__ = (f'Make a new {typename} object from a sequence '
'or iterable')# 為_make添加說明
def _replace(self, /, **kwds): # 定義_replace方法
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise ValueError(f'Got unexpected field names: {list(kwds)!r}')
return result
_replace.__doc__ = (f'Return a new {typename} object replacing specified '
'fields with new values')# 為_replace方法添加說明
def __repr__(self):# 定義__repr__方法 在print的時候調(diào)用
'Return a nicely formatted representation string'
return self.__class__.__name__ + repr_fmt % self
def _asdict(self): # 定義_asdict方法 轉(zhuǎn)換成字典輸出
'Return a new dict which maps field names to their values.'
return _dict(_zip(self._fields, self))
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return _tuple(self)
# Modify function metadata to help with introspection and debugging
for method in (__new__, _make.__func__, _replace,
__repr__, _asdict, __getnewargs__):
method.__qualname__ = f'{typename}.{method.__name__}'
# Build-up the class namespace dictionary
# and use type() to build the result class
class_namespace = {
'__doc__': f'{typename}({arg_list})',
'__slots__': (),
'_fields': field_names,
'_field_defaults': field_defaults,
# alternate spelling for backward compatibility
'_fields_defaults': field_defaults,
'__new__': __new__,
'_make': _make,
'_replace': _replace,
'__repr__': __repr__,
'_asdict': _asdict,
'__getnewargs__': __getnewargs__,
}
for index, name in enumerate(field_names):
doc = _sys.intern(f'Alias for field number {index}')
class_namespace[name] = _tuplegetter(index, doc)# 為我們定義的屬性字段賦值
result = type(typename, (tuple,), class_namespace)
# For pickling to work, the __module__ variable needs to be set to the frame
# where the named tuple is created. Bypass this step in environments where
# sys._getframe is not defined (Jython for example) or sys._getframe is not
# defined for arguments greater than 0 (IronPython), or where the user has
# specified a particular module.
if module is None:# 使用默認module名稱
try:
module = _sys._getframe(1).f_globals.get('__name__', '__main__')
except (AttributeError, ValueError):
pass
if module is not None:# 重新命名module名稱
result.__module__ = module
return result
使用Card = namedtuple('Card', ['rank', 'suit'])
在通過名字獲取值的方式上類似于class Card:
def __init__(self, rank, suit):
self.rank = rank
self.suit = suit
列表推導式[表達式 for 變量 in 列表]
[表達式 for 變量 in 列表 if 條件]
排序sort 是應用在 list 上的方法,sorted 可以對所有可迭代的對象進行排序操作。
list 的 sort 方法返回的是對已經(jīng)存在的列表進行操作,而內(nèi)建函數(shù) sorted 方法返回的是一個新的 list,而不是在原來的基礎(chǔ)上進行的操作。
sortIn[1]:a = [3, 2, 1]
In[2]:a.sort()
In[3]:a
Out[3]:[1, 2, 3]
sorted
key 指定帶有單個參數(shù)的函數(shù),用于從 iterable 的每個元素中提取用于比較的鍵 (例如 key=str.lower)。默認值為 None (直接比較元素)。In[1]:sorted([3, 2, 1])
Out[1]:[1, 2, 3]
魔方方法
__repr__和__str__repr:在repr()方法中使用。當沒有實現(xiàn)該方法的時候,打印實例可能為
str:在str()方法中使用,在print()方法中使用
當一個對象沒有__str__的時候會調(diào)用__repr__
自己定義__bool__方法
如果沒有定義的話,在執(zhí)行bool(x)的時候默認會調(diào)用bool(x.__len__())
總結(jié)
以上是生活随笔為你收集整理的流畅的python第一章_《流畅的Python》第一章学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 读书笔记 23种设计模式总结
- 下一篇: Python: adb自动化ce'shi