Как посмотреть все методы класса python
Перейти к содержимому

Как посмотреть все методы класса python

  • автор:

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

Наследование в 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): # вызов конструктора родителя, w и h оба s super(Square, self).__init__(s, s) self.s = s

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

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

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

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

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

# subclass check issubclass(Square, Rectangle) # True # instantiate r = Rectangle(3, 4) s = Square(2) isinstance(r, Rectangle) # True isinstance(r, Square) # False # Прямоугольник это не квадрат isinstance(s, Rectangle) # True # Квадрат это прямоугольник isinstance(s, Square) # True

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

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

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) d1 = D(1) d2 = D(2) d1.x # [1, 2] d2.x # [1, 2] D.x # [1, 2] 

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

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

class A(object): def f(self, x): return 2 * x A.f

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

A.f # (в Python 2.x) A.f.__class__ # A.f.__func__ #

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

import inspect inspect.isfunction(A.f) # True inspect.ismethod(A.f) # False

В обеих версиях функции Python / метод A.f может быть вызван непосредственно, при условии , что вы передаете экземпляр класса 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.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 , что a.f тогда? Ну, интуитивно это должно быть тем же самым методом 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 # > a.f(2) # 4 # Note: связаванный метод объекта a.f создается каждый раз когда он вызывается: 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 # > D.f(12) # 24 D.g # D.g("world") # Hello, world

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

d = D() d.multiplier = 1337 (D.multiplier, d.multiplier) # (2, 1337) d.f # > d.f(10) # 20

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

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

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

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

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

# old-style class class Old: pass # old-style instance old = Old() old.__class__ # type(old) # issubclass(Old, object) # False

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

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

class MyClass: pass my_inst = MyClass() type(my_inst) # my_inst.__class__ # issubclass(MyClass, object) # True 

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

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

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 тоже изменилась

Такое поведение вызвано тем, что в 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 не изменилась

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

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

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'
FooBar.mro() #[, , , ]

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

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

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

Другая характерная особенность в наследстве является 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

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

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

Дескрипторы

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

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

Они могут контролировать пунктирный поиск на экземпляре, и используются для реализации функций, staticmethod , classmethod и property .

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

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

Давайте предположим , что мы имеем относительно простой 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 .
  2. Кроме того, если есть больше падежей и / или больше параметров, которые обладают такой гибкостью, ветвление if / elif / else может быстро раздражать.

Введите методы класса. Вместо того , чтобы иметь один инициализатор, мы создадим отдельный инициализатору, называемый 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__ :

  • https://docs.python.org/2/library/functions.html#classmethod
  • https://docs.python.org/3.5/library/functions.html#classmethod

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

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

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

Monkey Patching (исправление обезьяны)

В этом случае «исправление обезьяны» означает добавление новой переменной или метода в класс после его определения. Например, скажем , мы определили класс 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

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

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

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

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 ().

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

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

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

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))

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

Теперь давайте сделаем несколько экземпляров нашего 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'

Cвойства

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

class MyClass(object): def __init__(self): self._my_string = "" @property def string(self): 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 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 #True bilbo.is_wounded #False bilbo.is_dead #False bilbo.take_damage( 50 ) bilbo.hp #50 bilbo.is_alive #True bilbo.is_wounded #True bilbo.is_dead #False bilbo.take_damage( 50 ) bilbo.hp # out : 0 bilbo.is_alive #False bilbo.is_wounded #False bilbo.is_dead #True 

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

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

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: # Непотокобезопасный вспомогательный класс для упрощения реализации синглетонов. Это следует использовать в качестве декоратора, а не метакласса, для класса, который должен быть синглтоном. # Декорированный класс может определить одну функцию `__init__`, которая принимает только аргумент `self`. Кроме этого, нет никаких ограничений, которые применяются к декорированному классу # Чтобы получить экземпляр синглтона, используйте метод `Instance`. Попытка использовать __call__ приведет к возникновению ошибки TypeError. # Ограничения: декорированный класс не может быть унаследован. def __init__(self, decorated): self._decorated = decorated def Instance(self): #Возвращает экземпляр синглтона. При первом вызове он создает новый экземпляр оформленного класса и вызывает его метод __init__. При всех последующих вызовах возвращается уже созданный экземпляр. 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

Объектно-ориентированное программирование

Python имеет множество встроенных типов, например, int, str и так далее, которые мы можем использовать в программе. Но также Python позволяет определять собственные типы с помощью классов . Класс представляет некоторую сущность. Конкретным воплощением класса является объект.

