„ Програмиране с Python“, ФМИ
19.03.2007г.
Множествено наследяване (1)
При класове от стар стил, атрибутите се търсят в родителите по дълбочина
class A:
def spam(self): print "A's spam"
class B(A): pass
class C(A):
def spam(self): print "C's spam"
class D(B, C): pass
d = D()
d.spam() # A's spam
Множествено наследяване (2)
При класове от нов стил, атрибутите се търсят в родителите по широчина
class A(object):
def spam(self): print "A's spam"
class B(A): pass
class C(A):
def spam(self): print "C's spam"
class D(B, C): pass
d = D()
d.spam() # C's spam
Динамични класове
class Person(object):
def __init__(self, name): self.name = name
def sayHi(self, someone): print "Hello %s, I'm %s" % (someone, self.name)
class NamedThing(object):
def sayMyName(self): print "Beware, for I am %s" % self.name
popStarClass = type('PopStar', (Person,), {})
popStarClass.__bases__ = (Person, NamedThing)
def popStarSayHi(self, someone):
super(popStarClass, self).sayHi(someone)
print "Do you want my autograph?"
popStarClass.sayHi = popStarSayHi
mityo = popStarClass("Mityo the Python")
mityo.sayHi("Dim")
mityo.sayMyName()
Hello Dim, I'm Mityo the Python
Do you want my autograph?
Beware, for I am Mityo the Python
Равенство на обекти
- Можете да проверите дали два обекта са равни по стойност с оператора
==
- Можете да проверите дали две имена сочат към един и същи обект с оператора
is
>>> a = ['spam', 'eggs', 42]
>>> b = ['spam', 'eggs', 42]
>>> a is b
False
>>> a == b
True
>>> c = a
>>> a == c
True
>>> a is c
True
Предефиниране на равенство (1)
Можете да предефинирате равенството за обекти от даден клас с функцията __eq__
class Person(object):
def __init__(self, name, age):
self.name, self.age = name, age
def __eq__(self, other):
return isinstance(other, Person) and self.name == other.name \
and self.age == other.age
mityo = Person("Mityo the Python", 30)
mityo2 = Person("Mityo the Python", 30)
mityo3 = Person("Mityo the Gun", 30)
print mityo == mityo2 # True
print mityo is mityo2 # False
print mityo == mityo3 # False
Предефиниране на равенство (2)
По подразбиране, __eq__
е имплементирана с is
class Food(object): pass
spam = Food()
eggs = Food()
moreSpam = spam
print spam == moreSpam, spam is moreSpam # True True
print spam == eggs, spam is eggs # False False
str и repr (1)
- В Python от всеки обект могат да се получат две важни неща - текстов низ (
str
) и "репрезентация" (repr
) - Текстовото представяне се използва при
str(обект)
или при"%s" % обект
- Репрезентацията представлява текст, който ако се изпълни като Python код ще създаде обекта на който е извикан - т.е.
eval(repr(обект)) == обект
- Репрезентация се извежда с
repr(обект)
.
>>> print "Spam\nand\neggs"
Spam
and
eggs
>>> print repr("Spam\nand\neggs")
'Spam\nand\neggs'
str и repr (2)
Можете да дефинирате текстово представяне и репрезентация със "служебните" методи __str__
и __repr__
.
class Person(object):
...
def __repr__(self):
return "Person(%s, %s)" % (repr(self.name), repr(self.age))
def __str__(self):
return self.name
>>> mityo = Person("Mityo the Python", 33)
>>> str(mityo)
Mityo the Python
>>> repr(mityo)
Person('Mityo the Python', 33)
>>> mityo
Person('Mityo the Python', 33)
>>> eval(repr(mityo))
Person('Mityo the Python', 33)
Сравняване на обекти (1)
class Person:
def __init__(self, name): self.name = name
def __eq__(self, other):
return self.name == other.name
>>> mityo = Person("Mityo the Python")
>>> mityo2 = Person("Mityo the Python")
>>> mityo == mityo2
True
>>> mityo != mityo2
True
>>> print "WTF?!"
__eq__
не предефинира!=
- За целта трябва да дефинирате метода
__ne__
Сравняване на обекти (2)
Други методи за сравняване на обекти:
__lt__(self, other)
# self <>__le__(self, other)
# self <= other__gt__(self, other)
# self > other__ge__(self, other)
# self >= other
Сравняване на обекти (3)
Можете да предефинирате всичките шест оператора __cmp__(self, other)
. Този метод трябва да сравнява self
и other
и да връща:
- Отрицателно число, ако
self <>.
- Нула, ако
self == other
. - Положително число, ако
self > other
.
class Person(object):
...
def __cmp__(self, other):
if self.name < other.name: return -1
elif self.name == other.name: return 0
else: return 1
>>> mityo = Person("Mityo the Python")
>>> dim = Persom("Dim")
>>> mityo > dim
True
Хеш функции
Можете да "задавате" хеш стойностите на вашите обекти дефинирайки метода __hash__
.
class Person(object):
...
def __hash__(self):
return len(self.name) + self.age
Можете да вземете хеша на даден обект с функцията hash()
.
>>> mityo = hash(Person("Mityo da Gun", 30))
42
Аритметични оператори (1)
Можете да предефинирате аритметичните оператори за вашите типове.
__add__(self, other)
заself + other
__sub__(self, other)
заself - other
__mul__(self, other)
заself * other
__div__(self, other)
заself / other
__floordiv__(self, other)
заself // other
__mod__(self, other)
заself % other
__lshift__(self, other)
заself <<>
__rshift__(self, other)
заself >> other
__and__(self, other)
заself & other
__xor__(self, other)
заself ^ other
__or__(self, other)
заself | other
Аритметични оператори (2)
- Всеки оператор има вариантен метод за прилагане на операцията "на място" - например
+=
,/=
и т.н. - Метода има същото име, но със
i
след двете подчертавки -__add__
става__iadd__
- Хубаво е когато дефинирате такива методи, те да променят
self
и да връщатself
a, b, c = MagicNumber(3), MagicNumber(5), MagicNumber(7)
a = a + b # MagicNumber.__add__(a, b)
a += c # MagicNumber.__iadd__(a, c)
Аритметични оператори (3)
- Аритметичните оператори имат още един вариант - когато обекта е от дясната страна на операцията
- Те започват с
r
, т.e. "десния" вариант на__add__
е__radd__
- При
a + b
, ще се извикаb.__radd__
само акоа
не дефинира__add__
, аb
дефинира__radd__
. - Ако
b
е от тип, наследник наa
, то Python ще опита да извикаb.__radd__
преди да пробва сa.__add__
. По този начин наследници могат да предефинират аритметични операции
Преобразуване до стандартни типове
Има методи, които може да предефинирате, за преобразования от вашия клас към стандартен тип:
__int__(self)
заint(обект)
.__long__(self)
заlong(обект)
.__float__(self)
заfloat(обект)
.__complex__(self)
заcomplex(обект)
.__nonzero__(self)
заbool(обект)
.
Колекции
Python ви предлага и оператори, с които можете да третирате вашия клас като колекция:
__len__(self)
заlen(обект)
.__getitem__(self, key)
заобект[key]
.__setitem__(self, key, value)
заобект[key] == value
__delitem__(self, key)
заdel обект[key]
.__contains__(self, item)
заitem in обект
.
Обекти които могат да бъдат извиквани като функции
Можете да предефинирате оператора две скоби ()
.
class Stamp(object):
def __init__(self, name): self.name = name
def __call__(self, something):
print "%s was stamped by %s" % (something, self.name)
>>> stamp = Stamp("The goverment")
>>> stamp("That thing there")
That thing there was stamped by The goverment
Атрибути (1)
getattr(обект, име_на_атрубит)
връщаобект.атрибут
, където атрибут.setattr(обект, име_на_атрибут, стойност)
присвоява стойност наобект.атрибут
.delattr(обект, име_на_атрибут)
работи катоdel обект.атрибут
.
class Spam: pass
>>> spam = Spam()
>>> spam.eggs = "Eggs"
>>> getattr(spam, 'eggs')
Eggs
>>> setattr(spam, 'bacon', 'Spam, eggs and bacon')
>>> spam.bacon
Spam, eggs and bacon
>>> delattr(spam, 'bacon')
Атрибути (2)
Можете да предефинирате достъпа до атрибутите на вашите обекти с __getattr__
, __setattr__
и __delattr__
. Сигнатурите са следните:
__getattr__(self, name)
заsomething = object.name
__setattr__(self, name, value)
заobject.name = "Foo"
__delattr__(self, name)
заdel object.name
Атрибути (3)
__getattr__(self, name)
се извиква само, ако обекта няма атрибут с име name
.
class Spam(object):
def __getattr__(self, name):
print "Getting attribute: " + name
return None
spam = Spam()
spam.eggs = "Eggs"
print spam.eggs
print spam.foo
Eggs
Getting attribute: foo
None
Атрибути (4)
__setattr__
се извиква, когато присвоявате стойност на атрибута на даден обект. За да не изпаднете в безкрайна рекурсия, ползвайте object.__setattr__
class Turtle(object):
def __setattr__(self, name, value):
print "Setting attribute: " + name
object.__setattr__(self, name, value)
turtle = Turtle()
turtle.spam = "Spam" # prints 'Setting attribute: spam'
Атрибути (5)
Класовете нов стил имат специален метод __getattribute__
, който работи подобно на __getattr__
, с тази разлика че се извиква винаги, без значение дали обекта има такъв атрибут или не. Отново, за да не изпаднете в бездънна рекурсия, ползвайте object.__getattribute__
.
class Crab(object):
def __getattribute__(self, name):
print "Getting attribute: " + name
return object.__getattribute__(self, name)
crab = Crab()
crab.spam = "Spam"
crab.eggs = "Eggs"
print crab.spam
print crab.eggs
Getting attribute: spam
Spam
Getting attribute: eggs
Eggs
Множествено наследяване
Просто изброявате повече от един клас в скобите.
class A: pass
class B: pass
class C: pass
class D(A, B, C): pass
Няма коментари:
Публикуване на коментар