Как избежать явного "я" в Python?
Я изучаю Python, следуя инструкциям pygame.
В этой связи я нашел широкое использование ключевого слова self и, исходя из основного фона Java, обнаружил, что я забываю вводить себя. Например, вместо self.rect.centerx
я бы набрал rect.centerx
, потому что для меня rect уже является переменной-членом класса.
Параллель Java, о которой я могу думать, для этой ситуации - это префикс всех ссылок на переменные-члены с этим.
Я застрял, префиксные все переменные-члены, или есть способ объявить их, что позволит мне избежать этого?
Даже если то, что я предлагаю, не является питоническим, мне все равно хотелось бы узнать, возможно ли это.
Я рассмотрел эти связанные вопросы SO, но они не совсем отвечают на то, что я хочу:
Ответы
Ответ 1
Python требует указать 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.>
Помните, что оба этих примера экстремальны, и вы не увидите их каждый день, и я не предлагаю вам часто писать такой код, но они явно показывают, что явные потребности явным образом требуются.
Ответ 2
Фактически self
не является ключевым словом, это просто имя, условно заданное первому параметру методов экземпляра в Python. И этот первый параметр не может быть пропущен, так как это единственный механизм, который метод знает о том, какой экземпляр вашего класса он вызывает.
Ответ 3
Вы можете использовать любое имя, которое вы хотите, например
class test(object):
def function(this, variable):
this.variable = variable
или даже
class test(object):
def function(s, variable):
s.variable = variable
но вы застряли в использовании имени для области.
Я не рекомендую использовать что-то другое для себя, если у вас нет убедительной причины, поскольку это сделало бы его чуждым для опытных питонистов.
Ответ 4
Предыдущие ответы - это в основном варианты "ты не можешь" или "ты не должен". Хотя я согласен с последним мнением, вопрос технически до сих пор остается без ответа.
Кроме того, есть законные причины, по которым кто-то может захотеть сделать что-то в соответствии с тем, что задает реальный вопрос. Иногда я сталкиваюсь с длинными математическими уравнениями, в которых использование длинных имен делает уравнение неузнаваемым. Вот несколько способов, как вы могли бы сделать это в стандартном примере:
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)
- это в основном то, о чем на самом деле просит вопрос, но позвольте мне прояснить, что я не думаю, что это вообще хорошая идея.
Для получения дополнительной информации и способов перебора переменных класса или даже функций см. ответы и обсуждение на этот вопрос. Для обсуждения других способов динамического именования переменных и почему это, как правило, не очень хорошая идея, смотрите этот пост в блоге.
Ответ 5
да, вы всегда должны указывать self
, потому что явное лучше, чем неявное, согласно философии python.
Вы также узнаете, что способ программирования в python сильно отличается от того, как вы программируете в java, поэтому использование self
имеет тенденцию к снижению, потому что вы не проецируете все внутри объекта. Скорее, вы больше используете функцию уровня модуля, которая может быть лучше протестирована.
Кстати, . Сначала я ненавидел его, теперь я ненавижу обратное. то же для управления потоком с отступом.
Ответ 6
self является частью синтаксиса python для доступа к элементам объектов, поэтому я боюсь, что вы застряли с ним
Ответ 7
"Я" является обычным заполнителем текущего экземпляра объекта класса. Его используют, когда вы хотите ссылаться на свойство объекта или поле или метод внутри класса, как будто вы имеете в виду "себя". Но чтобы сделать его короче, кто-то в области программирования Python начал использовать "я" , другие сферы используют "this", но они делают его ключевым словом, которое нельзя заменить. Я скорее использовал "его" для повышения удобочитаемости кода. Его одна из хороших вещей в 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)
Теперь мы заменяем "я" на "его":
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)
который теперь более читаем?
Ответ 8
Да, самость утомительна. Но, лучше?
class Test:
def __init__(_):
_.test = 'test'
def run(_):
print _.test
Ответ 9
На самом деле вы можете использовать рецепт "Неявное Я" из презентации Армина Ронахера "5 лет плохих идей" (Google google it).
Это очень умный рецепт, как и почти все от Армина Ронахера, но я не думаю, что эта идея очень привлекательна. Я думаю, что предпочел бы явное это в С#/Java.
Обновить. Ссылка на "рецепт плохой идеи": https://speakerdeck.com/mitsuhiko/5-years-of-bad-ideas?slide=58
Ответ 10
От: Self Hell - больше функций с сохранением состояния.
... гибридный подход работает лучше всего. Все ваши методы класса, которые на самом деле делать вычисления должны быть перемещены в замыкания, а расширения для очистки синтаксиса должны храниться в классах. Заполните замыкания на классы, рассматривая класс как пространство имен. Закрытие - это, по существу, статические функции, и поэтому не требуется selfs *, даже в классе...