map(lambda _: ' '.join(_), [('Стефан', 'Кънев'),
('Николай', 'Бачийски'),
('Точо', '.', 'Точев'),
('Димитър', 'Димитров')])
Обектно-ориентирано програмиране...
class Vector:
def __init__(self, x, y, z): self._coords = list(map(float, [x, y, z]))
def length(self): return sum([_ ** 2 for _ in self._coords]) ** 0.5
def dot(self, other):
return Vector(self.y() * other.z() - self.z() * other.y(),
self.z() * other.x() - self.x() * other.z(),
self.x() * other.y() - self.y() * other.x())
def normalize(self):
self._coords = [_ / self.length() for _ in self._coords]
def x(self): return self._coords[0]
def y(self): return self._coords[1]
def z(self): return self._coords[2]
x, y = Vector(0, 2.0, 0), Vector(3.0, 0, 0)
z = x.dot(y)
z.normalize()
print(z._coords)
_име
се смятат за protected__име
се смятат за private__име
до _клас__име
. Това се нарича name mangling и ефектът му е подобен на private в други езици
class Spam:
def __stuff(self): pass
>>> dir(Spam)
['_Spam__stuff', '__doc__', '__module__', ...]
class Base:
def __init__(self, name, age):
self.__name = name
self._age = age
def report_base(self):
print("Base:", self.__name, self._age)
class Derived(Base):
def __init__(self, name, age, derived_name):
Base.__init__(self, name, age)
self.__name = derived_name
self._age = 33
def report_derived(self):
print("Derived:", self.__name, self._age)
>>> derived = Derived("Mityo the Python", 30, "Mityo the Gun")
>>> derived.report_base()
Base: Mityo the Python 33
>>> derived.report_derived()
Derived: Mityo the Gun 33
>>> print(derived._Base__name, ", ", derived._Derived__name, sep='')
Mityo the Python, Mityo the Gun
super
class A:
def spam(self, sth): print("A's spam and {0}".format(sth))
class B(A):
def spam(self, sth):
print("B's spam and {0}".format(sth))
super().spam(sth) # еквивалентно на super(B, self).method(eggs)
print("B's spam and {0} (again)".format(sth))
>>> B().spam("eggs")
B's spam and eggs
A's spam and eggs
B's spam and eggs (again)
>>> super(B, B()).spam("eggs")
A's spam and eggs
Атрибутите се търсят в родителите по дълбочина (отляво надясно)
class A:
def spam(self): print("A's spam")
class B(A): pass
class C:
def spam(self): print("C's spam")
class D(B, C): pass
d = D()
d.spam() # A's spam
Всъщност в python използват "call-next-method"
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() # C's spam
super
(2)class A:
def x(self):
print('A')
class B(A):
def x(self):
super().x()
print('B')
class C(A):
def x(self):
super().x()
print('C')
class D(B,C):
def x(self):
super().x()
print('D')
D().x()
isinstance
и issubclass
isinstance(3, int) # True
isinstance(4.5, int) # False
issubclass(int, object) # True
issubclass(float, int) # False
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')
==
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
Можете да предефинирате равенството за обекти от даден клас с метода__eq__
class Vector:
def __init__(self, x, y, z): self._coords = map(float, [x, y, z])
def __eq__(self, other):
return all([a == b for a, b in zip(self._coords, other._coords)])
По подразбиране, __eq__
е имплементирана с is
class Food: pass
spam = Food()
eggs = Food()
more_spam = spam
print(spam == more_spam, spam is more_spam) # True True
print(spam == eggs, spam is eggs) # False False
class Vector:
def __init__(self, x, y, z): self._coords = list(map(float, [x, y, z]))
def __eq__(self, other):
return all([a == b for a, b in zip(self._coords, other._coords)])
>>> a, b = Vector(1.0, 1.0, 1.0), Vector(1.0, 1.0, 1.0)
>>> print(a == b)
True
>>> print(a != b)
False
__eq__
предефинира !=
__ne__
Други методи за сравняване на обекти:
__lt__(self, other)
# self < other__le__(self, other)
# self <= other__gt__(self, other)
# self > other__ge__(self, other)
# self >= otherstr
) и "репрезентация" (repr
)str(обект)
eval(repr(обект)) == обект
repr(обект)
>>> print("Spam\nand\neggs")
Spam
and
eggs
>>> print(repr("Spam\nand\neggs"))
'Spam\nand\neggs'
Можете да дефинирате текстово представяне и репрезентация със "служебните" методи __str__
и __repr__
.
class Person:
...
def __repr__(self):
return "Person({0!r}, {1!r})".format(self.name, self.age)
def __str__(self):
return self.name
>>> mityo = Person("Mityo the Python", 33)
>>> print(str(mityo))
Mityo the Python
>>> print(repr(mityo))
Person('Mityo the Python', 33)
>>> mityo
Person('Mityo the Python', 33)
>>> eval(repr(mityo))
Person('Mityo the Python', 33)
Можете да "задавате" хеш стойностите на вашите обекти дефинирайки метода __hash__
.
class Person:
...
def __hash__(self):
return len(self.name) + self.age
Можете да вземете хеша на даден обект с функцията hash()
.
>>> mityo = hash(Person("Mityo da Gun", 30))
42
Можете да задавате как да излиза обекта при формат.
class Spam:
def __format__(self, string):
return 'spam' + (' ' + string if string else '')
>>> print('{0}'.format(Spam()))
spam
>>> print('{0:a lot}'.format(Spam()))
spam a lot
Можете да предефинирате аритметичните оператори за вашите типове.
__add__(self, other)
за self + other
__sub__(self, other)
за self - other
__mul__(self, other)
за self * other
__truediv__(self, other)
за self / other
__floordiv__(self, other)
за self // other
__mod__(self, other)
за self % other
__lshift__(self, other)
за self << other
__rshift__(self, other)
за self >> other
__and__(self, other)
за self & other
__xor__(self, other)
за self ^ other
__or__(self, other)
за self | other
+=
, /=
и т.н.i
след двете подчертавки - __add__
става __iadd__
self
и да връщат self
a OP= b
и недефиниран __iOP__
се извиква a = a OP b
a, b, c = MagicNumber(3), MagicNumber(5), MagicNumber(7)
a = a + b # MagicNumber.__add__(a, b)
a += c # MagicNumber.__iadd__(a, c)
r
, т.e. "десния" вариант на __add__
е __radd__
a + b
, ще се извика b.__radd__
само ако а
не дефинира __add__
, а b
дефинира __radd__
.b
е от тип, наследник на a
, то Python ще опита да извика b.__radd__
преди да пробва с a.__add__
. По този начин наследници могат да предефинират аритметични операции.Има методи, които може да предефинирате, за преобразования от вашия клас към стандартен тип:
__int__(self)
за int(обект)
__float__(self)
за float(обект)
__complex__(self)
за complex(обект)
__bool__(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:
def __init__(self, name): self.name = name
def __call__(self, something):
print("{0} was stamped by {1}".format(something, self.name))
>>> stamp = Stamp("The goverment")
>>> stamp("That thing there")
That thing there was stamped by The goverment
Можете да предефинирате достъпа до атрибутите на вашите обекти с __getattr__
, __setattr__
и __delattr__
. Сигнатурите са следните:
__getattr__(self, name)
за something = object.name
__setattr__(self, name, value)
за object.name = "Foo"
__delattr__(self, name)
за del object.name
__getattr__(self, name)
се извиква само, ако обекта няма атрибут с име name
.
class Spam:
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
__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'
Класовете имат специален метод __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