programing

파이썬에서 명시적인 '셀프'를 피하는 방법은 무엇입니까?

sourcejob 2023. 7. 18. 21:42
반응형

파이썬에서 명시적인 '셀프'를 피하는 방법은 무엇입니까?

저는 파이게임 튜토리얼을 따라 파이썬을 배우고 있습니다.

거기서 저는 self라는 키워드를 광범위하게 사용하는 것을 발견했고, 주로 Java 배경에서 왔으며, 저는 self를 입력하는 것을 계속 잊고 있다는 것을 알게 되었습니다.예를 들어, 대신에self.rect.centerx는 니다합력라고 하겠습니다.rect.centerx왜냐하면 rect는 이미 클래스의 멤버 변수이기 때문입니다.

이 상황에 대해 제가 생각할 수 있는 자바 병렬은 멤버 변수에 대한 모든 참조 앞에 이것을 붙여야 한다는 것입니다.

모든 구성원 변수 앞에 self를 붙여야 합니까, 아니면 그렇게 하지 않아도 되는 선언을 할 수 있는 방법이 있습니까?

제가 제안하고 있는 것이 비단뱀이 아니라고 해도, 가능한지 알고 싶습니다.이 가능한지 알고 싶습니다.

관련 SO 질문들을 살펴보았지만, 질문들은 제가 무엇을 추구하는지에 대해 제대로 답변하지 않습니다.

Java 용어:Python에는 멤버 함수가 없으며 모든 클래스 함수는 정적이며 멤버 함수로 호출될 때 첫 번째 인수로 실제 클래스 인스턴스를 참조하여 호출됩니다.

이것은 코드가 다음을 가질 때를 의미합니다.class MyClass그리고 당신은 인스턴스를 만듭니다.m = MyClass(), 호출m.do_something()다음과 같이 실행됩니다.MyClass.do_something(m).

또한 이 첫 번째 인수는 기술적으로 원하는 모든 것이라고 할 수 있지만 관례는 다음과 같습니다.self그리고 다른 사람(자신의 미래의 자신 포함)이 자신의 코드를 쉽게 읽을 수 있기를 원한다면 그 관습을 고수해야 합니다.

그 결과 전체 클래스 정의가 보이지 않더라도 구성원이 무엇인지에 대한 혼동이 전혀 없습니다.이로 인해 다음과 같은 유용한 속성이 발생합니다. 실수로 비회원을 그림자로 만들어 코드를 해제하는 멤버를 추가할 수 없습니다.

한 가지 극단적인 예: 클래스에 포함될 수 있는 기본 클래스에 대한 지식 없이 클래스를 작성할 수 있으며 항상 멤버에 액세스하는지 여부를 알 수 있습니다.

class A(some_function()):
  def f(self):
    self.member = 42
    self.method()

완전한 코드입니다! (some_function은 기본으로 사용된 형식을 반환합니다.)

클래스의 메소드가 동적으로 구성되는 또 다른 경우:

class B(object):
  pass

print B()
# <__main__.B object at 0xb7e4082c>

def B_init(self):
  self.answer = 42
def B_str(self):
  return "<The answer is %s.>" % self.answer
# notice these functions require no knowledge of the actual class
# how hard are they to read and realize that "members" are used?

B.__init__ = B_init
B.__str__ = B_str

print B()
# <The answer is 42.>

기억하세요, 이 두 가지 예는 모두 극단적이고 매일 볼 수 없을 것입니다. 그리고 저는 여러분이 종종 이렇게 코드를 작성해야 한다고 제안하는 것도 아니지만, 그들은 분명히 자신이 요구되는 측면을 보여줍니다.

이전 답변은 기본적으로 "할 수 없습니다" 또는 "하면 안 됩니다"의 변형입니다.저는 후자의 정서에 동의하지만, 그 질문은 기술적으로 여전히 답이 없습니다.

게다가, 실제 질문이 무엇을 요구하는지에 따라 누군가가 무언가를 하고 싶어할 수 있는 정당한 이유가 있습니다.제가 가끔 마주치는 것은 긴 수학 방정식입니다. 긴 이름을 사용하면 방정식을 인식할 수 없게 됩니다.다음은 통조림 예제에서 이 작업을 수행하는 몇 가지 방법입니다.

