underscore(_, __) in python

InAnarchy·2023년 4월 11일
0

Python

목록 보기
1/14
post-thumbnail
post-custom-banner

인터프리터에서 사용

  • 마지막으로 실행된 결과값을 저장하는 용도
  • 연산은 물론이고 다른 변수에 저장할 수도 있다.
>>> 1+2+3
6
>>> _
6
>>> _*3
18
>>> _
18
>>> 2 + _
20
>>> _
20
>>> a = _
>>> a
20
>>> _
20

무시하는 값

#하나의 값만 무시
a,_,b = (1,2,3)
print(_) #2
print(a,b) #1 3
#여러 개의 값 무시
a,*_,b = (1,2,3,4,5)
print(_) #[2, 3, 4]
print(a,b) #1 5

for문에서 사용

for _ in range(5):
  print(_) #0 1 2 3 4

자릿수 구분

x = 1_000_000_000
hex = 0xffff_ffff

print(x,hex) #1000000000 4294967295

네이밍 컨벤션

_single_leading_underscore

  • weak “internal use” indicator
  • 변수나 메서드가 외부에서 직접적으로 호출되지 않아야 하거나, 내부적으로만 사용될 때
  • 그러나 호출을 "완전히 막을 수는 없다"
  • 다른 클래스에서 _single_leading_underscore 를 사용한 변수나 메서드에 접근하는 것은 좋은 습관이 아님
class Person:
    def __init__(self, name, _age):
        self.name = name
        self._age = _age #_single_leading_underscore

    def _get_age(self): #_single_leading_underscore
        return self._age
        
class Employee(Person): #Employee는 Person을 상속받고
    def __init__(self, name, _age, salary):
        super().__init__(name, _age)
        self.salary = salary

    def get_salary(self):
        return self.salary

employee = Employee("me", 24, 100) #객체 생성 
print(employee._age)  # _single_leading_underscore를 사용한 변수에 접근
print(employee._get_age())  # _single_leading_underscore를 사용한 메서드에 접근

위 코드에서 객체를 생성하고 '_age'와 '_get_age()'메서드에 외부에서 직접 접근했다.
사용가능하긴 하지만 외부에서 접근할 수 없다는 네이밍 컨벤션을 어긴 것이므로 좋은 습관이 아니다.

두번째 예시를 보자.

#my_module.py
def _private_function():
    return "This is a private function"

public_variable = "This is a public variable"

만약 from my_module import *이라고 한다면?

from my_module import *

print(public_variable)  # "This is a public variable"
print(_private_function()) #not defiend

프라이빗 함수는 정의되지 않았다는 오류가 발생한다.
이 때 import * 에서는 single leading underscore를 사용한 변수나 함수를 가져오지 않는다.

from M import * does not import objects whose names start with an underscore.
PEP 8 문서 참고

그렇다면 모듈 자체를 임포트해보자.

import my_module

print(my_module.public_variable)  # "This is a public variable"
print(my_module._private_function())  # "This is a private function"

함수를 직접적으로 import하지 않고 모듈 전체를 import하여
'my_module._private_function()' 형식으로 호출하여 _private_function() 함수를 호출하였다.
이 경우에는 사용이 가능하다.

singletrailing_underscore

  • 변수나 함수명 등을 파이썬 키워드로 사용할 때 충돌을 피하기 위해 사용
  • used by convention to avoid conflicts with Python keyword
  • 자바로 치면 protected 느낌?
def calculate_area(width, height):
    return width * height

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return calculate_area(self.width, self.height)

# 키워드 'class'와 충돌을 피하기 위해 'class_'를 사용한 변수 선언
class_ = "Mathematics"

rectangle1 = Rectangle(4, 5)
print(f"Area of rectangle with width {rectangle1.width} and height {rectangle1.height}: {rectangle1.area()}")
print(f"Class: {class_}")
Area of rectangle with width 4 and height 5: 20
Class: Mathematics

