Классы, объекты и методы в Python

Введение

Примеры

  • 24

    Основное наследование

    Наследование в Python основано на сходных идеях, используемых в других объектно-ориентированных языках, таких как Java, C ++ и т. Д. Новый класс может быть получен из существующего класса следующим образом.

     class BaseClass(object):
        pass
    
    class DerivedClass(BaseClass):
        pass
    
     

    BaseClass является уже существующий (родительский) класс, а DerivedClass это новый (дочерний) класс , который наследует (или подклассов) атрибуты BaseClass . Примечание: По состоянию на Python 2.2, все классы неявно наследуются от object класса , который является базовым классом для всех встроенных типов.

    Определим родительский Rectangle класс в примере ниже, который неявно наследует от object :

     class Rectangle():
        def __init__(self, w, h):
            self.w = w
            self.h = h
    
        def area(self):
            return self.w * self.h
    
        def perimeter(self):
            return 2 * (self.w + self.h)
     

    Rectangle класс может быть использован в качестве базового класса для определения Square класса, как квадрат является частным случаем прямоугольника.

     class Square(Rectangle):
        def __init__(self, s):
            # call parent constructor, w and h are both s
            super(Square, self).__init__(s, s)
            self.s = s
    
     

    Square класс автоматически наследует все атрибуты Rectangle класса, а также класса объектов. super() используется для вызова __init__() метод Rectangle класса, по существу , вызовом любой перекрытый метод базового класса. Примечание: в Python 3, super() не требует аргументов.

    Объекты производного класса могут получать доступ и изменять атрибуты своих базовых классов:

     r.area()
    # Output: 12
    r.perimeter()  
    # Output: 14
    
    s.area()
    # Output: 4
    s.perimeter()
    # Output: 8
    
     

    Встроенные функции, которые работают с наследованием

    issubclass(DerivedClass, BaseClass) : возвращает True , если DerivedClass является подклассом BaseClass

    isinstance(s, Class) : возвращает True , если ы является экземпляром Class или любой из производных классов Class

     # subclass check        
    issubclass(Square, Rectangle)
    # Output: True
    
    # instantiate
    r = Rectangle(3, 4)
    s = Square(2)
    
    isinstance(r, Rectangle)  
    # Output: True
    isinstance(r, Square)
    # Output: False
    # A rectangle is not a square
    
    isinstance(s, Rectangle)
    # Output: True
    # A square is a rectangle
    isinstance(s, Square)
    # Output: True 
  • 3

    Переменные класса и экземпляра

    Переменные экземпляра уникальны для каждого экземпляра, а переменные класса являются общими для всех экземпляров.

     class C:
        x = 2  # class variable
    
        def __init__(self, y):
            self.y = y  # instance variable
    
    C.x
    # 2
    C.y
    # AttributeError: type object 'C' has no attribute 'y'
    
    c1 = C(3)
    c1.x
    # 2
    c1.y
    # 3
    
    c2 = C(4)
    c2.x
    # 2
    c2.y
    # 4
    
     

    Переменные класса могут быть доступны в экземплярах этого класса, но присвоение атрибуту класса создаст переменную экземпляра, которая затеняет переменную класса

     c2.x = 4
    c2.x
    # 4
    C.x
    # 2
    
     

    Обратите внимание , что мутирует переменный класс случаев может привести к неожиданным последствиям.

     class D:
        x = []
        def __init__(self, item):
            self.x.append(item)  # note that this is not an assigment!
    
    d1 = D(1)
    d2 = D(2)
    
    d1.x
    # [1, 2]
    d2.x
    # [1, 2]
    D.x
    # [1, 2] 
  • 30

    Связанные, несвязанные и статические методы

    Идея связанных и несвязанных методов был удален в Python 3 . В Python 3 при объявлении метода в классе, вы используете def ключевое слово, тем самым создавая объект функции. Это обычная функция, и окружающий класс работает как пространство имен. В следующем примере мы указываем метод f в пределах класса A , и это становится функцией Af :

    класс A (объект): def f (self, x): return 2 * x Af # (в Python 3.x)

    В Python 2 поведение отличается: объекты функций внутри класса были неявно заменены объектами типа instancemethod , которые назывались несвязанных метода , потому что они не были связаны с каким - либо конкретным экземпляром класса. Удалось получить доступ к основной функции с помощью .__func__ свойства.

    Af # (в Python 2.x) Af__class__ # Af__func__ #

    Последнее поведение подтверждается проверкой - методы распознаются как функции в Python 3, в то время как различие поддерживается в Python 2.

    импорт inspect inspect.isfunction (Af) # True inspect.ismethod (Af) # False импорт inspect inspect.isfunction (Af) # False inspect.ismethod (Af) # True

    В обеих версиях функции Python / метод Af может быть вызван непосредственно, при условии , что вы передаете экземпляр класса A в качестве первого аргумента.

     A.f(1, 7)
    # Python 2: TypeError: unbound method f() must be called with
    #                      A instance as first argument (got int instance instead) 
    # Python 3: 14   
    a = A()
    A.f(a, 20)
    # Python 2 & 3: 40
    
     

    Теперь предположим , что является экземпляром класса a A , что af тогда? Ну, интуитивно это должно быть тем же самым методом f класса A , только он должен каким - то образом «знает» , что он был применен к объекту a - в Python это называется метод , связанный с . a

    В суровых буднях детали следующим образом : запись af вызывает магический __getattribute__ метод , который сначала проверяет , является ли имеет атрибут с именем a a f (не), а затем проверяет , класс A , содержит ли это метод с таким именем (он делает), и создает новый объект m типа method , который имеет ссылку на исходные Af в m.__func__ и ссылку на объект a в m.__self__ . Когда этот объект вызывается как функция, он просто выполняет следующие действия : m(...) => m.__func__(m.__self__, ...) . Таким образом , этот объект называется связанный метод потому , что при вызове он знает , чтобы поставить объект был привязан к качестве первого аргумента. (Эти вещи работают одинаково в Python 2 и 3).

     a = A()
    a.f
    # <bound method A.f of <__main__.A object at ...>>
    a.f(2)
    # 4
    
    # Note: the bound method object a.f is recreated *every time* you call it:
    a.f is a.f  # False
    # As a performance optimization you can store the bound method in the object's
    # __dict__, in which case the method object will remain fixed:
    a.f = a.f
    a.f is a.f  # True
    
     

    Наконец, Python имеет методы класса и статические методы - специальные виды методов. Методы класса работают точно так же , как и обычные методы, за исключением того, что при вызове на объекте они связываются с классом объекта , а не к объекту. Таким образом , m.__self__ = type(a) . При вызове такого связанного метода, он проходит класс в качестве первого аргумента. a Статические методы еще проще: они вообще ничего не связывают и просто возвращают базовую функцию без каких-либо преобразований.

     class D(object):
        multiplier = 2
    
        @classmethod
        def f(cls, x):
            return cls.multiplier * x
    
        @staticmethod
        def g(name):
            print("Hello, %s" % name)
    
    D.f
    # <bound method type.f of <class '__main__.D'>>
    D.f(12)
    # 24
    D.g
    # <function D.g at ...>
    D.g("world")
    # Hello, world
    
     

    Обратите внимание, что методы класса привязаны к классу даже при обращении к экземпляру:

     d = D()
    d.multiplier = 1337
    (D.multiplier, d.multiplier)
    # (2, 1337)
    d.f
    # <bound method D.f of <class '__main__.D'>>
    d.f(10)
    # 20
    
     

    Стоит отметить , что на самом низком уровне, функции, методы, staticmethods и т.д., на самом деле дескрипторы , которые вызывают __get__ , __set и , возможно , `del__` специальные методы. Для более подробной информации о методах классов и статических методах:

  • 9

    Классы нового стиля против старого стиля

    Новые классы в стиле были введены в Python 2.2 для объединения классов и типов. Они наследуют от верхнего уровня object типа. Класс нового типа является определенный пользователем тип, и очень похож на встроенных типов.

     # new-style class
    class New(object):
        pass
    
    # new-style instance
    new = New()
    
    new.__class__
    # <class '__main__.New'>
    type(new)
    # <class '__main__.New'>
    issubclass(New, object)
    # True
    
     

    Классы старого типа не наследуют от object . Экземпляры старого типа всегда реализуется с помощью встроенного в instance типа.

     # old-style class
    class Old:
        pass
    
    # old-style instance
    old = Old()
    
    old.__class__
    # <class __main__.Old at ...>
    type(old)
    # <type 'instance'>
    issubclass(Old, object)
    # False
    
     

    В Python 3 классы старого стиля были удалены.

    Новые классы стиля в Python 3 неявно наследуют от object , поэтому нет необходимости указывать MyClass(object) больше.

     class MyClass:
        pass
    
    my_inst = MyClass()
    
    type(my_inst)
    # <class '__main__.MyClass'>
    my_inst.__class__
    # <class '__main__.MyClass'>
    issubclass(MyClass, object)
    # True
    
     
  • 3

    Значения по умолчанию для переменных экземпляра

    Если переменная содержит значение неизменяемого типа (например, строку), тогда можно назначить значение по умолчанию, подобное этому.

     class Rectangle(object):
        def __init__(self, width, height, color='blue'):
            self.width = width
            self.height = height
            self.color = color
    
        def area(self):
            return self.width  * self.height 
    
    # Create some instances of the class
    default_rectangle = Rectangle(2, 3)
    print(default_rectangle.color) # blue
    
    red_rectangle = Rectangle(2, 3, 'red')
    print(red_rectangle.color) # red
    
     

    Нужно быть осторожным при инициализации изменяемых объектов, таких как списки в конструкторе. Рассмотрим следующий пример:

     class Rectangle2D(object):
        def __init__(self, width, height, pos=[0,0], color='blue'):  
            self.width = width
            self.height = height
            self.pos = pos
            self.color = color
    
    r1 = Rectangle2D(5,3)
    r2 = Rectangle2D(7,8)
    r1.pos[0] = 4
    r1.pos # [4, 0]
    r2.pos # [4, 0] r2's pos has changed as well
    
     

    Такое поведение вызвано тем, что в Python параметры по умолчанию связаны при выполнении функции, а не при ее объявлении. Чтобы получить переменную экземпляра по умолчанию, которая не разделяется между экземплярами, следует использовать такую ​​конструкцию:

     class Rectangle2D(object):
        def __init__(self, width, height, pos=None, color='blue'):  
            self.width = width
            self.height = height
            self.pos = pos or [0, 0] # default value is [0, 0]
            self.color = color
    
    r1 = Rectangle2D(5,3)
    r2 = Rectangle2D(7,8)
    r1.pos[0] = 4
    r1.pos # [4, 0]
    r2.pos # [0, 0] r2's pos hasn't changed 
    
     

    Смотрите также Мутабельные Аргументы по умолчанию и «изумление» Наималейшего и изменяемый по умолчанию аргумент .

  • 5

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

    Python использует C3 линеаризацию алгоритм для определения порядка , в котором для решения атрибутов класса, включая методы. Это известно как Порядок разрешения методов (MRO).

    Вот простой пример:

     class Foo(object):
        foo = 'attr foo of Foo'
    
    
    class Bar(object):
        foo = 'attr foo of Bar' # we won't see this.
        bar = 'attr bar of Bar'
    
    class FooBar(Foo, Bar):
        foobar = 'attr foobar of FooBar'
    
     

    Теперь, если мы создаем экземпляр FooBar, если мы ищем атрибут foo, мы видим, что атрибут Foo находится первым

     fb = FooBar()
    
     

    а также

     >>> fb.foo
    'attr foo of Foo'
    
    
     

    Вот MRO FooBar:

     >>> FooBar.mro()
    [<class '__main__.FooBar'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <type 'object'>]
    
     

    Можно просто сказать, что алгоритм Python MRO

    1. Глубина первого (например , FooBar затем Foo ) , если
    2. общий родительский ( object ) блокируется ребенком ( Bar ) и
    3. круговые отношения не допускаются.

    То есть, например, Bar не может наследовать от FooBar, а FooBar наследует от Bar.

    Для комплексного примера в Python см запись Википедии .

    Другая характерная особенность в наследстве является super . Супер может получить функции родительских классов.

     class Foo(object):
        def foo_method(self):
            print "foo Method"
    
    class Bar(object):
        def bar_method(self):
            print "bar Method"
    
    class FooBar(Foo, Bar):
        def foo_method(self):
            super(FooBar, self).foo_method()
    
    
    
     

    Множественное наследование с помощью метода init класса, когда у каждого класса есть собственный метод init, тогда мы пытаемся получить множественное наследование, тогда вызывается только метод init класса, который наследуется первым.

    для примера ниже Foo метод инициализировать класс вызывался класс Bar не INIT вызывался

         class Foo(object):
            def __init__(self):
                print "foo init"
    
        class Bar(object):
            def __init__(self):
                print "bar init"
    
        class FooBar(Foo, Bar):
            def __init__(self):
                print "foobar init"
                super(FooBar, self).__init__()
    
        a = FooBar()
    
     

    Выход:

         foobar init
        foo init
    
     

    Но это не значит , что бар класс не наследуется. Instance конечного класса FooBar также экземпляр класса Bar и класса Foo.

     print isinstance(a,FooBar)
    print isinstance(a,Foo)
    print isinstance(a,Bar) 
    
     

    Выход:

     True
    True
    True 
  • 1

    Дескрипторы и точечные поиски

    Дескрипторы являются объектами , которые являются ( как правило) атрибутами классов и которые имеют какие - либо из __get__ , __set__ или __delete__ специальных методов.

    Дескрипторы данных имеют какой - либо из __set__ или __delete__

    Они могут контролировать пунктирный поиск на экземпляре, и используются для реализации функций, staticmethod , classmethod и property . Пунктирная поиск (например , экземпляр foo класс Foo отрываясь атрибут bar - т.е. foo.bar ) использует следующий алгоритм:

    1. bar ищется в классе, Foo . Если она есть , и это дескриптор данных, то используется дескриптор данных. Вот как property имеет возможность контролировать доступ к данным в экземпляре, и экземпляры не могут изменить это. Если дескриптор данных не существует, то

    2. bar ищется в инстанции __dict__ . Вот почему мы можем переопределить или заблокировать методы, вызываемые из экземпляра с точечным поиском. Если bar существует в случае, она используется. Если нет, то мы

    3. искать в классе Foo для bar . Если это Descriptor, то используется протокол дескриптора. Это как функции (в данном контексте, несвязанные методы), classmethod и staticmethod реализуются. Иначе он просто возвращает объект там, или есть AttributeError

  • 9

    Методы класса: альтернативные инициализаторы

    Методы класса представляют альтернативные способы создания экземпляров классов. Чтобы проиллюстрировать это, давайте посмотрим на пример.

    Давайте предположим , что мы имеем относительно простой Person класс:

     class Person(object):
    
        def __init__(self, first_name, last_name, age):
            self.first_name = first_name
            self.last_name = last_name
            self.age = age
            self.full_name = first_name + " " + last_name
    
        def greet(self):
            print("Hello, my name is " + self.full_name + ".")
    
     

    Возможно, было бы удобно иметь возможность создавать экземпляры этого класса, указав полное имя вместо имени и фамилии отдельно. Один из способов сделать это будет иметь last_name быть необязательным параметром, и при условии , что , если не дано, мы прошли полное имя:

     class Person(object):
    
        def __init__(self, first_name, age, last_name=None):
            if last_name is None:
                self.first_name, self.last_name = first_name.split(" ", 2)
            else:
                self.first_name = first_name
                self.last_name = last_name
    
            self.full_name = self.first_name + " " + self.last_name
            self.age = age
    
        def greet(self):
            print("Hello, my name is " + self.full_name + ".")
    
     

    Однако с этим битом кода связаны две основные проблемы:

    1. Параметры first_name и last_name теперь вводит в заблуждение, так как вы можете ввести полное имя для first_name . Кроме того, если есть больше падежей и / или больше параметров, которые обладают такой гибкостью, ветвление if / elif / else может быстро раздражать.

    2. Не совсем так важно, но все же стоит отметить: что , если last_name не None , но first_name не расщепляется на две или больше вещей через пробелы? У нас есть еще один уровень проверки ввода и / или обработки исключений ...

    Введите методы класса. Вместо того , чтобы иметь один инициализатор, мы создадим отдельный инициализатору, называемый from_full_name , и украсить его с (встроенный) classmethod декоратора.

    class Person(object):
    
        def __init__(self, first_name, last_name, age):
            self.first_name = first_name
            self.last_name = last_name
            self.age = age
            self.full_name = first_name + " " + last_name
    
        @classmethod
        def from_full_name(cls, name, age):
            if " " not in name:
                raise ValueError
            first_name, last_name = name.split(" ", 2)
            return cls(first_name, last_name, age)
    
        def greet(self):
            print("Hello, my name is " + self.full_name + ".")
    
    

    Обратите внимание на cls вместо self в качестве первого аргумента from_full_name . Методы класса применяется к общему классу, не является экземпляром данного класса (что self обычно обозначает). Так что , если cls является наш Person класс, то возвращается значение из from_full_name метода класса является Person(first_name, last_name, age) , который использует Person «s __init__ создать экземпляр Person класса. В частности, если мы должны были сделать подкласс Employee из Person , то from_full_name будет работать в Employee классе , а также.

    Для того, чтобы показать , что это работает , как и ожидалось, давайте создавать экземпляры Person в более чем одним способом , без разветвлений в __init__ :

     In [2]: bob = Person("Bob", "Bobberson", 42)
    
    In [3]: alice = Person.from_full_name("Alice Henderson", 31)
    
    In [4]: bob.greet()
    Hello, my name is Bob Bobberson.
    
    In [5]: alice.greet()
    Hello, my name is Alice Henderson.
    
    
     

    Другие ссылки:

  • 3

    Классная композиция

    Композиция классов позволяет явные отношения между объектами. В этом примере люди живут в городах, которые принадлежат странам. Композиция позволяет людям получить доступ ко всем людям, живущим в их стране:

    class Country(object):
        def __init__(self):
            self.cities=[]
    
        def addCity(self,city):
            self.cities.append(city)
    
    
    class City(object):
        def __init__(self, numPeople):
            self.people = []
            self.numPeople = numPeople
    
    
        def addPerson(self, person):
            self.people.append(person)
    
        def join_country(self,country):
            self.country = country
            country.addCity(self)
    
            for i in range(self.numPeople):
                    person(i).join_city(self)
    
    
    class Person(object):
        def __init__(self, ID):
            self.ID=ID
    
        def join_city(self, city):
            self.city = city
            city.addPerson(self)
    
        def people_in_my_country(self):
            x= sum([len(c.people) for c in self.city.country.cities])
            return x
    
    US=Country()
    NYC=City(10).join_country(US)
    SF=City(5).join_country(US)
    
    print(US.cities[0].people[0].people_in_my_country())
    
    # 15
  • 20

    Обезьяна Ямочный

    В этом случае «исправление обезьяны» означает добавление новой переменной или метода в класс после его определения. Например, скажем , мы определили класс A , как

     class A(object):
        def __init__(self, num):
            self.num = num
    
        def __add__(self, other):
            return A(self.num + other.num)
    
     

    Но теперь мы хотим добавить еще одну функцию позже в коде. Предположим, что эта функция выглядит следующим образом.

     def get_num(self):
        return self.num
    
     

    Но как же мы добавим это как метод в A ? Это просто мы просто по существу поместить эту функцию в с помощью оператора присваивания. A

     A.get_num = get_num
    
     

    Почему это работает? Потому что функции - это объекты, как и любой другой объект, а методы - это функции, принадлежащие классу.

    Функция get_num должна быть доступна для всех существующих (уже создан) , а также к новым экземплярам A

    Эти дополнения доступны для всех экземпляров этого класса (или его подклассов) автоматически. Например:

     foo = A(42)
    
    A.get_num = get_num
    
    bar = A(6);
    
    foo.get_num() # 42
    
    bar.get_num() # 6
    
    
     

    Обратите внимание, что, в отличие от некоторых других языков, этот метод не работает для определенных встроенных типов и не считается хорошим стилем.

  • 3

    Список всех членов класса

    dir() функция может быть использована для получения списка членов класса:

     dir(Class)
    
     

    Например:

     >>> dir(list)
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    
     

    Обычно ищут только "немагических" участников. Это можно сделать с помощью простого понимания , в котором перечислены члены, имена которых не начиная с __ :

     >>> [m for m in dir(list) if not m.startswith('__')]
    ['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    
     

    Предостережения:

    Классы можно определить __dir__() метод. Если этот метод существует вызова dir() будем называть __dir__() , в противном случае Python будет пытаться создать список членов класса. Это означает, что функция dir может иметь неожиданные результаты. Две цитаты важности из официальной документации питона :

    Если объект не содержит каталог ( как правило ), функция пытается все возможное , чтобы собрать информацию из атрибута Dict объекта, если он определен, и от его типа объекта. Полученный список не обязательно является полным, и может быть неточным , если объект имеет собственный GetAttr ().

    Примечание: Поскольку реж () поставляется в первую очередь для удобства использования в интерактивной командной строке, он пытается поставить интересный набор имен больше , чем он пытается поставить строго или последовательно определенный набор имен, и его детальное поведение может измениться по релизы. Например, атрибуты метакласса отсутствуют в списке результатов, когда аргумент является классом.

  • 44

    Введение в классы

    Класс, функционирующий как шаблон, который определяет основные характеристики конкретного объекта. Вот пример:

     class Person(object):
         """A simple class."""                            # docstring
         species = "Homo Sapiens"                         # class attribute
    
         def __init__(self, name):                        # special method
             """This is the initializer. It's a special
             method (see below).
             """
             self.name = name                             # instance attribute
    
         def __str__(self):                               # special method
             """This method is run when Python tries 
             to cast the object to a string. Return 
             this string when using print(), etc.
             """
             return self.name
    
         def rename(self, renamed):                       # regular method
             """Reassign and print the name attribute."""
             self.name = renamed
             print("Now my name is {}".format(self.name))
    
     

    Есть несколько вещей, на которые стоит обратить внимание при рассмотрении приведенного выше примера.

    1. Класс состоит из атрибутов (данных) и методов (функций).
    2. Атрибуты и методы просто определяются как обычные переменные и функции.
    3. Как было отмечено в соответствующей строке документации, то __init__() метод вызывается инициализатором. Он эквивалентен конструктору в других объектно-ориентированных языках и является методом, который запускается в первый раз при создании нового объекта или нового экземпляра класса.
    4. Атрибуты , которые применимы ко всему классу определяются первым, и называются атрибутами класса.
    5. Атрибуты, относящиеся к определенному экземпляру класса (объект) называются атрибутами экземпляра. Они , как правило , определяется внутри __init__() ; это не является необходимым, но рекомендуется (так как атрибуты определяются вне __init__() рискуют быть доступны , прежде чем они определены).
    6. Каждый метод, включенный в определение класса, передает рассматриваемый объект в качестве первого параметра. Слово self используется для этого параметра (использование self на самом деле условно, так как слово self не имеет собственного значения в Python, но это один из самых уважаемых конвенций Python, и вы всегда должны следовать).
    7. Те, кто привык к объектно-ориентированному программированию на других языках, могут быть удивлены несколькими вещами. Одним из них является , что Python не имеет реального понятия private элементов, так что все, по умолчанию, имитирует поведение C ++ / Java public ключевого слова. Для получения дополнительной информации см. Пример «Члены частного класса» на этой странице.
    8. Некоторые методы класса имеет следующий вид: __functionname__(self, other_stuff) . Все такие методы называются «магическими методами» и являются важной частью классов в Python. Например, перегрузка операторов в Python реализована магическими методами. Для получения дополнительной информации см соответствующей документации .

    Теперь давайте сделаем несколько экземпляров нашего Person класса!

     >>> # Instances
    >>> kelly = Person("Kelly")
    >>> joseph = Person("Joseph")
    >>> john_doe = Person("John Doe")
    
     

    В настоящее время мы имеем три Person объектов, kelly , joseph и john_doe .

    Мы можем получить доступ к атрибутам класса из каждого экземпляра с помощью оператора точки . Еще раз обратите внимание на разницу между атрибутами класса и экземпляра:

     >>> # Attributes
    >>> kelly.species
    'Homo Sapiens'
    >>> john_doe.species
    'Homo Sapiens'
    >>> joseph.species
    'Homo Sapiens'
    >>> kelly.name
    'Kelly'
    >>> joseph.name
    'Joseph'
    
    
     

    Мы можем выполнить методы класса с использованием того же оператора точки . :

     >>> # Methods
    >>> john_doe.__str__()
    'John Doe'
    >>>  print(john_doe)
    'John Doe'
    >>>  john_doe.rename("John")
    'Now my name is John'
    
    
     
  • 4

    свойства

    Классы Python поддерживают свойства, которые выглядят как обычный переменный объект, но с возможностью прикрепления пользовательского поведения и документации.

     class MyClass(object):
    
        def __init__(self):
           self._my_string = ""
    
        @property
        def string(self):
            """A profoundly important string."""
            return self._my_string
    
        @string.setter
        def string(self, new_value):
            assert isinstance(new_value, str), \
                   "Give me a string, not a %r!" % type(new_value)
            self._my_string = new_value
    
        @string.deleter
        def x(self):
            self._my_string = None
    
     

    Объекта , класса MyClass , будет иметь имеют свойство .string , однако его поведение теперь жестко контролируется:

     mc = MyClass()
    mc.string = "String!"
    print(mc.string)
    del mc.string
    
     

    Помимо полезного синтаксиса, описанного выше, синтаксис свойства позволяет проверять или добавлять другие дополнения к этим атрибутам. Это может быть особенно полезно с общедоступными API-интерфейсами, где пользователю должен быть предоставлен определенный уровень помощи.

    Другое распространенное использование свойств - это предоставление классу возможности представлять «виртуальные атрибуты» - атрибуты, которые на самом деле не хранятся, но вычисляются только по запросу.

    class Character(object):
        def __init__(name, max_hp):
            self._name = name
            self._hp = max_hp
            self._max_hp = max_hp
    
        # Make hp read only by not providing a set method
        @property
        def hp(self):
            return self._hp
    
        # Make name read only by not providing a set method
        @property
        def name(self):
            return self.name
    
        def take_damage(self, damage):
            self.hp -= damage
            self.hp = 0 if self.hp <0 else self.hp
    
        @property
        def is_alive(self):
            return self.hp != 0
    
        @property
        def is_wounded(self):
            return self.hp < self.max_hp if self.hp > 0 else False
    
        @property
        def is_dead(self):
            return not self.is_alive
    
    bilbo = Character('Bilbo Baggins', 100)
    bilbo.hp
    # out : 100
    bilbo.hp = 200        
    # out : AttributeError: can't set attribute
    # hp attribute is read only.
    
    bilbo.is_alive
    # out : True
    bilbo.is_wounded
    # out : False
    bilbo.is_dead
    # out : False
    
    bilbo.take_damage( 50 )
    
    bilbo.hp
    # out : 50
    
    bilbo.is_alive
    # out : True
    bilbo.is_wounded
    # out : True
    bilbo.is_dead
    # out : False
    
    bilbo.take_damage( 50 )
    bilbo.hp
    # out : 0
    
    bilbo.is_alive
    # out : False
    bilbo.is_wounded
    # out : False
    bilbo.is_dead
    # out : True 
  • 3

    Синглтон класс

    Синглтон - это шаблон, который ограничивает создание экземпляра класса одним экземпляром / объектом. Для получения дополнительной информации о питоных одноэлементных шаблонах проектирования, см здесь .

     class Singleton:
        def __new__(cls):
            try:
                it = cls.__it__
            except AttributeError:
                it = cls.__it__ = object.__new__(cls)
            return it
    
        def __repr__(self):
            return '<{}>'.format(self.__class__.__name__.upper())
    
        def __eq__(self, other):
             return other is self
    
     

    Другой способ - украсить свой класс. Следуя пример из этого ответа создать класс Singleton:

    class Singleton:
        """
        A non-thread-safe helper class to ease implementing singletons.
        This should be used as a decorator -- not a metaclass -- to the
        class that should be a singleton.
    
        The decorated class can define one `__init__` function that
        takes only the `self` argument. Other than that, there are
        no restrictions that apply to the decorated class.
    
        To get the singleton instance, use the `Instance` method. Trying
        to use `__call__` will result in a `TypeError` being raised.
    
        Limitations: The decorated class cannot be inherited from.
    
        """
    
        def __init__(self, decorated):
            self._decorated = decorated
    
        def Instance(self):
            """
            Returns the singleton instance. Upon its first call, it creates a
            new instance of the decorated class and calls its `__init__` method.
            On all subsequent calls, the already created instance is returned.
    
            """
            try:
                return self._instance
            except AttributeError:
                self._instance = self._decorated()
                return self._instance
    
        def __call__(self):
            raise TypeError('Singletons must be accessed through `Instance()`.')
    
        def __instancecheck__(self, inst):
            return isinstance(inst, self._decorated)
    
     

    Для использования вы можете использовать Instance метод

     @Singleton
    class Single:
        def __init__(self):
            self.name=None
            self.val=0
        def getName(self):
            print(self.name)
    
    x=Single.Instance()
    y=Single.Instance()
    x.name='I\'m single'
    x.getName() # outputs I'm single
    y.getName() # outputs I'm single
    
    
     

Синтаксис

Параметры

Примечания