Можно еще провести следующую аналогию. У нас у всех есть некоторое представление о человеке, у которого есть имя, возраст, какие-то другие характеристики Человек может выполнять некоторые действия — ходить, бегать, думать и т.д. То есть это представление, которое включает набор характеристик и действий, можно назвать классом. Конкретное воплощение этого шаблона может отличаться, например, одни люди имеют одно имя, другие — другое имя. И реально существующий человек будет представлять объект этого класса.

Класс определяется с помощью ключевого слова class :

class название_класса: атрибуты_класса методы_класса

Внутри класса определяются его атрибуты, которые хранят различные характеристики класса, и методы — функции класса.

Создадим простейший класс:

class Person: pass

В данном случае определен класс Person, который условно представляет человека. В данном случае в классе не определяется никаких методов или атрибутов. Однако поскольку в нем должно быть что-то определено, то в качестве заменителя функционала класса применяется оператор pass . Этот оператор применяется, когда синтаксически необходимо определить некоторый код, однако мы не хотим его, и вместо конкретного кода вставляем оператор pass.

После создания класса можно определить объекты этого класса. Например:

class Person: pass tom = Person() # определение объекта tom bob = Person() # определение объекта bob

После определения класса Person создаются два объекта класса Person — tom и bob. Для создания объекта применяется специальная функция — конструктор , которая называется по имени класса и которая возвращает объект класса. То есть в данном случае вызов Person() представляет вызов конструктора. Каждый класс по умолчанию имеет конструктор без параметров:

tom = Person() # Person() - вызов конструктора, который возвращает объект класса Person

Методы классов

Методы класса фактически представляют функции, которые определенны внутри класса и которые определяют его поведение. Например, определим класс Person с одним методом:

class Person: # определение класса Person def say_hello(self): print("Hello") tom = Person() tom.say_hello() # Hello

Здесь определен метод say_hello() , который условно выполняет приветствие — выводит строку на консоль. При определении методов любого класса следует учитывать, что все они должны принимать в качестве первого параметра ссылку на текущий объект, который согласно условностям называется self . Через эту ссылку внутри класса мы можем обратиться к функциональности текущего объекта. Но при самом вызове метода этот параметр не учитывается.

Используя имя объекта, мы можем обратиться к его методам. Для обращения к методам применяется нотация точки — после имени объекта ставится точка и после нее идет вызов метода:

объект.метод([параметры метода])

Например, обращение к методу say_hello() для вывода приветствия на консоль:

tom.say_hello() # Hello

В итоге данная программа выведет на консоль строку «Hello».

Если метод должен принимать другие параметры, то они определяются после параметра self , и при вызове подобного метода для них необходимо передать значения:

class Person: # определение класса Person def say(self, message): # метод print(message) tom = Person() tom.say("Hello METANIT.COM") # Hello METANIT.COM

Здесь определен метод say() . Он принимает два параметра: self и message. И для второго параметра — message при вызове метода необходимо передать значение.

self

Через ключевое слово self можно обращаться внутри класса к функциональности текущего объекта:

self.атрибут # обращение к атрибуту self.метод # обращение к методу

Например, определим два метода в классе Person:

class Person: def say(self, message): print(message) def say_hello(self): self.say("Hello work") # обращаемся к выше определенному методу say tom = Person() tom.say_hello() # Hello work

Здесь в одном методе — say_hello() вызывается другой метод — say() :

self.say("Hello work")

Поскольку метод say() принимает кроме self еще параметры (параметр message), то при вызове метода для этого параметра передается значение.

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

def say_hello(self): say("Hello work") # ! Ошибка

То мы столкнемся с ошибкой

Конструкторы

Для создания объекта класса используется конструктор. Так, выше когда мы создавали объекты класса Person, мы использовали конструктор по умолчанию, который не принимает параметров и который неявно имеют все классы:

tom = Person()

Однако мы можем явным образом определить в классах конструктор с помощью специального метода, который называется __init__() (по два прочерка с каждой стороны). К примеру, изменим класс Person, добавив в него конструктор:

class Person: # конструктор def __init__(self): print("Создание объекта Person") def say_hello(self): print("Hello") tom = Person() # Создание объекта Person tom.say_hello() # Hello

Итак, здесь в коде класса Person определен конструктор и метод say_hello() . В качестве первого параметра конструктор, как и методы, также принимает ссылку на текущий объект — self. Обычно конструкторы применяются для определения действий, которые должны производиться при создании объекта.