__double_leading_underscore

  • 상속 관계에서 예기치 않은 오버라이딩을 방지
  • 클래스 속성명이나 메서드에 대해 name mangling을 적용하기 위해 사용

네임 맹글링이란?

  • 해당 속성이나 메서드를 클래스 외부에서 접근하기 어렵게 만들어 클래스 내부에서 사용하도록 의도한 것
  • 속성이나 메서드 이름 앞에 _클래스명을 추가함
MyBaseClass에서 __double_leading_underscore 속성은
_MyBaseClass__double_leading_underscore로 변경됨
  • 자바로 치면 private 느낌?
class MyBaseClass:
    def __init__(self):
        self.public_var = "I'm a public variable"
        self._single_leading_underscore = "I'm a 'protected' variable"
        self.__double_leading_underscore = "I'm a 'private' variable with name mangling"
        #_MyBaseClass__double_leading_underscore

    def __private_method(self):
        print("I'm a 'private' method with name mangling")

class DerivedClass(MyBaseClass):
    def __init__(self):
        super().__init__()
        self.__double_leading_underscore = "I'm another 'private' variable with name mangling in the derived class"
        #_DerivedClass__double_leading_underscore

    def access_base_private_method(self):
        self._MyBaseClass__private_method()
       

instance = MyBaseClass()
print(instance.public_var)
print(instance._single_leading_underscore)
# print(instance.__double_leading_underscore)  # AttributeError
print(instance._MyBaseClass__double_leading_underscore)  # Name mangling 접근

derived_instance = DerivedClass()
derived_instance.access_base_private_method()
print(derived_instance._MyBaseClass__double_leading_underscore)
print(derived_instance._DerivedClass__double_leading_underscore)


이 코드에서

__double_leading_underscore
__private_methode()

는 이름 맹글링을 적용하여 클래스 내부에서만 사용하도록 의도된 것을 나타낸다.
그러나 _MyBaseClass__double_leading_underscore 형식으로 접근하는 것이 가능하다.

class DerivedClass(MyBaseClass):
    def __init__(self):
        super().__init__()
        self.__double_leading_underscore = "I'm another 'private' variable with name mangling in the derived class"

    def access_base_private_method(self):
        self._MyBaseClass__private_method()

DerivedClass에서는 조상 클래스의 private메서드를 접근한다.

그런데
MyBaseClass의 __double_leading_underscore와 DerivedClass의 __double_leading_underscore는 서로 다른 이름으로 저장되어 있. 따라서 각 클래스에서 정의된 속성이 서로 영향을 주지 않으며, 예기치 않은 속성의 오버라이딩을 방지할 수 있다.

double_leading_and_trailing_underscore

  • 파이썬에서 이름 앞뒤로 두 개의 밑줄
  • 특별한 메서드 또는 속성에 사용되며, 이를 magic메서드라 부름__init__, __import__, __file__
class Circle:
    def __init__(self, radius):
        self.radius = radius

    def __str__(self):
        return f"Circle with radius {self.radius}"

    def __eq__(self, other):
        if isinstance(other, Circle):
            return self.radius == other.radius
        return False

    def __add__(self, other):
        if isinstance(other, Circle):
            return Circle(self.radius + other.radius)
        return NotImplemented

circle1 = Circle(5)
circle2 = Circle(5)
circle3 = Circle(7)

# __str__ 메서드를 사용하여 객체를 문자열로 표현
print(circle1)  # 출력: Circle with radius 5

# __eq__ 메서드를 사용하여 두 객체의 동일성을 비교
print(circle1 == circle2)  # 출력: True
print(circle1 == circle3)  # 출력: False

# __add__ 메서드를 사용하여 두 객체를 더함
circle4 = circle1 + circle3
print(circle4)  # 출력: Circle with radius 12
Circle with radius 5
True
False
Circle with radius 12

REFERNCE
Python DOCS
Geeksforgeeks
Pep8
Stackoverflow

profile
github blog 쓰다가 관리하기 귀찮아서 돌아왔다
post-custom-banner

0개의 댓글