Обектно-ориентирано програмиране...
class Vector(object):
def __init__(self, x, y, z): self._coords = 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
object или клас, който наследява object - list, dict, tuple, str и т.н.__new__.__slots__.
class Something(object):
__slots__ = ['spam', 'eggs']
>>> smth = Something()
>>> smth.spam = 1
>>> smth.eggs = 2
>>> smth.foo = 3
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
AttributeError: 'Something' object has no attribute 'foo'
Обикновенно се налага, когато наследявате immutable стандартни класове
class SpamTuple(tuple):
def __new__(cls, number = 1):
result = ("Spam",) * number
return tuple.__new__(cls, result)
def countSpam(self):
return len(self)
spams = SpamTuple(3)
print spams # ('Spam', 'Spam', 'Spam')
print spams.countSpam() # 3
При класове от стар стил, атрибутите се търсят в родителите по дълбочина
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
При класове от нов стил, атрибутите се търсят в родителите по широчина
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
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(object):
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(object): pass
spam = Food()
eggs = Food()
moreSpam = spam
print spam == moreSpam, spam is moreSpam # True True
print spam == eggs, spam is eggs # False False
class Vector(object):
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)])
>>> a, b = Vector(1.0, 1.0, 1.0), Vector(1.0, 1.0, 1.0)
>>> print a == b
True
>>> print a != b
True
>>> print "WTF?!"
__eq__ не предефинира !=__ne__Други методи за сравняване на обекти:
__lt__(self, other) # self < other__le__(self, other) # self <= other__gt__(self, other) # self > other__ge__(self, other) # self >= otherМожете да предефинирате всичките шест оператора __cmp__(self, other). Този метод трябва да сравнява self и other и да връща:
self < other.self == other.self > other.class Vector(object):
...
def __cmp__(self, other):
if self.length() < other.length(): return -1
elif self.length() == other.length(): return 0
else: return 1
str) и "репрезентация" (repr)str(обект) или при "%s" % обектeval(repr(обект)) == обектrepr(обект).
>>> print "Spam\nand\neggs"
Spam
and
eggs
>>> print repr("Spam\nand\neggs")
'Spam\nand\neggs'
Можете да дефинирате текстово представяне и репрезентация със "служебните" методи __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)
Можете да "задавате" хеш стойностите на вашите обекти дефинирайки метода __hash__.
class Person(object):
...
def __hash__(self):
return len(self.name) + self.age
Можете да вземете хеша на даден обект с функцията hash().
>>> mityo = hash(Person("Mityo da Gun", 30))
42
Можете да предефинирате аритметичните оператори за вашите типове.
__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 << 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, 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(обект).__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
Можете да предефинирате достъпа до атрибутите на вашите обекти с __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(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
__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