import numpy as np
class MyFunkyGaussian() :
    def __init__(self, A, x0, w, s, y0) :
        self.A = float(A)
        self.x0 = x0
        self.w = w
        self.y0 = y0
        self.s = s

    # The correct way, but subjectively less readable to some (like me) 
    def calc1(self, x) :
        return (self.A/(self.w*np.sqrt(np.pi))/(1+self.s*self.w**2/2)
                * np.exp( -(x-self.x0)**2/self.w**2)
                * (1+self.s*(x-self.x0)**2) + self.y0 )

    # The correct way if you really don't want to use 'self' in the calculations
    def calc2(self, x) :
        # Explicity copy variables
        A, x0, w, y0, s = self.A, self.x0, self.w, self.y0, self.s
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

    # Probably a bad idea...
    def calc3(self, x) :
        # Automatically copy every class vairable
        for k in self.__dict__ : exec(k+'= self.'+k)
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

g = MyFunkyGaussian(2.0, 1.5, 3.0, 5.0, 0.0)
print(g.calc1(0.5))
print(g.calc2(0.5))
print(g.calc3(0.5))

예 - 세번예 - 예: 사용을 사용합니다.for k in self.__dict__ : exec(k+'= self.'+k)기본적으로 질문이 실제로 요구하는 것이지만, 일반적으로 좋은 생각이라고 생각하지 않는다는 것을 분명히 말씀드리겠습니다.

클래스 변수 또는 함수를 통해 반복하는 방법에 대한 자세한 내용은 질문에 대한 답변 및 토론을 참조하십시오.변수 이름을 동적으로 지정하는 다른 방법과 이러한 방법이 일반적으로 좋지 않은 이유에 대한 자세한 내용은 이 블로그 게시물을 참조하십시오.

업데이트: Python3의 함수에서 로컬을 동적으로 업데이트하거나 변경할 수 있는 방법이 없으므로 calc3 및 유사한 변형은 더 이상 불가능합니다.내가 지금 생각할 수 있는 유일한 python3 호환 솔루션은 사용하는 것입니다.globals:

def calc4(self, x) :
        # Automatically copy every class variable in globals
        globals().update(self.__dict__)
        sqrt, exp, pi = np.sqrt, np.exp, np.pi
        return ( A/( w*sqrt(pi) )/(1+s*w**2/2)
                * exp( -(x-x0)**2/w**2 )
                * (1+s*(x-x0)**2) + y0 )

일반적으로 이것은 끔찍한 관행이 될 것입니다.

은 정로말.self이는 키워드가 아니라 Python에서 인스턴스 메서드의 첫 번째 매개 변수에 일반적으로 지정된 이름일 뿐입니다.첫 번째 매개 변수는 생략할 수 없습니다. 클래스의 어떤 인스턴스에 호출되는지 메서드가 알 수 있는 유일한 메커니즘이기 때문입니다.

예를 들어, 원하는 이름을 사용할 수 있습니다.

class test(object):
    def function(this, variable):
        this.variable = variable

아니 심지어는

class test(object):
    def function(s, variable):
        s.variable = variable

하지만 당신은 스코프의 이름을 사용해야 합니다.

저는 여러분이 설득력 있는 이유가 없는 한, 자신과 다른 것을 사용하는 것을 추천하지 않습니다. 왜냐하면 그것은 숙련된 파이썬티스타들에게 이질적인 것이 될 것이기 때문입니다.

예, 항지야합니를 지정해야 .self파이썬 철학에 따르면 명시적이 암시적보다 낫기 때문입니다.

또한 파이썬에서 프로그래밍하는 방법이 자바에서 프로그래밍하는 방법과 매우 다르다는 것을 알게 될 것이며, 따라서 의 사용.self개체 내부의 모든 것을 투영하지 않기 때문에 감소하는 경향이 있습니다.테스트를 더 잘 수행할 수 있는 모듈 수준 함수를 더 많이 사용합니다.

그나저나.처음에는 싫었지만 지금은 반대로 싫습니다.들여쓰기 방식 흐름 제어의 경우에도 동일합니다.