Теперь при создании объекта:

tom = Person()

будет производится вызов конструктора __init__() из класса Person, который выведет на консоль строку «Создание объекта Person».

Атрибуты объекта

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

class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека tom = Person("Tom") # обращение к атрибутам # получение значений print(tom.name) # Tom print(tom.age) # 1 # изменение значения tom.age = 37 print(tom.age) # 37

Теперь конструктор класса Person принимает еще один параметр — name. Через этот параметр в конструктор будет передаваться имя создаваемого человека.

Внутри конструктора устанавливаются два атрибута — name и age (условно имя и возраст человека):

def __init__(self, name): self.name = name self.age = 1

Атрибуту self.name присваивается значение переменной name. Атрибут age получает значение 1.

Если мы определили в классе конструктор __init__, мы уже не сможем вызвать конструктор по умолчанию. Теперь нам надо вызывать наш явным образом опреледеленный конструктор __init__, в который необходимо передать значение для параметра name:

tom = Person("Tom")

Далее по имени объекта мы можем обращаться к атрибутам объекта — получать и изменять их значения:

print(tom.name) # получение значения атрибута name tom.age = 37 # изменение значения атрибута age

В принципе нам необязательно определять атрибуты внутри класса — Python позволяет сделать это динамически вне кода:

class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека tom = Person("Tom") tom.company = "Microsoft" print(tom.company) # Microsoft

Здесь динамически устанавливается атрибут company, который хранит место работы человека. И после установки мы также можем получить его значение. В то же время подобное определение чревато ошибками. Например, если мы попытаемся обратиться к атрибуту до его определения, то программа сгенерирует ошибку:

tom = Person("Tom") print(tom.company) # ! Ошибка - AttributeError: Person object has no attribute company

Для обращения к атрибутам объекта внутри класса в его методах также применяется слово self:

class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека def display_info(self): print(f"Name: Age: ") tom = Person("Tom") tom.display_info() # Name: Tom Age: 1

Здесь определяется метод display_info(), который выводит информацию на консоль. И для обращения в методе к атрибутам объекта применяется слово self: self.name и self.age

Создание объектов

Выше создавался один объект. Но подобным образом можно создавать и другие объекты класса:

class Person: def __init__(self, name): self.name = name # имя человека self.age = 1 # возраст человека def display_info(self): print(f"Name: Age: ") tom = Person("Tom") tom.age = 37 tom.display_info() # Name: Tom Age: 37 bob = Person("Bob") bob.age = 41 bob.display_info() # Name: Bob Age: 41

Здесь создаются два объекта класса Person: tom и bob. Они соответствуют определению класса Person, имеют одинаковый набор атрибутов и методов, однако их состояние будет отличаться.

При выполнении программы Python динамически будет определять self — он представляет объект, у которого вызывается метод. Например, в строке:

tom.display_info() # Name: Tom Age: 37

Это будет объект tom

bob.display_info()

Это будет объект bob

В итоге мы получим следующий консольный вывод:

Name: Tom Age: 37 Name: Bob Age: 41

Как получить список объектов класса?

Из примера не очень понятно, что всё-таки вам нужно — список объектов, инстанцированных от этого класса? Или список объектов, которые являются аттрибутами класса?

10 ноя 2021 в 7:06
Аттрибутами класса
10 ноя 2021 в 7:36

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

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

print( ) 

UPD на комментарий:

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

value = getattr(Example, k) print(value) 

так и заменить его на новое значение:

setattr(Example, k, new_value_obj) 

Python: статические методы, методы класса и экземпляра класса

Согласно модели данных Python, язык предлагает три вида методов: статические, класса и экземпляра класса. Давайте посмотрим, что же происходит за кулисами каждого из видов методов. Понимание принципов их работы поможет в создании красивого и эффективного кода. Начнём с самого простого примера, в котором демонстрируются все три вида методов.

class ToyClass: 
def instancemethod(self):
return 'instance method called', self

@classmethod
def classmethod(cls):
return 'class method called', cls
@staticmethod
def staticmethod():
return 'static method called'

Методы экземпляра класса

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

Используя параметр self , мы можем менять состояние объекта и обращаться к другим его методам и параметрам. К тому же, используя атрибут self.__class__ , мы получаем доступ к атрибутам класса и возможности менять состояние самого класса. То есть методы экземпляров класса позволяют менять как состояние определённого объекта, так и класса.

Встроенный пример метода экземпляра — str.upper() :

