Как узнать имя класса
Перейти к содержимому

Как узнать имя класса

  • автор:

Как вывести имя экземпляра класса?

Чтобы вернуть имя переменной, можно поискать наш объект в globals().

class Foo: def get_var_name(self): for k, v in globals().items(): if v is self: return k def __str__(self): return f'>' foo = Foo() print(foo) #

Ссылку на один объект можно хранить в нескольких переменных, поэтому можно искать все совпадения:

class Foo: def get_var_names(self): return [k for k, v in globals().items() if v is self] def __str__(self): return f'>' foo = Foo() bar = foo abc = bar print(foo) #

Минус алгоритма — он работает только с глобальными переменными, поэтому локальные переменные не будут видны:

def go(): foo = Foo() bar = foo abc = bar print(foo) go() #

�� Как узнать имя экземпляра класса в Python

Приветствую! В этой статье мы рассмотрим, как узнать имя экземпляра класса в Python. Когда мы создаем объект (экземпляр) класса, нам может понадобиться узнать его имя для различных целей. Давайте рассмотрим несколько способов, которые помогут нам в этом.

Способ 1: Метод __class__.__name__

Первый способ — использовать метод __class__.__name__, который доступен для каждого объекта класса в Python.

class MyClass: pass obj = MyClass() print(obj.__class__.__name__)

Результатом выполнения кода будет вывод имени класса, в данном случае «MyClass».

Способ 2: Функция type()

Второй способ — использовать функцию type(), которая также позволяет узнать имя класса объекта.

class MyClass: pass obj = MyClass() print(type(obj).__name__)

Пример выше выведет то же самое имя класса «MyClass».

Способ 3: Метод __str__

Третий способ — переопределить метод __str__ внутри вашего класса. Этот метод вызывается при попытке привести объект к строке.

class MyClass: def __str__(self): return "MyClass" obj = MyClass() print(obj)

Результатом выполнения кода будет также «MyClass».

Заключение

Теперь вы знаете несколько способов, как узнать имя экземпляра класса в Python. Вы можете использовать методы __class__.__name__ и type(), а также переопределить метод __str__ внутри класса.

Узнать имя класса во время исполнения программы

У меня есть функция (используется для записи логов), которая вызывается в разных классах. Не хочется каждый раз переписывать код в ней для каждого нового класса(они будут и добавляться и убираться со временем, ну или вообще функция будет использоваться в дальнейшем в других проектах). Мне хотелось бы узнавать имя класса, из которого она вызывается (для задания имени файлу и прочих плюшек) не передавая лишних параметров в функцию. Это можно реализовать? Можно и boost`ом.

Отслеживать
задан 22 апр 2016 в 10:51
771 1 1 золотой знак 7 7 серебряных знаков 20 20 бронзовых знаков
это похоже на то, что Вы хотите stackoverflow.com/questions/1666802/is-there-a-class-macro-in-c
22 апр 2016 в 11:12
Если вам дан исчерпывающий ответ, отметьте его как верный (галка напротив выбранного ответа).
23 апр 2016 в 13:16

2 ответа 2

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

Функция typeid(object) возвращает объект типа type_info с информацией о типе объекта, для которого она вызывается (собственно, о классе). У этого объекта( type_info ) есть метод name() , который и возвращает имя класса. Для использования нужно подключить .

Так что в итоге для получения имени класса нужно использовать

Или, если функция не является методом класса, передать в typeid сам объект или разыменованный указатель.

Отслеживать
ответ дан 22 апр 2016 в 13:53
36 1 1 бронзовый знак

Никто не гарантирует, что name() вернёт «человеческое» имя. Как показывает практика, в некоторых компиляторах, эти имена ничего не могут сказать человеку.

23 апр 2016 в 9:26

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

Стек вызова можно проанализировать с помощью некоторых внешних библиотек / API операционной системы. Например: http://man7.org/linux/man-pages/man3/backtrace.3.html https://msdn.microsoft.com/en-us/library/ms680650%28VS.85%29.aspx . Но для применение этих средств может налагать дополнительные ограничения на собираемый код (сборка с отладочной информацией и т.д.).

Более разумно, ИМХО, передавать контекст вызова явно: это позволит использовать «штатные» средства c++: __FILE__ , __LINE__ , __func__ , . Извлечение контекста можно замаскировать макросом:

 struct Context< const char* file; unsigned line; const char* function; >; // Work around MSVS #ifndef __func__ #define __func__ __FUNCTION__ #endif #define CONTEXT() Context(< __FILE__, __LINE__, __func__>) void foo( int a, int b, Context c ); #define FOO(a, b) foo( a, b, CONTEXT() ) 

Имя класса можно извлечь либо разобрав имя __FUNCTION__ , либо из указателя this :

 typeid(this).name() 

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

С другой стороны для целей разделения логов может быть достаточно __FILE__ .

Классы, объекты и методы в 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

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

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