Доступ до змінних-членів класу в Python?


83
class Example(object):
    def the_example(self):
        itsProblem = "problem"

theExample = Example()
print(theExample.itsProblem)

Як отримати доступ до змінної класу? Я спробував додати це визначення:

def return_itsProblem(self):
    return itsProblem

Однак і це не вдається.


1
Назва змінено, питання на самому справі про клас «статичний» змінні: stackoverflow.com/questions/707380 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

Відповіді:


139

Відповідь, кількома словами

У вашому прикладі itsProblemце локальна змінна.

Ви повинні використовувати selfдля встановлення та отримання змінних екземпляра. Ви можете встановити його в __init__методі. Тоді ваш код буде таким:

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

Але якщо вам потрібна справжня змінна класу, тоді безпосередньо використовуйте назву класу:

class Example(object):
    itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)
print (Example.itsProblem)

Але будьте обережні з цим, оскільки theExample.itsProblemвін автоматично встановлюється рівним Example.itsProblem, але зовсім не однаковою змінною і може бути змінений самостійно.

Деякі пояснення

У Python змінні можна створювати динамічно. Тому ви можете зробити наступне:

class Example(object):
    pass

Example.itsProblem = "problem"

e = Example()
e.itsSecondProblem = "problem"

print Example.itsProblem == e.itsSecondProblem 

відбитки

Правда

Тому це саме те, що ви робите з попередніми прикладами.

Справді, в Python ми використовуємо selfяк this, але це трохи більше, ніж це. selfє першим аргументом будь-якого об'єктного методу, оскільки перший аргумент завжди є посиланням на об'єкт. Це автоматично, незалежно від того, називаєте ви це selfчи ні.

Це означає, що ви можете зробити:

class Example(object):
    def __init__(self):
        self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

або:

class Example(object):
    def __init__(my_super_self):
        my_super_self.itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

Це точно те саме. Першим аргументом будь-якого об'єктного методу є поточний об'єкт, ми називаємо його лише selfяк домовленість. І ви додаєте до цього об’єкта просто змінну, так само, як це робили б зовні.

Тепер про змінні класу.

Коли ви робите:

class Example(object):
    itsProblem = "problem"


theExample = Example()
print(theExample.itsProblem)

Ви помітите, що ми спочатку встановлюємо змінну класу , а потім отримуємо доступ до змінної об’єкта (екземпляра) . Ми ніколи не встановлюємо цю змінну об'єкта, але вона працює, як це можливо?

Ну, Python намагається спочатку отримати змінну об’єкта, але якщо він не може її знайти, надасть вам змінну класу. Попередження: змінна класу ділиться між екземплярами, а змінна об’єкта - ні.

Як висновок, ніколи не використовуйте змінні класу, щоб встановлювати значення за замовчуванням для змінних об’єкта. Використовуйте __init__для цього.

Врешті-решт ви дізнаєтесь, що класи Python - це екземпляри і, отже, самі об'єкти, що дає нове розуміння розуміння вищезазначеного. Поверніться і прочитайте це ще раз пізніше, як тільки ви це зрозумієте.


ви говорите: "theExample.itsProblem автоматично встановлюється рівним Example.itsProblem, але зовсім не однакова змінна і може бути змінена самостійно" - але це не зовсім правильно, і ваша фраза вводить в оману. Я сподіваюся , ви знаєте , що там відбувається, тому я пропоную це перефразувати , що: «це є та ж змінна, але вона може бути rebinded незалежно для кожного об'єкта».
jsbueno

Так, але прив'язка - це абсолютно невідома концепція когось для іншої мови програмування, наприклад Java або C (як я підозрюю, OP). Тоді я хотів би пояснити, що таке прив’язка, то пізнє прив’язка, то проблема з посиланнями на змінні об’єкти. Це було б занадто довго. Думаю, колись ти повинен пожертвувати точністю на вівтарі розуміння.
e-satisfa

Існує також (я думаю, що це може бути 2,7+) декоратор @classmethod, на який варто заглянути. цікаве обговорення тут - stackoverflow.com/questions/12179271 / ...
JSH

1
зв’язування назв: я вважаю поганою ідеєю давати неправдиві твердження, незалежно від рівня. Я пропоную це невелике редагування: Але будьте обережні з цим, оскільки theExample.itsProblemвін автоматично встановлюється рівним Example.itsProblem, але, з практичної точки зору *, зовсім не однакова змінна і може бути змінений самостійно. *: насправді він починається як той самий об'єкт, але дуже легко випадково змінити це, якщо ви не розумієте прив'язки
імен

11

Ви оголошуєте локальну змінну, а не змінну класу. Щоб встановити змінну екземпляра (атрибут), використовуйте

class Example(object):
    def the_example(self):
        self.itsProblem = "problem"  # <-- remember the 'self.'

theExample = Example()
theExample.the_example()
print(theExample.itsProblem)

Щоб встановити змінну класу (він же статичний член), використовуйте

class Example(object):
    def the_example(self):
        Example.itsProblem = "problem"
        # or, type(self).itsProblem = "problem"
        # depending what you want to do when the class is derived.

1
За винятком того, що змінні класу оголошуються один раз на рівні класу . Ваш спосіб скине його при кожному випадку, це насправді не те, що ви хочете. Також див. Stackoverflow.com/questions/2709821/python-self-explained для обгрунтування аргументу явного self.

2

Якщо у вас є функція екземпляра (тобто та, яка передається self), ви можете використовувати self, щоб отримати посилання на клас, що використовує self.__class__

Наприклад, у коді нижче торнадо створює екземпляр для обробки запитів, але ми можемо взяти get_handlerклас і використовувати його для утримання клієнта riak, тому нам не потрібно створювати його для кожного запиту.

import tornado.web
import riak

class get_handler(tornado.web.requestHandler):
    riak_client = None

    def post(self):
        cls = self.__class__
        if cls.riak_client is None:
            cls.riak_client = riak.RiakClient(pb_port=8087, protocol='pbc')
        # Additional code to send response to the request ...
    

Це дуже хороший приклад для демонстрації запитання з оригінальної назви ОП. Насправді приклад OPs не відповідає назві, і інші відповіді посилаються на приклад. У будь-якому випадку, це найкращий спосіб отримати доступ до змінної рівня класу, оскільки він не порушує принцип DRY. Як і деякі інші приклади. Краще використовувати self .__ class__ замість повторення назви класу. Це робить код надійним, робить рефакторинг простішим, і якщо ви наважитеся використовувати підкласи, це також може мати переваги.
mit

Читачів слід попередити, що використання обробника, як описано вище, може призвести до проблем не тільки в непоточних програмах. Безліч екземплярів класу теоретично можуть використовувати один і той же обробник паралельно, і якщо обробник не призначений для цього, що залежить від його внутрішньої структури, він може не працювати. "Паралельно" в однопотоковій програмі означає, що екземпляр першого класу не закінчив використання обробника, а потім другий примірник починає використовувати обробник. У таких випадках можна порадити використовувати замість цього змінну екземпляра.
mit

0

Реалізуйте оператор return, як у прикладі нижче! Ви повинні бути хорошими. Сподіваюся, це комусь допоможе ..

class Example(object):
    def the_example(self):
        itsProblem = "problem"
        return itsProblem 


theExample = Example()
print theExample.the_example()

1
Вам слід виправити відступ коду. На це запитання також є чудові відповіді, і ваша відповідь є основною варіацією цих відповідей, а не альтернативним рішенням ...
HEADLESS_0NE
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.