>>> "welcome".upper() # 'WELCOME'

Методы класса

Методы класса принимают класс в качестве параметра, который принято обозначать как cls . Он указывает на класс ToyClass, а не на объект этого класса. При декларации методов этого вида используется декоратор classmethod .

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

Встроенный пример метода класса — dict.fromkeys() — возвращает новый словарь с переданными элементами в качестве ключей.

dict.fromkeys('AEIOU') # 

Статические методы

Статические методы декларируются при помощи декоратора staticmethod . Им не нужен определённый первый аргумент (ни self , ни cls ).

Их можно воспринимать как методы, которые “не знают, к какому классу относятся”.

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

С теорией достаточно. Давайте разберёмся с работой методов, создав объект нашего класса и вызвав поочерёдно каждый из методов: instancemethod, classmethod and staticmethod.

>>> obj = ToyClass()
>>> obj.instancemethod()
('instance method called', ToyClass instance at 0x10f47e7a0>)
>>> ToyClass.instancemethod(obj)
('instance method called', ToyClass instance at 0x10f47e7a0>)

Пример выше подтверждает то, что метод instancemethod имеет доступ к объекту класса ToyClass через аргумент self . Кстати, вызов функции obj.instancemethod() используется лишь для удобства, то есть можно использовать и ToyClass.instancemethod(obj) .

Теперь давайте вызовем метод класса:

>>> obj.classmethod()
('class method called', )

Мы видим, что метод класса classmethod() имеет доступ к самому классу ToyClass, но не к его конкретному экземпляру объекта. Запомните, в Python всё является объектом. Класс тоже объект, который мы можем передать функции в качестве аргумента.

Заметьте, что self и cls — не обязательные названия и эти параметры можно называть иначе.

def instancemethod(self, . )
def classmethod(cls, . )
-------то же самое, что и----------def instancemethod(my_object, . )
def classmethod(my_class, . )

Это лишь общепринятые обозначения, которым следуют все. Тем не менее они должны находиться первыми в списке параметров.

Вызовем статический метод:

>>> obj.staticmethod()
static method called

Да, это может вас удивить, но статические методы можно вызывать через объект класса. Вызов через точку нужен лишь для удобства. На самом же деле в случае статического метода никакие аргументы ( self или cls ) методу не передаются.

То есть статические методы не могут получить доступ к параметрам класса или объекта. Они работают только с теми данными, которые им передаются в качестве аргументов.

Теперь давайте вызовем те же самые методы, но на самом классе.

>>> ToyClass.classmethod()
('class method called', )
>>> ToyClass.staticmethod()
'static method called'
>>> ToyClass.instancemethod()
TypeError: unbound method instancemethod()
must be called with ToyClass instance as
first argument (got nothing instead)

Метод класса и статический метод работают, как нужно. Однако вызов метода экземпляра класса выдаёт TypeError, так как метод не может получить на вход экземпляр класса.

Теперь, когда вы знаете разницу между тремя видами методов, давайте рассмотрим реальный пример для понимания того, когда и какой метод стоит использовать. Пример взят отсюда.

from datetime import dateclass Person: 
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def from_birth_year(cls, name, year):
return cls(name, date.today().year - year)
@staticmethod
def is_adult(age):
return age > 18
person1 = Person('Sarah', 25)
person2 = Person.from_birth_year('Roark', 1994)
>>> person1.name, person1.age
Sarah 25
>>> person2.name, person2.age
Roark 24
>>> Person.is_adult(25)
True

Когда использовать каждый из методов?

Выбор того, какой из методов использовать, может показаться достаточно сложным. Тем не менее с опытом этот выбор делать гораздо проще.

Чаще всего метод класса используется тогда, когда нужен генерирующий метод, возвращающий объект класса. Как видим, метод класса from_birth_year используется для создания объекта класса Person по году рождения, а не возрасту.

Статические методы в основном используются как вспомогательные функции и работают с данными, которые им передаются.

Запомнить

  • Методы экземпляра класса получают доступ к объекту класса через параметр self и к классу через self.__class__ .
  • Методы класса не могут получить доступ к определённому объекту класса, но имеют доступ к самому классу через cls .
  • Статические методы работают как обычные функции, но принадлежат области имён класса. Они не имеют доступа ни к самому классу, ни к его экземплярам.
  • Даже если вы программируете только ради интереса, изучение ООП в Python поможет писать код так, чтобы в дальнейшем было легче искать ошибки и использовать его повторно.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *