„ Програмиране с Python“, ФМИ
Стефан Кънев & Николай Бачийски
14.05.2007г.
За какво ще става дума
- Разпознаване на типове
- Копиране на обекти
- Наследяване на вградени типове
type
type
връща специален обект от тип тип, стойност годна само за директни проверкиdef update(val):
if type(val) == type(0):
_update(val)
else:
raise ValueError("Cannot update non-integer!")>>> type('baba')
>>> type([])
>>> type(type('sugrug'))
Модулът types
- Ако става дума за вграден тип,
type
връща обект, който може да бъде намерен в модулаtypes
from types import *
def update(val):
if type(val) == IntType:
_update(val)
else:
raise ValueError("Cannot update non-integer!")- В този модул може да намерите повечето вградени типове, като имената им са с главни букви и имат
Type
отзад:DictType
,ListType
,TupleType
,BuiltinFunctionType
и т.н.
Копиране на обекти
a = b
не копира стойностите, а насочваa
иb
към един и същи обект!- Идиом за плитко копиране на списъци:
newlist = l[:]
- Още един идиом за плитко копиране:
newlist = [x for x in l]
, прави същото като горния names = 'a b c'.split()
grades = [1, 2, 3]
both = [names, grades]
shallowCopy = both[:]
names.append('d')
print shallowCopy[0]- Така копираме елементите само на едно ниво.
Плитко копиране на произволни обекти
- Не винаги си имаме работа със писъци, понякога не е толкова лесно да копираме един обект.
- На помощ ни идва вградения модул
copy
import copy
class C:
def __init__(self, l): self.l = l
def __getitem__(self, i): return self.l[i]
items = [1, 2, 3]
c = C(items)
shallow = copy.copy(c)
print c[2], shallow[2]
(3, 3)
items.append(4)
print c[3], shallow[3]
(4, 4)
shallow.l = [42]
print c.l, shallow.l
([1, 2, 3, 4], [42])
Дълбоко копиране
- Защо е необходимо?
import copy
items = [1, 2, 3]
d = dict(items=items)
shallow = copy.copy(d)
deep = copy.deepcopy(d)
items.append(4)
print shallow['items'], deep['items']
В картинки (1)
items = [1, 2, 3]
d = dict(items=items)
shallow = copy.copy(d)
deep = copy.deepcopy(d)
В картинки (2)
items.append(4)
Наследяване на вградени типове
- Цел: създаване на обекти, които приличат на такива от някой вграден тип (речник, списък, низ)
- Разширяване функционалността на вградени типове — речник, чийто ключове могат да се достъпват и като атрибути
- Удобство — ако обектът ни има поведение на списък, по-добре да ползваме познатия писъчен протокол, вместо да измисляме нови методи
Без наследяване
- Можем да постигнем целта си и без наследяване
- Ако имате желание да дефинирате сами всички методи на
list
, огромна част, от които се припокриват като функционалност с тези от вградените списъци - Понякога е удачно: трябва ни само индексиране(
[]
,__getitem__
) и не искаме да си замърсяваме класа с всички методи наlist
Старият начин
Преди 2.3 не е било възможно стандартните класове като list
, dict
, str
да се наследяват. Използвали са се няколко стандартни модула, които са предоставяли специални класове, които да бъдат наследявани:
UserDict.UserDict
— речник, който не поддържа итерация (за съвместимост със стари версии)UserDict.IterableUserDict
— речник, който си поддържа и итерацияUserDict.DictMixin
— добавя стандартните методи на класове, които вече поддържат стандартния интерфейс:__getitem__()
,__setitem__()
,__delitem__()
,keys()
.UserList.UserList
UserString.UserString
UserString.MutableString
— малко по-различен низ, може да бъде променян в движение
Всички си имат по един атрибут data
, в който се пазят реално данните.
Пример: речник с атрибути
class AttrDict(dict):
def __getattr__(self, attr):
if attr in self:
return self[attr]
else:
raise AttributeError("exists neither an attribute nor a key called '%s'." % attr)
if __name__ == "__main__":
d = AttrDict(a = 5, get = 6)
print d.a
print d.get
print d.baba
Частичен пример: низове с case-insensitive сравнения
def lowerFuncs(*names):
def lowerFunc(clsname, bases, classDict):
for name in names:
def comparator(self, other, *args, **kwargs):
return getattr(str, name)(self._lower, other.lower(), *args, **kwargs)
classDict[name] = comparator
return type(clsname, bases, classDict)
return lowerFunc
class CIStr(str):
__metaclass__ = lowerFuncs('__eq__', '__le__', '__lt__', '__ge__', '__gt__')
def __init__(self, *args, **kwargs):
str.__init__(self, *args, **kwargs)
# string will never change, so calc once
self._lower = self.lower()
def startswith(self, prefix, *args, **kwargs):
return str.startswith(self.__lower, prefix.lower(), *args, **kwargs)
def index(sub, *args, **kwargs):
return str.index(self.__lower, sub.lower(), *args, **kwargs)
… # и така нататък...
if __name__ == "__main__":
s = CIStr("Baba")
print s == "baba"
Няма коментари:
Публикуване на коментар