"self"는 클래스의 현재 개체 인스턴스의 일반적인 자리 표시자입니다."자체"를 참조하는 것처럼 클래스 내에서 개체의 속성이나 필드 또는 메서드를 참조할 때 사용됩니다.그러나 파이썬 프로그래밍 영역의 누군가가 "self"를 더 짧게 사용하기 위해 다른 영역에서는 "self"를 사용하지만 대체할 수 없는 키워드로 만듭니다.저는 오히려 코드 가독성을 높이기 위해 "its"를 사용했습니다.Python의 좋은 점 중 하나입니다. "self"가 아닌 객체의 인스턴스에 대한 자리 표시자를 자유롭게 선택할 수 있습니다.자기 자신에 대한 예:

class UserAccount():    
    def __init__(self, user_type, username, password):
        self.user_type = user_type
        self.username = username            
        self.password = encrypt(password)        

    def get_password(self):
        return decrypt(self.password)

    def set_password(self, password):
        self.password = encrypt(password)

이제 'self'를 'its'로 바꿉니다.

class UserAccount():    
    def __init__(its, user_type, username, password):
        its.user_type = user_type
        its.username = username            
        its.password = encrypt(password)        

    def get_password(its):
        return decrypt(its.password)

    def set_password(its, password):
        its.password = encrypt(password)

어느 것이 지금 더 읽기 쉽습니까?

시작: Self Hell - 더 상태 저장 기능.

...하이브리드 방식이 가장 효과적입니다.실제로 계산을 수행하는 모든 클래스 메소드는 폐쇄로 이동되어야 하며 구문 정리를 위한 확장은 클래스에 유지되어야 합니다.클래스를 네임스페이스처럼 처리하여 클래스에 폐쇄를 채웁니다.폐쇄는 본질적으로 정적 함수이므로 클래스에서조차 자체*를 필요로 하지 않습니다.

셀프는 객체의 멤버에 액세스하기 위한 파이썬 구문의 일부이기 때문에 당신이 그것을 고수하고 있는 것 같습니다.

실제로 Armin Ronacher 프레젠테이션 "5년간의 나쁜 아이디어"(구글링)의 "암묵적인 자아" 레시피를 사용할 수 있습니다.

Armin Ronacher의 거의 모든 것처럼 매우 영리한 요리법이지만, 저는 이 아이디어가 그다지 매력적이라고 생각하지 않습니다.저는 이것을 C#/Java로 명시하는 것을 선호합니다.

업데이트. "나쁜 아이디어 레시피" 링크: https://speakerdeck.com/mitsuhiko/5-years-of-bad-ideas?slide=58

여기서 나는 속성을 복사하기 위해 @argentum2f의 답변에서 아이디어를 따릅니다.이것은 장식가에 의해 자동화될 수 있으며 Python 3과 함께 작동합니다.물론 속성을 복사한다는 것은 속성을 변경할 수 없다는 것을 의미하므로 이름은@const_self장식가를 위한.

와 함께@const_self사용할 속성과 이름이 같은 첫 번째 인수를 사용하여 메서드를 정의하고 noself.

from cmath import sqrt

def const_self(fun):
    fun_args = fun.__code__.co_varnames[:fun.__code__.co_argcount]

    def fun_with_self(*args, **kwargs):
        self = args[0]
        other_args = list(args[1:])

        used_attributes = [arg for arg in fun_args if hasattr(self, arg)]
        self_args = [getattr(self, attr) for attr in used_attributes]

        return fun(*(self_args + other_args), **kwargs)

    return fun_with_self

class QuadraticEquation:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    @const_self
    def roots(a, b, c, dummy, lazy = False):
        print("Dummy is", dummy)
        if lazy: return # A lazy calculator does not calculate
        return (-b - sqrt(b**2 - 4*a*c)) /2/a, (-b + sqrt(b**2 - 4*a*c)) /2/a

물론 그 코드에서 많은 부분이 개선되어야 합니다.적어도 다음과 같은 방법을 정의하면 실패합니다.def fun(a, dummy, b, c): print(a,b,c)여기와 그것은 문서 문자열을 보존하지 않습니다.하지만 저는 그것이 그 생각을 충분히 잘 보여준다고 생각합니다.

네, 자아는 지루합니다.하지만, 그게 더 나은가요?

class Test:

    def __init__(_):
        _.test = 'test'

    def run(_):
        print _.test

언급URL : https://stackoverflow.com/questions/1984104/how-to-avoid-explicit-self-in-python

반응형