Класове и обекти, част 1

„ Програмиране с Python“, ФМИ

14.03.2007г.

Python и Зен философията

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Класовете, обектите и питоните

Основи на класовете (1)

Основи на класовете (2)


class Person:
    """Represents a person."""
    people = 0

    def __init__(self, name):
        """Constructs a new person."""
        self.name = name
        Person.people += 1

    def sayHi(self):
        """Presents one's self."""
        print "Hello, I'm %s!" % self.name

>>> mityo = Person("Mityo the Python")
>>> mityo.sayHi()
Hello, I'm Mityo the Python!
>>> guido = Person("Guido")
>>> guido.sayHi()
Hello, I'm Guido!
>>> print Person.people
2

Полета (1)


class Spam:
    def __init__(self, arg)
        self.stored = arg

>>> spam = Spam(42)
>>> print spam.stored
42
>>> spam.stored = 60
>>> print spam.stored
60
>>> spam.foo = 10
>>> print spam.foo
10

Полета (2)

По този начин може да използвате класовете като структури:

class Student: pass

>>> john = Student()
>>> john.name = "Ivan"
>>> john.age = 21
>>> john.facultyNumber = 98789

Методи


class Person:
    def __init__(self, name):
        self.name = name

    def greet(self, somebody):
        print "Hello %s, I'm %s!" % (somebody, self.name)

>>> mityo = Person("Mityo the Python")
>>> mityo.greet('Dim')
Hello Dim, I'm Mityo the Python!
>>> Person.greet(mityo, 'Dim')
Hello Dim, I'm Mityo the Python!

Методи (2)

Интересен страничен (или не толкова страничен) ефект е следното:

>>> person = Person("Mityo the Python")
>>> greetSomeone = person.greet
...
>>> greetSomeone("Dim")
Hello Dim, I'm Mityo the Python!

Обаче:

>>> greeter = Person.greet
>>> greeter(mityo, "Dim")

Статични методи

При статичните методи положението е малко странно:

class Person:
    people = []
    def register(name):
        Person.people.append(name)
        print len(Person.people), "people are registered now"
    register = staticmethod(register)

>>> Person.register("Mityo the Python")
1 people are registered now
>>> Person.register("Pooh")
2 people are registered now

Класови методи

В Python има "класови" методи, които вземат класът на който са извикани като първи аргумент. Понякога е полезно при наследяване:

class Something:
    def greet(cls, someone):
        print someone, "was greeted from", cls
    greet = classmethod(greet)

>>> Something.greet("Mityo")
Mityo was greeted from __main__.Something

Конструкция


class Person:
    def __init__(self, name, age, location="Sofia")
        self.name = name
        self.age = age
        self.location = location

>>> person = Person("Mityo the Python", 30, "Great Tarnovo")

Наследяване

Проста хватка:

class Something:
    def __init__(self, name): self.name = name
    def introduce(self): "This is something called", self.name

class Vegetable(Something):
    def eat(self): print self, "was eaten"

class Animal(Something):
    def notice(self): print "Look! This is a", self.name
    def introduce(self): print "This is an animal called", self.name

>>> snake = Animal("python")
>>> snake.introduce()
This is an animal called python
>>> snake.notice()
Look! It's a python

Методи и променливи на родителите

Стандартното клас.метод би трябвало да ви е достатъчно:

class PopularPerson(Person):
    def greet(self, somebody):
        Person.greet(self, somebody)
        print "Do you want my autograph?"

>>> pop = PopularPerson("Mityo the Python")
>>> pop.greet("Dim")
Hello Dim, I'm Mityo the Python!
Do you want my autograph?

Protected и private


>>> class Spam:
...     def __stuff(self): pass
...
>>> dir(Spam)
['_Spam__stuff', '__doc__', '__module__']

Protected и private (2)

class Base:
    def __init__(self, name, age):
        self.__name = name
        self._age = age

    def reportBase(self):
        print "Base:", self.__name, self._age

class Derived(Base):
    def __init__(self, name, age, derivedName):
        Base.__init__(self, name, age)
        self.__name = derivedName
        self._age = 33

    def reportDerived(self):
        print "Derived:", self.__name, self._age

>>> derived = Derived("Mityo the Python", 30, "Mityo the Gun")
>>> derived.reportBase()
Base: Mityo the Python 33
>>> derived.reportDerived()
Derived: Mityo the Gun 33
>>> derived._Base__name, ", ", derived._Derived__name
Mityo the Python, Mityo the Gun

Класове в нов стил

Класове в нов стил — __new__


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

Класове в нов стил - __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'

Множествено наследяване

Просто изброявате повече от един клас в скобите.

class A: pass
class B: pass
class C: pass
class D(A, B, C): pass

Малко по-късно за класическите проблеми, които произтичат от това