Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

Виклик метода класу з доступом до простору імен класу при побудові класу в Python

with 2 comments

Ось нарешті можливість застосувати метакласи! 😉

Власне те що мені було потрібно – це трошки скоротити код ініціалізації атрибутів класу, написавши функцію яка використовуючи вже ініціалізовані атрибути обчислює за ними нові. Справжній код я замінюю еквівалентим, але таки що демонструє пошук рішення:

class SelfUnconscious(object):
    knowledge = dict(
        life=42,
    )
    def reason(about):
        return knowledge.get(about, "don't know about %s" % about)

    sense = reason('life')

#Traceback (most recent call last):
#  File "class_scope.py", line 1, in <module>
#    class SelfUnconscious(object):
#  File "class_scope.py", line 8, in SelfUnconscious
#    sense = reason('life')
#  File "class_scope.py", line 6, in reason
#    return knowledge.get(about, "don't know about %s" % about)
#NameError: global name 'knowledge' is not defined

Хм, метод класу не бачить простір імен в який сам і попадає. Спробуємо передати як параметр.

class SelfUnconscious(object):
    knowledge = dict(
        life=42,
    )
    @classmethod
    def reason(cls, about):
        return cls.knowledge.get(about, "don't know about %s" % about)

    sense = reason('life')

# Traceback (most recent call last):
#   File "class_scope.py", line 1, in <module>
#     class SelfUnconscious(object):
#   File "class_scope.py", line 30, in SelfUnconscious
#     sense = reason('life')
# TypeError: 'classmethod' object is not callable

Хм, не можна викликати методи класу до того як буде завершено побудову цього класу. Шкода. При побудові їх все одно видно, але це зовсім і не методи. Цікаво то як…

class SelfUnconscious(object):
    knowledge = dict(
        life=42,
    )
    @classmethod
    def reason(cls, about):
        return SelfUnconscious.knowledge.get(about, "don't know about %s" % about)

    sense = SelfUnconscious.reason('life')

# Traceback (most recent call last):
#   File "class_scope.py", line 1, in <module>
#     class SelfUnconscious(object):
#   File "class_scope.py", line 45, in SelfUnconscious
#     sense = SelfUnconscious.reason('life')
# NameError: name 'SelfUnconscious' is not defined

Знову ж таки, немає ще цього класу.

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

class SelfUnconscious(object):
    knowledge = dict(
        life=42,
    )
    def reason(about, knowledge):
        return knowledge.get(about, "don't know about %s" % about)

    sense = reason('life', knowledge)

print(SelfUnconscious.sense)
# 42

Складніше коли атрибутів багато, і хочеться доступу до всіх. В такому разі таки можна використати метакласи. Метакласи це просто – це об’єкти, екземплярами яких є класи. Відповідно виклик цього об’єкту поверне нам клас. Можна почати з функції:


def run_init_method(cls):
    cls.class_init()
    return cls

@run_init_method
class SelfUnconscious(object):

    @classmethod
    def reason(cls, about):
        return cls.knowledge.get(about, "don't know about %s" % about)

    @classmethod
    def class_init(cls):
        cls.knowledge = dict(
            life=42,
        )
        cls.sense = cls.reason('life')

print(SelfUnconscious.sense)
# 42

Ах, все готово, метакласи таки справді в 99% випадків не потрібні. На роботі взагалі обійшовся явною передачею всіх атрибутів в мето. Але колись прийде час і я таки знатиму Python до кінця.

Advertisements

Written by bunyk

Вересень 8, 2012 at 22:30

Оприлюднено в Кодерство

Tagged with

Відповідей: 2

Subscribe to comments with RSS.

  1. [i]Але колись прийде час і я таки знатиму Python до кінця.[/i]
    — похвальне бажання) І чесно кажучи, після тієї ж Схеми, де мову справді можна розписати до кінця в одній книжці, іноді складно змиритись із думкою, що в деяких мовах просто банально багато фіч, як у тому ж Пітоні (у нього ж не така вже й лаконічна семантика?) чи Хаскелі, який також тривіально не реалізовується (хоч, думаю, варто подивитись на маленькі недоХаскелі, в яких код людської довжини). Успіхів)

    dmytrish

    Вересень 9, 2012 at 16:52

  2. А при чем тут метаклассы? Это просто декоратор, уже после создания класса вызывает у него какой-то метод. Метаклассы управляют самим процессом создания класса. Ваш вариант на метаклассах был бы таким (в минимальном варианте):

    def my_func_meta(name, bases, attrs):
        cls = type(name, bases, attrs)
        cls.class_init()
        return cls
    
    class X(object):
        @classmethod
        def class_init(cls):
            print "inited"
        
        __metaclass__ = my_func_meta
    

    koder

    Вересень 12, 2012 at 12:17


Залишити відповідь

Заповніть поля нижче або авторизуйтесь клікнувши по іконці

Лого WordPress.com

Ви коментуєте, використовуючи свій обліковий запис WordPress.com. Log Out / Змінити )

Twitter picture

Ви коментуєте, використовуючи свій обліковий запис Twitter. Log Out / Змінити )

Facebook photo

Ви коментуєте, використовуючи свій обліковий запис Facebook. Log Out / Змінити )

Google+ photo

Ви коментуєте, використовуючи свій обліковий запис Google+. Log Out / Змінити )

З’єднання з %s

%d блогерам подобається це: