Как и любой другой язык программирования, Python имеет спецификаторы доступа для реализации принципов ООП, таких как наследование, инкапсуляция и сокрытие данных.
Существует четыре основных типа спецификаторов доступа:
- публичный
- частный
- защищенный
- по умолчанию
Для членов классов они могут быть:
- элементы данных (переменные/константы)
- функции-члены (методы).
Теперь для членов данных они могут быть:
- переменные класса (определены прямо внутри класса, а сами не используются)
- Переменные экземпляра (определены внутри init и используются self)
- функциональные переменные (определенные внутри функции)
Для функций это могут быть:
- публичный
- частный
- защищенный
Что мы подразумеваем под спецификацией доступа?
Существует несколько типов доступа, которые определяют область действия класса, его данные-члены и методы-члены, в основном, где их можно использовать.
Внутри класса
Если вы находитесь внутри класса, к каким функциям и членам вы можете получить доступ? Бывают случаи, когда публичные функции могут обращаться к приватным функциям, потому что они вызываются внутри класса.
Есть такие вопросы:
- Могут ли публичные функции получить доступ к защищенной функции? Если да, то в каких сценариях?
- Частная функция может получить доступ к богато украшенной функции внутри класса? Да в основном.
Как это работает, когда публичная функция одного класса пытается получить доступ к защищенной функции другого класса? Что, если это производный класс.
Несколько золотых правил
Вне зависимости от необходимости создавать объект или нет, поведение «публичной» функции «приватного» класса будет одинаковым. Доступ будет определяться спецификатором доступа к классу и спецификатором доступа к функции.
Точно так же для членов данных, независимо от того, являются ли они членами класса или переменными экземпляра, спецификатор доступа к классу и спецификатор доступа к переменной будут определять область действия этой переменной.
Влияет ли спецификатор доступа производного класса на область действия объявленных в нем функций? Например, если мы создадим частный класс Cucumber из открытого класса Fruits, который имеет защищенную функцию cut Fruit, будет ли область действия этой функции cut Fruit в производном классе Cucumber зависеть от того факта, что этот новый класс (Cucumber) является Private? Пища для размышлений.
Вне области класса
Для доступа к функции или члену данных без создания объекта класса вы просто вызываете функцию или получаете доступ к члену данных, используя класс напрямую.
Classname. Function() Classname. Variable
Использование объектов одного класса для доступа к переменным и методам экземпляра за пределами класса
Другой способ доступа к членам класса — создание объекта класса следующим образом:
class.Obj = classname(params) Obj.variablename Obj. Function name()
Таким образом, если у вас есть методы класса, вы получаете к ним доступ без создания объекта класса. Эти функции не имеют self в качестве первого параметра. Теперь, если у вас есть функции экземпляра, вы сначала создаете объект, а затем вызываете эти функции с объектом, как указано в приведенном выше фрагменте кода.
Производный класс
Кроме того, мы проверяем, как ведут себя спецификаторы доступа при наследовании классов. Мы рассмотрим случаи, когда производные классы могут или не могут получить доступ к членам данных и функциям-членам супер/базового класса.
Для каждого из спецификаторов доступа мы рассмотрим все эти сценарии.
Спецификаторы общего доступа
Публичные члены доступны из любой части программы. Это также спецификатор доступа по умолчанию в python. По сути, если вы не укажете какой-либо спецификатор доступа явно, это то, что python принимает за ваш спецификатор доступа.
Сценарий 1 : вне класса функция вызывается с использованием только имени класса.
Мы проверяем заданные публичные, приватные и защищенные функции одного и того же публичного класса, какова их область видимости вне класса и какие из них доступны в этой области видимости.
# same class without object class PublicClass: def __init__(self, name = "default_name", area_of_expertise = "default area of expertise"): self.name = name self.area_of_expertise = area_of_expertise def display_area_of_expertise(self): print(self.area_of_expertise) def multiply_by_3(x): y = x*3 return y def _divide_by_3(x): y = x//3 return y def __add_3(x): y = x//3 return y # NameError: name 'multiply_by_3' is not defined # y = multiply_by_3(7) # print(y) y = PublicClass.multiply_by_3(7) # public function of public class print(y) # y = PublicClass.__add_3(77) # private function of public class # print(y) # Gives Error : AttributeError: type object 'PublicClass' has no attribute '__add_3' y = PublicClass._divide_by_3(30) # protected function of public class print(y)
Сценарий 2: Использование объекта класса для вызова функции
Учитывая публичные, приватные и защищенные методы экземпляра одного и того же публичного класса, мы проверяем, какова их область видимости вне класса и какие из них доступны в этой области видимости при вызове с объектами этого класса.
# With object of same class class PublicClass: def __init__(self, name, area_of_expertise): self.name = name self.area_of_expertise = area_of_expertise def display_area_of_expertise(self): print(self.area_of_expertise) def display_area_of_expertise_public(self): print(self.area_of_expertise) def __display_area_of_expertise_private(self): print(self.area_of_expertise) def _display_area_of_expertise_protected(self): print(self.area_of_expertise) obj1 = PublicClass("Nemesis", "python") obj1.display_area_of_expertise_public() # public function of public class print(obj1.name) print(obj1.area_of_expertise) obj2 = PublicClass("Nemesis","python_private") y = obj2.__display_area_of_expertise_private() # private instance method of protected class print(y) # Output : AttributeError: 'PublicClass' object has no attribute '__display_area_of_expertise_private' obj3 = PublicClass("Nemesis_1","python_protected") y = obj3._display_area_of_expertise_protected() # protected instance method of protected class
Когда вы пишете функцию, которая будет связана с объектом класса, вы передаете self
, чтобы указать это.
Первым выводом obj1.display_area_of_expertise()
будет python. Второй выход, то есть obj2.display_area_of_expertise()
, будет парфюмом.
Сценарий 3: наследование — поведение производного класса, вызываемого без объекта
Учитывая общедоступные, частные и защищенные методы одного и того же общедоступного класса, мы проверяем, какова их область действия за пределами класса при вызове из производного класса, который наследует его как базовый класс. Проверяем, какие из них доступны под этой областью видимости при вызове без объектов этого класса.
# derived class without object class PublicClass: def __init__(self, name, area_of_expertise): self.name = name self.area_of_expertise = area_of_expertise def display_area_of_expertise(self): print(self.area_of_expertise) def multiply_by_3(x): y = x*3 return y def _divide_by_3(x): y = x//3 return y def __add_3(x): y = x//3 return y class DerivedClass(PublicClass): def __init__(self, name, area_of_expertise): PublicClass.__init__(self, name, area_of_expertise) def display_area_of_expertise_outside(self): print(self.display_area_of_expertise) def multiply_by_3(x): return PublicClass.multiply_by_3(x) def _divide_by_3(x): return PublicClass._divide_by_3(x) def __add_3(x): return PublicClass.__add_3(x) y = DerivedClass.multiply_by_3(7) # public fn of public class print(y) # y = DerivedClass.__add_3(77) # private fn of public class # print(y) # Gives Error : AttributeError: type object '_PublicClass' has no attribute '__add_3' y = DerivedClass._divide_by_3(30) # protected fn of public class print(y)
Сценарий 4 : наследование — Поведение производного класса, вызываемого с помощью объекта
Учитывая общедоступные, частные и защищенные методы одного и того же общедоступного класса, мы проверяем, какова их область действия за пределами класса при вызове из производного класса, который наследует его как базовый класс. Мы проверяем, какие из них доступны в этой области при вызове с объектами этого производного класса.
# derived class without object class PublicClass: def __init__(self, name, area_of_expertise): self.name = name self.area_of_expertise = area_of_expertise def display_area_of_expertise(self): print(self.area_of_expertise) def display_area_of_expertise_public(self): print(self.area_of_expertise) def __display_area_of_expertise_private(self): print(self.area_of_expertise) def _display_area_of_expertise_protected(self): print(self.area_of_expertise) class DerivedClass(PublicClass): def __init__(self, name, area_of_expertise): PublicClass.__init__(self, name, area_of_expertise) def display_area_of_expertise_outside(self): print(self.display_area_of_expertise) obj1 = DerivedClass("Nemesis_1","python_public") y = obj1.display_area_of_expertise_public() # public fn of public class obj2 = DerivedClass("Nemesis","python_private") y = obj2.__display_area_of_expertise_private() # private instance method of public class print(y) # Output : AttributeError: 'DerivedClass' object has no attribute '__display_area_of_expertise_private' obj3 = DerivedClass("Nemesis_1","python_protected") y = obj3._display_area_of_expertise_protected() # protected instance method of public class # miscellaneous # obj4 = DerivedClass("Gucci", "Perfume") # obj4.display_area_of_expertise() # print(obj4.name) # print(obj4.multiply_by_3(10)) # so you cant do this as the first argument in this call is self, but this is not a object method.
Спецификатор частного доступа
Чтобы указать частный доступ для любой переменной или функции, используйте двойное подчеркивание перед именем. Частные члены данных и функции доступны только внутри класса. Объекты класса могут использовать его.
Сценарий 1: Вне класса функция вызывается с использованием только имени класса:
Мы проверяем заданные публичные, приватные и защищенные функции одного и того же приватного класса, какова их область видимости вне класса и какие из них доступны в этой области видимости.
'''Outside class without object''' class __PrivateClass: def __init__(self, name, area_of_expertise): self.name = name self.__area_of_expertise = area_of_expertise def __display_area_of_expertise_private(self): print("Inside private function") print(self.__area_of_expertise) def display_area_of_expertise_public(self): print("Inside public function") self.__display_area_of_expertise_private() def __multiply_byobj2.display_area_of_expertise()
private(x): y = x*3 return y def multiply_by_3(x): # NameError: name '_PrivateClass__multiply_byobj2.display_area_of_expertise()
private' is not defined # you cant use private function of private class from public function without object # y = __multiply_byobj2.display_area_of_expertise()
private(x) # return y return x*3 def multiple_byobj2.display_area_of_expertise()
obj(self, x): y = self.__multiply_byobj2.display_area_of_expertise()
private(x) return y def _divide_by_3(x): y = x//3 return y def __add_3(x): y = x//3 return y y = __PrivateClass.multiply_by_3(7) # public fn of private class print(y) # y = __PrivateClass.__add_3(77) # private fn of private class # print(y) # Gives Error : AttributeError: type object '__PrivateClass' has no attribute '__add_3' y = __PrivateClass._divide_by_3(30) # protected fn of protected class print(y)
Сценарий 2 : использование объектов для доступа к функции-члену закрытого класса
Учитывая открытые, закрытые и защищенные методы экземпляра одного и того же частного класса, мы проверяем, какова их область видимости вне класса и какие из них доступны в этой области видимости при вызове с объектами этого класса.
'''Outside class with object''' class __PrivateClass: def __init__(self, name, area_of_expertise): self.name = name self.__area_of_expertise = area_of_expertise def __display_area_of_expertise_protected(self): print("Inside private function") print(self.__area_of_expertise) def display_area_of_expertise_public(self): print("Inside public function") self.__display_area_of_expertise_protected() def __multiply_byobj2.display_area_of_expertise()
private(x): y = x*3 return y def multiply_by_3(x): y = __multiply_byobj2.display_area_of_expertise()
private(x) return y obj1 = __PrivateClass("Nemesis_1","python_public") y = obj1.display_area_of_expertise_public() # public fn of private class # obj2 = __PrivateClass("Nemesis_2","python_private") # y = obj2.__display_area_of_expertise_private() # private instance method of private class # AttributeError: '__PrivateClass' object has no attribute '__display_area_of_expertise_private' obj3 = __PrivateClass("Nemesis_3","python_protected") y = obj3._display_area_of_expertise_protected() # protected instance method of private class # AttributeError: '__PrivateClass' object has no attribute '_display_area_of_expertise_protected'
Сценарий 3: наследование — поведение производного класса, вызываемого без объекта
Учитывая общедоступные, частные и защищенные методы одного и того же частного класса, мы проверяем, какова их область действия за пределами класса при вызове из производного класса, который наследует его как базовый класс. Проверяем, какие из них доступны под этой областью видимости при вызове без объектов этого класса.
# derived class without object class __PrivateClass: def __init__(self, name, area_of_expertise): self.name = name self.__area_of_expertise = area_of_expertise def __display_area_of_expertise_private(self): print("Inside private function") print(self.__area_of_expertise) def display_area_of_expertise_public(self): print("Inside public function") self.__display_area_of_expertise_private() def __multiply_byobj2.display_area_of_expertise()
private(x): y = x*3 return y def multiply_by_3(x): y = __multiply_byobj2.display_area_of_expertise()
private(x) return y class DerivedClass(__PrivateClass): def __init__(self, name, area_of_expertise): __PrivateClass.__init__(self, name, area_of_expertise) def display_area_of_expertise_from_derived_class(self): print(self.display_area_of_expertise_public()) def multiply_byobj2.display_area_of_expertise()
priv(x): y = __PrivateClass.__multiply_byobj2.display_area_of_expertise()
private(x) #internally calls private function return y def multiply_byobj2.display_area_of_expertise()
pub(x): y = __PrivateClass.multiply_by_3(x) #internally calls public function return y def multiply_by_3(x): return __PrivateClass.multiply_by_3(x) def _divide_by_3(x): return __PrivateClass._divide_by_3(x) def __add_3(x): return __PrivateClass.__add_3(x) # y = DerivedClass.multiply_by_3(7) # public instance method of private class # print(y) # output : NameError: name '_DerivedClass__PrivateClass' is not defined y = DerivedClass.__add_3(77) # private fn of private class print(y) # AttributeError: type object 'DerivedClass' has no attribute '__add_3' # y = DerivedClass._divide_by_3(30) # protected fn of private class # print(y) # output : NameError: name '_DerivedClass__PrivateClass' is not defined # print(DerivedClass.multiply_byobj2.display_area_of_expertise()
priv(60)) # AttributeError: type object 'PrivateClass' has no attribute '_DerivedClass__multiply_byobj2.display_area_of_expertise()
private' # print(DerivedClass.multiply_byobj2.display_area_of_expertise()
pub(60)) # NameError: name '_PrivateClass__multiply_byobj2.display_area_of_expertise()
private' is not defined
Сценарий 4: наследование — поведение производного класса и объектов производного класса
Учитывая общедоступные, частные и защищенные методы одного и того же общедоступного класса, мы проверяем, какова их область действия за пределами класса при вызове из производного класса, который наследует его как базовый класс. Мы проверяем, какие из них доступны в этой области при вызове с объектами этого производного класса.
# derived class with object class __PrivateClass: def __init__(self, name, area_of_expertise): self.name = name self.__area_of_expertise = area_of_expertise def __display_area_of_expertise_private(self): print("Inside private function") print(self.__area_of_expertise) def display_area_of_expertise_public(self): print("Inside public function") self.__display_area_of_expertise_private() def __multiply_byobj2.display_area_of_expertise()
private(x): y = x*3 return y def multiply_by_3(x): y = __multiply_byobj2.display_area_of_expertise()
private(x) return y class DerivedClass(__PrivateClass): def __init__(self, name, area_of_expertise): __PrivateClass.__init__(self, name, area_of_expertise) def display_area_of_expertise_from_derived_class(self): print(self.display_area_of_expertise_public()) def multiply_byobj2.display_area_of_expertise()
priv(x): y = __PrivateClass.__multiply_byobj2.display_area_of_expertise()
private(x) #internally calls private function return y def multiply_byobj2.display_area_of_expertise()
pub(x): y = __PrivateClass.multiply_by_3(x) #internally calls public function return y def multiply_by_3(x): return __PrivateClass.multiply_by_3(x) def _divide_by_3(x): return __PrivateClass._divide_by_3(x) def __add_3(x): return __PrivateClass.__add_3(x) obj1 = DerivedClass("Nemesis_1","python_public") y = obj1.display_area_of_expertise_public() # public instance fn of private class # Output : NameError: name '_DerivedClass__PrivateClass' is not defined # obj2 = DerivedClass("Nemesis","python_private") # y = obj2.__display_area_of_expertise_private() # private instance method of private class # print(y) # Output : AttributeError: 'DerivedClass' object has no attribute '__display_area_of_expertise_private' obj3 = DerivedClass("Nemesis_1","python_protected") y = obj3._display_area_of_expertise_protected() # protected instance method of private class #miscellaeous obj = DerivedClass("Tim","Python ofc!!!") obj.display_area_of_expertise_from_derived_class() # with object we were able to access the private function of super class through publiv function of base class
Поэтому, если мы попытаемся использовать эту функцию вне этого класса, мы сможем сделать это только с объектом этого класса. Базовая функциональность будет скрыта от нас, что реализует частную область видимости.
Теперь посмотрим, как это работает, когда один дочерний класс наследует частные члены и функции от базового класса.
Защищено
protected -> использует одно подчеркивание перед именем переменной и функцией
Защищенные члены класса доступны производному от него классу.
Сценарий 1: Вне класса функция вызывается с использованием только имени класса
Мы проверяем заданные публичные, приватные и защищенные функции одного и того же защищенного класса, какова их область видимости вне класса и какие из них доступны в этой области видимости.
# same class without object class _ProtectedClass: def __init__(self, name, area_of_expertise): self.name = name self._area_of_expertise = area_of_expertise def _display_area_of_expertise(self): print(self._area_of_expertise) def multiply_by_3(x): y = x*3 return y def _divide_by_3(x): y = x//3 return y def __add_3(x): y = x//3 return y y = _ProtectedClass.multiply_by_3(7) # public fn of protected class print(y) # y = _ProtectedClass.__add_3(77) # private fn of protected class # print(y) # Gives Error : AttributeError: type object '_ProtectedClass' has no attribute '__add_3' y = _ProtectedClass._divide_by_3(30) # protected fn of protected class print(y)
Сценарий 2 : использование объектов для доступа к функции-члену закрытого класса
Учитывая открытые, частные и защищенные методы экземпляра одного и того же защищенного класса, мы проверяем, какова их область видимости вне класса и какие из них доступны в этой области видимости при вызове с объектами этого класса.
# same class with object class _ProtectedClass: def __init__(self, name, area_of_expertise): self.name = name self._area_of_expertise = area_of_expertise def display_area_of_expertise_public(self): print(self._area_of_expertise) def __display_area_of_expertise_private(self): print(self._area_of_expertise) def _display_area_of_expertise_protected(self): print(self._area_of_expertise) obj1 = _ProtectedClass("Nemesis_1","python_public") y = obj1.display_area_of_expertise_public() # public fn of protected class # obj2 = _ProtectedClass("Nemesis","python_private") # y = obj2.__display_area_of_expertise_private() # private instance method of protected class # print(y) # AttributeError: '_ProtectedClass' object has no attribute '__display_area_of_expertise_private' obj3 = _ProtectedClass("Nemesis_1","python_protected") y = obj3._display_area_of_expertise_protected() # protected instance method of protected class
Сценарий 3 : наследование — Поведение производного класса, вызываемого без объекта
Учитывая общедоступные, частные и защищенные методы одного и того же частного класса, мы проверяем, какова их область действия за пределами класса при вызове из производного класса, который наследует его как базовый класс. Проверяем, какие из них доступны под этой областью видимости при вызове без объектов этого класса.
# Derived class without object class _ProtectedClass: def __init__(self, name, area_of_expertise): self.name = name self._area_of_expertise = area_of_expertise def _display_area_of_expertise(self): print(self._area_of_expertise) def multiply_by_3(x): y = x*3 return y def _divide_by_3(x): y = x//3 return y def __add_3(x): y = x//3 return y class DerivedClass(_ProtectedClass): def __init__(self, name, area_of_expertise): _ProtectedClass.__init__(name, area_of_expertise) def _display_area_of_expertise(self): return _ProtectedClass._display_area_of_expertise() def multiply_by_3(x): return _ProtectedClass.multiply_by_3(x) def _divide_by_3(x): return _ProtectedClass._divide_by_3(x) def __add_3(x): return _ProtectedClass.__add_3(x) y = DerivedClass.multiply_by_3(7) # public fn of protected class print(y) # y = DerivedClass.__add_3(77) # private fn of protected class # print(y) # Gives Error : AttributeError: type object '_ProtectedClass' has no attribute '__add_3' y = DerivedClass._divide_by_3(30) # protected fn of protected class print(y)
Сценарий 4 : наследование — Поведение производного класса, вызываемого с помощью объекта
Учитывая общедоступные, частные и защищенные методы одного и того же общедоступного класса, мы проверяем, какова их область действия за пределами класса при вызове из производного класса, который наследует его как базовый класс. Мы проверяем, какие из них доступны в этой области при вызове с объектами этого производного класса.
# same class with object class _ProtectedClass: def __init__(self, name, area_of_expertise): self.name = name self._area_of_expertise = area_of_expertise def display_area_of_expertise_public(self): print(self._area_of_expertise) def __display_area_of_expertise_private(self): print(self._area_of_expertise) def _display_area_of_expertise_protected(self): print(self._area_of_expertise) class DerivedClass(_ProtectedClass): def __init__(self, name, area_of_expertise): _ProtectedClass.__init__(self, name, area_of_expertise) def display_area_of_expertise_from_derived_class(self): print(self.display_area_of_expertise_public()) def multiply_byobj2.display_area_of_expertise()
priv(x): y = _ProtectedClass.__multiply_byobj2.display_area_of_expertise()
private(x) #internally calls private function return y def multiply_byobj2.display_area_of_expertise()
pub(x): y = _ProtectedClass.multiply_by_3(x) #internally calls public function return y obj1 = DerivedClass("Nemesis_1","python_public") y = obj1.display_area_of_expertise_public() # public fn of protected class # obj2 = DerivedClass("Nemesis","python_private") # y = obj2.__display_area_of_expertise_private() # private instance method of protected class # print(y) # Output : AttributeError: 'DerivedClass' object has no attribute '__display_area_of_expertise_private' obj3 = DerivedClass("Nemesis_1","python_protected") y = obj3._display_area_of_expertise_protected() # protected instance method of protected class
Заключение
Вот ссылка на гитхаб со всем кодом. Вы можете раскомментировать и выполнить код файла, чтобы проверить, как работает каждая функция.
Есть много других способов, которыми вы можете поэкспериментировать со спецификаторами доступа в Python. Вы можете сделать гораздо больше, так что вы можете продолжать экспериментировать! Далее мы рассмотрим статические методы и методы класса в Python. Это будет основой для создания файловой системы на питоне, что является основной целью.